From 9d0ba2bb3f808d1efe38bb289121ffa3433d8ef9 Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Mon, 21 Jan 2013 02:31:43 -0500
Subject: [PATCH] updated mrpeach externals and supporting defs, updated todo
 for syncing externals, updated makefile for mrpeach

---
 externals/mrpeach/midifile/midifile.c         | 170 ++++-
 externals/mrpeach/net/LICENSE.txt             | 676 ++++++++++++++++++
 externals/mrpeach/net/Makefile                | 410 +++++++++++
 externals/mrpeach/net/README.txt              |   7 +
 externals/mrpeach/net/{ => examples}/test.txt |   0
 externals/mrpeach/net/httpreceive-help.pd     | 104 +++
 externals/mrpeach/net/httpreceive.c           | 214 ++++++
 externals/mrpeach/net/httpreq-help.pd         | 104 +++
 externals/mrpeach/net/httpreq.c               | 176 +++++
 externals/mrpeach/net/net-meta.pd             |   6 +
 externals/mrpeach/net/tcpclient.c             | 164 +++--
 externals/mrpeach/net/tcpreceive.c            |   2 +-
 externals/mrpeach/net/tcpserver.c             |   8 +-
 externals/mrpeach/net/tcpsocket.FUDI-help.pd  |   4 +
 .../mrpeach/{osc => net}/tcpsocket.FUDI.pd    |   0
 externals/mrpeach/net/tcpsocket.OSC-help.pd   |   4 +
 externals/mrpeach/net/tcpsocket.OSC.pd        |  89 +++
 .../{osc => net}/tcpsocketserver-help.pd      | 600 ++++++++--------
 .../mrpeach/{osc => net}/tcpsocketserver.pd   | 217 +++---
 externals/mrpeach/net/udpreceive~-help.pd     |  88 +++
 externals/mrpeach/net/udpreceive~.c           |   6 +-
 externals/mrpeach/net/udpsend~.c              |   8 +-
 externals/mrpeach/osc/LICENSE.txt             |  16 +
 externals/mrpeach/osc/Makefile                | 392 +++++++++-
 externals/mrpeach/osc/README.txt              |  38 +
 externals/mrpeach/osc/osc-meta.pd             |   7 +
 externals/mrpeach/osc/packOSC.c               | 267 ++++---
 externals/mrpeach/osc/packingOSC.h            |  45 ++
 externals/mrpeach/osc/routeOSC.c              | 292 +++++---
 externals/mrpeach/osc/tcpsocket.OSC.pd        | 245 -------
 externals/mrpeach/osc/unpackOSC-help.pd       |  52 ++
 externals/mrpeach/osc/unpackOSC.c             |  63 +-
 externals/mrpeach/xbee/packxbee-help.pd       | 584 +++++++++++++++
 externals/mrpeach/xbee/packxbee.c             | 667 +++++++++++++++++
 externals/mrpeach/xbee/pdxbee.h               |  41 ++
 externals/mrpeach/xbee/unpackxbee.c           | 522 ++++++++++++++
 externals/pd-l2ork-TODO.txt                   |   1 +
 externals/pdp/include/pdp_config.h            |   2 +-
 38 files changed, 5235 insertions(+), 1056 deletions(-)
 create mode 100644 externals/mrpeach/net/LICENSE.txt
 create mode 100644 externals/mrpeach/net/Makefile
 create mode 100644 externals/mrpeach/net/README.txt
 rename externals/mrpeach/net/{ => examples}/test.txt (100%)
 create mode 100644 externals/mrpeach/net/httpreceive-help.pd
 create mode 100644 externals/mrpeach/net/httpreceive.c
 create mode 100644 externals/mrpeach/net/httpreq-help.pd
 create mode 100644 externals/mrpeach/net/httpreq.c
 create mode 100644 externals/mrpeach/net/net-meta.pd
 create mode 100644 externals/mrpeach/net/tcpsocket.FUDI-help.pd
 rename externals/mrpeach/{osc => net}/tcpsocket.FUDI.pd (100%)
 create mode 100644 externals/mrpeach/net/tcpsocket.OSC-help.pd
 create mode 100644 externals/mrpeach/net/tcpsocket.OSC.pd
 rename externals/mrpeach/{osc => net}/tcpsocketserver-help.pd (65%)
 rename externals/mrpeach/{osc => net}/tcpsocketserver.pd (70%)
 create mode 100644 externals/mrpeach/net/udpreceive~-help.pd
 create mode 100644 externals/mrpeach/osc/LICENSE.txt
 create mode 100644 externals/mrpeach/osc/README.txt
 create mode 100644 externals/mrpeach/osc/osc-meta.pd
 create mode 100644 externals/mrpeach/osc/packingOSC.h
 delete mode 100644 externals/mrpeach/osc/tcpsocket.OSC.pd
 create mode 100644 externals/mrpeach/osc/unpackOSC-help.pd
 create mode 100644 externals/mrpeach/xbee/packxbee-help.pd
 create mode 100644 externals/mrpeach/xbee/packxbee.c
 create mode 100644 externals/mrpeach/xbee/pdxbee.h
 create mode 100644 externals/mrpeach/xbee/unpackxbee.c

diff --git a/externals/mrpeach/midifile/midifile.c b/externals/mrpeach/midifile/midifile.c
index c36e80ab3..de87d1afc 100644
--- a/externals/mrpeach/midifile/midifile.c
+++ b/externals/mrpeach/midifile/midifile.c
@@ -62,7 +62,7 @@ typedef struct t_midifile
     size_t              total_time; /* current time for this MIDI file in delta_time units */
     t_atom              midi_data[3]; /* one MIDI packet as a list */
     t_outlet            *midi_list_outlet;
-    t_outlet            *bang_outlet;
+    t_outlet            *status_outlet;
     t_outlet            *total_time_outlet;
     FILE                *fP;
     FILE                *tmpFP;
@@ -109,6 +109,7 @@ static void *midifile_new(t_symbol *s, int argc, t_atom *argv);
 static void midifile_verbosity(t_midifile *x, t_floatarg verbosity);
 static void midifile_single_track(t_midifile *x, t_floatarg track);
 static void midifile_dump(t_midifile *x, t_floatarg track);
+static t_symbol *midifile_key_name(int sf, int mi);
 void midifile_setup(void);
 
 void midifile_setup(void)
@@ -175,8 +176,8 @@ static void *midifile_new(t_symbol *s, int argc, t_atom *argv)
     }
     x->midi_list_outlet = outlet_new(&x->x_obj, &s_list);
     x->total_time_outlet = outlet_new(&x->x_obj, &s_float); /* current total_time */
-    x->bang_outlet = outlet_new(&x->x_obj, &s_bang); /* bang at end of file */
-    post("midifile 2008 Martin Peach");
+    x->status_outlet = outlet_new(&x->x_obj, &s_anything);/* last outlet for everything else */
+    post("midifile 20110212 by Martin Peach");
     return (void *)x;
 }
 
@@ -266,7 +267,7 @@ static void midifile_flush(t_midifile *x)
 
     if(x->state != mfWriting) return; /* only if we're writing */
 
-    outlet_bang(x->bang_outlet); /* bang so tick count can be saved externally */
+    outlet_bang(x->status_outlet); /* bang so tick count can be saved externally */
     midifile_write_end_of_track(x, end_time);
     written = midifile_write_header(x);
 /* now copy the MIDI data from tmpFP to fP */
@@ -413,7 +414,7 @@ static void midifile_bang(t_midifile *x)
             { /* set ended flag, only bang once */
                 if (x->verbosity > 1)
                     post ("ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks);
-                outlet_bang(x->bang_outlet);
+                outlet_bang(x->status_outlet);
                 ++x->ended;
             }
             /* fall through into mfWriting */
@@ -460,7 +461,7 @@ static void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv)
                     written = midifile_write_variable_length_value(x->tmpFP, x->track_chunk[0].delta_time);
                     dt_written = 1;
                 }
-                if (j == x->track_chunk[0].running_status) continue;/* don't save redundant status byte */
+                //if (j == x->track_chunk[0].running_status) continue;/* don't save redundant status byte */
                 if (j >= 0x80 && j <= 0xEF)x->track_chunk[0].running_status = j;/* new running status */
                 else if (j >= 0xF0 && j <= 0xF7)
                 {
@@ -560,7 +561,7 @@ static void midifile_float(t_midifile *x, t_float ticks)
             {
                 if (x->verbosity)
                     post ("midifile: ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks);
-                outlet_bang(x->bang_outlet);
+                outlet_bang(x->status_outlet);
             }
             break;
         case mfWriting: /* add ticks to current time */
@@ -590,6 +591,7 @@ static int midifile_read_header_chunk(t_midifile *x)
     char    buf[4];
     size_t  n;
     int     div, smpte, ticks;
+    t_atom  output_atom;
 
     if (x->fP == NULL)
     {
@@ -649,6 +651,8 @@ static int midifile_read_header_chunk(t_midifile *x)
             sP = "Unknown format";
     }
     if (x->verbosity) post("midifile: Header chunk format: %d (%s)", x->header_chunk.chunk_format, sP);
+    SETFLOAT(&output_atom, x->header_chunk.chunk_format);
+    outlet_anything( x->status_outlet, gensym("format"), 1, &output_atom);
 
     n = fread(cP, 1L, 2L, x->fP);
     x->offset += n;
@@ -659,6 +663,8 @@ static int midifile_read_header_chunk(t_midifile *x)
     }
     x->header_chunk.chunk_ntrks = midifile_get_multibyte_2(cP);
     if (x->verbosity) post("midifile: Header chunk ntrks: %d", x->header_chunk.chunk_ntrks);
+    SETFLOAT(&output_atom, x->header_chunk.chunk_ntrks);
+    outlet_anything( x->status_outlet, gensym("tracks"), 1, &output_atom);
     if (x->header_chunk.chunk_ntrks > MAX_TRACKS)
     {
         error ("midifile: Header chunk ntrks (%d) exceeds midifile MAX_TRACKS, set to %d",
@@ -680,8 +686,18 @@ static int midifile_read_header_chunk(t_midifile *x)
         ticks = div & 0x0FF;
         if (x->verbosity)
             post("midifile: Header chunk division: 0x%X: %d frames per second, %d ticks per frame", div, smpte, ticks);
+        SETFLOAT(&output_atom, smpte);
+        outlet_anything( x->status_outlet, gensym("frames_per_sec"), 1, &output_atom);
+        SETFLOAT(&output_atom, ticks);
+        outlet_anything( x->status_outlet, gensym("ticks_per_frame"), 1, &output_atom);
+    }
+    else
+    {
+        if (x->verbosity)
+            post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div);
+        SETFLOAT(&output_atom, div);
+        outlet_anything( x->status_outlet, gensym("ticks_per_quarternote"), 1, &output_atom);
     }
-    else if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div);
     return 1;
 }
 
@@ -1162,8 +1178,11 @@ static void midifile_get_next_track_chunk_data(t_midifile *x, int mfindex)
     size_t          delta_time, time_sig, len, i;
     unsigned char   status, c, d, nn, dd, cc, bb, mi, mcp, n;
     char            sf;
+    char            fps, hour, min, sec, frame, subframe;
+
     unsigned short  sn;
     unsigned char   tt[3];
+    t_atom          output_atom[6];
 
     cP = x->track_chunk[mfindex].track_data + x->track_chunk[mfindex].track_index;
     last_cP = x->track_chunk[mfindex].track_data + x->track_chunk[mfindex].chunk_length;
@@ -1220,13 +1239,24 @@ static void midifile_get_next_track_chunk_data(t_midifile *x, int mfindex)
                     x->midi_data[0].a_w.w_float = status;
                     outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data);
                     break;
-                case 0xFF:
+                case 0xFF: /* meta event */
                     c = *cP++;
                     cP = midifile_read_var_len(cP, &len);/* meta length */
                     if (x->verbosity) post("midifile: Track %d Meta: %02X length %lu", mfindex, c, len);
                     switch (c)
                     {
-                        case 0x58:
+                        case 0x59: /* key signature */
+                            sf = *(signed char *)cP++;
+                            mi = *cP++;
+                            if (x->verbosity)
+                                post ("midifile: Key Signature: %d %s, %s",
+                                    sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major");
+                            SETFLOAT(&output_atom[0], sf);
+                            SETFLOAT(&output_atom[1], mi);
+                            SETSYMBOL(&output_atom[2], midifile_key_name(sf, mi));
+                            outlet_anything( x->status_outlet, gensym("key_sig"), 3, output_atom);
+                            break;
+                        case 0x58: /* time signature */
                             nn = *cP++;
                             dd = *cP++;
                             dd = 1<<(dd);
@@ -1235,87 +1265,150 @@ static void midifile_get_next_track_chunk_data(t_midifile *x, int mfindex)
                             if (x->verbosity)
                                 post ("midifile: Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarternote",
                                     nn, dd, cc, bb);
+                            SETFLOAT(&output_atom[0], nn);
+                            SETFLOAT(&output_atom[1], dd);
+                            SETFLOAT(&output_atom[2], cc);
+                            SETFLOAT(&output_atom[3], bb);
+                            outlet_anything( x->status_outlet, gensym("time_sig"), 4, output_atom);
                             break;
-                        case 0x59:
-                            sf = *(signed char *)cP++;
-                            mi = *cP++;
-                            if (x->verbosity)
-                                post ("midifile: Key Signature: %d %s, %s",
-                                    sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major");
+                        case 0x54: /* smpte  offset */
+                            hour = *cP++; /* hour is mixed with fps as 0ffhhhhhh */
+                            switch (hour>>6)
+                            {
+                                case 0:
+                                    fps = 24;
+                                    break;
+                                case 1:
+                                    fps = 25;
+                                    break;
+                                case 2:
+                                    fps = 29;/* 30 fps dropframe */
+                                    break;
+                                case 3:
+                                    fps = 30;
+                                default:
+                                    fps = 0; /* error */
+                            }
+                            hour = hour & 0x3F;
+                            min = *cP++;
+                            sec = *cP++;
+                            frame = *cP++;
+                            subframe = *cP++;
+                            if (x->verbosity) post ("midifile: %lu SMPTE offset: %d:%d:%d:%d:%d, %d fps", hour, min, sec, frame, subframe, fps);
+                            SETFLOAT(&output_atom[0], hour);
+                            SETFLOAT(&output_atom[1], min);
+                            SETFLOAT(&output_atom[2], sec);
+                            SETFLOAT(&output_atom[3], frame);
+                            SETFLOAT(&output_atom[4], subframe);
+                            SETFLOAT(&output_atom[5], fps);
+                            outlet_anything( x->status_outlet, gensym("smpte"), 6, output_atom);
                             break;
-                        case 0x51:
+                        case 0x51: /* set tempo */
                             tt[0] = *cP++;
                             tt[1] = *cP++;
                             tt[2] = *cP++;
                             time_sig = midifile_get_multibyte_3(tt);
                             if (x->verbosity) post ("midifile: %lu microseconds per MIDI quarter-note", time_sig);
+                            SETFLOAT(&output_atom[0], time_sig);
+                            outlet_anything( x->status_outlet, gensym("microsec_per_quarternote"), 1, output_atom);
                             break;
-                        case 0x2F:
+                        case 0x2F: /* end of track */
                             if (x->verbosity) post ("midifile: End of Track %d", mfindex);
                             delta_time = NO_MORE_ELEMENTS;
+                            SETFLOAT(&output_atom[0], mfindex);
+                            SETFLOAT(&output_atom[1], x->total_time);
+                            outlet_anything( x->status_outlet, gensym("end"), 2, output_atom);
                             cP += len;
                             break;
                         case 0x21:
                             tt[0] = *cP++;
                             if (x->verbosity) post ("midifile: MIDI port or cable number (unofficial): %d", tt[0]);
                             break;
-                        case 0x20:
+                        case 0x20: /* MIDI channel prefix */
                             mcp = *cP++;
                             if (x->verbosity) post ("midifile: MIDI Channel Prefix: %d", mcp);
+                            SETFLOAT(&output_atom[0], mfindex);
+                            SETFLOAT(&output_atom[1], mcp);
+                            outlet_anything( x->status_outlet, gensym("channel"), 2, output_atom);
                             break;
-                        case 0x06:
+                        case 0x07: /* cue point */
+                            str = cP;
+                            c = cP[len];
+                            cP[len] = '\0'; /* null terminate temporarily */
+                            if (x->verbosity) post ("midifile: Cue Point: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("cue"), 1, output_atom);
+                            cP[len] = c;
+                            cP += len;
+                            break;
+                        case 0x06: /* marker */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Marker: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("marker"), 1, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x05:
+                        case 0x05: /* lyrics */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Lyric: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("lyrics"), 1, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x04:
+                        case 0x04: /* instrument name */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Instrument Name: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("instr_name"), 1, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x03:
+                        case 0x03: /* sequence/track name */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Sequence/Track Name: %s", str);
+                            SETFLOAT(&output_atom[0], mfindex);
+                            SETSYMBOL(&output_atom[1], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("name"), 2, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x02:
+                        case 0x02:/* copyright notice */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Copyright Notice: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("copyright"), 1, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x01:
+                        case 0x01: /* text event */
                             str = cP;
                             c = cP[len];
                             cP[len] = '\0'; /* null terminate temporarily */
                             if (x->verbosity) post ("midifile: Text Event: %s", str);
+                            SETSYMBOL(&output_atom[0], gensym(str));
+                            outlet_anything( x->status_outlet, gensym("text"), 1, output_atom);
                             cP[len] = c;
                             cP += len;
                             break;
-                        case 0x00:
+                        case 0x00: /* sequence number */
                             tt[0] = *cP++;
                             tt[1] = *cP++;
                             sn = midifile_get_multibyte_2(tt);
                             if (x->verbosity) post ("midifile: Sequence Number %d", sn);
+                            SETFLOAT(&output_atom[0], sn);
+                            outlet_anything( x->status_outlet, gensym("seq_num"), 1, output_atom);
                             break;
                         default:
                             if (x->verbosity) post ("midifile: Unknown: %02X", c);
@@ -1463,4 +1556,29 @@ static void midifile_skip_next_track_chunk_data(t_midifile *x, int mfindex)
     else x->track_chunk[mfindex].total_time += delta_time;
 }
 
+static t_symbol *midifile_key_name(int sf, int mi)
+{
+    /* set a symbole to the key name baseed on */
+    /* sf= number of sharps if positive, else flats
+    /* mi = 0=major 1= minor */
+    char    *maj_key[15]={"B",  "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A",  "E",  "B",  "F#", "Db"};
+    char    *min_key[15]={"G#", "Eb", "Bb", "F",  "C",  "G",  "D", "A", "E", "B", "F#", "C#", "G#", "D#", "Bb"};
+    char    buf[8] = {"no_key."};
+    int     i;
+
+    if ((sf >= -7)&&(sf <= 7))
+    {
+        if (mi == 1)
+        {
+            i = sprintf(buf, "%s", min_key[sf+7]);
+            sprintf(buf+i, "%s", "Minor");
+        }
+        else if (mi == 0)
+        {
+            i = sprintf(buf, "%s", maj_key[sf+7]);
+            sprintf(buf+i, "%s", "Major");
+        }
+    }
+    return gensym(buf);
+}
 /* fin midifile.c */
diff --git a/externals/mrpeach/net/LICENSE.txt b/externals/mrpeach/net/LICENSE.txt
new file mode 100644
index 000000000..443254047
--- /dev/null
+++ b/externals/mrpeach/net/LICENSE.txt
@@ -0,0 +1,676 @@
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+ 
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/externals/mrpeach/net/Makefile b/externals/mrpeach/net/Makefile
new file mode 100644
index 000000000..778403cdd
--- /dev/null
+++ b/externals/mrpeach/net/Makefile
@@ -0,0 +1,410 @@
+## Pd library template version 1.0.11
+# For instructions on how to use this template, see:
+#  http://puredata.info/docs/developer/MakefileTemplate
+LIBRARY_NAME = net
+
+# add your .c source files, one object per file, to the SOURCES
+# variable, help files will be included automatically, and for GUI
+# objects, the matching .tcl file too
+SOURCES = httpreceive.c httpreq.c tcpclient.c tcpreceive.c tcpsend.c tcpserver.c udpreceive.c udpreceive~.c udpsend.c udpsend~.c
+
+# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
+# be included automatically
+PDOBJECTS = tcpsocket.FUDI.pd tcpsocket.OSC.pd tcpsocketserver.pd
+
+# example patches and related files, in the 'examples' subfolder
+EXAMPLES = test.txt
+
+# manuals and related files, in the 'manual' subfolder
+MANUAL = 
+
+# if you want to include any other files in the source and binary tarballs,
+# list them here.  This can be anything from header files, test patches,
+# documentation, etc.  README.txt and LICENSE.txt are required and therefore
+# automatically included
+EXTRA_DIST = 
+
+
+
+#------------------------------------------------------------------------------#
+#
+# things you might need to edit if you are using other C libraries
+#
+#------------------------------------------------------------------------------#
+
+ALL_CFLAGS = -I"$(PD_INCLUDE)"
+ALL_LDFLAGS =  
+SHARED_LDFLAGS =
+ALL_LIBS = 
+
+
+#------------------------------------------------------------------------------#
+#
+# you shouldn't need to edit anything below here, if we did it right :)
+#
+#------------------------------------------------------------------------------#
+
+# these can be set from outside without (usually) breaking the build
+CFLAGS = -Wall -W -g
+LDFLAGS =
+LIBS =
+
+# get library version from meta file
+LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
+
+ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"'
+
+PD_INCLUDE = $(PD_PATH)/include/pd
+# where to install the library, overridden below depending on platform
+prefix = /usr/local
+libdir = $(prefix)/lib
+pkglibdir = $(libdir)/pd-externals
+objectsdir = $(pkglibdir)
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -p -m 644
+INSTALL_DATA = $(INSTALL) -p -m 644
+INSTALL_DIR     = $(INSTALL) -p -m 755 -d
+
+ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
+	         $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
+
+DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
+ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
+
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Darwin)
+  CPU := $(shell uname -p)
+  ifeq ($(CPU),arm) # iPhone/iPod Touch
+    SOURCES += $(SOURCES_iphoneos)
+    EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
+    OS = iphoneos
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
+    CC=$(IPHONE_BASE)/gcc
+    CPP=$(IPHONE_BASE)/cpp
+    CXX=$(IPHONE_BASE)/g++
+    ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
+    IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
+    OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
+    ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS)
+    ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
+    SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT)
+    ALL_LIBS += -lc $(LIBS_iphoneos)
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+  else # Mac OS X
+    SOURCES += $(SOURCES_macosx)
+    EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
+    OS = macosx
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast
+# build universal 32-bit on 10.4 and 32/64 on newer
+    ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
+      FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4
+    else
+      FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+      SOURCES += $(SOURCES_iphoneos)
+    endif
+    ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include
+    # if the 'pd' binary exists, check the linking against it to aid with stripping
+    BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd)
+    ALL_LDFLAGS += $(FAT_FLAGS) -bundle $(BUNDLE_LOADER) -undefined dynamic_lookup -L/sw/lib
+    SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \
+	-install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0
+    ALL_LIBS += -lc $(LIBS_macosx)
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
+    pkglibdir=$(HOME)/Library/Pd
+  endif
+endif
+# Tho Android uses Linux, we use this fake uname to provide an easy way to
+# setup all this things needed to cross-compile for Android using the NDK
+ifeq ($(UNAME),ANDROID)
+  CPU := arm
+  SOURCES += $(SOURCES_android)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = android
+  PD_PATH = /usr
+  NDK_BASE := /usr/local/android-ndk
+  NDK_PLATFORM_VERSION := 5
+  NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm
+  NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+  NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86
+  CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  CFLAGS += 
+  LDFLAGS += -rdynamic -shared
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  LIBS += -lc $(LIBS_android)
+  STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
+	--strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),Linux)
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU)
+  # GNU/Hurd, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU/kFreeBSD)
+  # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_cygwin)
+  EXTENSION = dll
+  SHARED_EXTENSION = dll
+  OS = cygwin
+  PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += 
+  ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc -lpd $(LIBS_cygwin)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_windows)
+  EXTENSION = dll
+  SHARED_EXTENSION = dll
+  OS = windows
+  PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd)
+  # MinGW doesn't seem to include cc so force gcc
+  CC=gcc
+  OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -mms-bitfields
+  ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj"
+  SHARED_LDFLAGS += -shared
+  ALL_LIBS += -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 $(LIBS_windows)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+
+# in case somebody manually set the HELPPATCHES above
+HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
+
+ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS)
+ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS)
+ALL_LIBS := $(LIBS) $(ALL_LIBS)
+
+SHARED_SOURCE ?= $(shell test ! -e lib$(LIBRARY_NAME).c || \
+	echo lib$(LIBRARY_NAME).c )
+SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h)
+SHARED_LIB = $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION))
+
+.PHONY = install libdir_install single_install install-doc install-examples install-manual clean distclean dist etags $(LIBRARY_NAME)
+
+all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB)
+
+%.o: %.c
+	$(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c"
+
+%.$(EXTENSION): %.o $(SHARED_LIB)
+	$(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o"  $(ALL_LIBS) $(SHARED_LIB)
+	chmod a-x "$*.$(EXTENSION)"
+
+# this links everything into a single binary file
+$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o
+	$(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS)
+	chmod a-x $(LIBRARY_NAME).$(EXTENSION)
+
+$(SHARED_LIB): $(SHARED_SOURCE:.c=.o)
+	$(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(LIBS)
+
+install: libdir_install
+
+# The meta and help files are explicitly installed to make sure they are
+# actually there.  Those files are not optional, then need to be there.
+libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
+		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES))" || (\
+		$(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \
+		$(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION))))
+	test -z "$(strip $(SHARED_LIB))" || \
+		$(INSTALL_DATA) $(SHARED_LIB) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+
+# install library linked as single binary
+single_install: $(LIBRARY_NAME) install-doc install-examples install-manual
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+
+install-doc:
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
+	$(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
+
+install-examples:
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
+		done
+
+install-manual:
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
+		done
+
+
+clean:
+	-rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o)
+	-rm -f -- $(SOURCES:.c=.$(EXTENSION))
+	-rm -f -- $(LIBRARY_NAME).o
+	-rm -f -- $(LIBRARY_NAME).$(EXTENSION)
+	-rm -f -- $(SHARED_LIB)
+
+distclean: clean
+	-rm -f -- $(DISTBINDIR).tar.gz
+	-rm -rf -- $(DISTBINDIR)
+	-rm -f -- $(DISTDIR).tar.gz
+	-rm -rf -- $(DISTDIR)
+	-rm -f -- $(ORIGDIR).tar.gz
+	-rm -rf -- $(ORIGDIR)
+
+
+$(DISTBINDIR):
+	$(INSTALL_DIR) $(DISTBINDIR)
+
+libdir: all $(DISTBINDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
+	$(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR)
+	$(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTBINDIR)
+#	tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
+
+$(DISTDIR):
+	$(INSTALL_DIR) $(DISTDIR)
+
+$(ORIGDIR):
+	$(INSTALL_DIR) $(ORIGDIR)
+
+dist: $(DISTDIR)
+	$(INSTALL_DATA) Makefile  $(DISTDIR)
+	$(INSTALL_DATA) README.txt $(DISTDIR)
+	$(INSTALL_DATA) LICENSE.txt $(DISTDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
+	test -z "$(strip $(ALLSOURCES))" || \
+		$(INSTALL_DATA) $(ALLSOURCES)  $(DISTDIR)
+	test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl))  $(DISTDIR)
+	test -z "$(strip $(SHARED_HEADER))" || \
+		$(INSTALL_DATA) $(SHARED_HEADER)  $(DISTDIR)
+	test -z "$(strip $(SHARED_SOURCE))" || \
+		$(INSTALL_DATA) $(SHARED_SOURCE)  $(DISTDIR)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS)  $(DISTDIR)
+	test -z "$(strip $(HELPPATCHES))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTDIR)
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DISTDIR)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
+		done
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DISTDIR)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
+		done
+	tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
+
+# make a Debian source package
+dpkg-source:
+	debclean
+	make distclean dist
+	mv $(DISTDIR) $(ORIGDIR)
+	tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
+	rm -f -- $(DISTDIR).tar.gz
+	rm -rf -- $(DISTDIR) $(ORIGDIR)
+	cd .. && dpkg-source -b $(LIBRARY_NAME)
+
+etags:
+	etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h
+
+showsetup:
+	@echo "CC: $(CC)"
+	@echo "CFLAGS: $(CFLAGS)"
+	@echo "LDFLAGS: $(LDFLAGS)"
+	@echo "LIBS: $(LIBS)"
+	@echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+	@echo "ALL_LDFLAGS: $(ALL_LDFLAGS)"
+	@echo "ALL_LIBS: $(ALL_LIBS)"
+	@echo "PD_INCLUDE: $(PD_INCLUDE)"
+	@echo "PD_PATH: $(PD_PATH)"
+	@echo "objectsdir: $(objectsdir)"
+	@echo "LIBRARY_NAME: $(LIBRARY_NAME)"
+	@echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
+	@echo "SOURCES: $(SOURCES)"
+	@echo "SHARED_HEADER: $(SHARED_HEADER)"
+	@echo "SHARED_SOURCE: $(SHARED_SOURCE)"
+	@echo "SHARED_LIB: $(SHARED_LIB)"
+	@echo "PDOBJECTS: $(PDOBJECTS)"
+	@echo "ALLSOURCES: $(ALLSOURCES)"
+	@echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))"
+	@echo "UNAME: $(UNAME)"
+	@echo "CPU: $(CPU)"
+	@echo "pkglibdir: $(pkglibdir)"
+	@echo "DISTDIR: $(DISTDIR)"
+	@echo "ORIGDIR: $(ORIGDIR)"
diff --git a/externals/mrpeach/net/README.txt b/externals/mrpeach/net/README.txt
new file mode 100644
index 000000000..1c590f537
--- /dev/null
+++ b/externals/mrpeach/net/README.txt
@@ -0,0 +1,7 @@
+A collection of network objects for Pure Data.
+For more info see http://puredata.org
+or
+http://sourceforge.net/projects/pure-data/
+Bugs and feature requests should be filed at http://sourceforge.net/tracker/?group_id=55736
+Send questions to the mailing list at http://lists.puredata.info/listinfo/pd-list
+
diff --git a/externals/mrpeach/net/test.txt b/externals/mrpeach/net/examples/test.txt
similarity index 100%
rename from externals/mrpeach/net/test.txt
rename to externals/mrpeach/net/examples/test.txt
diff --git a/externals/mrpeach/net/httpreceive-help.pd b/externals/mrpeach/net/httpreceive-help.pd
new file mode 100644
index 000000000..5dc140a51
--- /dev/null
+++ b/externals/mrpeach/net/httpreceive-help.pd
@@ -0,0 +1,104 @@
+#N canvas 525 51 712 894 10;
+#X obj 119 146 httpreq;
+#X obj 44 56 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X msg 84 94 GET http://132.205.142.12/index.php;
+#X obj 136 309 unpack 0 0 0 0;
+#X floatatom 136 332 3 0 0 0 - - -;
+#X floatatom 163 332 3 0 0 0 - - -;
+#X floatatom 190 332 3 0 0 0 - - -;
+#X floatatom 217 332 3 0 0 0 - - -;
+#X text 81 350 from;
+#X obj 119 257 tcpclient;
+#X obj 153 283 tgl 15 0 empty empty connected 18 7 0 8 -24198 -13381
+-1 0 1;
+#X text 190 256 tcpclient opens a tcp socket to send and receive bytes
+on;
+#X floatatom 270 342 9 0 0 0 - - -;
+#X floatatom 313 320 9 0 0 0 - - -;
+#X text 382 319 Size of the send buffer;
+#X obj 270 274 route sent buf blocked;
+#X text 340 341 Number of bytes sent;
+#X obj 356 298 print sender_blocked!;
+#X msg 85 206 connect 132.205.142.12 80;
+#X obj 119 450 httpreceive;
+#X floatatom 182 483 5 0 0 0 - - -;
+#X symbolatom 150 642 10 0 0 0 - - -;
+#X obj 150 620 prepend set;
+#X symbolatom 216 600 50 0 0 0 - - -;
+#X obj 216 578 prepend set;
+#X obj 150 526 route reason Date Content-Length Content-Type;
+#X symbolatom 350 568 50 0 0 0 - - -;
+#X obj 350 546 prepend set;
+#X floatatom 283 558 5 0 0 0 - - -;
+#X msg 64 74 GET http://132.205.142.12/nothing;
+#X msg 44 165 dump \$1;
+#X obj 44 139 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 37 328 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1
+0 1;
+#X msg 37 351 verbosity \$1;
+#X obj 457 543 print more_status;
+#X obj 76 392 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X text 515 726 Author: Martin Peach;
+#X text 515 743 Date: 2011/01/13;
+#X text 224 481 The right outlet is the status code.;
+#X text 166 693 The left outlet is the message body as a list of bytes
+;
+#X text 154 505 The middle outlet is the status header as name/value
+pairs;
+#X obj 119 693 spigot;
+#X obj 119 723 print message_body;
+#X obj 152 671 tgl 15 0 empty empty printing_long_messages_can_hang_Pd
+17 7 0 10 -4034 -257985 -1 0 1;
+#X text 175 147 [httpreq] sends an HTTP/1.1 request as a list of bytes
+(actually float atoms) \, suitable for [tcpclient];
+#X text 195 444 [htpreceive] expects an HTTP/1.1 response as one or
+more lists of bytes.;
+#X text 187 557 message length:;
+#X obj 27 14 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1
+1 1;
+#X msg 27 37 verbosity \$1;
+#X msg 105 115 HEAD http://132.205.142.12/index.php;
+#X text 175 185 So far only GET and HEAD requests are supported;
+#X text 274 73 should return 404 not found;
+#X text 306 93 should return a web page;
+#X text 332 114 should return only the metainformation;
+#X connect 0 0 9 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 3 1 5 0;
+#X connect 3 2 6 0;
+#X connect 3 3 7 0;
+#X connect 9 0 19 0;
+#X connect 9 1 3 0;
+#X connect 9 2 10 0;
+#X connect 9 3 15 0;
+#X connect 15 0 12 0;
+#X connect 15 1 13 0;
+#X connect 15 2 17 0;
+#X connect 18 0 9 0;
+#X connect 19 0 41 0;
+#X connect 19 1 25 0;
+#X connect 19 2 20 0;
+#X connect 22 0 21 0;
+#X connect 24 0 23 0;
+#X connect 25 0 22 0;
+#X connect 25 1 24 0;
+#X connect 25 2 28 0;
+#X connect 25 3 27 0;
+#X connect 25 4 34 0;
+#X connect 27 0 26 0;
+#X connect 29 0 0 0;
+#X connect 30 0 9 0;
+#X connect 31 0 30 0;
+#X connect 32 0 33 0;
+#X connect 33 0 19 0;
+#X connect 35 0 19 0;
+#X connect 41 0 42 0;
+#X connect 43 0 41 1;
+#X connect 47 0 48 0;
+#X connect 48 0 0 0;
+#X connect 49 0 0 0;
diff --git a/externals/mrpeach/net/httpreceive.c b/externals/mrpeach/net/httpreceive.c
new file mode 100644
index 000000000..6b8d17152
--- /dev/null
+++ b/externals/mrpeach/net/httpreceive.c
@@ -0,0 +1,214 @@
+/* httpreceive.c Started by Martin Peach 20110111 */
+/* httpreceive will process http 1.1 responses received as lists of bytes from something like [tcpclient] */
+/* See http://www.w3.org/Protocols/rfc2616/rfc2616.html */
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+
+static t_class *httpreceive_class;
+
+#define STATUS_BUF_LEN 4096 /* how big can the status part get? */
+
+typedef struct _httpreceive
+{
+    t_object    x_obj;
+    t_outlet    *x_status_out;
+    t_outlet    *x_message_out;
+    t_outlet    *x_statuscode_out;
+    int         x_state;
+    int         x_remaining;
+    int         x_verbosity;
+    char        *x_status_buf;
+    size_t      x_status_buf_len;
+    int         x_status_buf_write_index;
+} t_httpreceive;
+
+#define MAX_GETSTRING 256
+
+static void httpreceive_bang(t_httpreceive *x);
+static void httpreceive_list(t_httpreceive *x, t_symbol *s, int argc, t_atom *argv);
+static void httpreceive_verbosity(t_httpreceive *x, t_floatarg verbosity);
+static void httpreceive_free (t_httpreceive *x);
+static void *httpreceive_new (void);
+void httpreceive_setup(void);
+
+static void httpreceive_bang(t_httpreceive *x)
+{
+  post("httpreceive_bang %p", x);
+}
+
+static void httpreceive_list(t_httpreceive *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int     i, j, k, m, n, message_len = 0;
+    char    buf[256];
+    t_atom  status_list[2];
+
+    /* first check that all the atoms are integer floats on 0-255 */
+    for (i = 0; i < argc; ++i)
+    {
+        if (argv[i].a_type != A_FLOAT)
+        {
+            pd_error(x, "list element %d is not a float", i);
+            return;
+        }
+        j = argv[i].a_w.w_float;
+        if (j != argv[i].a_w.w_float)
+        {
+            pd_error(x, "list element %d is not an integer", i);
+            return;
+        }
+        if ((j < -128) || (j > 255))
+        {
+            pd_error(x, "list element %d is not on [0...255]", i);
+            return;
+        }
+    }
+    if (x->x_verbosity) post ("httpreceive_list %d elements, x_state %d x_remaining %d", i, x->x_state, x->x_remaining);
+
+ 
+    for (i = 0; ((i < argc) && (x->x_state == 0)); ++i)
+    {
+        j = argv[i].a_w.w_float;
+        x->x_status_buf[x->x_status_buf_write_index] = j;
+        /* status ends with CRLFCRLF */
+        if
+        (
+            (x->x_status_buf_write_index > 3)
+            && (j == 10) && (x->x_status_buf[x->x_status_buf_write_index-1] == 13)
+            && (x->x_status_buf[x->x_status_buf_write_index-2] == 10)
+            && (x->x_status_buf[x->x_status_buf_write_index-3] == 13)
+        )
+        {
+            x->x_state = 1;/* complete status header is in x->x_status_buf */
+            x->x_status_buf[x->x_status_buf_write_index+1] = 0;
+            if (x->x_verbosity) post("httpreceive_list: status: %s", x->x_status_buf);
+            /* get status code from first line */
+            if ((1 != sscanf(x->x_status_buf, "HTTP/1.1 %d", &j)) && (1 != sscanf(x->x_status_buf, "HTTP/1.0 %d", &j)))
+            {
+                pd_error(x, "httpreceive_list: malformed status line");
+                post("httpreceive_list: status: %s", x->x_status_buf);
+            }
+            else
+            {
+                outlet_float(x->x_statuscode_out, j);
+                if (x->x_verbosity) post("httpreceive_list: status code: %d", j);
+                for (j = 8; j < x->x_status_buf_write_index; ++j)
+                if (x->x_status_buf[j] >= 'A') break; /* skip to start of reason phrase */
+                for (k = 0; j < x->x_status_buf_write_index; ++j, ++k)
+                {
+                    if  (13 == x->x_status_buf[j]) break;
+                    buf[k] = x->x_status_buf[j];/* copy reason phrase to buf */
+                }
+                buf[k] = 0;
+                /* make buf into a symbol */
+                SETSYMBOL(&status_list[0], gensym(buf));
+                /* output it through status outlet */ 
+                outlet_anything(x->x_status_out, gensym("reason"), 1, &status_list[0]);
+                /* loop through all the response header fields */                        
+
+                do
+                {
+                    /* skip to first non-whitespace on next line: */
+                    for (; j < x->x_status_buf_write_index; ++j)
+                    if (x->x_status_buf[j] > 32) break;
+                    /* copy the field name to buf */
+                    for (k = 0; j < x->x_status_buf_write_index; ++j, ++k)
+                    {
+                        if (':' == x->x_status_buf[j]) break;
+                        buf[k] = x->x_status_buf[j];
+                    }
+                    j++; /* skip the colon */
+                    buf[k] = 0;
+                    SETSYMBOL(&status_list[0], gensym(buf)); /* field name */
+                    /* skip whitespace: */
+                    for (; j < x->x_status_buf_write_index; ++j)
+                    if (x->x_status_buf[j] != 32) break;
+                    /* copy the token to buf */
+                    for (k = 0; j < x->x_status_buf_write_index; ++j, ++k)
+                    {
+                        if (13 == x->x_status_buf[j]) break;
+                        buf[k] = x->x_status_buf[j];
+                    }
+                    buf[k] = 0;
+                    /* if the value is a number, set it to a float, else it's a symbol */
+                    for (m = 0; m < k; ++m) if ((buf[m] < '0' || buf[m] > '9')) break;
+                    if (m == k)
+                    {                            
+                        sscanf(buf, "%d", &n);
+                        SETFLOAT(&status_list[1], n);
+                        /* if this is Content-Length, we know the message_length */
+                        if (atom_getsymbol(&status_list[0]) == gensym("Content-Length")) x->x_remaining = n;
+                    }
+                    else SETSYMBOL(&status_list[1], gensym(buf));
+                    outlet_anything(x->x_status_out, status_list[0].a_w.w_symbol, 1, &status_list[1]);
+                } while (j < x->x_status_buf_write_index-3);
+
+            }
+        } // if end of status response
+        else x->x_status_buf_write_index++;
+        if (x->x_status_buf_write_index >= x->x_status_buf_len)
+        {
+            pd_error(x, "httpreceive_list: status buffer full");
+            x->x_status_buf_write_index = 0;
+            x->x_state = 0;
+            x->x_remaining = 0;
+        }
+    } // for each byte
+    if (1 == x->x_state)
+    {
+        /* any remaining atoms are the message body. For now just output them */
+        /* but if the incoming bytes are in more than one list this won't work, */
+        /*we'll need to cache them until we have Content-Length */
+        if (x->x_verbosity) post ("httpreceive_list: x->x_remaining is %d", x->x_remaining);
+        message_len = argc - i;
+        if (x->x_verbosity) post ("httpreceive_list: message_len is %d", message_len);
+        if (message_len <= x->x_remaining) x->x_remaining -= message_len;
+        outlet_list(x->x_message_out, &s_list, message_len, &argv[i]);
+        x->x_status_buf_write_index = 0;
+        if (0 == x->x_remaining) x->x_state = 0;
+    }
+}
+
+static void httpreceive_verbosity(t_httpreceive *x, t_float verbosity)
+{
+    x->x_verbosity = verbosity;
+    if (x->x_verbosity != 0) post ("httpreceive_verbosity %d", x->x_verbosity);
+}
+
+static void httpreceive_free (t_httpreceive *x)
+{
+    if ((NULL != x->x_status_buf)&&(0 != x->x_status_buf_len)) freebytes(x->x_status_buf, x->x_status_buf_len);
+}
+
+static void *httpreceive_new (void)
+{
+    t_httpreceive *x = (t_httpreceive *)pd_new(httpreceive_class);
+    if (NULL != x)
+    {
+        x->x_message_out = outlet_new(&x->x_obj, &s_anything);
+        x->x_status_out = outlet_new(&x->x_obj, &s_anything);
+        x->x_statuscode_out = outlet_new(&x->x_obj, &s_float);  /* rightmost outlet */
+        x->x_state = 0; /* waiting for a list of bytes */
+        x->x_status_buf_len = STATUS_BUF_LEN;
+        if (NULL == (x->x_status_buf = getbytes(STATUS_BUF_LEN)))
+        {
+            pd_error(x, "httpreceive_new: no memory available for x_status_buf");
+            x->x_status_buf_len = 0;
+        }
+        x->x_status_buf_write_index = 0;
+        x->x_remaining = 0;
+        x->x_verbosity = 0;
+    }
+    
+    return (void *)x;
+}
+
+void httpreceive_setup(void)
+{
+    httpreceive_class = class_new(gensym("httpreceive"), (t_newmethod)httpreceive_new, (t_method)httpreceive_free, sizeof(t_httpreceive), CLASS_DEFAULT, 0);
+    class_addbang(httpreceive_class, httpreceive_bang);
+    class_addlist (httpreceive_class, (t_method)httpreceive_list);
+    class_addmethod(httpreceive_class, (t_method)httpreceive_verbosity, gensym("verbosity"), A_FLOAT, 0);
+}
+/* fin httpreceive.c */
diff --git a/externals/mrpeach/net/httpreq-help.pd b/externals/mrpeach/net/httpreq-help.pd
new file mode 100644
index 000000000..5dc140a51
--- /dev/null
+++ b/externals/mrpeach/net/httpreq-help.pd
@@ -0,0 +1,104 @@
+#N canvas 525 51 712 894 10;
+#X obj 119 146 httpreq;
+#X obj 44 56 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X msg 84 94 GET http://132.205.142.12/index.php;
+#X obj 136 309 unpack 0 0 0 0;
+#X floatatom 136 332 3 0 0 0 - - -;
+#X floatatom 163 332 3 0 0 0 - - -;
+#X floatatom 190 332 3 0 0 0 - - -;
+#X floatatom 217 332 3 0 0 0 - - -;
+#X text 81 350 from;
+#X obj 119 257 tcpclient;
+#X obj 153 283 tgl 15 0 empty empty connected 18 7 0 8 -24198 -13381
+-1 0 1;
+#X text 190 256 tcpclient opens a tcp socket to send and receive bytes
+on;
+#X floatatom 270 342 9 0 0 0 - - -;
+#X floatatom 313 320 9 0 0 0 - - -;
+#X text 382 319 Size of the send buffer;
+#X obj 270 274 route sent buf blocked;
+#X text 340 341 Number of bytes sent;
+#X obj 356 298 print sender_blocked!;
+#X msg 85 206 connect 132.205.142.12 80;
+#X obj 119 450 httpreceive;
+#X floatatom 182 483 5 0 0 0 - - -;
+#X symbolatom 150 642 10 0 0 0 - - -;
+#X obj 150 620 prepend set;
+#X symbolatom 216 600 50 0 0 0 - - -;
+#X obj 216 578 prepend set;
+#X obj 150 526 route reason Date Content-Length Content-Type;
+#X symbolatom 350 568 50 0 0 0 - - -;
+#X obj 350 546 prepend set;
+#X floatatom 283 558 5 0 0 0 - - -;
+#X msg 64 74 GET http://132.205.142.12/nothing;
+#X msg 44 165 dump \$1;
+#X obj 44 139 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 37 328 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1
+0 1;
+#X msg 37 351 verbosity \$1;
+#X obj 457 543 print more_status;
+#X obj 76 392 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X text 515 726 Author: Martin Peach;
+#X text 515 743 Date: 2011/01/13;
+#X text 224 481 The right outlet is the status code.;
+#X text 166 693 The left outlet is the message body as a list of bytes
+;
+#X text 154 505 The middle outlet is the status header as name/value
+pairs;
+#X obj 119 693 spigot;
+#X obj 119 723 print message_body;
+#X obj 152 671 tgl 15 0 empty empty printing_long_messages_can_hang_Pd
+17 7 0 10 -4034 -257985 -1 0 1;
+#X text 175 147 [httpreq] sends an HTTP/1.1 request as a list of bytes
+(actually float atoms) \, suitable for [tcpclient];
+#X text 195 444 [htpreceive] expects an HTTP/1.1 response as one or
+more lists of bytes.;
+#X text 187 557 message length:;
+#X obj 27 14 tgl 15 0 empty empty empty 17 7 0 10 -4034 -257985 -1
+1 1;
+#X msg 27 37 verbosity \$1;
+#X msg 105 115 HEAD http://132.205.142.12/index.php;
+#X text 175 185 So far only GET and HEAD requests are supported;
+#X text 274 73 should return 404 not found;
+#X text 306 93 should return a web page;
+#X text 332 114 should return only the metainformation;
+#X connect 0 0 9 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 3 1 5 0;
+#X connect 3 2 6 0;
+#X connect 3 3 7 0;
+#X connect 9 0 19 0;
+#X connect 9 1 3 0;
+#X connect 9 2 10 0;
+#X connect 9 3 15 0;
+#X connect 15 0 12 0;
+#X connect 15 1 13 0;
+#X connect 15 2 17 0;
+#X connect 18 0 9 0;
+#X connect 19 0 41 0;
+#X connect 19 1 25 0;
+#X connect 19 2 20 0;
+#X connect 22 0 21 0;
+#X connect 24 0 23 0;
+#X connect 25 0 22 0;
+#X connect 25 1 24 0;
+#X connect 25 2 28 0;
+#X connect 25 3 27 0;
+#X connect 25 4 34 0;
+#X connect 27 0 26 0;
+#X connect 29 0 0 0;
+#X connect 30 0 9 0;
+#X connect 31 0 30 0;
+#X connect 32 0 33 0;
+#X connect 33 0 19 0;
+#X connect 35 0 19 0;
+#X connect 41 0 42 0;
+#X connect 43 0 41 1;
+#X connect 47 0 48 0;
+#X connect 48 0 0 0;
+#X connect 49 0 0 0;
diff --git a/externals/mrpeach/net/httpreq.c b/externals/mrpeach/net/httpreq.c
new file mode 100644
index 000000000..bf0b52a20
--- /dev/null
+++ b/externals/mrpeach/net/httpreq.c
@@ -0,0 +1,176 @@
+/* httptreq.c Started by Martin Peach 20110111 */
+/* httpreq will generate http 1.1 requests as lists of bytes suitable for input to tcpclient */
+/* See http://www.w3.org/Protocols/rfc2616/rfc2616.html */
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+
+static t_class *httpreq_class;
+
+typedef struct _httpreq
+{
+    t_object    x_obj;
+    t_outlet    *x_reqout;
+    int         x_verbosity;    
+} t_httpreq;
+
+#define MAX_GETSTRING 256
+static void httpreq_bang(t_httpreq *x);
+static void httpreq_get(t_httpreq *x, t_symbol *s);
+static void httpreq_head(t_httpreq *x, t_symbol *s);
+static void httpreq_verbosity(t_httpreq *x, t_floatarg verbosity);
+static void *httpreq_new (void);
+void httpreq_setup(void);
+
+static void httpreq_bang(t_httpreq *x)
+{
+  post("httpreq_bang %p", x);
+}
+
+static void httpreq_get(t_httpreq *x, t_symbol *s)
+{
+    unsigned int    i, j, len;    
+    char            buf[MAX_GETSTRING];
+    char            request_line[1024];
+    t_atom          request_atoms[1024];
+
+    len = strlen (s->s_name);
+    if (len > MAX_GETSTRING)
+    {
+        pd_error(x, "httpreq_get: string too long (%d), should be less than %d", len, MAX_GETSTRING);
+        return;
+    }
+    for (i = 0; i < strlen(s->s_name); ++i) buf[i] = s->s_name[i];
+    buf[i] = 0;    
+
+    if (0 != strncmp("http://", buf, 7))
+    {
+        pd_error(x, "httpreq_get: url doesn't begin with 'http://' (%d)", len);
+        return;
+    }
+/*
+5.1 Request-Line
+The Request-Line begins with a method token, 
+followed by the Request-URI and the protocol version, 
+and ending with CRLF. 
+The elements are separated by SP characters. 
+No CR or LF is allowed except in the final CRLF sequence.
+
+Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
+*/
+    j = sprintf(request_line, "GET ");
+    for (i = 7; i < len; ++i)
+    { /* skip  "http://" and the host name */
+        if ('/' == buf[i]) break;
+    }
+    for (; i < len; ++i, ++j)
+    {
+        if (buf[i] <= 0x20) break;
+        request_line[j] = buf[i];
+    }
+    j += sprintf(&request_line[j], " HTTP/1.1");
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    j += sprintf(&request_line[j], "Host: ");
+    for (i = 7; i < len; ++i, ++j)
+    { /* copy the host name */
+        if ('/' == buf[i]) break;
+        request_line[j] = buf[i];
+    }
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    request_line[j] = 0; // terminate string
+
+/* output the request line as a list of floats */
+    for (i = 0; i < j; ++i)
+    {
+        SETFLOAT(&request_atoms[i], request_line[i]);
+    }
+    if (x->x_verbosity) post("httpreq_get: %s", request_line);
+    outlet_list(x->x_reqout, &s_list, j, &request_atoms[0]);
+}
+
+static void httpreq_head(t_httpreq *x, t_symbol *s)
+{ /* this is the same as get except for the method */
+    unsigned int    i, j, len;    
+    char            buf[MAX_GETSTRING];
+    char            request_line[1024];
+    t_atom          request_atoms[1024];
+
+    len = strlen (s->s_name);
+    if (len > MAX_GETSTRING)
+    {
+        pd_error(x, "httpreq_head: string too long (%d), should be less than %d", len, MAX_GETSTRING);
+        return;
+    }
+    for (i = 0; i < strlen(s->s_name); ++i) buf[i] = s->s_name[i];
+    buf[i] = 0;    
+
+    if (0 != strncmp("http://", buf, 7))
+    {
+        pd_error(x, "httpreq_head: url doesn't begin with 'http://' (%d)", len);
+        return;
+    }
+
+    j = sprintf(request_line, "HEAD ");
+    for (i = 7; i < len; ++i)
+    { /* skip  "http://" and the host name */
+        if ('/' == buf[i]) break;
+    }
+    for (; i < len; ++i, ++j)
+    {
+        if (buf[i] <= 0x20) break;
+        request_line[j] = buf[i];
+    }
+    j += sprintf(&request_line[j], " HTTP/1.1");
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    j += sprintf(&request_line[j], "Host: ");
+    for (i = 7; i < len; ++i, ++j)
+    { /* copy the host name */
+        if ('/' == buf[i]) break;
+        request_line[j] = buf[i];
+    }
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    request_line[j++] = 0xD; // <CR>
+    request_line[j++] = 0xA; // <LF>
+    request_line[j] = 0; // terminate string
+
+/* output the request line as a list of floats */
+    for (i = 0; i < j; ++i)
+    {
+        SETFLOAT(&request_atoms[i], request_line[i]);
+    }
+    if (x->x_verbosity) post("httpreq_head: %s", request_line);
+    outlet_list(x->x_reqout, &s_list, j, &request_atoms[0]);
+}
+
+static void httpreq_verbosity(t_httpreq *x, t_float verbosity)
+{
+    x->x_verbosity = verbosity;
+    if (x->x_verbosity != 0) post ("httpreq_verbosity %d", x->x_verbosity);
+}
+
+static void *httpreq_new (void)
+{
+    t_httpreq *x = (t_httpreq *)pd_new(httpreq_class);
+    if (NULL != x)
+    {
+        x->x_reqout = outlet_new(&x->x_obj, &s_anything);
+    }
+    return (void *)x;
+}
+
+void httpreq_setup(void)
+{
+    httpreq_class = class_new(gensym("httpreq"), (t_newmethod)httpreq_new, 0, sizeof(t_httpreq), CLASS_DEFAULT, 0);
+    class_addbang(httpreq_class, httpreq_bang);
+    class_addmethod (httpreq_class, (t_method)httpreq_get, gensym ("GET"), A_DEFSYM, 0);
+    class_addmethod (httpreq_class, (t_method)httpreq_head, gensym ("HEAD"), A_DEFSYM, 0);
+    class_addmethod(httpreq_class, (t_method)httpreq_verbosity, gensym("verbosity"), A_FLOAT, 0);
+}
+/* fin httpreq.c */
diff --git a/externals/mrpeach/net/net-meta.pd b/externals/mrpeach/net/net-meta.pd
new file mode 100644
index 000000000..903905af7
--- /dev/null
+++ b/externals/mrpeach/net/net-meta.pd
@@ -0,0 +1,6 @@
+#N canvas 17 107 200 200 10;
+#N canvas 486 145 761 300 META 1;
+#X text 10 5 VERSION 0.1;
+#X text 11 25 NAME net;
+#X text 9 45 AUTHOR Martin Peach martin.peach@sympatico.ca;
+#X restore 10 10 pd META;
diff --git a/externals/mrpeach/net/tcpclient.c b/externals/mrpeach/net/tcpclient.c
index cc6058cc5..bba25f1d8 100644
--- a/externals/mrpeach/net/tcpclient.c
+++ b/externals/mrpeach/net/tcpclient.c
@@ -25,7 +25,7 @@
 /* Based on PureData by Miller Puckette and others.                             */
 /*                                                                              */
 /* ---------------------------------------------------------------------------- */
-//define DEBUG
+//#define DEBUG
 
 #include "m_pd.h"
 #include "s_stuff.h"
@@ -34,7 +34,7 @@
 #include <sys/types.h>
 #include <string.h>
 #include <pthread.h>
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
 #include <sys/socket.h>
 #include <sys/errno.h>
 #include <netinet/in.h>
@@ -55,38 +55,55 @@
 
 static t_class *tcpclient_class;
 static char objName[] = "tcpclient";
-#define MAX_UDP_RECEIVE 65536L // longer than data in maximum UDP packet
+#define MAX_TCPCLIENT_SEND_BUF 65536L // longer than data in maximum UDP packet
+
+/* each send is handled by a new thread with a new parameter struct: */
+/* these are stored under x->x_tsp[0..MAX_TCPCLIENT_THREADS-1] */
+/* The buffer is preallocated for speed. */
+typedef struct _tcpclient_sender_params
+{
+    char                x_sendbuf[MAX_TCPCLIENT_SEND_BUF]; /* possibly allocate this dynamically for space over speed */
+    int                 x_buf_len;
+    int                 x_sendresult;
+    pthread_t           sendthreadid;
+    int                 threadisvalid; /*  non-zero if sendthreadid is an active thread */
+    struct _tcpclient   *x_x;
+} t_tcpclient_sender_params;
+#define MAX_TCPCLIENT_THREADS 32
+/* MAX_TCPCLIENT_THREADS is small to avoid wasting space. This is the maximum number of concurrent threads. */
 
 typedef struct _tcpclient
 {
-    t_object        x_obj;
-    t_clock         *x_clock;
-    t_clock         *x_poll;
-    t_clock         *x_sendclock;
-    t_outlet        *x_msgout;
-    t_outlet        *x_addrout;
-    t_outlet        *x_connectout;
-    t_outlet        *x_statusout;
-    int             x_dump; // 1 = hexdump received bytes
-    int             x_verbosity; // 1 = post connection state changes to main window
-    int             x_fd; // the socket
-    int             x_fdbuf; // the socket's buffer size
-    char            *x_hostname; // address we want to connect to as text
-    int             x_connectstate; // 0 = not connected, 1 = connected
-    int             x_port; // port we're connected to
-    long            x_addr; // address we're connected to as 32bit int
-    t_atom          x_addrbytes[4]; // address we're connected to as 4 bytes
-    t_atom          x_msgoutbuf[MAX_UDP_RECEIVE]; // received data as float atoms
-    unsigned char   x_msginbuf[MAX_UDP_RECEIVE]; // received data as bytes
-    char            *x_sendbuf; // pointer to data to send
-    int             x_sendbuf_len; // number of bytes in sendbuf
-    int             x_sendresult;
-    int             x_blocked;
+    t_object                    x_obj;
+    t_clock                     *x_clock;
+    t_clock                     *x_poll;
+    t_clock                     *x_sendclock;
+    t_outlet                    *x_msgout;
+    t_outlet                    *x_addrout;
+    t_outlet                    *x_connectout;
+    t_outlet                    *x_statusout;
+    int                         x_dump; // 1 = hexdump received bytes
+    int                         x_verbosity; // 1 = post connection state changes to main window
+    int                         x_fd; // the socket
+    int                         x_fdbuf; // the socket's buffer size
+    char                        *x_hostname; // address we want to connect to as text
+    int                         x_connectstate; // 0 = not connected, 1 = connected
+    int                         x_port; // port we're connected to
+    long                        x_addr; // address we're connected to as 32bit int
+    t_atom                      x_addrbytes[4]; // address we're connected to as 4 bytes
+    t_atom                      x_msgoutbuf[MAX_TCPCLIENT_SEND_BUF]; // received data as float atoms
+    unsigned char               x_msginbuf[MAX_TCPCLIENT_SEND_BUF]; // received data as bytes
+    char                        *x_sendbuf; // pointer to data to send
+    int                         x_sendbuf_len; // number of bytes in sendbuf
+    int                         x_sendresult;
+    int                         x_blocked;
     /* multithread stuff */
-    pthread_t       x_threadid; /* id of child thread */
-    pthread_attr_t  x_threadattr; /* attributes of child thread */
-    pthread_t       x_sendthreadid; /* id of child thread for sending */
-    pthread_attr_t  x_sendthreadattr; /* attributes of child thread for sending */
+    pthread_t                   x_threadid; /* id of connector child thread */
+    pthread_attr_t              x_threadattr; /* attributes of connector child thread */
+    pthread_attr_t              x_sendthreadattr; /* attributes of all sender child thread for sending */
+    int                         x_nextthread; /* next unused x_tsp */
+    t_tcpclient_sender_params   x_tsp[MAX_TCPCLIENT_THREADS];
+/* Thread params are used round-robin to avoid overwriting buffers when doing multiple sends */
 } t_tcpclient;
 
 static void tcpclient_verbosity(t_tcpclient *x, t_float verbosity);
@@ -97,7 +114,7 @@ static void *tcpclient_child_connect(void *w);
 static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno);
 static void tcpclient_disconnect(t_tcpclient *x);
 static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv);
-int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len);
+static int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len);
 static void *tcpclient_child_send(void *w);
 static void tcpclient_sent(t_tcpclient *x);
 static int tcpclient_get_socket_send_buf_size(t_tcpclient *x);
@@ -106,7 +123,7 @@ static void tcpclient_buf_size(t_tcpclient *x, t_symbol *s, int argc, t_atom *ar
 static void tcpclient_rcv(t_tcpclient *x);
 static void tcpclient_poll(t_tcpclient *x);
 static void tcpclient_unblock(t_tcpclient *x);
-static void *tcpclient_new(t_floatarg udpflag);
+static void *tcpclient_new(void);
 static void tcpclient_free(t_tcpclient *x);
 void tcpclient_setup(void);
 
@@ -227,8 +244,14 @@ static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fpo
 
 static void tcpclient_disconnect(t_tcpclient *x)
 {
+    int i;
+
     if (x->x_fd >= 0)
     {
+        for (i = 0; i < MAX_TCPCLIENT_THREADS;++i)
+        { /* wait for any sender threads to finish */
+            while (x->x_tsp[i].threadisvalid != 0);
+        }
         sys_closesocket(x->x_fd);
         x->x_fd = -1;
         x->x_connectstate = 0;
@@ -245,10 +268,7 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
     int             i, j, d;
     unsigned char   c;
     float           f, e;
-    char            *bp;
-    int             length;
     size_t          sent = 0;
-    int             result;
     char            fpath[FILENAME_MAX];
     FILE            *fptr;
 
@@ -275,7 +295,6 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
                 return;
             }
             c = (unsigned char)d;
-//            if (0 == tcpclient_send_byte(x, c)) break;
             byte_buf[j++] = c;
             if (j >= BYTE_BUF_LEN)
             {
@@ -285,7 +304,6 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
         }
         else if (argv[i].a_type == A_SYMBOL)
         {
-
             atom_string(&argv[i], fpath, FILENAME_MAX);
             fptr = fopen(fpath, "rb");
             if (fptr == NULL)
@@ -297,14 +315,12 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
             while ((d = fgetc(fptr)) != EOF)
             {
                 c = (char)(d & 0x0FF);
-//                if (0 == tcpclient_send_byte(x, c)) break;
                 byte_buf[j++] = c;
                 if (j >= BYTE_BUF_LEN)
                 {
                     sent += tcpclient_send_buf(x, byte_buf, j);
                     j = 0;
                 }
-//                ++j;
             }
             fclose(fptr);
             fptr = NULL;
@@ -318,14 +334,13 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
     }
     if (j > 0)
     sent += tcpclient_send_buf(x, byte_buf, j);
-
 }
 
 
-int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len)
+static int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len)
 {
-    fd_set          wfds;
-    struct timeval  timeout;
+    t_tcpclient_sender_params   *tsp = &x->x_tsp[x->x_nextthread];
+    int                         i, max;
 
     if (x->x_blocked) return 0;
     if (x->x_fd < 0)
@@ -334,39 +349,57 @@ int tcpclient_send_buf(t_tcpclient *x, char *buf, int buf_len)
         x->x_blocked++;
         return 0;
     }
-    x->x_sendbuf = buf;
-    x->x_sendbuf_len = buf_len;
-    if((x->x_sendresult = pthread_create(&x->x_sendthreadid, &x->x_sendthreadattr, tcpclient_child_send, x)) < 0)
+    max = (buf_len > MAX_TCPCLIENT_SEND_BUF)? MAX_TCPCLIENT_SEND_BUF: buf_len;
+    while(0 != tsp->threadisvalid); /* wait for thread to clear */
+    for (i = 0; i < max; ++i)
+    {
+        tsp->x_sendbuf[i] = buf[i];
+    }
+    tsp->x_buf_len = i;
+    x->x_sendbuf_len += i;
+    tsp->x_x = x;
+    tsp->threadisvalid = 1;
+    if((tsp->x_sendresult = pthread_create(&tsp->sendthreadid, &x->x_sendthreadattr, tcpclient_child_send, tsp)) < 0)
     {
+        tsp->threadisvalid = 0;
         post("%s_send_buf: could not create new thread (%d)", objName);
         clock_delay(x->x_sendclock, 0); // calls tcpclient_sent
         return 0;
     }
-    return buf_len;
+    x->x_nextthread++;
+    if (x->x_nextthread >= MAX_TCPCLIENT_THREADS) x->x_nextthread = 0;
+    return max;
 }
 
 /* tcpclient_child_send runs in sendthread */
 static void *tcpclient_child_send(void *w)
 {
-    t_tcpclient         *x = (t_tcpclient*) w;
+    t_tcpclient_sender_params *tsp = (t_tcpclient_sender_params*) w;
 
-    x->x_sendresult = send(x->x_fd, x->x_sendbuf, x->x_sendbuf_len, 0);
-    clock_delay(x->x_sendclock, 0); // calls tcpclient_sent when it's safe to do so
-    return(x);
+    tsp->x_sendresult = send(tsp->x_x->x_fd, tsp->x_sendbuf, tsp->x_buf_len, 0);
+    clock_delay(tsp->x_x->x_sendclock, 0); // calls tcpclient_sent when it's safe to do so
+    tsp->threadisvalid = 0; /* this thread is over */
+    return(tsp);
 }
 
 static void tcpclient_sent(t_tcpclient *x)
 {
     t_atom  output_atom;
 
-    if (x->x_sendresult <= 0)
+    if (x->x_sendresult < 0)
     {
         sys_sockerror("tcpclient: send");
-        post("%s_send_byte: could not send data ", objName);
+        post("%s_sent: could not send data ", objName);
         x->x_blocked++;
         SETFLOAT(&output_atom, x->x_sendresult);
         outlet_anything( x->x_statusout, gensym("blocked"), 1, &output_atom);
     }
+    else if (x->x_sendresult == 0)
+    { /* assume the message is queued and will be sent real soon now */
+        SETFLOAT(&output_atom, x->x_sendbuf_len);
+        outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom);
+        x->x_sendbuf_len = 0; /* we might be called only once for multiple calls to  tcpclient_send_buf */
+    }
     else
     {
         SETFLOAT(&output_atom, x->x_sendresult);
@@ -414,9 +447,7 @@ static int tcpclient_set_socket_send_buf_size(t_tcpclient *x, int size)
 /* Get/set the send buffer size of client socket */
 static void tcpclient_buf_size(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
 {
-    int     client = -1;
     float   buf_size = 0;
-    t_atom  output_atom[3];
 
     if(x->x_connectstate == 0)
     {
@@ -470,7 +501,7 @@ static void tcpclient_rcv(t_tcpclient *x)
         if(FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &exceptset))
         {
             /* read from server */
-            ret = recv(sockfd, x->x_msginbuf, MAX_UDP_RECEIVE, 0);
+            ret = recv(sockfd, x->x_msginbuf, MAX_TCPCLIENT_SEND_BUF, 0);
             if(ret > 0)
             {
 #ifdef DEBUG
@@ -523,7 +554,7 @@ static void tcpclient_unblock(t_tcpclient *x)
     x->x_blocked = 0;
 }
 
-static void *tcpclient_new(t_floatarg udpflag)
+static void *tcpclient_new(void)
 {
     int i;
 
@@ -535,10 +566,10 @@ static void *tcpclient_new(t_floatarg udpflag)
     x->x_sendclock = clock_new(x, (t_method)tcpclient_sent);
     x->x_clock = clock_new(x, (t_method)tcpclient_tick);
     x->x_poll = clock_new(x, (t_method)tcpclient_poll);
-    x->x_verbosity = 0; /* default post status changes to main window */
+    x->x_verbosity = 1; /* default post status changes to main window */
     x->x_fd = -1;
     /* convert the bytes in the buffer to floats in a list */
-    for (i = 0; i < MAX_UDP_RECEIVE; ++i)
+    for (i = 0; i < MAX_TCPCLIENT_SEND_BUF; ++i)
     {
         x->x_msgoutbuf[i].a_type = A_FLOAT;
         x->x_msgoutbuf[i].a_w.w_float = 0;
@@ -551,6 +582,7 @@ static void *tcpclient_new(t_floatarg udpflag)
     x->x_addr = 0L;
     x->x_blocked = 1;
     x->x_connectstate = 0;
+    x->x_nextthread = 0;
     /* prepare child threads */
     if(pthread_attr_init(&x->x_threadattr) < 0)
         post("%s: warning: could not prepare child thread", objName);
@@ -561,7 +593,6 @@ static void *tcpclient_new(t_floatarg udpflag)
     if(pthread_attr_setdetachstate(&x->x_sendthreadattr, PTHREAD_CREATE_DETACHED) < 0)
         post("%s: warning: could not prepare child thread", objName);
     clock_delay(x->x_poll, 0);	/* start polling the input */
-    post("tcpclient 20100505 Martin Peach-style");
     return (x);
 }
 
@@ -576,9 +607,18 @@ static void tcpclient_free(t_tcpclient *x)
 
 void tcpclient_setup(void)
 {
+    char    aboutStr[MAXPDSTRING];
+
+    snprintf(aboutStr, MAXPDSTRING, "%s: (GPL) 20111103 Martin Peach, compiled for pd-%d.%d on %s %s",
+             objName, PD_MAJOR_VERSION, PD_MINOR_VERSION, __DATE__, __TIME__);
+
+#if PD_MAJOR_VERSION==0 && PD_MINOR_VERSION<43
+    post(aboutStr);
+#else
+    logpost(NULL, 3, aboutStr);
+#endif
     tcpclient_class = class_new(gensym(objName), (t_newmethod)tcpclient_new,
-        (t_method)tcpclient_free,
-        sizeof(t_tcpclient), 0, A_DEFFLOAT, 0);
+        (t_method)tcpclient_free, sizeof(t_tcpclient), 0, 0);
     class_addmethod(tcpclient_class, (t_method)tcpclient_connect, gensym("connect")
         , A_SYMBOL, A_FLOAT, 0);
     class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0);
diff --git a/externals/mrpeach/net/tcpreceive.c b/externals/mrpeach/net/tcpreceive.c
index 418e77bce..feb2234c5 100644
--- a/externals/mrpeach/net/tcpreceive.c
+++ b/externals/mrpeach/net/tcpreceive.c
@@ -44,7 +44,7 @@ typedef struct _tcpreceive
 	t_tcpconnection x_connection[MAX_CONNECTIONS];
     t_atom          x_addrbytes[5];
     t_atom          x_msgoutbuf[MAX_UDP_RECEIVE];
-    char            x_msginbuf[MAX_UDP_RECEIVE];
+    unsigned char   x_msginbuf[MAX_UDP_RECEIVE];
 } t_tcpreceive;
 
 void tcpreceive_setup(void);
diff --git a/externals/mrpeach/net/tcpserver.c b/externals/mrpeach/net/tcpserver.c
index 7cd561736..b7cc25477 100644
--- a/externals/mrpeach/net/tcpserver.c
+++ b/externals/mrpeach/net/tcpserver.c
@@ -35,7 +35,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 #include <pthread.h>
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -117,7 +117,7 @@ typedef struct _tcpserver_broadcast_params
     t_tcpserver *x;
     t_int       argc;
     t_atom      argv[MAX_UDP_RECEIVE];
-} t_tcpserver_broadcast_params;
+} t_tcpserver_broadcast_params;
 
 static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(void *owner, t_tcpserver_socketnotifier notifier,
     t_tcpserver_socketreceivefn socketreceivefn);
@@ -1211,7 +1211,7 @@ static void tcpserver_free(t_tcpserver *x)
 {
     int     i;
 
-    //post("tcp_server_free...");
+    post("tcp_server_free...");
     for(i = 0; i < MAX_CONNECT; i++)
     {
         if (x->x_sr[i] != NULL) 
@@ -1229,7 +1229,7 @@ static void tcpserver_free(t_tcpserver *x)
         sys_rmpollfn(x->x_connectsocket);
         sys_closesocket(x->x_connectsocket);
     }
-    //post("...tcp_server_free");
+    post("...tcp_server_free");
 }
 
 void tcpserver_setup(void)
diff --git a/externals/mrpeach/net/tcpsocket.FUDI-help.pd b/externals/mrpeach/net/tcpsocket.FUDI-help.pd
new file mode 100644
index 000000000..e48173114
--- /dev/null
+++ b/externals/mrpeach/net/tcpsocket.FUDI-help.pd
@@ -0,0 +1,4 @@
+#N canvas 171 298 450 300 10;
+#X text 79 81 This is a support object for;
+#X obj 252 81 pddp/helplink tcpsocketserver;
+#X obj 178 123 tcpsocket.FUDI;
diff --git a/externals/mrpeach/osc/tcpsocket.FUDI.pd b/externals/mrpeach/net/tcpsocket.FUDI.pd
similarity index 100%
rename from externals/mrpeach/osc/tcpsocket.FUDI.pd
rename to externals/mrpeach/net/tcpsocket.FUDI.pd
diff --git a/externals/mrpeach/net/tcpsocket.OSC-help.pd b/externals/mrpeach/net/tcpsocket.OSC-help.pd
new file mode 100644
index 000000000..90b62c0ee
--- /dev/null
+++ b/externals/mrpeach/net/tcpsocket.OSC-help.pd
@@ -0,0 +1,4 @@
+#N canvas 171 298 450 300 10;
+#X obj 178 123 tcpsocket.OSC;
+#X text 79 81 This is a support object for;
+#X obj 252 81 pddp/helplink tcpsocketserver;
diff --git a/externals/mrpeach/net/tcpsocket.OSC.pd b/externals/mrpeach/net/tcpsocket.OSC.pd
new file mode 100644
index 000000000..f3e47da36
--- /dev/null
+++ b/externals/mrpeach/net/tcpsocket.OSC.pd
@@ -0,0 +1,89 @@
+#N canvas 636 71 455 534 10;
+#X obj 50 49 == \$2;
+#X obj 7 28 route in socket;
+#X obj 7 76 spigot;
+#N canvas 622 183 512 335 reset 0;
+#X obj 23 41 route \$2;
+#X obj 23 63 route reset;
+#X obj 23 83 t b b;
+#X msg 55 170 done;
+#X obj 23 113 outlet;
+#X text 161 33 this is used to:;
+#X text 87 114 a) reset the sockethandler on a new connection;
+#X text 88 129 (for instance \, if the previous connection was quitted
+in the middle of a packet).;
+#X text 55 213 b) check for the socketserver \, if a sockethandler
+on specified socket already exists.;
+#X obj 55 191 s \$1.TCPSOCKET;
+#X obj 23 19 r \$1.TCPSOCKET;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 2 1 3 0;
+#X connect 3 0 9 0;
+#X connect 10 0 0 0;
+#X restore 40 102 pd reset;
+#X obj 104 280 route socket ip;
+#X obj 41 367 list append;
+#X obj 58 323 list append;
+#X obj 7 299 t a b b b;
+#X obj 7 414 list prepend out;
+#X obj 41 391 list prepend socket.out;
+#X obj 58 345 list prepend ip.out;
+#X obj 7 442 list trim;
+#X text 16 220 the lower part makes [tcpsocketserver] behave like [tcpserver]
+;
+#X obj -2 136 cnv 15 450 70 empty empty empty 20 12 0 14 -204786 -66577
+0;
+#X text 70 162 <- PUT HERE THE PROTOCOL SPECIFIC DELIMITER CODE;
+#X text 15 197 --------------------------------------------------------
+;
+#X text 13 129 --------------------------------------------------------
+;
+#X obj 7 6 r \$1.TCPSOCKET;
+#X obj 7 465 s \$1.TCPSOCKET;
+#X obj 104 256 r \$1.TCPSOCKET;
+#X text 200 454 Author: Roman Haefeli;
+#X text 55 75 <- only pass stream of own socket;
+#N canvas 389 116 266 236 OSC 0;
+#X obj 27 18 inlet;
+#X obj 27 186 outlet;
+#X obj 144 23 inlet;
+#X text 194 23 reset;
+#X obj 27 123 mrpeach/slipdec 16384;
+#X obj 27 151 spigot 1;
+#X obj 144 45 t b b b;
+#X msg 163 67 192 192;
+#X msg 183 99 0;
+#X msg 144 100 1;
+#X connect 0 0 4 0;
+#X connect 2 0 6 0;
+#X connect 4 0 5 0;
+#X connect 5 0 1 0;
+#X connect 6 0 9 0;
+#X connect 6 1 7 0;
+#X connect 6 2 8 0;
+#X connect 7 0 4 0;
+#X connect 8 0 5 1;
+#X connect 9 0 5 1;
+#X restore 7 161 pd OSC;
+#X text 201 474 Version: 2011-01-05;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 1 1 0 0;
+#X connect 2 0 22 0;
+#X connect 3 0 22 1;
+#X connect 4 0 5 1;
+#X connect 4 1 6 1;
+#X connect 5 0 9 0;
+#X connect 6 0 10 0;
+#X connect 7 0 8 0;
+#X connect 7 2 5 0;
+#X connect 7 3 6 0;
+#X connect 8 0 11 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 0;
+#X connect 11 0 18 0;
+#X connect 17 0 1 0;
+#X connect 19 0 4 0;
+#X connect 22 0 7 0;
diff --git a/externals/mrpeach/osc/tcpsocketserver-help.pd b/externals/mrpeach/net/tcpsocketserver-help.pd
similarity index 65%
rename from externals/mrpeach/osc/tcpsocketserver-help.pd
rename to externals/mrpeach/net/tcpsocketserver-help.pd
index d0e60454d..96dd00198 100644
--- a/externals/mrpeach/osc/tcpsocketserver-help.pd
+++ b/externals/mrpeach/net/tcpsocketserver-help.pd
@@ -1,301 +1,299 @@
-#N canvas 35 3 878 523 10;
-#X declare -stdpath extra/mrpeach;
-#X declare -stdlib extra/pdstring declare -stdlib extra/maxlib;
-#X declare -stdpath extra/mrpeach;
-#X declare -stdlib extra/pdstring declare -stdlib extra/maxlib;
-#X declare -stdpath extra/mrpeach;
-#X msg 471 74 print;
-#X text 521 75 list of connections;
-#X text 627 103 send to all clients;
-#X text 629 132 send to client 1;
-#X text 615 155 send to client on socket 504;
-#X text 613 28 'send' prefix is optional;
-#X text 474 48 (the first number is socket number);
-#X msg 556 257 disconnectsocket \$1;
-#X msg 484 284 disconnectclient \$1;
-#X floatatom 506 215 5 0 0 0 - - -;
-#X obj 484 235 f;
-#X obj 484 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699
--241291 -1;
-#X floatatom 578 216 5 0 0 0 - - -;
-#X obj 556 235 f;
-#X obj 556 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699
--241291 -1;
-#X text 483 197 disconnect by socket or client number;
-#X obj 618 335 unpack 0 0 0 0;
-#X floatatom 618 355 3 0 0 0 - - -;
-#X floatatom 649 355 3 0 0 0 - - -;
-#X floatatom 681 356 3 0 0 0 - - -;
-#X floatatom 715 356 3 0 0 0 - - -;
-#X text 616 372 IP;
-#X floatatom 569 355 5 0 0 0 - - -;
-#X text 566 371 socket;
-#X floatatom 520 376 5 0 0 0 - - -;
-#X text 520 391 number of connections;
-#X obj 471 433 spigot;
-#X obj 510 413 tgl 15 0 empty empty enable_print 17 7 0 10 -24198 -258699
--258699 0 1;
-#X text 15 37 [tcpsocketserver <protocol> <port>];
-#X obj 469 311 cnv 15 185 22 empty empty empty 20 12 0 14 -204786 -66577
-0;
-#X obj 471 314 tcpsocketserver FUDI 2468;
-#X text 15 115 [tcpsocketserver] is able to handle multiple sockets
-of a packet oriented protocol correctly \, unlike [tcpserver] \, which
-might mix up packets from different sockets.;
-#X text 24 308 - OSC;
-#X text 16 245 each protocol requires its own specific socket handler
-abstraction \, which should be named [tcpsocket.PROTOCOL]. currently
-available are the protocols:;
-#X text 23 293 - FUDI;
-#N canvas 704 167 472 356 EXTENDABILITY 0;
-#X text 3 39 Support for more protocols can easily be added. In order
-to do so:;
-#X text 5 10 EXTENDABILITY;
-#X text 6 105 - open tcpsocket.NEWPROTOCOL.pd;
-#X text 7 127 - edit the green-marked subpatch;
-#X text 10 208 - save it;
-#X text 12 227 - in order to use it \, instantiate:;
-#X text 46 247 [tcpsocketserver NEWPROTOCOL <port>];
-#X text 8 148 - replace code with code \, that creates proper packets
-out of the incoming stream for the desired protocol. don't forget to
-implement a reset mechanism \, in case a socket is closed in the middle
-of packet transmission.;
-#X text 5 83 - copy tcpsocket.FUDI.pd to tcpsocket.NEWPROTOCOL.pd;
-#X restore 21 387 pd EXTENDABILITY;
-#X text 17 453 Author: Roman Haefeli;
-#X text 16 468 Version: 2009-01-11;
-#X text 15 65 [tcpsocketserver] is meant to be a protocol-aware drop-in
-replacement for [tcpserver]. it uses same the same inlet and outlet
-configuration as [tcpserver].;
-#X text 469 478 only well-formed FUDI messages are received here.;
-#N canvas 469 232 147 274 EXAMPLES 0;
-#N canvas 231 0 579 756 FUDI 0;
-#X obj 9 39 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661
--66577 0;
-#X obj 25 193 tcpclient;
-#X msg 369 94 connect localhost 11001;
-#X msg 393 115 disconnect;
-#X obj 369 72 sel 1 0;
-#X obj 369 51 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
-1;
-#X obj 25 259 print CLIENT_1;
-#X msg 25 70 one two;
-#X obj 25 91 any2string 0 -1;
-#X msg 69 151 59 10;
-#X msg 33 117 32 116 104 114 101 101 23;
-#X obj 9 286 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661
--66577 0;
-#X msg 369 341 connect localhost 11001;
-#X msg 393 362 disconnect;
-#X obj 369 319 sel 1 0;
-#X obj 369 298 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
-1;
-#X obj 25 214 string2any 0 59;
-#X obj 25 234 route bang;
-#X obj 25 373 netclient;
-#X obj 8 9 declare -stdlib extra/pdstring declare -stdlib extra/maxlib
-;
-#X obj 25 402 print CLIENT_2;
-#X text 169 324 <- send FUDI message;
-#X obj 10 444 cnv 15 550 300 empty empty FUDI_server 20 12 0 14 -241408
--66577 0;
-#X obj 12 600 tcpsocketserver FUDI 11001;
-#X obj 12 674 string2any 0 59;
-#X obj 12 695 route bang;
-#X obj 191 620 unpack 0 0 0 0;
-#X floatatom 191 640 3 0 0 0 - - -;
-#X floatatom 222 640 3 0 0 0 - - -;
-#X floatatom 254 641 3 0 0 0 - - -;
-#X floatatom 288 641 3 0 0 0 - - -;
-#X text 189 657 IP;
-#X floatatom 131 640 5 0 0 0 - - -;
-#X floatatom 71 641 5 0 0 0 - - -;
-#X text 60 656 clients;
-#X text 127 656 socket;
-#X text 132 675 <--;
-#X text 165 675 [tcpsocketserver FUDI] does _not_ remove the trailing
-' \; ';
-#X text 165 70 1) start a FUDI message;
-#X text 232 118 2) continue;
-#X text 118 152 3) finish FUDI message (with semicolon - newline);
-#X text 391 52 connect;
-#X text 390 296 connect;
-#X text 20 475 [tcpsocketserver FUDI] doesn't take care of building
-FUDI-compliant messages. this should be done by the user.;
-#X text 154 216 4) try sending a message from client_2 during composing
-a message with client_1 and see \, how the server behaves.;
-#X text 279 522 <- this doesn't work;
-#X text 315 549 <- this should;
-#X msg 25 323 send four five six;
-#X msg 43 550 client 2 115 101 118 101 110 32 59 10;
-#X msg 42 521 client 2 115 101 118 101 110 32;
-#X obj 12 720 print SERVER;
-#X connect 1 0 16 0;
-#X connect 2 0 1 0;
-#X connect 3 0 1 0;
-#X connect 4 0 2 0;
-#X connect 4 1 3 0;
-#X connect 5 0 4 0;
-#X connect 7 0 8 0;
-#X connect 8 0 1 0;
-#X connect 9 0 1 0;
-#X connect 10 0 1 0;
-#X connect 12 0 18 0;
-#X connect 13 0 18 0;
-#X connect 14 0 12 0;
-#X connect 14 1 13 0;
-#X connect 15 0 14 0;
-#X connect 16 0 17 0;
-#X connect 17 1 6 0;
-#X connect 18 0 20 0;
-#X connect 23 0 24 0;
-#X connect 23 1 33 0;
-#X connect 23 2 32 0;
-#X connect 23 3 26 0;
-#X connect 24 0 25 0;
-#X connect 25 1 50 0;
-#X connect 26 0 27 0;
-#X connect 26 1 28 0;
-#X connect 26 2 29 0;
-#X connect 26 3 30 0;
-#X connect 47 0 18 0;
-#X connect 48 0 23 0;
-#X connect 49 0 23 0;
-#X restore 23 25 pd FUDI;
-#N canvas 231 0 579 756 OSC 0;
-#X obj 9 39 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661
--66577 0;
-#X obj 25 211 tcpclient;
-#X msg 357 229 disconnect;
-#X obj 333 186 sel 1 0;
-#X obj 333 165 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
-1;
-#X obj 25 259 print CLIENT_1;
-#X obj 9 286 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661
--66577 0;
-#X msg 393 362 disconnect;
-#X obj 369 319 sel 1 0;
-#X obj 369 298 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
-1;
-#X obj 8 9 declare -stdlib extra/pdstring declare -stdlib extra/maxlib
-;
-#X obj 25 417 print CLIENT_2;
-#X obj 10 444 cnv 15 550 300 empty empty OSC_server 20 12 0 14 -241408
--66577 0;
-#X obj 188 636 unpack 0 0 0 0;
-#X floatatom 188 656 3 0 0 0 - - -;
-#X floatatom 219 656 3 0 0 0 - - -;
-#X floatatom 251 657 3 0 0 0 - - -;
-#X floatatom 285 657 3 0 0 0 - - -;
-#X text 186 673 IP;
-#X floatatom 130 656 5 0 0 0 - - -;
-#X floatatom 73 657 5 0 0 0 - - -;
-#X text 62 672 clients;
-#X text 126 672 socket;
-#X text 355 166 connect;
-#X text 390 296 connect;
-#X obj 16 616 tcpsocketserver OSC 11002;
-#X obj 16 694 unpackOSC;
-#X obj 16 720 print SERVER;
-#X msg 333 208 connect localhost 11002;
-#X msg 369 341 connect localhost 11002;
-#X obj 25 234 unpackOSCstream;
-#X obj 25 373 tcpclient;
-#X obj 25 395 unpackOSCstream;
-#X msg 49 498 /synth1/tone3/freq 440;
-#X msg 25 79 0 0 0 16 47 102 114 101 113;
-#X msg 41 104 0 0 0 44 105 0 0 0 0 1 184;
-#X text 155 324 send OSC message;
-#X msg 25 323 /amplitude 0.78;
-#X obj 25 347 packOSCstream;
-#X obj 16 522 packOSCstream;
-#X obj 16 594 list trim;
-#X msg 16 473 /synth3/tone4/amplitude 0.36;
-#X obj 180 555 hradio 15 1 0 2 empty empty empty 0 -8 0 10 -4034 -1
--1 0;
-#X obj 180 573 + 1;
-#X text 221 555 client;
-#X obj 16 551 list prepend 1;
-#X obj 16 573 list prepend client;
-#X text 236 80 1) start sending an OSC packet;
-#X text 247 106 2) complete the OSC packet;
-#X text 59 137 also try sending an OSC packet from client_2 between
-1) and 2);
-#X text 124 520 <- use [packOSCstream] in order to create OSC packets
-suitable for tcp transport.;
-#X text 238 486 send to clients;
-#X text 93 695 <---;
-#X text 139 694 CAUTION: not [unpackOSCstream] is used here \, since
-[tcpsocket.OSC] already removes the 4-byte header.;
-#X connect 1 0 30 0;
-#X connect 2 0 1 0;
-#X connect 3 0 28 0;
-#X connect 3 1 2 0;
-#X connect 4 0 3 0;
-#X connect 7 0 31 0;
-#X connect 8 0 29 0;
-#X connect 8 1 7 0;
-#X connect 9 0 8 0;
-#X connect 13 0 14 0;
-#X connect 13 1 15 0;
-#X connect 13 2 16 0;
-#X connect 13 3 17 0;
-#X connect 25 0 26 0;
-#X connect 25 1 20 0;
-#X connect 25 2 19 0;
-#X connect 25 3 13 0;
-#X connect 26 0 27 0;
-#X connect 28 0 1 0;
-#X connect 29 0 31 0;
-#X connect 30 0 5 0;
-#X connect 31 0 32 0;
-#X connect 32 0 11 0;
-#X connect 33 0 39 0;
-#X connect 34 0 1 0;
-#X connect 35 0 1 0;
-#X connect 37 0 38 0;
-#X connect 38 0 31 0;
-#X connect 39 0 45 0;
-#X connect 40 0 25 0;
-#X connect 41 0 39 0;
-#X connect 42 0 43 0;
-#X connect 43 0 45 1;
-#X connect 45 0 46 0;
-#X connect 46 0 40 0;
-#X restore 23 49 pd OSC;
-#X restore 21 365 pd EXAMPLES;
-#X obj 471 455 print FUDI;
-#X msg 471 101 broadcast 97 98 99 59 10;
-#X msg 471 128 client 1 97 98 99 59 10;
-#X msg 471 155 send 504 97 98 99 59 10;
-#X msg 471 28 10 97 98 99 59 10;
-#X text 17 8 TCPSOCKETSERVER - a protocol-aware wrapper aroun [tcpserver]
-;
-#X text 13 167 [tcpsocketserver] dynamically creates (internally) an
-instance of a socket handler abstraction [tcpsocket.PROTOCOL] for each
-opened socket. every socket handler creates proper packets from the
-incoming stream and sends them to the left outlet of [tcpsocketserver].
-;
-#X connect 0 0 30 0;
-#X connect 7 0 30 0;
-#X connect 8 0 30 0;
-#X connect 9 0 10 1;
-#X connect 10 0 8 0;
-#X connect 11 0 10 0;
-#X connect 12 0 13 1;
-#X connect 13 0 7 0;
-#X connect 14 0 13 0;
-#X connect 16 0 17 0;
-#X connect 16 1 18 0;
-#X connect 16 2 19 0;
-#X connect 16 3 20 0;
-#X connect 26 0 41 0;
-#X connect 27 0 26 1;
-#X connect 30 0 26 0;
-#X connect 30 1 24 0;
-#X connect 30 2 22 0;
-#X connect 30 3 16 0;
-#X connect 42 0 30 0;
-#X connect 43 0 30 0;
-#X connect 44 0 30 0;
-#X connect 45 0 30 0;
+#N canvas 361 252 878 523 10;
+#X declare -stdpath extra/mrpeach;
+#X declare -stdpath extra/mrpeach;
+#X declare -lib moocow;
+#X declare -stdpath extra/mrpeach;
+#X declare -lib moocow;
+#X msg 471 74 print;
+#X text 521 75 list of connections;
+#X text 627 103 send to all clients;
+#X text 629 132 send to client 1;
+#X text 615 155 send to client on socket 504;
+#X text 613 28 'send' prefix is optional;
+#X text 474 48 (the first number is socket number);
+#X msg 556 257 disconnectsocket \$1;
+#X msg 484 284 disconnectclient \$1;
+#X floatatom 506 215 5 0 0 0 - - -;
+#X obj 484 235 f;
+#X obj 484 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699
+-241291 -1;
+#X floatatom 578 216 5 0 0 0 - - -;
+#X obj 556 235 f;
+#X obj 556 216 bng 15 250 50 0 empty empty empty 17 7 0 10 -258699
+-241291 -1;
+#X text 483 197 disconnect by socket or client number;
+#X obj 618 335 unpack 0 0 0 0;
+#X floatatom 618 355 3 0 0 0 - - -;
+#X floatatom 649 355 3 0 0 0 - - -;
+#X floatatom 681 356 3 0 0 0 - - -;
+#X floatatom 715 356 3 0 0 0 - - -;
+#X text 616 372 IP;
+#X floatatom 569 355 5 0 0 0 - - -;
+#X text 566 371 socket;
+#X floatatom 520 376 5 0 0 0 - - -;
+#X text 520 391 number of connections;
+#X obj 471 433 spigot;
+#X obj 510 413 tgl 15 0 empty empty enable_print 17 7 0 10 -24198 -258699
+-258699 0 1;
+#X text 15 37 [tcpsocketserver <protocol> <port>];
+#X obj 469 311 cnv 15 185 22 empty empty empty 20 12 0 14 -204786 -66577
+0;
+#X obj 471 314 tcpsocketserver FUDI 2468;
+#X text 15 115 [tcpsocketserver] is able to handle multiple sockets
+of a packet oriented protocol correctly \, unlike [tcpserver] \, which
+might mix up packets from different sockets.;
+#X text 24 308 - OSC;
+#X text 16 245 each protocol requires its own specific socket handler
+abstraction \, which should be named [tcpsocket.PROTOCOL]. currently
+available are the protocols:;
+#X text 23 293 - FUDI;
+#N canvas 702 157 472 356 EXTENDABILITY 0;
+#X text 3 39 Support for more protocols can easily be added. In order
+to do so:;
+#X text 5 10 EXTENDABILITY;
+#X text 6 105 - open tcpsocket.NEWPROTOCOL.pd;
+#X text 7 127 - edit the green-marked subpatch;
+#X text 10 208 - save it;
+#X text 12 227 - in order to use it \, instantiate:;
+#X text 46 247 [tcpsocketserver NEWPROTOCOL <port>];
+#X text 8 148 - replace code with code \, that creates proper packets
+out of the incoming stream for the desired protocol. don't forget to
+implement a reset mechanism \, in case a socket is closed in the middle
+of packet transmission.;
+#X text 5 83 - copy tcpsocket.FUDI.pd to tcpsocket.NEWPROTOCOL.pd;
+#X restore 21 387 pd EXTENDABILITY;
+#X text 17 453 Author: Roman Haefeli;
+#X text 16 468 Version: 2009-01-11;
+#X text 15 65 [tcpsocketserver] is meant to be a protocol-aware drop-in
+replacement for [tcpserver]. it uses same the same inlet and outlet
+configuration as [tcpserver].;
+#X text 469 478 only well-formed FUDI messages are received here.;
+#N canvas 463 454 147 274 EXAMPLES 0;
+#N canvas 705 77 571 769 FUDI 0;
+#X obj 8 52 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661
+-66577 0;
+#X obj 24 206 tcpclient;
+#X msg 368 107 connect localhost 11001;
+#X msg 392 128 disconnect;
+#X obj 368 85 sel 1 0;
+#X obj 368 64 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
+1;
+#X obj 24 272 print CLIENT_1;
+#X msg 24 83 one two;
+#X obj 24 104 any2string 0 -1;
+#X msg 68 164 59 10;
+#X msg 32 130 32 116 104 114 101 101 23;
+#X obj 8 299 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661
+-66577 0;
+#X msg 368 354 connect localhost 11001;
+#X msg 392 375 disconnect;
+#X obj 368 332 sel 1 0;
+#X obj 368 311 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
+1;
+#X obj 24 227 string2any 0 59;
+#X obj 24 247 route bang;
+#X obj 24 386 netclient;
+#X obj 24 415 print CLIENT_2;
+#X text 168 337 <- send FUDI message;
+#X obj 9 457 cnv 15 550 300 empty empty FUDI_server 20 12 0 14 -241408
+-66577 0;
+#X obj 11 613 tcpsocketserver FUDI 11001;
+#X obj 11 687 string2any 0 59;
+#X obj 11 708 route bang;
+#X obj 190 633 unpack 0 0 0 0;
+#X floatatom 190 653 3 0 0 0 - - -;
+#X floatatom 221 653 3 0 0 0 - - -;
+#X floatatom 253 654 3 0 0 0 - - -;
+#X floatatom 287 654 3 0 0 0 - - -;
+#X text 188 670 IP;
+#X floatatom 130 653 5 0 0 0 - - -;
+#X floatatom 70 654 5 0 0 0 - - -;
+#X text 59 669 clients;
+#X text 126 669 socket;
+#X text 131 688 <--;
+#X text 164 688 [tcpsocketserver FUDI] does _not_ remove the trailing
+' \; ';
+#X text 164 83 1) start a FUDI message;
+#X text 231 131 2) continue;
+#X text 117 165 3) finish FUDI message (with semicolon - newline);
+#X text 390 65 connect;
+#X text 389 309 connect;
+#X text 19 488 [tcpsocketserver FUDI] doesn't take care of building
+FUDI-compliant messages. this should be done by the user.;
+#X text 153 229 4) try sending a message from client_2 during composing
+a message with client_1 and see \, how the server behaves.;
+#X text 278 535 <- this doesn't work;
+#X text 314 562 <- this should;
+#X msg 24 336 send four five six;
+#X msg 42 563 client 2 115 101 118 101 110 32 59 10;
+#X msg 41 534 client 2 115 101 118 101 110 32;
+#X obj 11 733 print SERVER;
+#X obj 20 32 import moocow;
+#X connect 1 0 16 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 2 0;
+#X connect 4 1 3 0;
+#X connect 5 0 4 0;
+#X connect 7 0 8 0;
+#X connect 8 0 1 0;
+#X connect 9 0 1 0;
+#X connect 10 0 1 0;
+#X connect 12 0 18 0;
+#X connect 13 0 18 0;
+#X connect 14 0 12 0;
+#X connect 14 1 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 17 0;
+#X connect 17 1 6 0;
+#X connect 18 0 19 0;
+#X connect 22 0 23 0;
+#X connect 22 1 32 0;
+#X connect 22 2 31 0;
+#X connect 22 3 25 0;
+#X connect 23 0 24 0;
+#X connect 24 1 49 0;
+#X connect 25 0 26 0;
+#X connect 25 1 27 0;
+#X connect 25 2 28 0;
+#X connect 25 3 29 0;
+#X connect 46 0 18 0;
+#X connect 47 0 22 0;
+#X connect 48 0 22 0;
+#X restore 23 25 pd FUDI;
+#N canvas 697 77 579 756 OSC 0;
+#X obj 9 39 cnv 15 550 240 empty empty client_1 20 12 0 14 -249661
+-66577 0;
+#X obj 25 211 tcpclient;
+#X msg 357 229 disconnect;
+#X obj 333 186 sel 1 0;
+#X obj 333 165 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
+1;
+#X obj 25 259 print CLIENT_1;
+#X obj 9 286 cnv 15 550 150 empty empty client_2 20 12 0 14 -249661
+-66577 0;
+#X msg 393 362 disconnect;
+#X obj 369 319 sel 1 0;
+#X obj 369 298 tgl 15 0 empty empty empty 17 7 0 10 -261234 -1 -1 0
+1;
+#X obj 25 417 print CLIENT_2;
+#X obj 10 444 cnv 15 550 300 empty empty OSC_server 20 12 0 14 -241408
+-66577 0;
+#X obj 188 636 unpack 0 0 0 0;
+#X floatatom 188 656 3 0 0 0 - - -;
+#X floatatom 219 656 3 0 0 0 - - -;
+#X floatatom 251 657 3 0 0 0 - - -;
+#X floatatom 285 657 3 0 0 0 - - -;
+#X text 186 673 IP;
+#X floatatom 130 656 5 0 0 0 - - -;
+#X floatatom 73 657 5 0 0 0 - - -;
+#X text 62 672 clients;
+#X text 126 672 socket;
+#X text 355 166 connect;
+#X text 390 296 connect;
+#X obj 16 616 tcpsocketserver OSC 11002;
+#X obj 16 694 unpackOSC;
+#X obj 16 720 print SERVER;
+#X msg 333 208 connect localhost 11002;
+#X msg 369 341 connect localhost 11002;
+#X obj 25 234 unpackOSCstream;
+#X obj 25 373 tcpclient;
+#X obj 25 395 unpackOSCstream;
+#X msg 49 498 /synth1/tone3/freq 440;
+#X msg 25 79 0 0 0 16 47 102 114 101 113;
+#X msg 41 104 0 0 0 44 105 0 0 0 0 1 184;
+#X text 155 324 send OSC message;
+#X msg 25 323 /amplitude 0.78;
+#X obj 25 347 packOSCstream;
+#X obj 16 522 packOSCstream;
+#X obj 16 594 list trim;
+#X msg 16 473 /synth3/tone4/amplitude 0.36;
+#X obj 180 555 hradio 15 1 0 2 empty empty empty 0 -8 0 10 -4034 -1
+-1 0;
+#X obj 180 573 + 1;
+#X text 221 555 client;
+#X obj 16 551 list prepend 1;
+#X obj 16 573 list prepend client;
+#X text 236 80 1) start sending an OSC packet;
+#X text 247 106 2) complete the OSC packet;
+#X text 59 137 also try sending an OSC packet from client_2 between
+1) and 2);
+#X text 124 520 <- use [packOSCstream] in order to create OSC packets
+suitable for tcp transport.;
+#X text 238 486 send to clients;
+#X text 93 695 <---;
+#X text 139 694 CAUTION: not [unpackOSCstream] is used here \, since
+[tcpsocket.OSC] already unwraps the OSC message;
+#X obj 8 9 import moocow;
+#X connect 1 0 29 0;
+#X connect 2 0 1 0;
+#X connect 3 0 27 0;
+#X connect 3 1 2 0;
+#X connect 4 0 3 0;
+#X connect 7 0 30 0;
+#X connect 8 0 28 0;
+#X connect 8 1 7 0;
+#X connect 9 0 8 0;
+#X connect 12 0 13 0;
+#X connect 12 1 14 0;
+#X connect 12 2 15 0;
+#X connect 12 3 16 0;
+#X connect 24 0 25 0;
+#X connect 24 1 19 0;
+#X connect 24 2 18 0;
+#X connect 24 3 12 0;
+#X connect 25 0 26 0;
+#X connect 27 0 1 0;
+#X connect 28 0 30 0;
+#X connect 29 0 5 0;
+#X connect 30 0 31 0;
+#X connect 31 0 10 0;
+#X connect 32 0 38 0;
+#X connect 33 0 1 0;
+#X connect 34 0 1 0;
+#X connect 36 0 37 0;
+#X connect 37 0 30 0;
+#X connect 38 0 44 0;
+#X connect 39 0 24 0;
+#X connect 40 0 38 0;
+#X connect 41 0 42 0;
+#X connect 42 0 44 1;
+#X connect 44 0 45 0;
+#X connect 45 0 39 0;
+#X restore 23 49 pd OSC;
+#X restore 21 365 pd EXAMPLES;
+#X obj 471 455 print FUDI;
+#X msg 471 101 broadcast 97 98 99 59 10;
+#X msg 471 128 client 1 97 98 99 59 10;
+#X msg 471 155 send 504 97 98 99 59 10;
+#X msg 471 28 10 97 98 99 59 10;
+#X text 17 8 TCPSOCKETSERVER - a protocol-aware wrapper aroun [tcpserver]
+;
+#X text 13 167 [tcpsocketserver] dynamically creates (internally) an
+instance of a socket handler abstraction [tcpsocket.PROTOCOL] for each
+opened socket. every socket handler creates proper packets from the
+incoming stream and sends them to the left outlet of [tcpsocketserver].
+;
+#X connect 0 0 30 0;
+#X connect 7 0 30 0;
+#X connect 8 0 30 0;
+#X connect 9 0 10 1;
+#X connect 10 0 8 0;
+#X connect 11 0 10 0;
+#X connect 12 0 13 1;
+#X connect 13 0 7 0;
+#X connect 14 0 13 0;
+#X connect 16 0 17 0;
+#X connect 16 1 18 0;
+#X connect 16 2 19 0;
+#X connect 16 3 20 0;
+#X connect 26 0 41 0;
+#X connect 27 0 26 1;
+#X connect 30 0 26 0;
+#X connect 30 1 24 0;
+#X connect 30 2 22 0;
+#X connect 30 3 16 0;
+#X connect 42 0 30 0;
+#X connect 43 0 30 0;
+#X connect 44 0 30 0;
+#X connect 45 0 30 0;
diff --git a/externals/mrpeach/osc/tcpsocketserver.pd b/externals/mrpeach/net/tcpsocketserver.pd
similarity index 70%
rename from externals/mrpeach/osc/tcpsocketserver.pd
rename to externals/mrpeach/net/tcpsocketserver.pd
index 3e8f8dd99..e6ed91cb1 100644
--- a/externals/mrpeach/osc/tcpsocketserver.pd
+++ b/externals/mrpeach/net/tcpsocketserver.pd
@@ -1,106 +1,111 @@
-#N canvas 332 12 333 552 10;
-#X declare -stdpath extra/mrpeach;
-#X obj 13 39 inlet;
-#X obj 13 464 outlet;
-#X obj 75 463 outlet;
-#X obj 137 463 outlet;
-#X obj 199 462 outlet;
-#X obj 36 187 list trim;
-#X obj 59 145 list trim;
-#X obj 59 124 list prepend socket;
-#X obj 36 166 list prepend num_of_clients;
-#X obj 82 103 list trim;
-#X obj 82 82 list prepend ip;
-#N canvas 816 227 247 348 \$0.TCPSOCKETCONTAINER 0;
-#X restore 14 372 pd \$0.TCPSOCKETCONTAINER;
-#N canvas 491 218 502 504 socketmanager 0;
-#X msg 24 196 \$1 reset;
-#X obj 25 259 route done;
-#X obj 5 175 t a a b;
-#X msg 25 280 0;
-#X msg 44 280 1;
-#X obj 5 303 spigot;
-#X obj 44 344 f;
-#X obj 76 344 + 20;
-#X obj 5 323 t a b b;
-#X obj 24 365 list append \$1;
-#X obj 24 388 list append;
-#X obj 5 412 list append;
-#X obj 5 476 s pd-\$0.TCPSOCKETCONTAINER;
-#X obj 5 432 list append \$0;
-#X obj 5 24 route socket num_of_clients;
-#X obj 84 46 t a a;
-#X obj 69 73 -;
-#X obj 69 94 == 1;
-#X obj 5 122 spigot;
-#X obj 5 3 r \$0.TCPSOCKET;
-#X obj 24 217 s \$0.TCPSOCKET;
-#X obj 25 238 r \$0.TCPSOCKET;
-#X msg 5 454 obj 10 \$3 tcpsocket.\$2 \$4 \$1 \, loadbang;
-#X obj 5 148 t a b;
-#X msg 65 132 0;
-#X text 116 78 when a new client connects (num_of_clients: +1);
-#X text 119 197 send a 'reset' to the according socket handler;
-#X text 114 266 and if it doesn't respond (which means \, there is
-no socket handler on specified socket) \,;
-#X text 119 368 create one (into pd-\$0.TCPSOCKETCONTAINER).;
-#X connect 0 0 20 0;
-#X connect 1 0 3 0;
-#X connect 2 0 5 0;
-#X connect 2 1 0 0;
-#X connect 2 2 4 0;
-#X connect 3 0 5 1;
-#X connect 4 0 5 1;
-#X connect 5 0 8 0;
-#X connect 6 0 7 0;
-#X connect 6 0 10 1;
-#X connect 7 0 6 1;
-#X connect 8 0 11 0;
-#X connect 8 1 9 0;
-#X connect 8 2 6 0;
-#X connect 9 0 10 0;
-#X connect 10 0 11 1;
-#X connect 11 0 13 0;
-#X connect 13 0 22 0;
-#X connect 14 0 18 0;
-#X connect 14 1 15 0;
-#X connect 15 0 16 1;
-#X connect 15 1 16 0;
-#X connect 16 0 17 0;
-#X connect 17 0 18 1;
-#X connect 18 0 23 0;
-#X connect 19 0 14 0;
-#X connect 21 0 1 0;
-#X connect 22 0 12 0;
-#X connect 23 0 2 0;
-#X connect 23 1 24 0;
-#X connect 24 0 18 1;
-#X restore 14 349 pd socketmanager;
-#X obj 13 60 tcpserver \$2;
-#X obj 13 417 r \$0.TCPSOCKET;
-#X obj 13 208 list prepend in;
-#X obj 13 440 route out num_of_clients socket.out ip.out;
-#X obj 13 230 list trim;
-#X obj 82 316 s \$0.TCPSOCKET;
-#X text 23 501 Author: Roman Haefeli;
-#X text 24 518 Version: 2009-01-11;
-#X text 94 292 [tcpsocketserver <protocol> <port>];
-#X obj 13 14 declare -stdpath extra/mrpeach;
-#X connect 0 0 13 0;
-#X connect 5 0 18 0;
-#X connect 6 0 18 0;
-#X connect 7 0 6 0;
-#X connect 8 0 5 0;
-#X connect 9 0 18 0;
-#X connect 10 0 9 0;
-#X connect 13 0 15 0;
-#X connect 13 1 8 0;
-#X connect 13 2 7 0;
-#X connect 13 3 10 0;
-#X connect 14 0 16 0;
-#X connect 15 0 17 0;
-#X connect 16 0 1 0;
-#X connect 16 1 2 0;
-#X connect 16 2 3 0;
-#X connect 16 3 4 0;
-#X connect 17 0 18 0;
+#N canvas 332 53 333 552 10;
+#X obj 13 9 inlet;
+#X obj 13 464 outlet;
+#X obj 71 463 outlet;
+#X obj 129 463 outlet;
+#X obj 187 462 outlet;
+#X obj 30 207 list trim;
+#X obj 47 165 list trim;
+#X obj 47 144 list prepend socket;
+#X obj 30 186 list prepend num_of_clients;
+#X obj 64 123 list trim;
+#X obj 64 102 list prepend ip;
+#N canvas 816 227 247 348 \$0.TCPSOCKETCONTAINER 0;
+#X restore 14 372 pd \$0.TCPSOCKETCONTAINER;
+#N canvas 491 218 502 504 socketmanager 0;
+#X msg 24 196 \$1 reset;
+#X obj 25 259 route done;
+#X obj 5 175 t a a b;
+#X msg 25 280 0;
+#X msg 44 280 1;
+#X obj 5 303 spigot;
+#X obj 44 344 f;
+#X obj 76 344 + 20;
+#X obj 5 323 t a b b;
+#X obj 24 365 list append \$1;
+#X obj 24 388 list append;
+#X obj 5 412 list append;
+#X obj 5 476 s pd-\$0.TCPSOCKETCONTAINER;
+#X obj 5 432 list append \$0;
+#X obj 5 24 route socket num_of_clients;
+#X obj 84 46 t a a;
+#X obj 69 73 -;
+#X obj 69 94 == 1;
+#X obj 5 122 spigot;
+#X obj 5 3 r \$0.TCPSOCKET;
+#X obj 24 217 s \$0.TCPSOCKET;
+#X obj 25 238 r \$0.TCPSOCKET;
+#X msg 5 454 obj 10 \$3 tcpsocket.\$2 \$4 \$1 \, loadbang;
+#X obj 5 148 t a b;
+#X msg 65 132 0;
+#X text 116 78 when a new client connects (num_of_clients: +1);
+#X text 119 197 send a 'reset' to the according socket handler;
+#X text 114 266 and if it doesn't respond (which means \, there is
+no socket handler on specified socket) \,;
+#X text 119 368 create one (into pd-\$0.TCPSOCKETCONTAINER).;
+#X connect 0 0 20 0;
+#X connect 1 0 3 0;
+#X connect 2 0 5 0;
+#X connect 2 1 0 0;
+#X connect 2 2 4 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 1;
+#X connect 5 0 8 0;
+#X connect 6 0 7 0;
+#X connect 6 0 10 1;
+#X connect 7 0 6 1;
+#X connect 8 0 11 0;
+#X connect 8 1 9 0;
+#X connect 8 2 6 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 13 0;
+#X connect 13 0 22 0;
+#X connect 14 0 18 0;
+#X connect 14 1 15 0;
+#X connect 15 0 16 1;
+#X connect 15 1 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 1;
+#X connect 18 0 23 0;
+#X connect 19 0 14 0;
+#X connect 21 0 1 0;
+#X connect 22 0 12 0;
+#X connect 23 0 2 0;
+#X connect 23 1 24 0;
+#X connect 24 0 18 1;
+#X restore 14 349 pd socketmanager;
+#X obj 13 30 tcpserver \$2;
+#X obj 13 417 r \$0.TCPSOCKET;
+#X obj 13 228 list prepend in;
+#X obj 13 250 list trim;
+#X obj 82 316 s \$0.TCPSOCKET;
+#X text 23 501 Author: Roman Haefeli;
+#X text 94 292 [tcpsocketserver <protocol> <port>];
+#X obj 82 78 list trim;
+#X obj 82 57 list prepend status;
+#X obj 13 440 route out num_of_clients socket.out ip.out status;
+#X text 24 518 Version: 2012-04-13;
+#X obj 245 461 outlet;
+#X connect 0 0 13 0;
+#X connect 5 0 17 0;
+#X connect 6 0 17 0;
+#X connect 7 0 6 0;
+#X connect 8 0 5 0;
+#X connect 9 0 17 0;
+#X connect 10 0 9 0;
+#X connect 13 0 15 0;
+#X connect 13 1 8 0;
+#X connect 13 2 7 0;
+#X connect 13 3 10 0;
+#X connect 13 4 21 0;
+#X connect 14 0 22 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 20 0 17 0;
+#X connect 21 0 20 0;
+#X connect 22 0 1 0;
+#X connect 22 1 2 0;
+#X connect 22 2 3 0;
+#X connect 22 3 4 0;
+#X connect 22 4 24 0;
diff --git a/externals/mrpeach/net/udpreceive~-help.pd b/externals/mrpeach/net/udpreceive~-help.pd
new file mode 100644
index 000000000..c7ed70ac3
--- /dev/null
+++ b/externals/mrpeach/net/udpreceive~-help.pd
@@ -0,0 +1,88 @@
+#N canvas 221 129 767 415 10;
+#N canvas 874 257 494 344 META 0;
+#X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan
+Wilkes for Pd version 0.42.;
+#X text 12 25 LICENSE GPL v2 or later;
+#X text 12 135 AUTHOR Martin Peach;
+#X text 12 5 KEYWORDS control network;
+#X text 12 45 DESCRIPTION receive datagrams over a udp connection and
+outputs them as a signal;
+#X restore 695 379 pd META;
+#X obj 522 267 print udpreceive~;
+#X symbolatom 177 354 10 0 0 0 - - -;
+#X floatatom 211 288 5 0 0 0 - - -;
+#X floatatom 246 267 7 0 0 0 - - -;
+#X floatatom 280 332 9 0 0 0 - - -;
+#X obj 177 313 prepend set;
+#X text 147 287 channels:;
+#X text 131 353 format:;
+#X text 231 331 bitrate:;
+#X text 182 266 framesize:;
+#X floatatom 315 289 9 0 0 0 - - -;
+#X floatatom 349 267 9 0 0 0 - - -;
+#X floatatom 384 310 5 0 0 0 - - -;
+#X floatatom 418 289 5 0 0 0 - - -;
+#X text 258 288 overflow:;
+#X text 289 266 underflow:;
+#X text 323 309 queuesize:;
+#X text 370 288 average:;
+#X msg 35 58 info;
+#X msg 15 38 reset;
+#X text 68 57 status info to rightmost outlet;
+#X text 53 37 reset underflow & overflow counters;
+#X floatatom 210 169 3 0 0 0 - - -;
+#X floatatom 233 169 3 0 0 0 - - -;
+#X floatatom 256 169 3 0 0 0 - - -;
+#X floatatom 279 169 3 0 0 0 - - -;
+#X floatatom 303 169 5 0 0 0 - - -;
+#X obj 210 143 unpack 0 0 0 0 0;
+#X text 173 168 from:;
+#X obj 82 152 dac~ 1 2;
+#X floatatom 453 332 9 0 0 0 - - -;
+#X text 401 331 packets:;
+#X text 348 142 To communicate \, a [udpreceive~] and [udpsend~] pair
+must have the same number of channels and the same blocksize. Also
+[udpsend~] must [connect( to the port on which [udpreceive~] is listening.
+;
+#X msg 56 79 buffer 2;
+#X text 118 78 set number of frames to buffer before playback;
+#X obj 177 230 route format channels framesize bitrate overflow underflow
+queuesize average packets tag_errors;
+#X floatatom 487 310 9 0 0 0 - - -;
+#X text 421 309 tag errors:;
+#X obj 144 181 env~;
+#X floatatom 144 204 9 0 0 0 - - -;
+#X text 204 193 The rightmost signal outlet outputs 1 if the stream
+is valid \, else 0;
+#X text 420 77 Arguments: port \, channels \, blocksize \, multicast_address.
+Blocksize should match [udpsend~]. multicast_address is optional. Arguments
+must be in that order.;
+#X obj 81 121 udpreceive~ 9999 2 512;
+#X text 221 120 receives 2 channels on port 9999 Same blocksize as
+udpsend~;
+#X connect 6 0 2 0;
+#X connect 19 0 43 0;
+#X connect 20 0 43 0;
+#X connect 28 0 23 0;
+#X connect 28 1 24 0;
+#X connect 28 2 25 0;
+#X connect 28 3 26 0;
+#X connect 28 4 27 0;
+#X connect 34 0 43 0;
+#X connect 36 0 6 0;
+#X connect 36 1 3 0;
+#X connect 36 2 4 0;
+#X connect 36 3 5 0;
+#X connect 36 4 11 0;
+#X connect 36 5 12 0;
+#X connect 36 6 13 0;
+#X connect 36 7 14 0;
+#X connect 36 8 31 0;
+#X connect 36 9 37 0;
+#X connect 36 10 1 0;
+#X connect 39 0 40 0;
+#X connect 43 0 30 0;
+#X connect 43 1 30 1;
+#X connect 43 2 39 0;
+#X connect 43 3 36 0;
+#X connect 43 4 28 0;
diff --git a/externals/mrpeach/net/udpreceive~.c b/externals/mrpeach/net/udpreceive~.c
index 75b5996eb..86a7f082b 100644
--- a/externals/mrpeach/net/udpreceive~.c
+++ b/externals/mrpeach/net/udpreceive~.c
@@ -37,7 +37,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <string.h>
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
 #include <sys/socket.h>
 #include <errno.h>
 #include <netinet/in.h>
@@ -67,7 +67,7 @@
 #define DEFAULT_NETWORK_POLLTIME 1      /* interval in ms for polling for input data (Max/MSP only) */
 #define DEFAULT_QUEUE_LENGTH 3          /* min. number of buffers that can be used reliably on your hardware */
 
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
 #define CLOSESOCKET(fd) close(fd)
 #endif
 #ifdef _WIN32
@@ -865,7 +865,7 @@ static int udpreceive_tilde_sockerror(char *s)
 #ifdef _WIN32
     if (err == WSAEWOULDBLOCK)
 #endif
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
     if (err == EAGAIN)
 #endif
     {
diff --git a/externals/mrpeach/net/udpsend~.c b/externals/mrpeach/net/udpsend~.c
index 2c56d8cb0..5846524ab 100644
--- a/externals/mrpeach/net/udpsend~.c
+++ b/externals/mrpeach/net/udpsend~.c
@@ -39,7 +39,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <math.h>
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
 #include <sys/socket.h>
 #include <errno.h>
 #include <netinet/in.h>
@@ -887,7 +887,7 @@ static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize)
         x->x_cbufsize = x->x_blocksize * sizeof(t_float) * x->x_ninlets;
         x->x_cbuf = (char *)t_getbytes(x->x_cbufsize);
 
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
         /* we don't want to get signaled in case send() fails */
         signal(SIGPIPE, SIG_IGN);
 #endif
@@ -990,7 +990,7 @@ static int udpsend_tilde_sockerror(char *s)
 #ifdef _WIN32
     if (err == WSAEWOULDBLOCK)
 #endif
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
     if (err == EAGAIN)
 #endif
     {
@@ -1001,7 +1001,7 @@ static int udpsend_tilde_sockerror(char *s)
 
 static void udpsend_tilde_closesocket(int fd)
 {
-#if defined(UNIX) || defined(unix)
+#ifndef _WIN32
     close(fd);
 #endif
 #ifdef _WIN32
diff --git a/externals/mrpeach/osc/LICENSE.txt b/externals/mrpeach/osc/LICENSE.txt
new file mode 100644
index 000000000..1778d9a59
--- /dev/null
+++ b/externals/mrpeach/osc/LICENSE.txt
@@ -0,0 +1,16 @@
+    OpenSoundControl for Pure data
+    Copyright (C) 2006-2011 Martin Peach
+
+    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 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 <http://www.gnu.org/licenses/>.
+
diff --git a/externals/mrpeach/osc/Makefile b/externals/mrpeach/osc/Makefile
index 718535983..06855f0b8 100644
--- a/externals/mrpeach/osc/Makefile
+++ b/externals/mrpeach/osc/Makefile
@@ -1,37 +1,381 @@
-# written by Alex Norman
-# added by Mathieu Bouchard
-# because there are several people who want to compile mrpeach/osc without pd-extended
+## Pd library template version 1.0.9-zmoelnig
+# For instructions on how to use this template, see:
+#  http://puredata.info/docs/developer/MakefileTemplate
+#
 
-#change these to your liking
-prefix = /usr/local/
-libdir = $(DESTDIR)/$(prefix)/lib/pd/extra/
+# the name of this library
+# must not contain any spaces or weird characters (as it's used for
+# filenames,...)
+LIBRARY_NAME = osc
+
+# add your .c source files, one object per file, to the SOURCES
+# variable, help files will be included automatically, and for GUI
+# objects, the matching .tcl file too
+SOURCES = packOSC.c  pipelist.c  routeOSC.c  unpackOSC.c
+
+# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
+# be included automatically
+PDOBJECTS = packOSCstream.pd unpackOSCstream.pd
+
+# example patches and related files, in the 'examples' subfolder
+EXAMPLES = 
+
+# manuals and related files, in the 'manual' subfolder
+MANUAL = 
+
+# if you want to include any other files in the source and binary tarballs,
+# list them here.  This can be anything from header files, test patches,
+# documentation, etc.  README.txt and LICENSE.txt are required and therefore
+# automatically included
+EXTRA_DIST = packingOSC.h
+
+
+HELPPATCHES = \
+	packOSC-help.pd \
+	packOSCstream-help.pd \
+	pipelist-help.pd routeOSC-help.pd \
+	unpackOSCstream-help.pd
+
+#------------------------------------------------------------------------------#
+#
+# things you might need to edit if you are using other C libraries
+#
+#------------------------------------------------------------------------------#
+
+# -I"$(PD_INCLUDE)" supports the header location for 0.43
+ALL_CFLAGS = -I"$(PD_INCLUDE)"
+ALL_LDFLAGS =  
+ALL_LIBS = 
+
+#------------------------------------------------------------------------------#
+#
+# you shouldn't need to edit anything below here, if we did it right :)
+#
+#------------------------------------------------------------------------------#
+
+# these can be set from outside without (usually) breaking the build
+CFLAGS = -Wall -W -g
+LDFLAGS=
+LIBS=
+
+# get library version from meta file
+LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
+
+ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"'
+
+PD_INCLUDE = $(PD_PATH)/include/pd
+# where to install the library, overridden below depending on platform
+prefix = /usr/local
+libdir = $(prefix)/lib
+pkglibdir = $(libdir)/pd-externals
+objectsdir = $(pkglibdir)
 
-INCLUDES += -I/usr/local/include/
-CFLAGS += ${INCLUDES} -shared
-SUFFIX = pd_linux
 INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -p -m 644
+INSTALL_DATA = $(INSTALL) -p -m 644
+INSTALL_DIR     = $(INSTALL) -p -m 755 -d
+
+ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
+	         $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
+
+DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
+ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
+
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Darwin)
+  CPU := $(shell uname -p)
+  ifeq ($(CPU),arm) # iPhone/iPod Touch
+    SOURCES += $(SOURCES_iphoneos)
+    EXTENSION = pd_darwin
+    OS = iphoneos
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
+    CC=$(IPHONE_BASE)/gcc
+    CPP=$(IPHONE_BASE)/cpp
+    CXX=$(IPHONE_BASE)/g++
+    ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
+    IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
+    OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
+    ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS)
+    ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
+    ALL_LIBS += -lc 
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+  else # Mac OS X
+    SOURCES += $(SOURCES_macosx)
+    EXTENSION = pd_darwin
+    OS = macosx
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast
+# build universal 32-bit on 10.4 and 32/64 on newer
+    ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
+      FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4
+    else
+      FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+      SOURCES += $(SOURCES_iphoneos)
+    endif
+    ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include
+    ALL_LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib
+    # if the 'pd' binary exists, check the linking against it to aid with stripping
+    ALL_LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd)
+    ALL_LIBS += -lc 
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
+    pkglibdir=$(HOME)/Library/Pd
+  endif
+endif
+# Tho Android uses Linux, we use this fake uname to provide an easy way to
+# setup all this things needed to cross-compile for Android using the NDK
+ifeq ($(UNAME),ANDROID)
+  CPU := arm
+  SOURCES += $(SOURCES_android)
+  EXTENSION = pd_linux
+  OS = android
+  PD_PATH = /usr
+  NDK_BASE := /usr/local/android-ndk
+  NDK_PLATFORM_VERSION := 5
+  NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm
+  NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+  NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86
+  CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  CFLAGS += 
+  LDFLAGS += -Wl,--export-dynamic -shared
+  LIBS += -lc
+  STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
+	--strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),Linux)
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -Wl,--export-dynamic  -shared -fPIC
+  ALL_LIBS += -lc
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU)
+  # GNU/Hurd, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -Wl,--export-dynamic  -shared -fPIC
+  ALL_LIBS += -lc
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU/kFreeBSD)
+  # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -Wl,--export-dynamic  -shared -fPIC
+  ALL_LIBS += -lc
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_cygwin)
+  EXTENSION = dll
+  OS = cygwin
+  PD_PATH = $(cygpath $(PROGRAMFILES))/pd
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += 
+  ALL_LDFLAGS += -Wl,--export-dynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+  ALL_LIBS += -lc -lpd
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_windows)
+  EXTENSION = dll
+  OS = windows
+  PD_PATH = $(shell cd "$(PROGRAMFILES)"/pd && pwd)
+  OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -mms-bitfields
+  ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import
+  ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" -lpd -lwsock32 -lkernel32 -luser32 -lgdi32
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
 
-SRC =   packOSC.c \
-	pipelist.c \
-	routeOSC.c \
-	unpackOSC.c
+# in case somebody manually set the HELPPATCHES above
+HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
 
-TARGETS	 = ${SRC:.c=.${SUFFIX}}
+CFLAGS += $(OPT_CFLAGS)
 
-build: ${TARGETS}
+ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS)
+ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS)
+ALL_LIBS := $(LIBS) $(ALL_LIBS)
 
-configure:
+.PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME)
 
-#build the libraries
-%.${SUFFIX}: %.c
-	${CC} ${CFLAGS} -o $*.${SUFFIX} $<
+all: $(SOURCES:.c=.$(EXTENSION))
+
+%.o: %.c
+	$(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c"
+
+%.$(EXTENSION): %.o
+	$(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o"  $(ALL_LIBS)
+	chmod a-x "$*.$(EXTENSION)"
+
+# this links everything into a single binary file
+$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o
+	$(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS)
+	chmod a-x $(LIBRARY_NAME).$(EXTENSION)
+
+install: libdir_install
+
+# The meta and help files are explicitly installed to make sure they are
+# actually there.  Those files are not optional, then need to be there.
+libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
+		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES))" || (\
+		$(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \
+		$(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION))))
+	test -z "$(strip $(shell ls $(SOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(shell ls $(SOURCES:.c=.tcl)) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+
+# install library linked as single binary
+single_install: $(LIBRARY_NAME) install-doc install-exec
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+
+install-doc:
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
+	$(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
+
+install-examples:
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
+		done
+
+install-manual:
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
+		done
 
-#install the libraries and documentation
-install: ${TARGETS}
-	${INSTALL} -t ${libdir} ${TARGETS}
-	${INSTALL} -t ${libdir} *.pd
 
 clean:
-	rm -f ${TARGETS}
+	-rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o)
+	-rm -f -- $(SOURCES:.c=.$(EXTENSION))
+	-rm -f -- $(LIBRARY_NAME).o
+	-rm -f -- $(LIBRARY_NAME).$(EXTENSION)
+
+distclean: clean
+	-rm -f -- $(DISTBINDIR).tar.gz
+	-rm -rf -- $(DISTBINDIR)
+	-rm -f -- $(DISTDIR).tar.gz
+	-rm -rf -- $(DISTDIR)
+	-rm -f -- $(ORIGDIR).tar.gz
+	-rm -rf -- $(ORIGDIR)
+
+
+$(DISTBINDIR):
+	$(INSTALL_DIR) $(DISTBINDIR)
+
+libdir: all $(DISTBINDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
+	$(INSTALL_DATA) $(SOURCES)  $(DISTBINDIR)
+	$(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTBINDIR)
+#	tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
+
+$(DISTDIR):
+	$(INSTALL_DIR) $(DISTDIR)
+
+$(ORIGDIR):
+	$(INSTALL_DIR) $(ORIGDIR)
+
+dist: $(DISTDIR)
+	$(INSTALL_DATA) Makefile  $(DISTDIR)
+	$(INSTALL_DATA) README.txt $(DISTDIR)
+	$(INSTALL_DATA) LICENSE.txt $(DISTDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
+	test -z "$(strip $(ALLSOURCES))" || \
+		$(INSTALL_DATA) $(ALLSOURCES)  $(DISTDIR)
+	test -z "$(strip $(shell ls $(ALLSOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(shell ls $(ALLSOURCES:.c=.tcl))  $(DISTDIR)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS)  $(DISTDIR)
+	test -z "$(strip $(HELPPATCHES))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTDIR)
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DISTDIR)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
+		done
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DISTDIR)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
+		done
+	tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
+
+# make a Debian source package
+dpkg-source:
+	debclean
+	make distclean dist
+	mv $(DISTDIR) $(ORIGDIR)
+	tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
+	rm -f -- $(DISTDIR).tar.gz
+	rm -rf -- $(DISTDIR) $(ORIGDIR)
+	cd .. && dpkg-source -b $(LIBRARY_NAME)
 
+etags:
+	etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h
 
+showsetup:
+	@echo "CFLAGS: $(CFLAGS)"
+	@echo "LDFLAGS: $(LDFLAGS)"
+	@echo "LIBS: $(LIBS)"
+	@echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+	@echo "ALL_LDFLAGS: $(ALL_LDFLAGS)"
+	@echo "ALL_LIBS: $(ALL_LIBS)"
+	@echo "PD_INCLUDE: $(PD_INCLUDE)"
+	@echo "PD_PATH: $(PD_PATH)"
+	@echo "objectsdir: $(objectsdir)"
+	@echo "LIBRARY_NAME: $(LIBRARY_NAME)"
+	@echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
+	@echo "SOURCES: $(SOURCES)"
+	@echo "PDOBJECTS: $(PDOBJECTS)"
+	@echo "ALLSOURCES: $(ALLSOURCES)"
+	@echo "UNAME: $(UNAME)"
+	@echo "CPU: $(CPU)"
+	@echo "pkglibdir: $(pkglibdir)"
+	@echo "DISTDIR: $(DISTDIR)"
+	@echo "ORIGDIR: $(ORIGDIR)"
diff --git a/externals/mrpeach/osc/README.txt b/externals/mrpeach/osc/README.txt
new file mode 100644
index 000000000..92763c981
--- /dev/null
+++ b/externals/mrpeach/osc/README.txt
@@ -0,0 +1,38 @@
+OpenSoundControl (OSC) for Pd
+=============================
+
+a collection of Pd objectclasses for OSC-messages.
+these objects only convert between Pd-messages and OSC-messages (binary format),
+so you will need a separate set of objects that implement the transport
+(OSI-Layer 4), for instance [udpsend]/[udpreceive] for sending OSC over UDP.
+
+Author: Martin Peach
+
+objectclasses
+
+- [packOSC]
+	convert a Pd-message to an OSC (binary) message
+	(useful if you want to transmit OSC over UDP or other protocols that
+	have the concept of variable length packets)
+
+- [unpackOSC]
+	convert an OSC (binary) message to a Pd-message
+	(useful if you want to transmit OSC over UDP or other protocols that
+	have the concept of variable length packets)
+
+- [routeOSC]
+	route OSC-like Pd-messages according to the first element in the path
+
+- [pipelist]
+	delay lists 
+	(useful if you want to respect timestamps)
+
+- [packOSCstream]
+	convert a Pd-message to an OSC (binary) message suitable for streaming transport
+	(useful if you want to transmit OSC over TCP/IP or a serial line)
+	
+- [unpackOSCstream]
+	convert an OSC (binary) message suitable for streaming transport to a Pd-message
+	(useful if you want to transmit OSC over TCP/IP or a serial line)
+
+
diff --git a/externals/mrpeach/osc/osc-meta.pd b/externals/mrpeach/osc/osc-meta.pd
new file mode 100644
index 000000000..d676e3b98
--- /dev/null
+++ b/externals/mrpeach/osc/osc-meta.pd
@@ -0,0 +1,7 @@
+#N canvas 18 212 200 200 10;
+#N canvas 28 50 420 300 META 1;
+#X text 13 61 NAME OSC;
+#X text 13 85 VERSION 0.1;
+#X text 13 129 AUTHOR Martin Peach;
+#X text 19 189 NOTE:;
+#X restore 10 10 pd META;
diff --git a/externals/mrpeach/osc/packOSC.c b/externals/mrpeach/osc/packOSC.c
index b2d108612..8af87700c 100644
--- a/externals/mrpeach/osc/packOSC.c
+++ b/externals/mrpeach/osc/packOSC.c
@@ -33,22 +33,8 @@ The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
 
 #define SC_BUFFER_SIZE 64000
 
-#include "m_pd.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
+#include "packingOSC.h"
 
-#ifdef _WIN32
-#include <winsock2.h>
-#include <sys/timeb.h>
-#else
-#include <ctype.h>
-#include <sys/time.h>
-#endif
-
-#ifdef unix
-#include <netinet/in.h>
-#endif
 /* This is from OSC-client.h :*/
 /*
 
@@ -92,14 +78,6 @@ The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
  to dereference a pointer to an 8 byte int that's not 8-byte aligned.
 */
 
-/* You may have to redefine this typedef if ints on your system
-  aren't 4 bytes. */
-typedef unsigned int uint4;
-typedef struct
-{
-    uint4 seconds;
-    uint4 fraction;
-} OSCTimeTag;
 
 /* Return the time tag 0x0000000000000001, indicating to the receiving device
    that it should process the message immediately. */
@@ -112,11 +90,6 @@ static OSCTimeTag OSCTT_CurrentTimePlusOffset(uint4 offset);
    change this to long or something else on your system.  */
 typedef int int4byte;
 
-/* The maximum depth of bundles within bundles within bundles within...
-   This is the size of a static array.  If you exceed this limit you'll
-   get an error message. */
-#define MAX_BUNDLE_NESTING 32
-
 /* Don't ever manipulate the data in the OSCbuf struct directly.  (It's
    declared here in the header file only so your program will be able to
    declare variables of type OSCbuf and have the right amount of memory
@@ -124,19 +97,19 @@ typedef int int4byte;
 
 typedef struct OSCbuf_struct
 {
-	char		*buffer; /* The buffer to hold the OSC packet */
-    size_t		size; /* Size of the buffer */
-    char		*bufptr; /* Current position as we fill the buffer */
-    int			state; /* State of partially-constructed message */
-    int4byte	*thisMsgSize; /* Pointer to count field before */
-                      /* currently-being-written message */
-    int4byte	*prevCounts[MAX_BUNDLE_NESTING]; /* Pointers to count */
-                      /* field before each currently open bundle */
-    int			bundleDepth; /* How many sub-sub-bundles are we in now? */
-    char		*typeStringPtr; /* This pointer advances through the type */
-                      /* tag string as you add arguments. */
-    int			gettingFirstUntypedArg; /* nonzero if this message doesn't have */
-                      /*  a type tag and we're waiting for the 1st arg */
+    char        *buffer; /* The buffer to hold the OSC packet */
+    size_t      size; /* Size of the buffer */
+    char        *bufptr; /* Current position as we fill the buffer */
+    int         state; /* State of partially-constructed message */
+    int4byte    *thisMsgSize; /* Pointer to count field before */
+                /* currently-being-written message */
+    int4byte    *prevCounts[MAX_BUNDLE_NESTING]; /* Pointers to count */
+                /* field before each currently open bundle */
+    int         bundleDepth; /* How many sub-sub-bundles are we in now? */
+    char        *typeStringPtr; /* This pointer advances through the type */
+                /* tag string as you add arguments. */
+    int         gettingFirstUntypedArg; /* nonzero if this message doesn't have */
+                /*  a type tag and we're waiting for the 1st arg */
 } OSCbuf;
 
 typedef struct
@@ -147,12 +120,12 @@ typedef struct
         int   i;
         float f;
         char  *s;
-	} datum;
+    } datum;
 } typedArg;
 
 /* Here are the possible values of the state field: */
 
-#define EMPTY 0	/* Nothing written to packet yet */
+#define EMPTY 0 /* Nothing written to packet yet */
 #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
 #define NEED_COUNT 2 /* Just opened a bundle; must write message name or */
                      /* open another bundle */
@@ -177,17 +150,14 @@ static int CheckTypeTag(OSCbuf *buf, char expectedType);
    you do it differently in different systems.) */
 static void OSC_initBuffer(OSCbuf *buf, size_t size, char *byteArray);
 
-
 /* Reset the given OSCbuf.  Do this after you send out the contents of
    the buffer and want to start writing new data into it. */
 static void OSC_resetBuffer(OSCbuf *buf);
 
-
 /* Is the buffer empty?  (I.e., would it be stupid to send the buffer
    contents to the synth?) */
 static int OSC_isBufferEmpty(OSCbuf *buf);
 
-
 /* How much space is left in the buffer? */
 static size_t OSC_freeSpaceInBuffer(OSCbuf *buf);
 
@@ -211,18 +181,18 @@ static int OSC_CheckOverflow(OSCbuf *buf, size_t bytesNeeded);
       single message.
     - For each message you want to send:
       - Call OSC_writeAddress() with the name of your message.  (In
-	    addition to writing your message name into the buffer, this
-	    procedure will also leave space for the size count of this message.)
+        addition to writing your message name into the buffer, this
+        procedure will also leave space for the size count of this message.)
       - Alternately, call OSC_writeAddressAndTypes() with the name of
         your message and with a type string listing the types of all the
         arguments you will be putting in this message.
-	  - Now write each of the arguments into the buffer, by calling one of:
-	    OSC_writeFloatArg()
-	    OSC_writeIntArg()
-	    OSC_writeStringArg()
+      - Now write each of the arguments into the buffer, by calling one of:
+        OSC_writeFloatArg()
+        OSC_writeIntArg()
+        OSC_writeStringArg()
         OSC_writeNullArg()
-	  - Now your message is complete; you can send out the buffer or you can
-	    add another message to it.
+      - Now your message is complete; you can send out the buffer or you can
+        add another message to it.
 */
 
 static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt);
@@ -240,7 +210,6 @@ static int OSC_writeNullArg(OSCbuf *buf, char type);
    needed for 4-byte alignment. */
 static int OSC_effectiveStringLength(char *string);
 
-
 static t_class *packOSC_class;
 
 typedef struct _packOSC
@@ -282,7 +251,7 @@ static void *packOSC_new(void)
 {
     t_packOSC *x = (t_packOSC *)pd_new(packOSC_class);
     x->x_typetags = 1; /* set typetags to 1 by default */
-    x->x_bundle   = 0; /* bundle is closed */
+    x->x_bundle = 0; /* bundle is closed */
     x->x_buflength = SC_BUFFER_SIZE;
     x->x_bufferForOSCbuf = (char *)getbytes(sizeof(char)*x->x_buflength);
     if(x->x_bufferForOSCbuf == NULL)
@@ -321,8 +290,12 @@ static void packOSC_openbundle(t_packOSC *x)
         result = OSC_openBundle(x->x_oscbuf, OSCTT_Immediately());
     else
         result = OSC_openBundle(x->x_oscbuf, OSCTT_CurrentTimePlusOffset((uint4)x->x_timeTagOffset));
-    if (result != 0) return;
-    x->x_bundle = 1;
+    if (result != 0)
+    { /* reset the buffer */
+        OSC_initBuffer(x->x_oscbuf, x->x_buflength, x->x_bufferForOSCbuf);
+        x->x_bundle = 0;
+    }
+    else x->x_bundle = 1;
     outlet_float(x->x_bdpthout, (float)x->x_oscbuf->bundleDepth);
 }
 
@@ -420,49 +393,49 @@ static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv)
         post("typeStr: %s, nTypeTags %lu", typeStr, nTypeTags);
 #endif
         nArgs = argc-2;
-		for (m = nTagsWithData = blobCount = 0; m < nTypeTags; ++m)
+        for (m = nTagsWithData = blobCount = 0; m < nTypeTags; ++m)
         {
 #ifdef DEBUG
             post("typeStr[%d] %c", m+1, typeStr[m+1]);
 #endif
             if ((c = typeStr[m+1]) == 0) break;
             if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I'))
-			{
+            {
                 ++nTagsWithData; /* anything other than these tags have at least one data byte */
 /*
-	OSC-blob
+    OSC-blob
     An int32 size count, followed by that many 8-bit bytes of arbitrary binary data, 
-	followed by 0-3 additional zero bytes to make the total number of bits a multiple of 32.
+    followed by 0-3 additional zero bytes to make the total number of bits a multiple of 32.
 */
-				if (c == 'b') blobCount++; /* b probably has more than one byte, so set a flag */
-			}
-		}
+                if (c == 'b') blobCount++; /* b probably has more than one byte, so set a flag */
+            }
+        }
         if (((blobCount == 0)&&(nTagsWithData != nArgs)) || ((blobCount != 0)&&(nTagsWithData > nArgs)))
         {
             error("packOSC: Tags count %d doesn't match argument count %d", nTagsWithData, nArgs);
-	        goto cleanup;
+            goto cleanup;
         }
         if (blobCount > 1)
         {
             error("packOSC: Only one blob per packet at the moment...");
-	        goto cleanup;
+            goto cleanup;
         }
         for (j = k = 0; j < m; ++j) /* m is the number of tags */
         {
             c = typeStr[j+1];
-			if (c == 'b')
-			{ /* A blob has to be the last item, until we get more elaborate. */
-				if (j != m-1)
-				{
-		            error("packOSC: Since I don't know how big the blob is, Blob must be the last item in the list");
-			        goto cleanup;
-				}
-				/* Pack all the remaining arguments as a blob */
-				for (; k < nArgs; ++k)
-				{
-					args[k] = packOSC_blob(&argv[k+2]);
-				}
-			}
+            if (c == 'b')
+            { /* A blob has to be the last item, until we get more elaborate. */
+                if (j != m-1)
+                {
+                    error("packOSC: Since I don't know how big the blob is, Blob must be the last item in the list");
+                    goto cleanup;
+                }
+                /* Pack all the remaining arguments as a blob */
+                for (; k < nArgs; ++k)
+                {
+                    args[k] = packOSC_blob(&argv[k+2]);
+                }
+            }
             else if (!(c == 'T' || c == 'F' || c == 'N' || c == 'I')) /* not no data */
             {
                 args[k] = packOSC_forceatom(&argv[k+2], c);
@@ -472,7 +445,7 @@ static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv)
         if(packOSC_writetypedmessage(x, x->x_oscbuf, messageName, nArgs, args, typeStr))
         {
             error("packOSC: usage error, write-msg failed.");
-	        goto cleanup;
+            goto cleanup;
         }
     }
     else
@@ -502,7 +475,7 @@ static void packOSC_sendtyped(t_packOSC *x, t_symbol *s, int argc, t_atom *argv)
         if(packOSC_writemessage(x, x->x_oscbuf, messageName, i, args))
         {
             error("packOSC: usage error, write-msg failed.");
-	        goto cleanup;
+            goto cleanup;
         }
     }
 
@@ -646,23 +619,23 @@ static typedArg packOSC_blob(t_atom *a)
     /* the atoms must all be bytesl */
     if(a->a_type != A_FLOAT)
     {
-		error("packOSC_blob: all values must be floats");
-	    return returnVal;
-	}
-	f = atom_getfloat(a);
-	i = (int)f;
-	if (i != f)
-	{
-		error("packOSC_blob: all values must be whole numbers");
-	    return returnVal;
-	}
-	if ((i < -128) || (i > 255))
-	{
-		error("packOSC_blob: all values must be bytes");
-	    return returnVal;
-	}
-	returnVal.type = BLOB_osc;
-	returnVal.datum.i = i;
+        error("packOSC_blob: all values must be floats");
+        return returnVal;
+    }
+    f = atom_getfloat(a);
+    i = (int)f;
+    if (i != f)
+    {
+        error("packOSC_blob: all values must be whole numbers");
+        return returnVal;
+    }
+    if ((i < -128) || (i > 255))
+    {
+        error("packOSC_blob: all values must be bytes");
+        return returnVal;
+    }
+    returnVal.type = BLOB_osc;
+    returnVal.datum.i = i;
     return returnVal;
 }
 
@@ -673,7 +646,7 @@ static typedArg packOSC_forceatom(t_atom *a, char ctype)
     t_int       i;
     t_symbol    s;
     static char buf[MAXPDSTRING];
-  
+
 #ifdef DEBUG
     atom_string(a, buf, MAXPDSTRING);
     post("packOSC: atom type %d (%s)", a->a_type, buf);
@@ -779,38 +752,38 @@ static int packOSC_writetypedmessage
             ++i;
         }
         if (j < numArgs)
-		{
-			switch (args[j].type)
-	        {
-	            case INT_osc:
+        {
+            switch (args[j].type)
+            {
+                case INT_osc:
 #ifdef DEBUG
-	                post("packOSC_writetypedmessage: int [%d]", args[j].datum.i);
+                    post("packOSC_writetypedmessage: int [%d]", args[j].datum.i);
 #endif
-	                returnVal = OSC_writeIntArg(buf, args[j].datum.i);
-	                break;
-	            case FLOAT_osc:
+                    returnVal = OSC_writeIntArg(buf, args[j].datum.i);
+                    break;
+                case FLOAT_osc:
 #ifdef DEBUG
-	                post("packOSC_writetypedmessage: float [%f]", args[j].datum.f);
+                    post("packOSC_writetypedmessage: float [%f]", args[j].datum.f);
 #endif
-	                returnVal = OSC_writeFloatArg(buf, args[j].datum.f);
-	                break;
-	            case STRING_osc:
+                    returnVal = OSC_writeFloatArg(buf, args[j].datum.f);
+                    break;
+                case STRING_osc:
 #ifdef DEBUG
-	                post("packOSC_writetypedmessage: string [%s]", args[j].datum.s);
+                    post("packOSC_writetypedmessage: string [%s]", args[j].datum.s);
 #endif
-	                returnVal = OSC_writeStringArg(buf, args[j].datum.s);
-	                break;
-				case BLOB_osc:
-					/* write all the blob elements at once */
+                    returnVal = OSC_writeStringArg(buf, args[j].datum.s);
+                    break;
+                case BLOB_osc:
+                    /* write all the blob elements at once */
 #ifdef DEBUG
-					post("packOSC_writetypedmessage calling OSC_writeBlobArg\n");
+                    post("packOSC_writetypedmessage calling OSC_writeBlobArg\n");
 #endif
-					return OSC_writeBlobArg(buf, &args[j], numArgs-j);
-	            default:
+                    return OSC_writeBlobArg(buf, &args[j], numArgs-j);
+                default:
 
-	                break; /* types with no data */
-	        }
-		}
+                    break; /* types with no data */
+            }
+        }
     }
     return returnVal;
 }
@@ -829,13 +802,13 @@ static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, in
     }
     else
     {
-		char *typeTags;
+        char *typeTags;
 
-		/* First figure out the type tags */
-		for (numTags = 0; numTags < numArgs; numTags++)
-		{
-			if (args[numTags].type == BLOB_osc) break; /* blob has one type tag and is the last element */
-		}
+        /* First figure out the type tags */
+        for (numTags = 0; numTags < numArgs; numTags++)
+        {
+            if (args[numTags].type == BLOB_osc) break; /* blob has one type tag and is the last element */
+        }
         typeTags=(char*)getbytes(sizeof(char)*(numTags+2)); /* number of args + ',' + '\0' */
 
         typeTags[0] = ',';
@@ -866,7 +839,7 @@ static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, in
         {
             error("packOSC: Problem writing address.");
         }
-		freebytes(typeTags, sizeof(char)*(numTags+2));
+        freebytes(typeTags, sizeof(char)*(numTags+2));
     }
     for (j = 0; j < numArgs; j++)
     {
@@ -882,7 +855,9 @@ static int packOSC_writemessage(t_packOSC *x, OSCbuf *buf, char *messageName, in
                 returnVal = OSC_writeStringArg(buf, args[j].datum.s);
                 break;
             case BLOB_osc:
-				post ("packOSC_writemessage calling OSC_writeBlobArg\n");
+#ifdef DEBUG
+                post ("packOSC_writemessage calling OSC_writeBlobArg\n");
+#endif
                 return OSC_writeBlobArg(buf, &args[j], numArgs-j); /* All the remaining args are blob */
             default:
                 break; /* just skip bad types (which we won't get anyway unless this code is buggy) */
@@ -929,14 +904,14 @@ static void packOSC_sendbuffer(t_packOSC *x)
  */
 
 /*
-	pd
-	-------------
+    pd
+    -------------
 
-	raf@interaccess.com:
-	rev. for Win32 build  (verified under Win-2ooo)		11-April-2002
+    raf@interaccess.com:
+    rev. for Win32 build  (verified under Win-2ooo)		11-April-2002
 
-	-- changed licence part (20040820) jdl
-	-- Version 2.4 changes not in here (20040820) jdl
+    -- changed licence part (20040820) jdl
+    -- Version 2.4 changes not in here (20040820) jdl
 
 */
 
@@ -949,7 +924,7 @@ static void OSC_initBuffer(OSCbuf *buf, size_t size, char *byteArray)
 }
 
 static void OSC_resetBuffer(OSCbuf *buf)
-{	
+{
     buf->bufptr = buf->buffer;
     buf->state = EMPTY;
     buf->bundleDepth = 0;
@@ -1015,7 +990,7 @@ static int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt)
 
     if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING)
     {
-        post("packOSC: Bundles nested too deeply; change MAX_BUNDLE_NESTING");
+        post("packOSC: Bundles nested too deeply: maybe change MAX_BUNDLE_NESTING from %d and recompile", MAX_BUNDLE_NESTING);
         return 2;
     }
 
@@ -1074,7 +1049,7 @@ static int OSC_closeBundle(OSCbuf *buf)
     if (buf->bundleDepth == 0)
     {
         /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
-        post("packOSC: Can't close bundle; no bundle is open!");
+        post("packOSC: Can't close bundle: no bundle is open!");
         return 5;
     }
 
@@ -1178,14 +1153,14 @@ static int OSC_writeAddressAndTypes(OSCbuf *buf, char *name, char *types)
 
 static int CheckTypeTag(OSCbuf *buf, char expectedType)
 {
-	char c;
+    char c;
 
     if (buf->typeStringPtr)
     {
-		c = *(buf->typeStringPtr);
+        c = *(buf->typeStringPtr);
         if (c != expectedType)
         {
-			if (expectedType == '\0')
+            if (expectedType == '\0')
             {
                 post("packOSC: According to the type tag (%c) I expected more arguments.", c);
             }
@@ -1356,8 +1331,8 @@ static int OSC_padStringWithAnExtraStupidComma(char *dest, char *str)
 }
 
 static int OSC_WriteStringPadding(char *dest, int i)
-{ 
-	/* pad with at least one zero to fit 4-byte */
+{
+    /* pad with at least one zero to fit 4-byte */
     dest[i] = '\0';
     i++;
 
@@ -1368,7 +1343,7 @@ static int OSC_WriteStringPadding(char *dest, int i)
 
 static int OSC_WriteBlobPadding(char *dest, int i)
 {
-	/* pad if necessary to fit 4-byte */
+    /* pad if necessary to fit 4-byte */
     for (; (i % STRING_ALIGN_PAD) != 0; i++) dest[i] = '\0';
     return i;
 }
diff --git a/externals/mrpeach/osc/packingOSC.h b/externals/mrpeach/osc/packingOSC.h
new file mode 100644
index 000000000..19002260a
--- /dev/null
+++ b/externals/mrpeach/osc/packingOSC.h
@@ -0,0 +1,45 @@
+/* packingOSC.h */
+#ifndef _PACKINGOSC
+#include "m_pd.h"
+
+    #include <stdio.h>
+    #include <string.h>
+    #include <stdlib.h>
+#ifdef _WIN32
+    #include <winsock2.h>
+    #include <sys/timeb.h>
+#else
+    #include <sys/types.h>
+    #include <netinet/in.h>
+    #include <ctype.h>
+    #include <sys/time.h>
+#endif /* _WIN32 */
+
+/* Declarations */
+#ifdef WIN32
+  typedef unsigned __int64 osc_time_t;
+#else
+  typedef unsigned long long osc_time_t;
+#endif
+
+#define MAX_MESG 65536 /* same as MAX_UDP_PACKET */
+/* The maximum depth of bundles within bundles within bundles within...
+   This is the size of a static array.  If you exceed this limit you'll
+   get an error message. */
+#define MAX_BUNDLE_NESTING 32
+/* You may have to redefine this typedef if ints on your system
+  aren't 4 bytes. */
+typedef unsigned int uint4;
+typedef struct
+{
+    uint4 seconds;
+    uint4 fraction;
+} OSCTimeTag;
+
+typedef union
+{
+    int     i;
+    float   f;
+} intfloat32;
+
+#endif // _PACKINGOSC
\ No newline at end of file
diff --git a/externals/mrpeach/osc/routeOSC.c b/externals/mrpeach/osc/routeOSC.c
index 5f48e4ff8..118623499 100644
--- a/externals/mrpeach/osc/routeOSC.c
+++ b/externals/mrpeach/osc/routeOSC.c
@@ -87,22 +87,33 @@ The OpenSound Control WWW page is
 
 typedef struct _routeOSC
 {
-    t_object    x_obj; // required header
-    t_int       x_num; // Number of prefixes we store
-    char        *x_prefixes[MAX_NUM];
-    void        *x_outlets[MAX_NUM+1]; // one for each prefix plus one for everything else
+    t_object    x_obj; /* required header */
+    t_int       x_num; /* Number of prefixes we store */
+    t_int       x_verbosity; /* level of debug output required */
+//    char        *x_prefixes[MAX_NUM]; /* the OSC addresses to be matched */
+//    int         x_prefix_depth[MAX_NUM]; /* the number of slashes in each prefix */
+//    void        *x_outlets[MAX_NUM+1]; /* one for each prefix plus one for everything else */
+    char        **x_prefixes; /* the OSC addresses to be matched */
+    int         *x_prefix_depth; /* the number of slashes in each prefix */
+    void        **x_outlets; /* one for each prefix plus one for everything else */
 } t_routeOSC;
 
 /* prototypes  */
 
 void routeOSC_setup(void);
+static void routeOSC_free(t_routeOSC *x);
 static int MyPatternMatch (const char *pattern, const char *test);
 static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv);
 static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv);
 static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv);
 static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv);
+static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv);
+static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v);
+static int routeOSC_count_slashes(char *prefix);
 static char *NextSlashOrNull(char *p);
+static char *NthSlashOrNull(char *p, int n);
 static void StrCopyUntilSlash(char *target, const char *source);
+static void StrCopyUntilNthSlash(char *target, const char *source, int n);
 
 /* from
     OSC-pattern-match.c
@@ -127,6 +138,9 @@ static int MyPatternMatch (const char *pattern, const char *test)
 
 static void routeOSC_free(t_routeOSC *x)
 {
+    freebytes(x->x_prefixes, x->x_num*sizeof(char *)); /* the OSC addresses to be matched */
+    freebytes(x->x_prefix_depth, x->x_num*sizeof(int));  /* the number of slashes in each prefix */
+    freebytes(x->x_outlets, (x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */
 }
 
 /* initialization routine */
@@ -134,10 +148,12 @@ static void routeOSC_free(t_routeOSC *x)
 void routeOSC_setup(void)
 {
     routeOSC_class = class_new(gensym("routeOSC"), (t_newmethod)routeOSC_new,
-        (t_method)routeOSC_free,sizeof(t_routeOSC), 0, A_GIMME, 0);
-    class_addlist(routeOSC_class, routeOSC_list);
+        (t_method)routeOSC_free, sizeof(t_routeOSC), 0, A_GIMME, 0);
     class_addanything(routeOSC_class, routeOSC_doanything);
+    class_addlist(routeOSC_class, routeOSC_list);
     class_addmethod(routeOSC_class, (t_method)routeOSC_set, gensym("set"), A_GIMME, 0);
+    class_addmethod(routeOSC_class, (t_method)routeOSC_paths, gensym("paths"), A_GIMME, 0);
+    class_addmethod(routeOSC_class, (t_method)routeOSC_verbosity, gensym("verbosity"), A_DEFFLOAT, 0);
 
     ps_emptySymbol = gensym("");
 
@@ -158,33 +174,45 @@ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv)
         return 0;
     }
     x->x_num = 0;
+/* first verify that all arguments are symbols whose first character is '/' */
     for (i = 0; i < argc; ++i)
     {
         if (argv[i].a_type == A_SYMBOL)
         {
             if (argv[i].a_w.w_symbol->s_name[0] == '/')
             { /* Now that's a nice prefix */
-                x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
                 ++(x->x_num);
             }
-        }
-        else if (argv[i].a_type == A_FLOAT)
-        {
-            error("* routeOSC: float arguments are not OK.");
-            return 0;
+            else
+            {
+                error("routeOSC: argument %d does not begin with a slash(/).", i);
+                return(0);
+            }
         }
         else
         {
-            error("* routeOSC: unrecognized argument type!");
+            error("routeOSC: argument %d is not a symbol.", i);
             return 0;
         }
     }
+/* now allocate the storage for each path */
+    x->x_prefixes = (char **)getzbytes(x->x_num*sizeof(char *)); /* the OSC addresses to be matched */
+    x->x_prefix_depth = (int *)getzbytes(x->x_num*sizeof(int));  /* the number of slashes in each prefix */
+    x->x_outlets = (void **)getzbytes((x->x_num+1)*sizeof(void *)); /* one for each prefix plus one for everything else */
+/* put the pointer to the path in x_prefixes */
+/* put the number of levels in x_prefix_depth */
+    for (i = 0; i < x->x_num; ++i)
+    {
+        x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
+        x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]);
+    }
     /* Have to create the outlets in reverse order */
     /* well, not in pd ? */
     for (i = 0; i <= x->x_num; i++)
     {
         x->x_outlets[i] = outlet_new(&x->x_obj, &s_list);
     }
+    x->x_verbosity = 0; /* quiet by default */
     return (x);
 }
 
@@ -192,7 +220,7 @@ static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
 {
     int i;
 
-	if (argc > x->x_num)
+    if (argc > x->x_num)
     {
         pd_error (x, "routeOSC: too many paths");
         return;
@@ -215,91 +243,106 @@ static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
         if (argv[i].a_w.w_symbol->s_name[0] == '/')
         { /* Now that's a nice prefix */
             x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name;
+            x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]);
         }
     }
 }
 
-static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
+static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
+{ /* print  out the paths we are matching */
+    int i;
+    
+    for (i = 0; i < x->x_num; ++i) post("path[%d]: %s (depth %d)", i, x->x_prefixes[i], x->x_prefix_depth[i]);
+}
+
+static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v)
 {
-    if(argc < 1)
-    {
-      pd_error(x, "* routeOSC: ignoring empty list...");
-      return;
-    }
-    if (argv[0].a_type == A_SYMBOL)
-    { 
-        /* Ignore the fact that this is a "list" */
-        routeOSC_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1);
-    }
-    else
-    {
-        // pd_error(x, "* OSC-route: invalid list beginning with a number");
-        // output on unmatched outlet jdl 20020908
-        if (argv[0].a_type == A_FLOAT)
-        {
-          outlet_float(x->x_outlets[x->x_num], atom_getfloat(argv));
-        }
-        else
-        {
-          pd_error(x, "* routeOSC: unrecognized atom type!");
-        }
-    }
+    x->x_verbosity = (v == 0)? 0: 1;
+    if (x->x_verbosity) post("routeOSC_verbosity(%p) is %d", x, x->x_verbosity);
+}
+
+static int routeOSC_count_slashes(char *prefix)
+{ /* find the path depth of the prefix by counting the numberof slashes */
+    int i = 0;
+    char *p = prefix;
+
+    while (*p != '\0') if (*p++ == '/') i++;
+    return i;
 }
 
 static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
 {
-    char *pattern, *nextSlash;
-    int i;
-    int matchedAnything;
-    // post("*** routeOSC_anything(s %s, argc %ld)", s->s_name, (long) argc);
+    char    *pattern, *nextSlash;
+    int     i, pattern_depth = 0, matchedAnything = 0;
+    int     noPath = 0; // nonzero if we are dealing with a simple list (as from a previous [routeOSC])
 
     pattern = s->s_name;
+    if (x->x_verbosity) post("routeOSC_doanything(%p): pattern is %s", x, pattern);
     if (pattern[0] != '/')
-    {
-        pd_error(x, "* routeOSC: invalid message pattern %s does not begin with /", s->s_name);
-        outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
-        return;
+    { // make a path '/'. Now s is actually the first item in the arguments list
+        pattern = gensym("/")->s_name;
+        noPath = 1;
+        if (x->x_verbosity)
+            post("routeOSC_doanything(%p): message pattern \"%s\" does not begin with /, setting path to %s", x, s->s_name, pattern);
     }
-    matchedAnything = 0;
 
-	nextSlash = NextSlashOrNull(pattern+1);
+    pattern_depth = routeOSC_count_slashes(pattern);
+    if (x->x_verbosity) post("routeOSC_doanything(%p): pattern_depth is %i", x, pattern_depth);
+    nextSlash = NextSlashOrNull(pattern+1);
     if (*nextSlash == '\0')
-    {
+    { /* pattern_depth == 1 */
         /* last level of the address, so we'll output the argument list */
     
         for (i = 0; i < x->x_num; ++i)
         {
-            if (MyPatternMatch(pattern+1, x->x_prefixes[i]+1))
+            if
+            (
+                (x->x_prefix_depth[i] <= pattern_depth)
+                && (MyPatternMatch(pattern+1, x->x_prefixes[i]+1))
+            )
             {
                 ++matchedAnything;
-                // I hate stupid Max lists with a special first element
-                if (argc == 0)
-                {
-                    outlet_bang(x->x_outlets[i]);
-                }
-                else if (argv[0].a_type == A_SYMBOL)
-                {
-                    // Promote the symbol that was argv[0] to the special symbol
-                    outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
-                }
-                else if (argc > 1)
-                {
-                    // Multiple arguments starting with a number, so naturally we have
-                    // to use a special function to output this "list", since it's what
-                    // Max originally meant by "list".
-                    outlet_list(x->x_outlets[i], 0L, argc, argv);
+                if (noPath)
+                { // just a list starting with a symbol
+                  // The special symbol is s
+                  if (x->x_verbosity) post("routeOSC_doanything _1_(%p): (%d) noPath: s is \"%s\"", x, i, s->s_name);
+                  outlet_anything(x->x_outlets[i], s, argc, argv);
                 }
-                else
+                else // normal OSC path
                 {
-                    // There was only one argument, and it was a number, so we output it
-                    // not as a list
-                    if (argv[0].a_type == A_FLOAT)
+                    // I hate stupid Max lists with a special first element
+                    if (argc == 0)
                     {
-                        outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
+                        if (x->x_verbosity) post("routeOSC_doanything _2_(%p): (%d) no args", x, i);
+                        outlet_bang(x->x_outlets[i]);
+                    }
+                    else if (argv[0].a_type == A_SYMBOL)
+                    {
+                        // Promote the symbol that was argv[0] to the special symbol
+                        if (x->x_verbosity) post("routeOSC_doanything _3_(%p): (%d) symbol: is \"%s\"", x, i, argv[0].a_w.w_symbol->s_name);
+                        outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
+                    }
+                    else if (argc > 1)
+                    {
+                        // Multiple arguments starting with a number, so naturally we have
+                        // to use a special function to output this "list", since it's what
+                        // Max originally meant by "list".
+                        if (x->x_verbosity) post("routeOSC_doanything _4_(%p): (%d) list:", x, i);
+                        outlet_list(x->x_outlets[i], 0L, argc, argv);
                     }
                     else
                     {
-                        pd_error(x, "* routeOSC: unrecognized atom type!");
+                        // There was only one argument, and it was a number, so we output it
+                        // not as a list
+                        if (argv[0].a_type == A_FLOAT)
+                        {
+                            if (x->x_verbosity) post("routeOSC_doanything _5_(%p): (%d) a single float", x, i);
+                            outlet_float(x->x_outlets[i], argv[0].a_w.w_float);
+                        }
+                        else
+                        {
+                            pd_error(x, "* routeOSC: unrecognized atom type!");
+                        }
                     }
                 }
             }
@@ -312,16 +355,44 @@ static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *ar
         t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */
         char patternBegin[1000];
 
-        /* Get the first level of the incoming pattern to match against all our prefixes */
-        StrCopyUntilSlash(patternBegin, pattern+1);
+        /* Get the incoming pattern to match against all our prefixes */
 
         for (i = 0; i < x->x_num; ++i)
         {
-            if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1))
+            restOfPattern = 0;
+            if (x->x_prefix_depth[i] <= pattern_depth)
             {
-                ++matchedAnything;
-                if (restOfPattern == 0) restOfPattern = gensym(nextSlash);
-                outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
+                StrCopyUntilNthSlash(patternBegin, pattern+1, x->x_prefix_depth[i]);
+                if (x->x_verbosity)
+                    post("routeOSC_doanything _6_(%p): (%d) patternBegin is %s", x, i, patternBegin);
+                if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1))
+                {
+                    if (x->x_verbosity)
+                        post("routeOSC_doanything _7_(%p): (%d) matched %s depth %d", x, i, x->x_prefixes[i], x->x_prefix_depth[i]);
+                    ++matchedAnything;
+                    nextSlash = NthSlashOrNull(pattern+1, x->x_prefix_depth[i]);
+                    if (x->x_verbosity)
+                        post("routeOSC_doanything _8_(%p): (%d) nextSlash %s [%d]", x, i, nextSlash, nextSlash[0]);
+                    if (*nextSlash != '\0')
+                    {
+                        if (x->x_verbosity) post("routeOSC_doanything _9_(%p): (%d) more pattern", x, i);
+                        restOfPattern = gensym(nextSlash);
+                        outlet_anything(x->x_outlets[i], restOfPattern, argc, argv);
+                    }
+                    else if (argc == 0)
+                    {
+                        if (x->x_verbosity) post("routeOSC_doanything _10_(%p): (%d) no more pattern, no args", x, i);
+                        outlet_bang(x->x_outlets[i]);
+                    }
+                    else
+                    {
+                        if (x->x_verbosity) post("routeOSC_doanything _11_(%p): (%d) no more pattern, %d args", x, i, argc);
+                        if (argv[0].a_type == A_SYMBOL) // Promote the symbol that was argv[0] to the special symbol
+                            outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1);
+                        else
+                            outlet_anything(x->x_outlets[i], gensym("list"), argc, argv);
+                    }
+                }
             }
         }
     }
@@ -329,8 +400,20 @@ static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *ar
     if (!matchedAnything)
     {
         // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908
+        if (x->x_verbosity) post("routeOSC_doanything _13_(%p) unmatched %d, %d args", x, i, argc);
         outlet_anything(x->x_outlets[x->x_num], s, argc, argv);
-	}
+    }
+}
+
+static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if (argv[0].a_type == A_SYMBOL) routeOSC_doanything(x, argv[0].a_w.w_symbol, argc-1, &argv[1]);
+    else
+    {
+        routeOSC_doanything(x, gensym("/"), argc, argv);
+        if (x->x_verbosity)
+            post("routeOSC_doanything(%p): message pattern is not a symbol, setting path to /", x);
+    }
 }
 
 static char *NextSlashOrNull(char *p)
@@ -339,6 +422,21 @@ static char *NextSlashOrNull(char *p)
     return p;
 }
 
+static char *NthSlashOrNull(char *p, int n)
+{
+    int i;
+    for (i = 0; i < n; ++i)
+    {
+        while (*p != '/')
+        { 
+            if (*p == '\0') return p;
+            p++;
+        }
+        if (i < n-1) p++; /* skip the slash unless it's the nth slash */
+    }
+    return p;
+}
+
 static void StrCopyUntilSlash(char *target, const char *source)
 {
     while (*source != '/' && *source != '\0')
@@ -350,6 +448,32 @@ static void StrCopyUntilSlash(char *target, const char *source)
     *target = 0;
 }
 
+static void StrCopyUntilNthSlash(char *target, const char *source, int n)
+{ /* copy the path up but not including the nth slash */
+    int i = n;
+
+    while (i > 0)
+    {
+        while (*source != '/')
+        {
+            *target = *source;
+            if (*source == '\0') return;
+            ++target;
+            ++source;
+        }
+        i--;
+        /* got  a slash. If it's the nth, don't include it */
+        if (i == 0)
+        {
+            *target = 0;
+            return;
+        }
+        *target = *source;
+        ++source;
+        ++target;
+    }
+}
+
 /* from
     OSC-pattern-match.c
     Matt Wright, 3/16/98
@@ -379,7 +503,7 @@ static int PatternMatch (const char *  pattern, const char * test)
             return PatternMatch (pattern, test+1);
         case ']':
         case '}':
-			      error("routeOSC: Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
+                  error("routeOSC: Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern);
             return 0;
         case '[':
             return MatchBrackets (pattern,test);
@@ -465,13 +589,13 @@ static int MatchList (const char *pattern, const char *test)
     restOfPattern++; /* skip close curly brace */
     pattern++; /* skip open curly brace */
     while (1)
-	{
+    {
         if (*pattern == ',') 
-		{
+        {
             if (PatternMatch (restOfPattern, tp)) return 1;
             tp = test;
             ++pattern;
-		}
+        }
         else if (*pattern == '}') return PatternMatch (restOfPattern, tp);
         else if (*pattern == *tp) 
         {
@@ -479,7 +603,7 @@ static int MatchList (const char *pattern, const char *test)
             ++tp;
         }
         else 
-		{
+        {
             tp = test;
             while (*pattern != ',' && *pattern != '}') pattern++;
             if (*pattern == ',') pattern++;
diff --git a/externals/mrpeach/osc/tcpsocket.OSC.pd b/externals/mrpeach/osc/tcpsocket.OSC.pd
deleted file mode 100644
index 1b838e373..000000000
--- a/externals/mrpeach/osc/tcpsocket.OSC.pd
+++ /dev/null
@@ -1,245 +0,0 @@
-#N canvas 585 75 446 533 10;
-#X obj 50 49 == \$2;
-#X obj 7 28 route in socket;
-#X obj 7 76 spigot;
-#N canvas 622 183 512 335 reset 0;
-#X obj 23 41 route \$2;
-#X obj 23 63 route reset;
-#X obj 23 83 t b b;
-#X msg 55 170 done;
-#X obj 23 113 outlet;
-#X text 161 33 this is used to:;
-#X text 87 114 a) reset the sockethandler on a new connection;
-#X text 88 129 (for instance \, if the previous connection was quitted
-in the middle of a packet).;
-#X text 55 213 b) check for the socketserver \, if a sockethandler
-on specified socket already exists.;
-#X obj 55 191 s \$1.TCPSOCKET;
-#X obj 23 19 r \$1.TCPSOCKET;
-#X connect 0 0 1 0;
-#X connect 1 0 2 0;
-#X connect 2 0 4 0;
-#X connect 2 1 3 0;
-#X connect 3 0 9 0;
-#X connect 10 0 0 0;
-#X restore 40 102 pd reset;
-#X obj 104 280 route socket ip;
-#X obj 41 367 list append;
-#X obj 58 323 list append;
-#X obj 7 299 t a b b b;
-#X obj 7 414 list prepend out;
-#X obj 41 391 list prepend socket.out;
-#X obj 58 345 list prepend ip.out;
-#X obj 7 442 list trim;
-#X text 16 220 the lower part makes [tcpsocketserver] behave like [tcpserver]
-;
-#X obj -2 136 cnv 15 450 70 empty empty empty 20 12 0 14 -204786 -66577
-0;
-#X text 70 162 <- PUT HERE THE PROTOCOL SPECIFIC DELIMITER CODE;
-#X text 15 197 --------------------------------------------------------
-;
-#X text 13 129 --------------------------------------------------------
-;
-#X obj 7 6 r \$1.TCPSOCKET;
-#X obj 7 465 s \$1.TCPSOCKET;
-#X obj 104 256 r \$1.TCPSOCKET;
-#X text 200 454 Author: Roman Haefeli;
-#X text 55 75 <- only pass stream of own socket;
-#N canvas 395 78 268 176 OSC 0;
-#X obj 27 18 inlet;
-#X obj 27 156 outlet;
-#X obj 144 23 inlet;
-#X text 194 23 reset;
-#N canvas 820 354 408 355 parse_frameheader 0;
-#X obj 14 10 inlet;
-#X obj 14 304 outlet;
-#X obj 322 178 outlet;
-#X obj 134 228 list prepend;
-#X obj 230 228 t a;
-#X obj 14 43 list prepend 0;
-#X obj 14 123 f;
-#X obj 14 144 + 1;
-#X obj 14 166 sel 4;
-#X obj 14 99 t b a;
-#X obj 14 69 route 0 1;
-#X text 97 64 0 = frame header;
-#X text 97 80 1 = frame content;
-#X obj 14 187 t b b;
-#X obj 109 22 r \$0.route;
-#X obj 46 230 s \$0.route;
-#X msg 46 208 1;
-#X obj 14 261 list append;
-#X obj 243 18 inlet;
-#X obj 243 44 b;
-#X msg 272 45 0;
-#X obj 272 65 s \$0.route;
-#N canvas 504 266 169 262 MSB_2SB_3SB_LSB->float 0;
-#X obj 7 10 inlet;
-#X obj 7 214 outlet;
-#X obj 7 33 unpack f f f f;
-#X obj 70 74 << 8;
-#X obj 38 118 << 16;
-#X obj 7 165 << 24;
-#X obj 70 98 +;
-#X obj 38 139 +;
-#X obj 7 190 +;
-#X connect 0 0 2 0;
-#X connect 2 0 5 0;
-#X connect 2 1 4 0;
-#X connect 2 2 3 0;
-#X connect 2 3 6 1;
-#X connect 3 0 6 0;
-#X connect 4 0 7 0;
-#X connect 5 0 8 0;
-#X connect 6 0 7 1;
-#X connect 7 0 8 1;
-#X connect 8 0 1 0;
-#X restore 14 282 pd MSB_2SB_3SB_LSB->float;
-#X text 288 19 new packet;
-#X text 23 327 frame length;
-#X text 322 201 data stream;
-#X connect 0 0 5 0;
-#X connect 3 0 4 0;
-#X connect 3 0 17 1;
-#X connect 4 0 3 1;
-#X connect 5 0 10 0;
-#X connect 6 0 7 0;
-#X connect 7 0 6 1;
-#X connect 7 0 8 0;
-#X connect 8 0 13 0;
-#X connect 9 0 6 0;
-#X connect 9 1 3 0;
-#X connect 10 0 9 0;
-#X connect 10 1 2 0;
-#X connect 13 0 17 0;
-#X connect 13 1 16 0;
-#X connect 14 0 5 1;
-#X connect 16 0 15 0;
-#X connect 17 0 22 0;
-#X connect 18 0 19 0;
-#X connect 18 0 20 0;
-#X connect 19 0 3 1;
-#X connect 20 0 21 0;
-#X connect 20 0 6 1;
-#X connect 22 0 1 0;
-#X restore 27 77 pd parse_frameheader;
-#N canvas 748 498 450 300 form_packet 0;
-#X obj 68 23 inlet;
-#X text 106 24 length;
-#X obj 194 22 inlet;
-#X text 244 23 stream;
-#X obj 120 190 list prepend;
-#X obj 216 190 t a;
-#X obj 14 123 f;
-#X obj 14 144 + 1;
-#X obj 14 99 t b a;
-#X obj 14 187 t b b;
-#X obj 46 213 list append;
-#X obj 14 166 sel 0;
-#X obj 46 253 outlet;
-#X text 100 254 OSC packet;
-#X text 261 262 EOP;
-#X obj 210 261 outlet;
-#X obj 68 88 t b a;
-#X msg 68 111 0;
-#X connect 0 0 16 0;
-#X connect 2 0 8 0;
-#X connect 4 0 5 0;
-#X connect 4 0 10 1;
-#X connect 5 0 4 1;
-#X connect 6 0 7 0;
-#X connect 7 0 6 1;
-#X connect 7 0 11 0;
-#X connect 8 0 6 0;
-#X connect 8 1 4 0;
-#X connect 9 0 15 0;
-#X connect 9 1 10 0;
-#X connect 10 0 12 0;
-#X connect 11 0 9 0;
-#X connect 16 0 17 0;
-#X connect 16 0 4 1;
-#X connect 16 1 11 1;
-#X connect 17 0 6 1;
-#X restore 27 129 pd form_packet;
-#X obj 169 85 b;
-#X obj 144 50 b;
-#N canvas 389 242 191 341 serialize 0;
-#X obj 5 100 t a a;
-#X obj 37 122 list prepend 0;
-#X obj 37 143 s \$0.inbuffer;
-#X obj 5 174 list length;
-#X obj 5 218 until;
-#X obj 5 195 t a b;
-#X obj 5 241 f;
-#X obj 50 244 + 1;
-#X msg 49 218 0;
-#X obj 5 267 tabread \$0.inbuffer;
-#X obj 5 50 inlet;
-#X obj 5 289 outlet;
-#N canvas 294 258 396 232 list_serialize_raw 0;
-#X obj 13 73 until;
-#X obj 13 97 list append;
-#X obj 13 47 t b a;
-#X obj 13 23 inlet;
-#X obj 13 169 outlet;
-#X obj 156 122 b;
-#X text 12 190 cut incoming list into pieces of a maximum of the buffersize.
-;
-#X obj 13 121 list split 65536;
-#X connect 0 0 1 0;
-#X connect 1 0 7 0;
-#X connect 2 0 0 0;
-#X connect 2 1 1 1;
-#X connect 3 0 2 0;
-#X connect 5 0 0 1;
-#X connect 7 0 4 0;
-#X connect 7 1 1 1;
-#X connect 7 2 5 0;
-#X connect 7 2 4 0;
-#X restore 5 74 pd list_serialize_raw;
-#X obj 5 12 table \$0.inbuffer 65536;
-#X connect 0 0 3 0;
-#X connect 0 1 1 0;
-#X connect 1 0 2 0;
-#X connect 3 0 5 0;
-#X connect 4 0 6 0;
-#X connect 5 0 4 0;
-#X connect 5 1 8 0;
-#X connect 6 0 7 0;
-#X connect 6 0 9 0;
-#X connect 7 0 6 1;
-#X connect 8 0 6 1;
-#X connect 9 0 11 0;
-#X connect 10 0 12 0;
-#X connect 12 0 0 0;
-#X restore 27 45 pd serialize;
-#X connect 0 0 8 0;
-#X connect 2 0 7 0;
-#X connect 4 0 5 0;
-#X connect 4 1 5 1;
-#X connect 5 0 1 0;
-#X connect 5 1 6 0;
-#X connect 6 0 4 1;
-#X connect 7 0 4 1;
-#X connect 8 0 4 0;
-#X restore 7 161 pd OSC;
-#X text 201 474 Version: 2009-02-02;
-#X connect 0 0 2 1;
-#X connect 1 0 2 0;
-#X connect 1 1 0 0;
-#X connect 2 0 22 0;
-#X connect 3 0 22 1;
-#X connect 4 0 5 1;
-#X connect 4 1 6 1;
-#X connect 5 0 9 0;
-#X connect 6 0 10 0;
-#X connect 7 0 8 0;
-#X connect 7 2 5 0;
-#X connect 7 3 6 0;
-#X connect 8 0 11 0;
-#X connect 9 0 11 0;
-#X connect 10 0 11 0;
-#X connect 11 0 18 0;
-#X connect 17 0 1 0;
-#X connect 19 0 4 0;
-#X connect 22 0 7 0;
diff --git a/externals/mrpeach/osc/unpackOSC-help.pd b/externals/mrpeach/osc/unpackOSC-help.pd
new file mode 100644
index 000000000..0f24a9f71
--- /dev/null
+++ b/externals/mrpeach/osc/unpackOSC-help.pd
@@ -0,0 +1,52 @@
+#N canvas 4 80 664 396 10;
+#X obj -104 176 cnv 15 100 60 empty empty empty 20 12 0 14 -4034 -66577
+0;
+#X obj -85 190 unpackOSC;
+#X floatatom 16 207 10 0 0 1 - - -;
+#X obj -85 257 pipelist;
+#X text -126 337 see:;
+#X text 21 337 for a way to send OSC over TCP or serial connections.
+;
+#X obj -91 338 unpackOSCstream;
+#X obj -92 214 print unpacked;
+#X text -29 253 If the OSC packet has a timetag \, [pipelist] will
+delay it until the time occurs;
+#N canvas 521 651 494 344 META 0;
+#X text 12 155 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan
+Wilkes for Pd version 0.42.;
+#X text 12 25 LICENSE GPL v2 or later;
+#X text 12 5 KEYWORDS control list_op;
+#X text 12 45 DESCRIPTION parses lists of floats (only integers on
+[0..255]) assuming they represent OSC packets.;
+#X text 12 75 INLET_0 list of floats on [0..255];
+#X text 12 95 OUTLET_0 OSC message;
+#X text 13 115 OUTLET_1 milliseconds until timetag time;
+#X text 12 135 AUTHOR Martin Peach;
+#X restore 449 362 pd META;
+#X obj -85 73 packOSC;
+#X obj -62 113 print bytes;
+#X msg -113 28 /some/path 1 2 3;
+#X msg -134 7 [ \, /another/one/ 4 \, ];
+#X obj -85 284 print delayed;
+#X msg -92 49 timetagoffset 1.1e+06;
+#X obj -46 93 print bundle_depth;
+#X text 354 317 2012/02/14 Martin Peach;
+#X text 107 15 [unpackOSC] processes lists of floats (only integers
+on [0..255]) as though they were OSC packets.;
+#X text -76 134 <- usually the bytes pass over the network with [udpsend]/[udpreceive]
+\, or serial port using [comport] with [slipenc] and [slipdec];
+#X text 48 49 timetag offset is in microseconds relative to sender's
+clock;
+#X text 83 201 second outlet is timetag offset in millieconds relative
+to receiver's clock;
+#X connect 1 0 3 0;
+#X connect 1 0 7 0;
+#X connect 1 1 2 0;
+#X connect 1 1 3 1;
+#X connect 3 0 14 0;
+#X connect 10 0 11 0;
+#X connect 10 0 1 0;
+#X connect 10 1 16 0;
+#X connect 12 0 10 0;
+#X connect 13 0 10 0;
+#X connect 15 0 10 0;
diff --git a/externals/mrpeach/osc/unpackOSC.c b/externals/mrpeach/osc/unpackOSC.c
index 1e83a66d7..45405a7fe 100644
--- a/externals/mrpeach/osc/unpackOSC.c
+++ b/externals/mrpeach/osc/unpackOSC.c
@@ -65,47 +65,8 @@ The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl
 
 */
 
-#include "m_pd.h"
+#include "packingOSC.h"
 
-    #include <stdio.h>
-    #include <string.h>
-    #include <stdlib.h>
-#ifdef _WIN32
-    #include <winsock2.h>
-    #include <sys/timeb.h>
-#else
-    #include <sys/types.h>
-    #include <netinet/in.h>
-    #include <ctype.h>
-    #include <sys/time.h>
-#endif /* _WIN32 */
-
-/* Declarations */
-#ifdef WIN32
-  typedef unsigned __int64 osc_time_t;
-#else
-  typedef unsigned long long osc_time_t;
-#endif
-
-#define MAX_MESG 65536
-/* MAX_MESG was 32768 MP: make same as MAX_UDP_PACKET */
-#define OSC_MAX_RECURSION 16 /* maximum bundle depth */
-/* ----------------------------- was dumpOSC ------------------------- */
-
-/* You may have to redefine this typedef if ints on your system
-  aren't 4 bytes. */
-typedef unsigned int uint4;
-typedef struct
-{
-    uint4 seconds;
-    uint4 fraction;
-} OSCTimeTag;
-
-typedef union
-{
-    int     i;
-    float   f;
-} intfloat32;
 
 static t_class *unpackOSC_class;
 
@@ -119,7 +80,8 @@ typedef struct _unpackOSC
     char        x_raw[MAX_MESG];/* bytes making up the entire OSC message */
     int         x_raw_c;/* number of bytes in OSC message */
     int         x_bundle_flag;/* non-zero if we are processing a bundle */
-    int         x_recursion_level;/* number of times we reenter unpackOSCPath */
+    int         x_recursion_level;/* number of times we reenter unpackOSC_list */
+    int         x_abort_bundle;/* non-zero if unpackOSC_list is not well formed */
 } t_unpackOSC;
 
 void unpackOSC_setup(void);
@@ -137,13 +99,13 @@ static t_float unpackOSC_DeltaTime(OSCTimeTag tt);
 static void *unpackOSC_new(void)
 {
     t_unpackOSC *x;
-
     x = (t_unpackOSC *)pd_new(unpackOSC_class);
     x->x_data_out = outlet_new(&x->x_obj, &s_list);
     x->x_delay_out = outlet_new(&x->x_obj, &s_float);
     x->x_raw_c = x->x_data_atc = 0;
     x->x_bundle_flag = 0;
     x->x_recursion_level = 0;
+    x->x_abort_bundle = 0;
     return (x);
 }
 
@@ -157,7 +119,6 @@ void unpackOSC_setup(void)
         (t_newmethod)unpackOSC_new, (t_method)unpackOSC_free,
         sizeof(t_unpackOSC), 0, 0);
     class_addlist(unpackOSC_class, (t_method)unpackOSC_list);
-    class_sethelpsymbol(unpackOSC_class, gensym("routeOSC")); /* same help patch as routeOSC*/
 }
 
 /* unpackOSC_list expects an OSC packet in the form of a list of floats on [0..255] */
@@ -167,6 +128,7 @@ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv)
     char            *messageName, *args, *buf;
     OSCTimeTag      tt;
 
+    if(x->x_abort_bundle) return; /* if backing quietly out of the recursive stack */
     if ((argc%4) != 0)
     {
         post("unpackOSC: Packet size (%d) not a multiple of 4 bytes: dropping packet", argc);
@@ -253,15 +215,16 @@ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv)
                 post("unpackOSC: Bad size count %d in bundle (only %d bytes left in entire bundle)",
                     size, argc-i-4);
                 x->x_recursion_level = 0;
-                return;	
+                return;
             }
 
             /* Recursively handle element of bundle */
             x->x_recursion_level++;
-            if (x->x_recursion_level > OSC_MAX_RECURSION)
+            if (x->x_recursion_level > MAX_BUNDLE_NESTING)
             {
-                post("unpackSOC: bundle depth %d exceeded", OSC_MAX_RECURSION);
+                post("unpackOSC: bundle depth %d exceeded", MAX_BUNDLE_NESTING);
                 x->x_recursion_level = 0;
+                x->x_abort_bundle = 1;/* we need to back out of the recursive stack*/
                 return;
             }
             unpackOSC_list(x, s, size, &argv[i+4]);
@@ -283,7 +246,7 @@ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv)
     {
         post("unpackOSC: Time message: %s\n :).\n", buf);
         x->x_recursion_level = 0;
-        return; 	
+        return;
     }
     else
     { /* This is not a bundle message or a time message */
@@ -314,6 +277,7 @@ static void unpackOSC_list(t_unpackOSC *x, t_symbol *s, int argc, t_atom *argv)
         outlet_anything(x->x_data_out, atom_getsymbol(x->x_data_at), x->x_data_atc-1, x->x_data_at+1);
     x->x_data_atc = 0;
     x->x_recursion_level = 0;
+    x->x_abort_bundle = 0;
 }
 
 static int unpackOSC_path(t_unpackOSC *x, char *path)
@@ -615,9 +579,10 @@ static int unpackOSC_IsNiceString(char *string, char *boundary)
         return 0;
     }
 
+    /* anything less than space (0x20) is no good, UTF-8 sequences will be accepted -- not strictly OSC v1.0 */
     for (i = 0; string[i] != '\0'; i++)
-        if ((!isprint(string[i])) || (string + i >= boundary)) return 0;
-
+        /* if ((!isprint(string[i])) || (string + i >= boundary)) return 0; */ /* only ASCII printable chars */
+        if ((0==(string[i]&0xE0)) || (string + i >= boundary)) return 0;
     /* If we made it this far, it's a null-terminated sequence of printing characters
        in the given boundary.  Now we just make sure it's null padded... */
 
diff --git a/externals/mrpeach/xbee/packxbee-help.pd b/externals/mrpeach/xbee/packxbee-help.pd
new file mode 100644
index 000000000..b1fdd3ab1
--- /dev/null
+++ b/externals/mrpeach/xbee/packxbee-help.pd
@@ -0,0 +1,584 @@
+#N canvas 154 423 1227 436 10;
+#X declare -lib mrpeach;
+#X msg 80 53 AT DH 0x0013A200;
+#X text 193 52 set upper 32 bits of destination address;
+#X msg 103 76 AT DL 0x407694DB;
+#X msg 128 101 AT MY;
+#X text 80 9 get upper 32 bits of destination address;
+#X text 97 31 get loweer 32 bits of destination address;
+#X msg 37 10 AT DH;
+#X msg 60 33 AT DL;
+#X msg 148 121 AT MP;
+#X text 171 99 get our 16-bit address (Read Only);
+#X msg 171 144 AT NC;
+#X text 210 141 get number of remaining children (Read Only);
+#X msg 193 166 AT SH;
+#X text 232 163 get serial number high 32 bits (Read Only);
+#X text 253 184 get serial number low 32 bits (Read Only);
+#X msg 214 187 AT SL;
+#X msg 234 207 AT NI diddley;
+#X text 321 204 set node identifier string;
+#X msg 254 227 AT NI;
+#X text 299 225 get node identifier string;
+#X text 527 50 prefix hexadecimal parameters with 0x;
+#X msg 274 247 AT NP;
+#X text 319 245 get maximum payload;
+#X msg 294 267 AT DD;
+#X text 336 264 get device type identifier;
+#X text 191 119 get endpoint parent's 16-bit address (Read Only);
+#X msg 328 301 AT CH;
+#X text 366 300 get operating channel;
+#X msg 348 321 AT ID;
+#X text 386 320 get 64-bit PAN ID;
+#X text 529 342 set 64-bit PAN ID;
+#X msg 390 363 AT ID 0x0;
+#X text 458 362 set coordinator chosen 64-bit PAN ID;
+#X msg 370 343 AT ID 0xFEEAFEEBFEECFEED;
+#X text 210 74 set lower 32 bits of destination address;
+#X msg 412 385 AT OP;
+#X text 455 383 get operating 64-bit PAN ID;
+#X msg 432 405 AT NH;
+#X msg 452 425 AT NH 0xFF;
+#X text 528 443 set maximum unicast hops (float arg);
+#X text 525 423 set maximum unicast hops (symbol arg);
+#X text 475 403 get maximum unicast hops (no arg);
+#X msg 492 465 AT BH;
+#X text 535 463 get maximum broadcastcast hops (no arg);
+#X text 585 483 set maximum broadcast hops (symbol arg);
+#X msg 512 485 AT BH 0x1E;
+#X msg 532 505 AT BH 3;
+#X text 585 502 set maximum broadcast hops (float arg);
+#X msg 552 525 AT OI;
+#X text 595 523 get operating 16-bit PAN ID;
+#X msg 472 445 AT NH 2;
+#X msg 573 546 AT NT;
+#X text 616 544 get node discovery timeout;
+#X text 662 564 set node discovery timeout;
+#X msg 593 566 AT NT 0xFF;
+#X msg 613 586 AT NO;
+#X msg 633 606 AT NO 3;
+#X text 656 584 get node discovery options;
+#X text 684 604 set node discovery options;
+#X msg 654 627 AT SC;
+#X msg 673 646 AT SC 0xFFFF;
+#X text 697 625 get scan channel bitmask;
+#X text 754 645 set scan channels;
+#X msg 692 665 AT SD;
+#X msg 711 684 AT SD 3;
+#X text 735 663 get scan duration;
+#X text 762 683 set scan duration;
+#X text 66 300 get zigbee stack profile;
+#X text 94 320 set zigbee stack profile;
+#X msg 28 301 AT ZS;
+#X msg 47 320 AT ZS 0;
+#X msg 68 341 AT NJ;
+#X msg 88 361 AT NJ 0xFF;
+#X text 106 340 get node join time;
+#X text 161 360 set node join time;
+#X obj 410 700 s topackxbee;
+#X obj 614 688 r topackxbee;
+#X msg 108 381 AT JV;
+#X text 146 380 get channel verification;
+#X text 181 400 set channel verification;
+#X msg 128 401 AT JV 1;
+#X text 203 437 get power level;
+#X msg 165 438 AT PL;
+#X msg 185 458 AT PM;
+#X text 223 457 get power mode;
+#X msg 205 478 AT DB;
+#X msg 225 498 AT PP;
+#X text 263 497 get peak power dBm;
+#X text 243 477 get received signal strength -dBm;
+#X text 283 517 get API mode;
+#X msg 245 518 AT AP;
+#X msg 325 598 AT AO;
+#X text 363 597 get API options;
+#X msg 345 618 AT BD;
+#X text 383 617 get interface data rate;
+#X msg 365 638 AT NB;
+#X text 403 637 get interface parity;
+#X msg 385 658 AT SB;
+#X text 423 657 get interface stop bits;
+#X msg 405 678 AT RO;
+#X text 443 677 get packetization timeout;
+#X obj 1080 736 s topackxbee;
+#X msg 954 593 AT D7;
+#X msg 936 575 AT D6;
+#X msg 708 347 AT IR;
+#X text 746 346 get IO sample rate;
+#X msg 728 367 AT IC;
+#X text 766 366 get IO digital change detection;
+#X msg 748 387 AT P0;
+#X text 786 386 get PWM0 function;
+#X msg 768 407 AT P1;
+#X text 806 406 get PWM1 function;
+#X msg 788 427 AT P2;
+#X text 826 426 get PWM2 function;
+#X msg 808 447 AT P3;
+#X text 846 446 get PWM3 function;
+#X msg 828 467 AT D0;
+#X text 872 466 get AD0/DIO0 function;
+#X msg 846 485 AT D1;
+#X msg 864 503 AT D2;
+#X text 908 502 get AD2/DIO2 function;
+#X text 890 484 get AD1/DIO1 function;
+#X msg 882 521 AT D3;
+#X msg 900 539 AT D4;
+#X msg 918 557 AT D5;
+#X text 926 520 get AD3/DIO3 function;
+#X text 944 538 get DIO4 function;
+#X text 962 556 get DIO5 function;
+#X text 974 574 get DIO6 configuration;
+#X text 992 592 get DIO7 configuration;
+#X msg 972 611 AT D8;
+#X text 1010 610 get DIO8 configuration;
+#X msg 991 630 AT LT;
+#X text 1026 628 get Associate LED blink time 10ms;
+#X msg 1009 648 AT PR;
+#X text 1044 646 get pullup resistors;
+#X text 1067 664 get supply voltage 1200/1024mV;
+#X msg 1028 667 AT %V;
+#X msg 1048 687 AT V+;
+#X text 1087 684 get supply voltage threshold 1200/1024mV;
+#X msg 1068 707 AT TP;
+#X text 1107 704 get temperature C;
+#X obj 1275 662 s topackxbee;
+#X msg 979 349 AT VR;
+#X text 1018 346 get firmware version;
+#X msg 999 369 AT HV;
+#X text 1038 366 get hardware version;
+#X msg 1019 389 AT AI;
+#X text 1058 386 get association indication;
+#X msg 1039 409 AT CC;
+#X text 1078 406 get AT command sequence character;
+#X msg 1069 439 AT ND;
+#X text 1108 436 node discover;
+#X text 1179 459 resolve destination node;
+#X msg 1109 479 AT IS;
+#X msg 1129 499 AT 1S;
+#X text 1157 477 force sample;
+#X text 1167 497 force xbee sample;
+#X msg 143 705 devices;
+#X msg 11 546 API 1;
+#X msg 33 568 API 2;
+#X obj 84 636 s topackxbee;
+#X text 50 545 set API mode 1;
+#X text 74 569 set API mode 2 (escaped characters);
+#X text 55 583 mode 2 is the default setting;
+#X text 314 537 set API mode;
+#X msg 265 538 AT AP 1;
+#X text 334 557 set API mode;
+#X msg 285 558 AT AP 2;
+#X msg 1162 532 AT AC;
+#X text 1202 530 apply changes;
+#X msg 1182 552 AT WR;
+#X text 1222 550 write parameters to non-volatile memory;
+#X msg 1202 572 AT RE;
+#X text 1242 570 restore defaults;
+#X msg 1222 592 AT FR;
+#X text 1262 590 software reset;
+#X msg 1242 612 AT NR;
+#X text 1282 610 network reset;
+#X msg 1262 632 AT CB 1;
+#X text 1312 630 commisioning pushbutton;
+#X text 1115 515 ***DANGEROUS***;
+#X text 14 704 list available ports;
+#X obj 792 322 s topackxbee;
+#X text 640 79 queue set interface data rate;
+#X msg 566 79 ATQ BD 7;
+#X msg 183 652 baud 115200;
+#X msg 207 676 baud 9600;
+#X text 660 99 queue set interface data rate;
+#X msg 586 99 ATQ BD 3;
+#X msg 150 751 verbosity \$1;
+#X obj 96 736 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034
+-1 -1 0;
+#X msg 713 226 verbosity \$1;
+#X obj 659 211 hradio 15 1 0 3 empty empty verbosity 0 -8 0 10 -4034
+-1 -1 2;
+#X msg 656 169 TX 0x0013A200406ADE1E 0x79D6 0 0 64;
+#X obj 237 742 t f f;
+#X obj 237 796 print data;
+#N canvas 43 599 1232 329 status 1;
+#X obj 73 16 inlet;
+#X floatatom 184 218 5 0 0 0 - - -;
+#X obj 254 99 print unpack5;
+#X obj 73 46 route AT_Command_Response;
+#X obj 73 82 list split 3;
+#X obj 184 142 route ND;
+#X obj 184 120 list trim;
+#X symbolatom 201 234 7 0 0 0 - - -;
+#X symbolatom 219 251 20 0 0 0 - - -;
+#X obj 73 120 unpack 0 0 0;
+#X floatatom 73 144 5 0 0 0 - - -;
+#X floatatom 107 164 5 0 0 0 - - -;
+#X floatatom 142 184 5 0 0 0 - - -;
+#X text -1 144 packet type;
+#X text 39 164 packet ID;
+#X text 64 183 data length;
+#X text 71 215 AT command status;
+#X text 155 233 addr16;
+#X text 175 249 addr64;
+#X obj 428 63 route ZigBee_Transmit_Status;
+#X floatatom 428 105 5 0 0 0 - - -;
+#X floatatom 449 123 5 0 0 0 - - -;
+#X text 354 105 packet type;
+#X text 381 123 packet ID;
+#X symbolatom 470 140 7 0 0 0 - - -;
+#X text 427 139 addr16;
+#X floatatom 533 192 5 0 0 0 - - -;
+#X floatatom 512 175 5 0 0 0 - - -;
+#X floatatom 491 158 5 0 0 0 - - -;
+#X text 360 156 transmit retry count;
+#X text 411 173 delivery status;
+#X text 427 190 discovery status;
+#X symbolatom 236 268 32 0 0 0 - - -;
+#X symbolatom 254 286 7 0 0 0 - - -;
+#X symbolatom 307 339 7 0 0 0 - - -;
+#X symbolatom 325 357 7 0 0 0 - - -;
+#X obj 184 196 unpack 0 s s s s 0 0 s s;
+#X floatatom 272 304 5 0 0 0 - - -;
+#X floatatom 289 321 5 0 0 0 - - -;
+#X text 139 267 Node Identifier;
+#X text 207 285 parent;
+#X text 197 301 device type;
+#X text 209 319 source event;
+#X text 252 337 profile;
+#X text 247 355 manufacturer;
+#X obj 428 85 unpack 0 0 s 0 0 0;
+#X obj 616 80 route ZigBee_Receive_Packet;
+#X obj 1181 114 print someotherpacket;
+#X symbolatom 685 177 7 0 0 0 - - -;
+#X symbolatom 662 159 17 0 0 0 - - -;
+#X text 639 176 addr16;
+#X text 618 157 addr64;
+#X floatatom 616 123 5 0 0 0 - - -;
+#X text 542 123 packet type;
+#X floatatom 709 195 5 0 0 0 - - -;
+#X text 610 193 receive options;
+#X obj 709 245 tgl 15 0 empty empty acknowledged 17 7 0 10 -4034 -1
+-1 0 1;
+#X obj 749 265 tgl 15 0 empty empty broadcast 17 7 0 10 -4034 -1 -1
+0 1;
+#X obj 789 285 tgl 15 0 empty empty encrypted 17 7 0 10 -4034 -1 -1
+0 1;
+#X obj 829 305 tgl 15 0 empty empty from_end_device 17 7 0 10 -4034
+-1 -1 0 1;
+#X obj 709 209 & 1;
+#X obj 749 209 & 2;
+#X obj 789 209 & 32;
+#X obj 829 209 & 64;
+#X obj 616 101 unpack 0 0 s s 0;
+#X floatatom 639 140 5 0 0 0 - - -;
+#X text 565 140 data length;
+#X obj 511 214 select 0 2 21 33 34 35 36 37;
+#X symbolatom 511 411 32 0 0 0 - - -;
+#X msg 511 238 set success;
+#X msg 676 396 set unknown;
+#X msg 531 257 set CCA_failurs;
+#X msg 572 297 set Network_ACK_Failure;
+#X msg 552 277 set Invalid_Destination_Endpoint;
+#X msg 593 317 set Not_Joined_To_Network;
+#X msg 612 337 set Self-Addresed;
+#X msg 634 356 set Address_Not_Found;
+#X msg 655 376 set Route_Not_Found;
+#X text 408 410 delivery status:;
+#X symbolatom 532 547 32 0 0 0 - - -;
+#X msg 613 532 set unknown;
+#X obj 532 435 select 0 1 2 3;
+#X msg 532 456 set No_Discovery_Overhead;
+#X msg 552 475 set Address_Discovery;
+#X msg 573 494 set Route_Discovery;
+#X msg 593 513 set Address_And_Route_Discovery;
+#X text 428 545 discovery status:;
+#X obj 936 97 route Remote_Command_Response;
+#X floatatom 936 150 5 0 0 0 - - -;
+#X floatatom 955 172 5 0 0 0 - - -;
+#X text 862 150 packet type;
+#X text 887 172 packet ID;
+#X floatatom 1053 279 5 0 0 0 - - -;
+#X symbolatom 975 212 20 0 0 0 - - -;
+#X text 931 210 addr64;
+#X symbolatom 994 193 7 0 0 0 - - -;
+#X symbolatom 1014 234 7 0 0 0 - - -;
+#X text 968 233 command;
+#X floatatom 1033 256 5 0 0 0 - - -;
+#X text 983 280 data length;
+#X text 991 256 status;
+#X obj 936 124 unpack 0 0 s s s 0 0;
+#X obj 229 162 print AT_response;
+#X text 948 192 addr16;
+#X obj 1101 160 select 0 1 2 3 4;
+#X symbolatom 1101 360 32 0 0 0 - - -;
+#X text 998 359 delivery status:;
+#X msg 1101 187 set OK;
+#X msg 1119 207 set ERROR;
+#X msg 1138 226 set Invalid_Command;
+#X msg 1157 246 set Invalid_Parameter;
+#X msg 1175 269 set Transmission_Failed;
+#X connect 0 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 1 19 0;
+#X connect 4 0 9 0;
+#X connect 4 1 6 0;
+#X connect 4 2 2 0;
+#X connect 5 0 36 0;
+#X connect 5 1 102 0;
+#X connect 6 0 5 0;
+#X connect 9 0 10 0;
+#X connect 9 1 11 0;
+#X connect 9 2 12 0;
+#X connect 19 0 45 0;
+#X connect 19 1 46 0;
+#X connect 36 0 1 0;
+#X connect 36 1 7 0;
+#X connect 36 2 8 0;
+#X connect 36 3 32 0;
+#X connect 36 4 33 0;
+#X connect 36 5 37 0;
+#X connect 36 6 38 0;
+#X connect 36 7 34 0;
+#X connect 36 8 35 0;
+#X connect 45 0 20 0;
+#X connect 45 1 21 0;
+#X connect 45 2 24 0;
+#X connect 45 3 28 0;
+#X connect 45 4 27 0;
+#X connect 45 4 67 0;
+#X connect 45 5 26 0;
+#X connect 45 5 81 0;
+#X connect 46 0 64 0;
+#X connect 46 1 87 0;
+#X connect 54 0 60 0;
+#X connect 54 0 61 0;
+#X connect 54 0 62 0;
+#X connect 54 0 63 0;
+#X connect 60 0 56 0;
+#X connect 61 0 57 0;
+#X connect 62 0 58 0;
+#X connect 63 0 59 0;
+#X connect 64 0 52 0;
+#X connect 64 1 65 0;
+#X connect 64 2 49 0;
+#X connect 64 3 48 0;
+#X connect 64 4 54 0;
+#X connect 67 0 69 0;
+#X connect 67 1 71 0;
+#X connect 67 2 73 0;
+#X connect 67 3 72 0;
+#X connect 67 4 74 0;
+#X connect 67 5 75 0;
+#X connect 67 6 76 0;
+#X connect 67 7 77 0;
+#X connect 67 8 70 0;
+#X connect 69 0 68 0;
+#X connect 70 0 68 0;
+#X connect 71 0 68 0;
+#X connect 72 0 68 0;
+#X connect 73 0 68 0;
+#X connect 74 0 68 0;
+#X connect 75 0 68 0;
+#X connect 76 0 68 0;
+#X connect 77 0 68 0;
+#X connect 80 0 79 0;
+#X connect 81 0 82 0;
+#X connect 81 1 83 0;
+#X connect 81 2 84 0;
+#X connect 81 3 85 0;
+#X connect 81 4 80 0;
+#X connect 82 0 79 0;
+#X connect 83 0 79 0;
+#X connect 84 0 79 0;
+#X connect 85 0 79 0;
+#X connect 87 0 101 0;
+#X connect 87 1 47 0;
+#X connect 101 0 88 0;
+#X connect 101 1 89 0;
+#X connect 101 2 93 0;
+#X connect 101 3 95 0;
+#X connect 101 4 96 0;
+#X connect 101 5 98 0;
+#X connect 101 5 104 0;
+#X connect 101 6 92 0;
+#X connect 104 0 107 0;
+#X connect 104 1 108 0;
+#X connect 104 2 109 0;
+#X connect 104 3 110 0;
+#X connect 104 4 111 0;
+#X connect 107 0 105 0;
+#X connect 108 0 105 0;
+#X connect 109 0 105 0;
+#X connect 110 0 105 0;
+#X connect 111 0 105 0;
+#X restore 317 783 pd status;
+#X obj 385 759 spigot;
+#X obj 385 781 print raw;
+#X obj 418 733 tgl 15 0 empty empty print_raw 17 7 0 10 -4034 -1 -1
+0 1;
+#X obj 715 780 print packed;
+#X obj 715 754 spigot;
+#X obj 748 730 tgl 15 0 empty empty print_packed 17 7 0 10 -4034 -1
+-1 0 1;
+#X obj 715 705 packxbee 2;
+#X obj 237 768 unpackxbee 2;
+#X msg 636 149 TX 0x0013A20040769444 0xFFFE 0 0 1 2 3 4;
+#X obj 412 2 import mrpeach;
+#X text 891 135 data packet: 64-bit_destination 16-bit_destination
+broadcast_radius options data;
+#X obj 898 97 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 1900 0;
+#X obj 895 116 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -8 0 10
+-262144 -1 -1 19 256;
+#X obj 895 74 f;
+#X obj 938 74 + 1;
+#X obj 1337 160 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1
+0 1;
+#X obj 982 72 % 128;
+#X obj 237 723 comport 4 9600;
+#X msg 617 130 TX 0x0013A200406BFE6C 0x51D6 0 0 136 \$1;
+#X msg 1337 273 4;
+#X msg 1356 253 5;
+#X obj 1337 209 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1
+1 1;
+#X obj 1337 230 sel 0 1;
+#X msg 777 290 RAT 0x0013A200406BFE6C 0x51D6 2 D0 \$1;
+#X obj 1337 185 metro 200;
+#X msg 753 266 RAT 0x0013A200406BFE6C 0x51D6 0 SL;
+#X msg 733 246 RAT 0x0013A200406BFE6C 0x51D6 0 SH;
+#X obj 895 32 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X obj 895 52 metro 200;
+#X text 856 220 remote AT command: 64-bit address \, 16-bit address
+\, options \, command \, parameters;
+#X text 1008 290 switch remote IO pin 0 high/low (options = 2 = apply
+changes immediately);
+#X msg 1089 459 AT DN IMCA_R1;
+#X connect 0 0 204 0;
+#X connect 2 0 204 0;
+#X connect 3 0 204 0;
+#X connect 6 0 204 0;
+#X connect 7 0 204 0;
+#X connect 8 0 204 0;
+#X connect 10 0 204 0;
+#X connect 12 0 204 0;
+#X connect 15 0 204 0;
+#X connect 16 0 204 0;
+#X connect 18 0 204 0;
+#X connect 21 0 204 0;
+#X connect 23 0 204 0;
+#X connect 26 0 204 0;
+#X connect 28 0 204 0;
+#X connect 31 0 204 0;
+#X connect 33 0 204 0;
+#X connect 35 0 204 0;
+#X connect 37 0 204 0;
+#X connect 38 0 204 0;
+#X connect 42 0 204 0;
+#X connect 45 0 204 0;
+#X connect 46 0 204 0;
+#X connect 48 0 204 0;
+#X connect 50 0 204 0;
+#X connect 51 0 204 0;
+#X connect 54 0 204 0;
+#X connect 55 0 204 0;
+#X connect 56 0 204 0;
+#X connect 59 0 204 0;
+#X connect 60 0 204 0;
+#X connect 63 0 204 0;
+#X connect 64 0 204 0;
+#X connect 69 0 75 0;
+#X connect 70 0 75 0;
+#X connect 71 0 75 0;
+#X connect 72 0 75 0;
+#X connect 76 0 204 0;
+#X connect 77 0 75 0;
+#X connect 80 0 75 0;
+#X connect 82 0 75 0;
+#X connect 83 0 75 0;
+#X connect 85 0 75 0;
+#X connect 86 0 75 0;
+#X connect 90 0 75 0;
+#X connect 91 0 75 0;
+#X connect 93 0 75 0;
+#X connect 95 0 75 0;
+#X connect 97 0 75 0;
+#X connect 99 0 75 0;
+#X connect 102 0 101 0;
+#X connect 103 0 101 0;
+#X connect 104 0 101 0;
+#X connect 106 0 101 0;
+#X connect 108 0 101 0;
+#X connect 110 0 101 0;
+#X connect 112 0 101 0;
+#X connect 114 0 101 0;
+#X connect 116 0 101 0;
+#X connect 118 0 101 0;
+#X connect 119 0 101 0;
+#X connect 122 0 101 0;
+#X connect 123 0 101 0;
+#X connect 124 0 101 0;
+#X connect 130 0 101 0;
+#X connect 132 0 101 0;
+#X connect 134 0 101 0;
+#X connect 137 0 101 0;
+#X connect 138 0 101 0;
+#X connect 140 0 101 0;
+#X connect 143 0 142 0;
+#X connect 145 0 142 0;
+#X connect 147 0 142 0;
+#X connect 149 0 142 0;
+#X connect 151 0 142 0;
+#X connect 154 0 142 0;
+#X connect 155 0 142 0;
+#X connect 158 0 215 0;
+#X connect 159 0 161 0;
+#X connect 160 0 161 0;
+#X connect 166 0 75 0;
+#X connect 168 0 75 0;
+#X connect 169 0 142 0;
+#X connect 171 0 142 0;
+#X connect 173 0 142 0;
+#X connect 175 0 142 0;
+#X connect 177 0 142 0;
+#X connect 179 0 142 0;
+#X connect 185 0 183 0;
+#X connect 186 0 215 0;
+#X connect 187 0 215 0;
+#X connect 189 0 183 0;
+#X connect 190 0 205 0;
+#X connect 191 0 190 0;
+#X connect 192 0 183 0;
+#X connect 193 0 192 0;
+#X connect 194 0 183 0;
+#X connect 195 0 205 0;
+#X connect 195 1 198 0;
+#X connect 198 0 199 0;
+#X connect 200 0 198 1;
+#X connect 202 0 201 0;
+#X connect 203 0 202 1;
+#X connect 204 0 202 0;
+#X connect 204 0 215 0;
+#X connect 205 0 196 0;
+#X connect 205 1 197 0;
+#X connect 206 0 183 0;
+#X connect 209 0 210 0;
+#X connect 210 0 216 0;
+#X connect 211 0 212 0;
+#X connect 211 0 209 0;
+#X connect 212 0 214 0;
+#X connect 213 0 222 0;
+#X connect 214 0 211 1;
+#X connect 215 0 195 0;
+#X connect 216 0 183 0;
+#X connect 217 0 221 0;
+#X connect 218 0 221 0;
+#X connect 219 0 220 0;
+#X connect 220 0 217 0;
+#X connect 220 1 218 0;
+#X connect 221 0 183 0;
+#X connect 222 0 219 0;
+#X connect 223 0 183 0;
+#X connect 224 0 183 0;
+#X connect 225 0 226 0;
+#X connect 226 0 211 0;
+#X connect 229 0 142 0;
diff --git a/externals/mrpeach/xbee/packxbee.c b/externals/mrpeach/xbee/packxbee.c
new file mode 100644
index 000000000..33a020197
--- /dev/null
+++ b/externals/mrpeach/xbee/packxbee.c
@@ -0,0 +1,667 @@
+/* packxbee outputs a list of floats which are the bytes making up an xbee api packet. */
+/* The packet can then be sent through [comport]. */
+/* Started by Martin Peach 20110731 */
+/* Information taken from "XBee®/XBee-PRO® ZB RF Modules" (document 90000976_G, 11/15/2010)*/
+/* by Digi International Inc. http://www.digi.com */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "pdxbee.h"
+
+static t_class *packxbee_class;
+
+
+typedef struct _packxbee
+{
+    t_object        x_obj;
+    t_outlet        *x_listout;
+    int             x_api_mode;
+    unsigned char   x_frameID;
+    unsigned char   x_frameType;
+    int             x_verbosity;
+    t_atom          x_outbuf[MAX_XBEE_PACKET_LENGTH];
+} t_packxbee;
+
+static void *packxbee_new(t_floatarg f);
+static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val);
+static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void packxbee_API(t_packxbee *x, t_float api);
+static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level);
+static void packxbee_free(t_packxbee *x);
+void packxbee_setup(void);
+
+static void *packxbee_new(t_floatarg f)
+{
+    int i;
+
+    t_packxbee *x = (t_packxbee *)pd_new(packxbee_class);
+    if (x)
+    {
+        x->x_listout = outlet_new(&x->x_obj, &s_list);
+        if (1 == f) x->x_api_mode = 1;
+        else x->x_api_mode = 2; /* default to escaped mode */
+        x->x_verbosity = 0; /* debug level */
+        for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */
+    }
+    return (x);
+}
+
+static void packxbee_API(t_packxbee *x, t_float api)
+{
+    if ((api == 1) || (api ==2)) x->x_api_mode = api;
+    else error ("packxbee: api mode must be 1 or 2");
+}
+
+static void packxbee_verbosity(t_packxbee *x, t_float verbosity_level)
+{
+    if (verbosity_level >= 0) x->x_verbosity = verbosity_level;
+    else error ("packxbee: verbosity_level must be positive");
+}
+
+static int packxbee_outbuf_add(t_packxbee *x, int index, unsigned char val)
+{
+    int i = index;
+
+/* if API mode is 2 all characters after the first are escaped if they are one of the sacred texts */
+/* to escape the character prefix it with XSCAPE and XOR it with 0x20 */
+    if
+    (
+        (2 == x->x_api_mode)
+        &&
+        (
+            ((0 < index)&&(XFRAME == val))
+            ||(XSCAPE == val)
+            ||(XON == val)
+            ||(XOFF == val)
+        )
+    )
+    { /* escape the character */
+        x->x_outbuf[i].a_w.w_float = XSCAPE;
+        ++i;
+        x->x_outbuf[i].a_w.w_float = val ^ 0x20;
+        ++i;
+    }
+    else
+    { /* otherwise just put it in the buffer */
+        x->x_outbuf[i++].a_w.w_float = val;
+    }
+    return i;
+}
+
+/* send a packet given a 64-bit address, a 16-bit address, broadcast radius, options, followed by raw data */
+static void packxbee_TX(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    unsigned char       floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */
+    unsigned long long  dest64;
+    unsigned int        dest16;
+    int                 result;
+    char                checksum = 0xFF;
+    unsigned char       broadcast_radius, options;
+    t_float             f;
+    int                 d, i, j, k;
+    int                 length = 0;
+    unsigned char       c;
+
+    if (argc < 5)
+    {
+        error("packxbee_TX: not enough parameters");
+        return;
+    }
+    /* first arg is dest64, a symbol starting with "0x" */
+    if (argv[0].a_type != A_SYMBOL)
+    {
+        error("packxbee_TX: first argument is not a symbol");
+        return;
+    }
+    if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x'))
+    {
+        error("packxbee_TX: first argument is not a hex string beginning with \"0x\"");
+        return;
+    }
+#ifdef _MSC_VER
+    result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64); 
+#else
+    result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%LX", &dest64);
+#endif
+    if (result == 0)
+    {
+        error("packxbee_TX: first argument is not a hex string");
+        return;
+    }
+#ifdef _MSC_VER
+    if (x->x_verbosity > 1) post ("packxbee_TX: dest64:0x%016I64X", dest64);
+#else
+    if (x->x_verbosity > 1) post ("packxbee_TX: dest64:0x%016LX", dest64);
+#endif
+    /* second arg is dest16 also a symbol starting with "0x" */
+    if (argv[1].a_type != A_SYMBOL)
+    {
+        error("packxbee_TX: second argument is not a symbol");
+        return;
+    }
+    if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x'))
+    {
+        error("packxbee_TX: second argument is not a hex string beginning with \"0x\"");
+        return;
+    }
+    result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16);
+    if (result == 0)
+    {
+        error("packxbee_TX: second argument is not a hex string");
+        return;
+    }
+    if (x->x_verbosity > 1) post ("packxbee_TX: dest16: 0x%X", dest16);
+    /* broadcast radius is a single byte as a float */
+    if (argv[2].a_type != A_FLOAT)
+    {
+        error("packxbee_TX: third argument is not a float");
+        return;
+    }
+    f = argv[2].a_w.w_float;
+    if (x->x_verbosity > 1)  post("packxbee_TX float parameter %f", f);
+    d = ((unsigned int)f)&0x0FF;
+    if (f != d)
+    {
+        post ("packxbee_TX third argument not a positive integer from 0 to 255");
+        return;
+    }
+    else broadcast_radius = d;
+    if (x->x_verbosity > 1)  post("packxbee_TX: broadcast_radius: %d", d);
+
+    /* options is a single byte as a float */
+    if (argv[3].a_type != A_FLOAT)
+    {
+        error("packxbee_TX: fourth argument is not a float");
+        return;
+    }
+    f = argv[3].a_w.w_float;
+    if (x->x_verbosity > 1)  post("packxbee_TX float parameter %f", f);
+    d = ((unsigned int)f)&0x0FF;
+    if (f != d)
+    {
+        post ("packxbee_TX fourth argument not a positive integer from 0 to 255");
+        return;
+    }
+    else options = d;
+    if (x->x_verbosity > 1)  post("packxbee_TX: options: %d", d);
+
+    x->x_frameType = ZigBee_Transmit_Request;/* because we're building a queued AT frame */
+    floatstring[0] = XFRAME; /* as usual */
+    floatstring[1] = 0; /* length MSB */
+    floatstring[2] = 0;/* length LSB */
+    floatstring[3] = x->x_frameType;
+    checksum -= x->x_frameType;
+    if (0 == x->x_frameID) x->x_frameID++;
+    checksum -= x->x_frameID; /* frame ID */
+    floatstring[4] = x->x_frameID++;
+    /* raw 8 byte address in big-endian order: */
+    floatstring[5] = (dest64>>56)&0x0FF;
+    checksum -= floatstring[5];
+    floatstring[6] = (dest64>>48)&0x0FF;
+    checksum -= floatstring[6];
+    floatstring[7] = (dest64>>40)&0x0FF;
+    checksum -= floatstring[7];
+    floatstring[8] = (dest64>>32)&0x0FF;
+    checksum -= floatstring[8];
+    floatstring[9] = (dest64>>24)&0x0FF;
+    checksum -= floatstring[9];
+    floatstring[10] = (dest64>>16)&0x0FF;
+    checksum -= floatstring[10];
+    floatstring[11] = (dest64>>8)&0x0FF;
+    checksum -= floatstring[11];
+    floatstring[12] = (dest64)&0x0FF;
+    checksum -= floatstring[12];
+
+    floatstring[13] = (dest16>>8)&0x0FF;
+    checksum -= floatstring[13];
+    floatstring[14] = (dest16)&0x0FF;
+    checksum -= floatstring[14];
+
+    floatstring[15] = broadcast_radius;
+    checksum -= floatstring[15];
+    floatstring[16] = options;
+    checksum -= floatstring[16];
+    /* the rest is payload */
+    i = 17;
+    for (k = 4; k < argc; ++k)
+    {
+        if (A_FLOAT == argv[k].a_type)
+        {
+            f = argv[k].a_w.w_float;
+            if (x->x_verbosity > 1)  post("packxbee_TX float parameter %f", f);
+            d = ((unsigned int)f)&0x0FF;
+            if (f != d)
+            {
+                post ("packxbee_TX %dth argument not a positive integer from 0 to 255", k+1);
+                return;
+            }
+            floatstring[i++] = d;
+            checksum -= d;
+        }
+        else if (A_SYMBOL == argv[k].a_type)
+        {
+            if (x->x_verbosity > 1)  post("packxbee_TX symbol parameter %s", argv[k].a_w.w_symbol->s_name);
+            j = i;
+            i += sprintf((char *)&floatstring[i], "%s", argv[k].a_w.w_symbol->s_name);
+            for (;j < i; ++j) checksum -= floatstring[j];
+        }
+        else
+        {
+            error("packxbee_TX %dth argument neither a float nor a symbol", k);
+            return;
+        }
+    }
+    length = i-3;
+    floatstring[LENGTH_LSB_INDEX] = length & 0x0FF;
+    floatstring[LENGTH_MSB_INDEX] = length >> 8;
+    floatstring[i++] = checksum;
+    k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */
+    for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]);
+    outlet_list(x->x_listout, &s_list, j, x->x_outbuf);
+    if(x->x_verbosity > 1)
+    {
+        for (k = 0; k < j; ++k)
+        {
+            c = (unsigned char)atom_getfloat(&x->x_outbuf[k]);
+            post("buf[%d]: %d [0x%02X]", k, c, c);
+        }
+    }
+}
+
+/* format a queued AT packet and send it through x_listout as a list of floats */
+static void packxbee_ATQ(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    x->x_frameType = AT_Command_Queue_Parameter_Value;/* we're building a queued AT frame */
+    packxbee_pack_frame(x, s, argc, argv);
+}
+
+/* format an AT packet and send it through x_listout as a list of floats */
+static void packxbee_AT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    x->x_frameType = AT_Command;/* we're building an AT frame */
+    packxbee_pack_frame(x, s, argc, argv);
+}
+
+/* format a remote AT packet and send it through x_listout as a list of floats */
+static void packxbee_RAT(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    x->x_frameType = Remote_Command_Request;/* we're building a remote AT frame */
+    if (argc < 3)
+    {
+        error("packxbee_RAT: not enough parameters");
+        return;
+    }
+    packxbee_pack_remote_frame(x, s, argc, argv);
+}
+
+static void packxbee_pack_remote_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int                 i, j, k, maxdigits, d;
+    char                checksum = 0xFF;
+    unsigned char       floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */
+    int                 length = 0;
+    unsigned char       c, digits;
+    t_float             f;
+
+    unsigned long long  dest64;
+    unsigned int        dest16;
+    int                 result;
+    unsigned char       options;
+
+
+    if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc);
+    if (argc >= 4) /* we must have addr64, addr16, option byte, and an AT command */
+    {
+        /* first arg is dest64, a symbol starting with "0x" */
+        if (argv[0].a_type != A_SYMBOL)
+        {
+            error("packxbee_pack_remote_frame: first argument is not a symbol");
+            return;
+        }
+        if ((argv[0].a_w.w_symbol->s_name[0] != '0')||(argv[0].a_w.w_symbol->s_name[1] != 'x'))
+        {
+            error("packxbee_pack_remote_frame: first argument is not a hex string beginning with \"0x\"");
+            return;
+        }
+#ifdef _MSC_VER
+        result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%I64X", &dest64);
+#else
+        result = sscanf(argv[0].a_w.w_symbol->s_name, "0x%LX", &dest64);
+#endif
+        if (result == 0)
+        {
+            error("packxbee_pack_remote_frame: first argument is not a hex string");
+            return;
+        }
+#ifdef _MSC_VER
+        if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest64:0x%016I64X", dest64);
+#else
+        if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest64:0x%016LX", dest64);
+#endif
+        /* second arg is dest16 also a symbol starting with "0x" */
+        if (argv[1].a_type != A_SYMBOL)
+        {
+            error("packxbee_pack_remote_frame: second argument is not a symbol");
+            return;
+        }
+        if ((argv[1].a_w.w_symbol->s_name[0] != '0')||(argv[1].a_w.w_symbol->s_name[1] != 'x'))
+        {
+            error("packxbee_pack_remote_frame: second argument is not a hex string beginning with \"0x\"");
+            return;
+        }
+        result = sscanf(argv[1].a_w.w_symbol->s_name, "0x%X", &dest16);
+        if (result == 0)
+        {
+            error("packxbee_pack_remote_frame: second argument is not a hex string");
+            return;
+        }
+        if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: dest16: 0x%X", dest16);
+        /* options is a single byte as a float */
+        if (argv[2].a_type != A_FLOAT)
+        {
+            error("packxbee_pack_remote_frame: third argument is not a float");
+            return;
+        }
+        f = argv[2].a_w.w_float;
+        if (x->x_verbosity > 0)  post("packxbee_pack_remote_frame float parameter %f", f);
+        d = ((unsigned int)f)&0x0FF;
+        if (f != d)
+        {
+            post ("packxbee_pack_remote_frame third argument not a positive integer from 0 to 255");
+            return;
+        }
+        else options = d;
+        if (x->x_verbosity > 0)  post("packxbee_pack_remote_frame: options: %d", d);
+        if (argv[3].a_type != A_SYMBOL)
+        {
+            post ("packxbee_pack_remote_frame: argument 4 must be an AT command");
+            return;
+        }
+        if (x->x_verbosity > 0) post ("packxbee_pack_remote_frame: argument 4 is %s", argv[3].a_w.w_symbol->s_name);
+        if (2 != strlen(argv[3].a_w.w_symbol->s_name))
+        {
+            post ("packxbee_pack_remote_frame: argument 4 must be a two-character AT command");
+            return;
+        }
+        if (((argv[3].a_w.w_symbol->s_name[0] < 0x20) || (argv[3].a_w.w_symbol->s_name[0] & 0x80))
+            || ((argv[3].a_w.w_symbol->s_name[1] < 0x20) || (argv[3].a_w.w_symbol->s_name[1] & 0x80)))
+        {
+            post ("packxbee_pack_remote_frame: argument 4 must be printable ascii");
+            return;
+        }
+        /* parameters seem valid, now build the frame */
+        i = 0;
+        floatstring[i++] = XFRAME; /* as usual */
+        floatstring[i++] = 0; /* length MSB */
+        floatstring[i++] = 0;/* length LSB */
+        floatstring[i++] = x->x_frameType;
+        checksum -= x->x_frameType;
+        if (0 == x->x_frameID) x->x_frameID++; /* never use zero as frame ID */
+        floatstring[i] = x->x_frameID++;
+        checksum -= floatstring[i++];
+
+        /* raw 8 byte address in big-endian order: */
+        floatstring[i] = (dest64>>56)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>48)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>40)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>32)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>24)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>16)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64>>8)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest64)&0x0FF;
+        checksum -= floatstring[i++];
+
+        floatstring[i] = (dest16>>8)&0x0FF;
+        checksum -= floatstring[i++];
+        floatstring[i] = (dest16)&0x0FF;
+        checksum -= floatstring[i++];
+
+        floatstring[i] = options;
+        checksum -= floatstring[i++];
+
+        c = argv[3].a_w.w_symbol->s_name[0];/* the first character of the AT command */
+        floatstring[i] = c;
+        checksum -= floatstring[i++];
+        c = argv[3].a_w.w_symbol->s_name[1];/* the second character of the AT command */
+        floatstring[i] = c;
+        checksum -= floatstring[i++];
+        j = i; /* save i in j so we can calculate checksum on any further parameters */
+        /* parameters if any */
+        if (argc >= 5)
+        { /* some parameters */
+            if (argv[4].a_type == A_SYMBOL)
+            {
+                if (x->x_verbosity > 0)  post("packxbee_pack_remote_frame symbol parameter %s", argv[4].a_w.w_symbol->s_name);
+                if (('0' == argv[4].a_w.w_symbol->s_name[0])&&(('x' == argv[4].a_w.w_symbol->s_name[1])))
+                { /* this is a hexadecimal number: strip the "0x" and copy the rest to the buffer as ascii digits */
+                    i += sprintf((char *)&floatstring[i], "%s", &argv[4].a_w.w_symbol->s_name[2]);
+                }
+                else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2)))
+                { /* we hope it's just an ascii string for the NI command */
+                    for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */
+                    {
+                        c = argv[4].a_w.w_symbol->s_name[k];
+                        if (0 == c) break;
+                        //checksum -= c;
+                        floatstring[i++] = c;
+                    }
+                }
+            }
+            else if (argv[4].a_type == A_FLOAT)
+            {
+                f = argv[4].a_w.w_float;
+                if (x->x_verbosity > 0)  post("packxbee_pack_remote_frame float parameter %f", f);
+                d = ((unsigned int)f)&0x0FF;
+                if (f != d)
+                {
+                    post ("packxbee_pack_remote_frame parameter not a positive integer from 0 to 255");
+                }
+                else
+                {
+                    // put the significant part of the raw value into floatstring in big endian order
+                    if (0 != ((d>>24) & 0x0FF)) digits = 4;
+                    else if (0 != ((d>>16) & 0x0FF)) digits = 3;
+                    else if (0 != ((d>>8) & 0x0FF)) digits = 2;
+                    else digits = 1;
+                    if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF;
+                    if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF;
+                    if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF;
+                    floatstring[i++] = d & 0x0FF;
+                }
+            }
+            else
+            {
+                post("packxbee_pack_remote_frame parameter not symbol or float: ignoring");
+            }
+            maxdigits = 32; /* the longest possible hex string is for the encryption key */
+            /* we leave it up to the user to send the correct values */
+            if (j != i)
+            { /* update the checksum */
+                for (; ((j < maxdigits)&&(j < i)); ++j)
+                {
+                    c = floatstring[j];
+                    if (0 == c) break;
+                    checksum -= c;
+                }
+            }
+        } /* argc >= 5 */
+    } /* argc >= 4 */
+    else
+    {
+        error("packxbee_pack_remote_frame: not enough parameters");
+        return;
+    }
+    length = i-3;
+    floatstring[LENGTH_LSB_INDEX] = length & 0x0FF;
+    floatstring[LENGTH_MSB_INDEX] = length >> 8;
+    floatstring[i++] = checksum;
+    k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */
+    for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]);
+    outlet_list(x->x_listout, &s_list, j, x->x_outbuf);
+    if(x->x_verbosity > 1)
+    {
+        for (k = 0; k < j; ++k)
+        {
+            c = (unsigned char)atom_getfloat(&x->x_outbuf[k]);
+            post("buf[%d]: %d [0x%02X]", k, c, c);
+        }
+    }
+}
+
+static void packxbee_pack_frame(t_packxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int             i, j, k, maxdigits, d;
+    char            checksum = 0xFF;
+    unsigned char   floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */
+    int             length = 0;
+    unsigned char   c, digits;
+    t_float         f;
+
+    if (x->x_verbosity > 0) post("packxbee_AT s is %s, argc is %d", s->s_name, argc);
+    if (argc >= 1)
+    {
+        if (argv[0].a_type != A_SYMBOL)
+        {
+            post ("packxbee_AT: argument 1 must be an AT command");
+            return;
+        }
+        if (x->x_verbosity > 0) post ("packxbee_AT: argument 1 is %s", argv[0].a_w.w_symbol->s_name);
+        if (2 != strlen(argv[0].a_w.w_symbol->s_name))
+        {
+            post ("packxbee_AT: argument 1 must be a two-character AT command");
+            return;
+        }
+        if (((argv[0].a_w.w_symbol->s_name[0] < 0x20) || (argv[0].a_w.w_symbol->s_name[0] & 0x80))
+            || ((argv[0].a_w.w_symbol->s_name[1] < 0x20) || (argv[0].a_w.w_symbol->s_name[1] & 0x80)))
+        {
+            post ("packxbee_AT: argument 1 must be printable ascii");
+            return;
+        }
+        i = 0;
+        floatstring[i++] = XFRAME; /* as usual */
+        floatstring[i++] = 0; /* length MSB */
+        floatstring[i++] = 0;/* length LSB */
+        floatstring[i] = x->x_frameType;
+        checksum -= floatstring[i++];
+        if (0 == x->x_frameID) x->x_frameID++;
+        floatstring[i] = x->x_frameID++;
+        checksum -= floatstring[i++];
+        c = argv[0].a_w.w_symbol->s_name[0];/* the first character of the AT command */
+        floatstring[i] = c;
+        checksum -= floatstring[i++];
+        c = argv[0].a_w.w_symbol->s_name[1];/* the second character of the AT command */
+        floatstring[i] = c;
+        checksum -= floatstring[i++];
+        j = i; /* store i in j to see if anything gets added later and we need to update the checksum */
+        /* parameters if any */
+        if (argc >= 2)
+        { /* some parameters */
+            if (argv[1].a_type == A_SYMBOL)
+            {
+                if (x->x_verbosity > 0)  post("packxbee_AT symbol parameter %s", argv[1].a_w.w_symbol->s_name);
+                if (('0' == argv[1].a_w.w_symbol->s_name[0])&&(('x' == argv[1].a_w.w_symbol->s_name[1])))
+                { /* this is a hexadecimal number: strip the "0x" and copy the rest to the buffer as ascii digits */
+                    i += sprintf((char *)&floatstring[i], "%s", &argv[1].a_w.w_symbol->s_name[2]);
+                }
+                else // if ((0 == strncmp("NI", argv[0].a_w.w_symbol->s_name, 2))||(0 == strncmp("DN", argv[0].a_w.w_symbol->s_name, 2)))
+                { /* we hope it's just an ascii string for the NI command */
+                    for (k = 0; (k < 20); ++k) /* no more than 20 characters in a node identifier */
+                    {
+                        c = argv[1].a_w.w_symbol->s_name[k];
+                        if (0 == c) break;
+//                        checksum -= c;
+                        floatstring[i++] = c;
+                    }
+                }
+            }
+            else if (argv[1].a_type == A_FLOAT)
+            {
+                f = argv[1].a_w.w_float;
+                if (x->x_verbosity > 0)  post("packxbee_AT float parameter %f", f);
+                d = ((unsigned int)f)&0x0FF;
+                if (f != d)
+                {
+                    post ("packxbee_AT parameter not a positive integer from 0 to 255");
+                }
+                else
+                {
+                    // put the significant part of the raw value into floatstring in big endian order
+                    if (0 != ((d>>24) & 0x0FF)) digits = 4;
+                    else if (0 != ((d>>16) & 0x0FF)) digits = 3;
+                    else if (0 != ((d>>8) & 0x0FF)) digits = 2;
+                    else digits = 1;
+                    if (4 == digits) floatstring[i++] = (d>>24) & 0x0FF;
+                    if (3 <= digits) floatstring[i++] = (d>>16) & 0x0FF;
+                    if (2 <= digits) floatstring[i++] = (d>>8) & 0x0FF;
+                    floatstring[i++] = d & 0x0FF;
+                }
+            }
+            else
+            {
+                post("packxbee_AT parameter not symbol or float: ignoring");
+            }
+            maxdigits = 32; /* the longest possible hex string is for the encryption key */
+            /* we leave it up to the user to send the correct values */
+            /* if anything was added to floatstring, calculate the checksum on it */
+            /* update the checksum */
+            if (j != i)
+            {
+                for (; ((j < maxdigits)&&(j < i)); ++j)
+                {
+                    c = floatstring[j];
+                    if (0 == c) break;
+                    checksum -= c;
+                }
+            }
+        } /* argc >= 2 */
+        length = i-3;
+        floatstring[LENGTH_LSB_INDEX] = length & 0x0FF;
+        floatstring[LENGTH_MSB_INDEX] = length >> 8;
+        floatstring[i++] = checksum;
+        k = j = 0; /* j indexes the outbuf, k indexes the floatbuf, i is the length of floatbuf */
+        for (k = 0; k < i; ++k) j = packxbee_outbuf_add(x, j, floatstring[k]);
+        outlet_list(x->x_listout, &s_list, j, x->x_outbuf);
+        if(x->x_verbosity > 1)
+        {
+            for (k = 0; k < j; ++k)
+            {
+                c = (unsigned char)atom_getfloat(&x->x_outbuf[k]);
+                post("buf[%d]: %d [0x%02X]", k, c, c);
+            }
+        }
+    } /* argc >= 1 */
+}
+
+static void packxbee_free(t_packxbee *x)
+{
+    /* free any memory we allocated */
+    /* stop any callbacks */
+}
+
+void packxbee_setup(void)
+{ 
+    packxbee_class = class_new(gensym("packxbee"), (t_newmethod)packxbee_new,
+        (t_method)packxbee_free,
+        sizeof(t_packxbee), 0, A_DEFFLOAT, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_AT, gensym("AT"), A_GIMME, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_ATQ, gensym("ATQ"), A_GIMME, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_RAT, gensym("RAT"), A_GIMME, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_TX, gensym("TX"), A_GIMME, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_API, gensym("API"), A_DEFFLOAT, 0);
+    class_addmethod(packxbee_class, (t_method)packxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0);
+}
+
+/* fin packxbee.c*/
diff --git a/externals/mrpeach/xbee/pdxbee.h b/externals/mrpeach/xbee/pdxbee.h
new file mode 100644
index 000000000..d3023c32c
--- /dev/null
+++ b/externals/mrpeach/xbee/pdxbee.h
@@ -0,0 +1,41 @@
+#ifndef _PDXBEE
+#define _PDXBEE
+
+// MAX_XBEE_PACKET_LENGTH is around 80
+#define MAX_XBEE_PACKET_LENGTH 128
+
+#define LENGTH_MSB_INDEX 1 /* offset in x_outbuf */
+#define LENGTH_LSB_INDEX 2 /* offset in x_outbuf */
+#define FRAME_TYPE_INDEX 3 /* offset in x_outbuf */
+#define FRAME_ID_INDEX 4 /* offset in x_outbuf */
+#define AT_COMMAND_INDEX 5 /* offset in x_outbuf */
+#define AT_PARAMETER_INDEX 6 /* offset in x_outbuf */
+
+/* API Frame Names and Values */
+
+#define AT_Command                                  0x08
+#define AT_Command_Queue_Parameter_Value            0x09
+#define ZigBee_Transmit_Request                     0x10
+#define Explicit_Addressing_ZigBee_Command_Frame    0x11
+#define Remote_Command_Request                      0x17
+#define Create_Source_Route                         0x21
+#define AT_Command_Response                         0x88
+#define Modem_Status                                0x8A
+#define ZigBee_Transmit_Status                      0x8B
+#define ZigBee_Receive_Packet                       0x90
+#define ZigBee_Explicit_Rx_Indicator                0x91
+#define ZigBee_IO_Data_Sample_Rx_Indicator          0x92
+#define XBee_Sensor_Read_Indicator                  0x94
+#define Node_Identification_Indicator               0x95
+#define Remote_Command_Response                     0x97
+#define Over_the_Air_Firmware_Update_Status         0xA0
+#define Route_Record_Indicator                      0xA1
+#define Many_to_One_Route_Request_Indicator         0xA3
+
+/* if API mode is 2 all characters after the first are escaped if they are one of */
+#define XFRAME 0x7E /* Frame Delimiter */
+#define XSCAPE 0x7D /* Escape */
+#define XON 0x11 /* XON */
+#define XOFF 0x13 /* XOFF */
+/* to escape the character prefix it with XSCAPE and XOR it with 0x20 */
+#endif /* _PDXBEE */
diff --git a/externals/mrpeach/xbee/unpackxbee.c b/externals/mrpeach/xbee/unpackxbee.c
new file mode 100644
index 000000000..b8b59006e
--- /dev/null
+++ b/externals/mrpeach/xbee/unpackxbee.c
@@ -0,0 +1,522 @@
+/* unpackxbee outputs a list of floats which are the bytes making up an xbee api packet. */
+/* The packet can then be sent through [comport]. */
+/* Started by Martin Peach 20110731 */
+/* Information taken from "XBee®/XBee-PRO® ZB RF Modules" (document 90000976_G, 11/15/2010)*/
+/* by Digi International Inc. http://www.digi.com */
+
+#include <stdio.h>
+//#include <string.h>
+#include "m_pd.h"
+#include "pdxbee.h"
+
+static t_class *unpackxbee_class;
+
+
+typedef struct _unpackxbee
+{
+    t_object        x_obj;
+    t_outlet        *x_status_out;
+    t_outlet        *x_payload_out;
+    int             x_api_mode;
+    unsigned char   x_frame_ID;
+    unsigned char   x_frame_type;
+    unsigned int    x_frame_length;
+    int             x_verbosity;
+    unsigned char   x_message[MAX_XBEE_PACKET_LENGTH];
+    unsigned int    x_message_index;
+    int             x_escaped;
+    t_atom          x_outbuf[MAX_XBEE_PACKET_LENGTH];
+    t_atom          x_statusbuf[32]; /* some number bigger than we will ever reach */
+} t_unpackxbee;
+
+static void *unpackxbee_new(t_floatarg f);
+static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv);
+static void unpackxbee_API(t_unpackxbee *x, t_float api);
+static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level);
+static void unpackxbee_free(t_unpackxbee *x);
+void unpackxbee_setup(void);
+
+static void *unpackxbee_new(t_floatarg f)
+{
+    int i;
+
+    t_unpackxbee *x = (t_unpackxbee *)pd_new(unpackxbee_class);
+    if (x)
+    {
+        x->x_payload_out = outlet_new(&x->x_obj, &s_list); /* the first outlet on the left */
+        x->x_status_out = outlet_new(&x->x_obj, &s_list);
+
+        if (1 == f) x->x_api_mode = 1;
+        else x->x_api_mode = 2; /* default to escaped mode */
+        x->x_verbosity = 0; /* debug level */
+        for(i = 0; i < MAX_XBEE_PACKET_LENGTH; ++i) x->x_outbuf[i].a_type = A_FLOAT; /* init output atoms as floats */
+    }
+    return (x);
+}
+
+static void unpackxbee_API(t_unpackxbee *x, t_float api)
+{
+    if ((api == 1) || (api ==2)) x->x_api_mode = api;
+    else error ("unpackxbee: api mode must be 1 or 2");
+}
+
+static void unpackxbee_verbosity(t_unpackxbee *x, t_float verbosity_level)
+{
+    if (verbosity_level >= 0) x->x_verbosity = verbosity_level;
+    else error ("packxbee: verbosity_level must be positive");
+}
+
+int unpackxbee_add(t_unpackxbee *x, unsigned char d)
+{
+    if (XFRAME == d)
+    {
+        if (x->x_verbosity > 0) post ("frame start");
+        x->x_message_index = 0;
+        x->x_frame_length = 0;
+        x->x_frame_type = 0;
+        x->x_escaped = 0;
+    }
+    if (2 == x->x_api_mode)
+    {
+        if (XSCAPE == d)
+        {
+            x->x_escaped = 1; /* we need to xor the next character with 0x20 */
+            return 0; /* don't store the escape character */
+        }
+        else if (1 == x->x_escaped)
+        {
+            d ^= 0x20; /* xor with 0x20 to restore the original character */
+            x->x_escaped = 0; /* don't do it again */
+        }
+    }
+    if (LENGTH_LSB_INDEX == x->x_message_index) /* length is a bigendian pair */
+    {
+        x->x_frame_length = (x->x_message[LENGTH_MSB_INDEX]<<8) + d;
+        if (x->x_verbosity > 0) post ("frame length %d", x->x_frame_length);
+    }
+    else if (FRAME_TYPE_INDEX == x->x_message_index)
+    {
+        x->x_frame_type = d;
+        if (x->x_verbosity > 0) post ("frame type 0x%02X", x->x_frame_type);
+    }
+    else if (FRAME_ID_INDEX == x->x_message_index)
+    { /* this is part of the payload and may not be valid in some frame types */
+        x->x_frame_ID = d;
+        if (x->x_verbosity > 0) post ("frame ID %d", x->x_frame_ID);
+    }
+    x->x_message[x->x_message_index++] = d; /* add the unescaped character to the output list */
+    return 1;
+}
+
+static void unpackxbee_input(t_unpackxbee *x, t_symbol *s, int argc, t_atom *argv)
+{
+    int                 i , j, k;
+    t_float             f;
+    unsigned int        d, checksum = 0;
+    unsigned char       c;
+    t_symbol            *type_selector;
+    int                 statuslength = 0, payloadstart = 0;
+    char                atbuf[64];
+    unsigned char       floatstring[256]; /* longer than the longest hex number with each character escaped plus the header and checksum overhead */
+    unsigned long long  addr64;
+    unsigned int        addr16;
+
+    if (x->x_verbosity > 0) post("unpackxbee_input: s is %s, argc is %d", s->s_name, argc);
+    for (i = 0; i < argc; ++i)
+    {
+        if (A_FLOAT == argv[i].a_type)
+        {
+            f = argv[i].a_w.w_float;
+            d = ((unsigned int)f)&0x0FF;
+            if (x->x_verbosity > 0) post("unpackxbee_input: argv[%d] is %f int is %d", i, f, d);
+            if (f != d)
+            {
+                post ("unpackxbee_input not a positive integer from 0 to 255");
+            }
+            else unpackxbee_add(x, d);
+        }
+        else
+            post("unpackxbee_input: item %d is not a float", i+1);
+    }
+    if ((x->x_frame_length > 0)&&(x->x_frame_length + 4 == x->x_message_index))
+    { /* end of frame reached */
+        k = x->x_frame_length+4; /* total packet length is payload + 1 start 2 length 1 checksum*/
+        if(x->x_verbosity > 0)
+        {
+            post("frame end");
+            for (j = 0; j < k; ++j)
+            {
+                c = x->x_message[j];
+                post("unpackxbee buf[%d]: %d [0x%02X]", j, c, c);
+            }
+        }
+        for (j = 3; j < k; ++j)
+        {
+            checksum += x->x_message[j];
+        }
+        checksum &= 0x0FF;
+        if (checksum != 0xFF)
+        {
+            post("unpackxbee: wrong checksum; dropping packet");
+            return;
+        }
+        if(x->x_verbosity > 0) post("unpackxbee checksum %d [0x%02X]", checksum, checksum);
+        switch(x->x_frame_type)
+        {
+            case AT_Command:
+                type_selector = gensym("AT_Command");
+                break;
+            case AT_Command_Queue_Parameter_Value:
+                type_selector = gensym("AT_Command_Queue_Parameter_Value");
+                break;
+            case ZigBee_Transmit_Request:
+                type_selector = gensym("ZigBee_Transmit_Request");
+                break;
+            case Explicit_Addressing_ZigBee_Command_Frame:
+                type_selector = gensym("Explicit_Addressing_ZigBee_Command_Frame");
+                break;
+            case Remote_Command_Request:
+                type_selector = gensym("Remote_Command_Request");
+                break;
+            case Create_Source_Route:
+                type_selector = gensym("Create_Source_Route");
+                break;
+            case AT_Command_Response:
+                type_selector = gensym("AT_Command_Response");
+                break;
+            case Modem_Status:
+                type_selector = gensym("Modem_Status");
+                break;
+            case ZigBee_Transmit_Status:
+                type_selector = gensym("ZigBee_Transmit_Status");
+                break;
+            case ZigBee_Receive_Packet:
+                type_selector = gensym("ZigBee_Receive_Packet");
+                break;
+            case ZigBee_Explicit_Rx_Indicator:
+                type_selector = gensym("ZigBee_Explicit_Rx_Indicator");
+                break;
+            case ZigBee_IO_Data_Sample_Rx_Indicator:
+                type_selector = gensym("ZigBee_IO_Data_Sample_Rx_Indicator");
+                break;
+            case XBee_Sensor_Read_Indicator:
+                type_selector = gensym("XBee_Sensor_Read_Indicator");
+                break;
+            case Node_Identification_Indicator:
+                type_selector = gensym("Node_Identification_Indicator");
+                break;
+            case Remote_Command_Response:
+                type_selector = gensym("Remote_Command_Response");
+                break;
+            case Over_the_Air_Firmware_Update_Status:
+                type_selector = gensym("Over_the_Air_Firmware_Update_Status");
+                break;
+            case Route_Record_Indicator:
+                type_selector = gensym("Route_Record_Indicator");
+                break;
+            case Many_to_One_Route_Request_Indicator:
+                type_selector = gensym("Many_to_One_Route_Request_Indicator");
+                break;
+            default:
+                type_selector = gensym("unknown");
+        }
+        statuslength = 0;
+        SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_type);
+        statuslength++;
+        if
+        (
+            (AT_Command_Response == x->x_frame_type)
+            ||(AT_Command == x->x_frame_type)
+            ||(AT_Command_Queue_Parameter_Value == x->x_frame_type)
+        )
+        {
+            if (x->x_verbosity > 0) 
+                post("AT_Command_Response  AT_Command AT_Command_Queue_Parameter_Value statuslength %d", statuslength);
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID);
+            statuslength++;
+            /* data doesn't include 1byte frame type 1byte ID 2byte AT command 1byte AT command status = 5bytes */
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-5);
+            statuslength++;
+            atbuf[0] = x->x_message[5]; /* the AT command string */
+            atbuf[1] = x->x_message[6];
+            atbuf[2] = '\0';
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym(atbuf));
+            statuslength++;
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[7]);/* AT command status */
+            statuslength++;
+            if ((0 == x->x_message[7]) && ('N' == x->x_message[5]) && ('D' == x->x_message[6]))
+            { /* a succesful node discover response: output the addresses as symbols */
+/*
+buf[0]: 126 [0x7E] ND packet start
+buf[1]: 0 [0x00] Length MSB
+buf[2]: 25 [0x19] Length LSB
+buf[3]: 136 [0x88] AT response
+buf[4]: 5 [0x05] packet ID
+buf[5]: 78 [0x4E] N
+buf[6]: 68 [0x44] D
+buf[7]: 0 [0x00] status
+*/
+                addr16 = (x->x_message[8]<<8) + x->x_message[9];
+                sprintf((char *)floatstring, "0x%X", addr16);
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring));
+                statuslength++;
+/*
+buf[8]: 121 [0x79] MY
+buf[9]: 214 [0xD6] 
+*/
+/* now switch endianness */
+
+                addr64 = x->x_message[10]; 
+                addr64 <<= 8;
+                addr64 |= x->x_message[11];
+                addr64 <<= 8;
+                addr64 |= x->x_message[12];
+                addr64 <<= 8;
+                addr64 |= x->x_message[13];
+                addr64 <<= 8;
+                addr64 |= x->x_message[14];
+                addr64 <<= 8;
+                addr64 |= x->x_message[15];
+                addr64 <<= 8;
+                addr64 |= x->x_message[16];
+                addr64 <<= 8;
+                addr64 |= x->x_message[17];
+#ifdef _MSC_VER
+                sprintf((char *)floatstring, "0x%016I64X", addr64);
+#else
+                sprintf((char *)floatstring, "0x%016LX", addr64);
+#endif
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* addr64 */
+                statuslength++;
+/* 
+buf[10]: 0 [0x00] SH
+buf[11]: 19 [0x13]
+buf[12]: 162 [0xA2]
+buf[13]: 0 [0x00]
+buf[14]: 64 [0x40] SL
+buf[15]: 106 [0x6A]
+buf[16]: 222 [0xDE]
+buf[17]: 30 [0x1E]
+*/
+                for (j = 0, i = 18; i < k; ++i, ++j)
+                {
+                    floatstring[j] = x->x_message[i];
+                    if (0 == floatstring[j])
+                    {
+                        i++;
+                        break;/* Node Identifier should be a null-terminated ascii string */
+                    }
+                }
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* Node Identifier */
+                statuslength++;
+/*
+buf[18]: 32 [0x20] NI
+buf[19]: 0 [0x00]
+*/
+                addr16 = (x->x_message[i]<<8) + x->x_message[i+1];
+                sprintf((char *)floatstring, "0x%X", addr16);
+                i += 2;
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* parent addr16 */
+                statuslength++;
+/*
+buf[20]: 255 [0xFF] parent
+buf[21]: 254 [0xFE]
+*/
+                SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* Device Type */
+                statuslength++;
+/*
+buf[22]: 1 [0x01] device type
+*/
+                SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* Source Event */
+                statuslength++;
+/*
+buf[23]: 0 [0x00] source event
+*/
+                addr16 = x->x_message[i++]<<8;
+                addr16 |= x->x_message[i++];
+                sprintf((char *)floatstring, "0x%X", addr16);
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* Profile ID */
+                statuslength++;
+/*
+buf[24]: 193 [0xC1] Profile ID
+buf[25]: 5 [0x05]
+*/
+                addr16 = (x->x_message[i]<<8) + x->x_message[i+1];
+                sprintf((char *)floatstring, "0x%X", addr16);
+                i += 2;
+                SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* Manufacturer ID */
+                statuslength++;
+/*
+buf[26]: 16 [0x10] Manufacturer ID
+buf[27]: 30 [0x1E]
+*/
+
+/*
+buf[28]: 36 [0x24] checksum
+*/
+                payloadstart = 0;/* no payload */
+            }
+            else
+            {
+                payloadstart = 8;
+            }
+        }
+/* RAT */
+        if (Remote_Command_Response == x->x_frame_type)
+        {
+            if (x->x_verbosity > 0) 
+                post("Remote_Command_Response statuslength %d", statuslength);
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID);
+            statuslength++;
+/*
+buf[0]: 126 [0x7E] packet start
+buf[1]: 0 [0x00] Length MSB
+
+buf[2]: 25 [0x19] Length LSB
+buf[3]: 151 [0x97] remote response frame type
+buf[4]: 5 [0x05] packet ID
+buf[5-12]: 0 [0x00] 64-bit source (remote) address
+buf[13-14]: 68 [0x44] 16-bit source address
+buf[15-16]: AT command
+buf[17]: status
+buf[18...] data
+*/
+
+            addr64 = x->x_message[5]; 
+            addr64 <<= 8;
+            addr64 |= x->x_message[6];
+            addr64 <<= 8;
+            addr64 |= x->x_message[7];
+            addr64 <<= 8;
+            addr64 |= x->x_message[8];
+            addr64 <<= 8;
+            addr64 |= x->x_message[9];
+            addr64 <<= 8;
+            addr64 |= x->x_message[10];
+            addr64 <<= 8;
+            addr64 |= x->x_message[11];
+            addr64 <<= 8;
+            addr64 |= x->x_message[12];
+#ifdef _MSC_VER
+            sprintf((char *)floatstring, "0x%016I64X", addr64);
+#else
+            sprintf((char *)floatstring, "0x%016LX", addr64);
+#endif
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* addr64 */
+            statuslength++;
+
+            addr16 = (x->x_message[13]<<8) + x->x_message[14];
+            sprintf((char *)floatstring, "0x%X", addr16);
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring));
+            statuslength++;
+            atbuf[0] = x->x_message[15]; /* the remote AT command string */
+            atbuf[1] = x->x_message[16];
+            atbuf[2] = '\0';
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym(atbuf));
+            statuslength++;
+
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[17]);/* AT command status */
+            statuslength++;
+            /* data doesn't include 1byte frame type 1byte ID 8byte addr64 2byte addr16 2byte AT command 1byte status = 15bytes */
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-15);
+            statuslength++;
+            payloadstart = 18;
+         }
+/* RAT */
+        else if (ZigBee_Transmit_Status == x->x_frame_type)
+        {
+            if (x->x_verbosity > 0) 
+                post("ZigBee_Transmit_Status statuslength %d", statuslength);
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID);
+            statuslength++;
+            sprintf(atbuf, "0x%X", (x->x_message[5]<<8) + x->x_message[6]); /* the 16-bit address as a symbol */
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym(atbuf));
+            statuslength++;
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[7]);/* Transmit Retry Count */
+            statuslength++;
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[8]);/* Delivery Status */
+            statuslength++;
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[9]);/* Discovery Status */
+            statuslength++;
+            payloadstart = 0; /* no payload */
+        }
+        else if (ZigBee_Receive_Packet == x->x_frame_type)
+        {
+            if (x->x_verbosity > 0) 
+                post("ZigBee_Receive_Packet statuslength %d", statuslength);
+            /* data doesn't include 1byte frametype, 8byte addr64, 2byte addr16, 1byte options = 12bytes*/
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-12);
+            statuslength++;
+            /* frame type */
+            /* 64-bit source address */
+            i = 4;
+            addr64 = x->x_message[i++]; 
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+            addr64 <<= 8;
+            addr64 |= x->x_message[i++];
+#ifdef _MSC_VER
+            sprintf((char *)floatstring, "0x%016I64X", addr64);
+#else
+            sprintf((char *)floatstring, "0x%016LX", addr64);
+#endif
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* addr64 */
+            statuslength++;
+            /* 16-bit source address */
+            addr16 = x->x_message[i++]<<8;
+            addr16 |= x->x_message[i++];
+            sprintf((char *)floatstring, "0x%X", addr16);
+            SETSYMBOL(&x->x_statusbuf[statuslength], gensym((char *)floatstring)); /* addr16 */
+            statuslength++;
+            /* receive options byte */
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_message[i++]);/* 1 2 32 64 */
+            statuslength++;
+            /* data */
+            payloadstart = i;
+        }
+        else
+        {
+            if (x->x_verbosity > 0) 
+                post("some other packet statuslength %d", statuslength);
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_ID);/* may not be valid */
+            statuslength++;
+            SETFLOAT(&x->x_statusbuf[statuslength], x->x_frame_length-2);/* payload doesn't include frame type and ID */
+            statuslength++;
+            payloadstart = 5;
+        }
+        outlet_anything(x->x_status_out, type_selector, statuslength, x->x_statusbuf);
+        if (payloadstart > 0)
+        {
+            for (j = 0, i = payloadstart; i < k-1; ++j, ++i)
+                SETFLOAT(&x->x_outbuf[j], x->x_message[i]); /* the payload */
+            if (j > 0)
+                outlet_list(x->x_payload_out, &s_list, j, x->x_outbuf);
+        }
+    }
+}
+
+static void unpackxbee_free(t_unpackxbee *x)
+{
+}
+
+void unpackxbee_setup(void)
+{ 
+    unpackxbee_class = class_new(gensym("unpackxbee"), (t_newmethod)unpackxbee_new,
+        (t_method)unpackxbee_free,
+        sizeof(t_unpackxbee), 0, A_DEFFLOAT, 0);
+    class_addanything(unpackxbee_class, (t_method)unpackxbee_input);
+    class_addmethod(unpackxbee_class, (t_method)unpackxbee_API, gensym("API"), A_DEFFLOAT, 0);
+    class_addmethod(unpackxbee_class, (t_method)unpackxbee_verbosity, gensym("verbosity"), A_DEFFLOAT, 0);
+}
+
+/* fin unpackxbee.c*/
diff --git a/externals/pd-l2ork-TODO.txt b/externals/pd-l2ork-TODO.txt
index 4b955ac38..e7b9880c8 100644
--- a/externals/pd-l2ork-TODO.txt
+++ b/externals/pd-l2ork-TODO.txt
@@ -3,6 +3,7 @@ AS OF 11/22/2012
 
 DONE:
 creb
+mrpeach
 
 MERGE:
 miXed
diff --git a/externals/pdp/include/pdp_config.h b/externals/pdp/include/pdp_config.h
index ba70e8244..5d6ecd71a 100644
--- a/externals/pdp/include/pdp_config.h
+++ b/externals/pdp/include/pdp_config.h
@@ -29,7 +29,7 @@
 /* #undef HAVE_PDP_READLINE */
 
 /* build pdp_sdl */
-/* #undef HAVE_PDP_SDL */
+#define HAVE_PDP_SDL 1
 
 /* build pdp_v4l */
 /* #undef HAVE_PDP_V4L */
-- 
GitLab