diff --git a/files.html b/files.html
index ccb783e678a55cf425152c551169df63fa545b40..56c23756a108e90063cb8218d761c6051ccff34a 100644
--- a/files.html
+++ b/files.html
@@ -9,26 +9,28 @@
       }
    </script>
    <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.git</i><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./.gitignore'>.gitignore</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./README.md'>README.md</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./files.html'>files.html</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./index.html'>index.html</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;js</i><br>
-<i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Windows</i><br>
-<i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node_modules</i><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/Windows/printserverWin.js'>printserverWin.js</a><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/echoserver.js'>echoserver.js</a><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/evalserver.js'>evalserver.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/files.js'>files.js</a><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/fileserver.js'>fileserver.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/load.js'>load.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/mods.js'>mods.js</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node_modules</i><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/printerserver.js'>printerserver.js</a><br>
+<i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old_servers</i><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/echoserver.js'>echoserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/evalserver.js'>evalserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/fileserver.js'>fileserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/printerserver.js'>printerserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/printserver.js'>printserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/printserverWin.js'>printserverWin.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/serialserver.js'>serialserver.js</a><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/old_servers/udpserver.js'>udpserver.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/printserver.js'>printserver.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/serialserver.js'>serialserver.js</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;three.js</i><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/three.js/three.min.js'>three.min.js</a><br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./js/udpserver.js'>udpserver.js</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./make'>make</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modules</i><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;apa</i><br>
diff --git a/js/printserver.js b/js/printserver.js
new file mode 100644
index 0000000000000000000000000000000000000000..d8a353cfc0f3d4983fb2cde11ce7d4b3ef4cd0e1
--- /dev/null
+++ b/js/printserver.js
@@ -0,0 +1,145 @@
+//
+// printserver.js
+//    WebSocket print server
+//
+// dependencies:
+//    npm install printer ws
+//    Windows
+//       npm install --global windows-build-tools
+//    Linux
+//       sudo apt-get install node-gyp
+//       sudo apt-get install libcups2-dev
+//
+// Neil Gershenfeld 
+// (c) Massachusetts Institute of Technology 2017
+// 
+// This work may be reproduced, modified, distributed, performed, and 
+// displayed for any purpose, but must acknowledge the mods
+// project. Copyright is retained and must be preserved. The work is 
+// provided as is no warranty is provided, and users accept all 
+// liability.
+//
+// check command line
+//
+if (process.argv.length < 4) {
+   console.log("command line: node printserver.js client_address server_port")
+   process.exit(-1)
+   }
+//
+// start server
+//
+var client_address = process.argv[2]
+var server_port = process.argv[3]
+console.log("listening for connection from client address "+client_address+" on server port "+server_port)
+//
+// requires
+//
+var printer = require("printer")
+//var util = require('util')
+var WebSocketServer = require('ws').Server
+//
+// start WebSocket server
+//
+wss = new WebSocketServer({port:server_port})
+//
+// handle connection
+//
+wss.on('connection',function(ws) {
+   //
+   // check address
+   //
+   if (!ws._socket.remoteAddress) {
+      console.log("connection rejected from "+ws._socket.remoteAddress)
+      ws.send('socket closed')
+      ws.close()
+      }
+   else {
+      console.log("connection accepted from "+ws._socket.remoteAddress)
+      }
+   //
+   // handle messages
+   //
+   var cancel
+   var pagesPrinted
+   ws.on("message",function(msg) {
+      //
+      // cancel job
+      //
+      if (msg == 'cancel') {
+         cancel = true
+         }
+      //
+      // start job
+      //
+      else {
+         pagesPrinted = 0
+         var printerName = printer.getDefaultPrinterName()
+         var job = JSON.parse(msg)
+         console.log('writing ' + job.name + ' (length ' + job.contents.length + ') to printer ' + printerName)
+         console.log(job.contents)
+         cancel = false
+         print()
+         //
+         // print all
+         //
+         function print() {
+            printer.printDirect({data:job.contents
+	            //, printer:'Roland GS-24' // printer name, if missing then will print to default printer
+                //, printer: job.device
+	            , type: 'RAW' // type: RAW, TEXT, PDF, JPEG, .. depends on platform
+	            , success: function (jobID) {
+	                console.log("sent to printer with ID: " + jobID)
+	                check_process()
+	                //
+	                // Check process
+	                //
+	                function check_process() {
+	                    var jobInfo
+		                try {
+		                    jobInfo = printer.getJob(printerName, jobID)
+		                } catch (err) {
+		                    ws.send('done')
+		                    return
+		                }
+
+		                pagesPrinted = jobInfo.pagesPrinted
+		                console.log("current job info:" + util.inspect(jobInfo, { depth: 10, colors: true }))
+		                if (jobInfo.status.indexOf('PRINTED') !== -1) {
+		                    ws.send('done')
+		                    return
+		                }
+
+		                //
+		                // cancel
+		                //
+		                if (cancel) {
+		                    console.log('cancelling...')
+		                    ws.send('cancel')
+		                    var is_ok = printer.setJob(printerName, jobID, 'CANCEL')
+		                    console.log("cancelled: " + is_ok)
+		                }
+		                    //
+		                    // continue
+		                    //
+		                else {
+		                    ws.send(jobInfo.status[0])
+		                    setTimeout(check_process, 1000)
+		                }
+		            }
+	            }
+	            , error:function(err){
+                    console.log(err)
+                    ws.send('error '+err+' 0 '+ 0)
+                  }
+            })
+
+         }
+       }
+    })
+   //
+   // close
+   //
+   ws.on("close",function() {
+      console.log("connection closed")
+      })
+   })
diff --git a/js/serialserver.js b/js/serialserver.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c3c01961e33cb4dce641bcf402ef6425ec62aec
--- /dev/null
+++ b/js/serialserver.js
@@ -0,0 +1,172 @@
+//
+// serialserver.js
+//    WebSocket serial server
+//
+// Neil Gershenfeld 
+// (c) Massachusetts Institute of Technology 2016
+// 
+// This work may be reproduced, modified, distributed, performed, and 
+// displayed for any purpose, but must acknowledge the mods
+// project. Copyright is retained and must be preserved. The work is 
+// provided as is; no warranty is provided, and users accept all 
+// liability.
+//
+// check command line
+//
+if (process.argv.length < 4) {
+   console.log("command line: node serialserver.js client_address server_port")
+   process.exit(-1)
+   }
+//
+// start server
+//
+var client_address = process.argv[2]
+var server_port = process.argv[3]
+console.log("listening for connection from client address "+client_address+" on server port "+server_port)
+var SerialPort = require('serialport')
+var port = null
+var WebSocketServer = require('ws').Server
+wss = new WebSocketServer({port:server_port})
+//
+// handle connection
+//
+wss.on('connection',function(ws) {
+   //
+   // check address
+   //
+   if (ws._socket.remoteAddress != client_address) {
+      console.log("connection rejected from "+ws._socket.remoteAddress)
+      ws.send('socket closed')
+      ws.close()
+      }
+   else {
+      console.log("connection accepted from "+ws._socket.remoteAddress)
+      }
+   //
+   // handle messages
+   //
+   var cancel
+   ws.on("message",function(message) {
+      var msg = JSON.parse(message)
+      //
+      // open port
+      //
+      if (msg.type == 'open') {
+         var device = msg.device
+         var baud = parseInt(msg.baud)
+         var flow = msg.flow
+         console.log('open '+device+' at '+baud+' flow '+flow)
+         if (flow == 'none')
+            port = new SerialPort(device,{baudRate:baud,parser:SerialPort.parsers.byteLength(1)})
+         else if (flow == 'rtscts')
+            port = new SerialPort(device,{baudRate:baud,parser:SerialPort.parsers.byteLength(1),rtscts:true})
+         port.on('open',function() {
+            ws.send('serial port opened')
+            if (flow == 'dsrdtr') {
+               port.set({dsr:true,dtr:true})
+               port.set({rts:false,cts:false})
+               }
+            })
+         port.on('error',function(err) {
+            ws.send(err.message)
+            })
+         port.on('data',function(data) {
+            ws.send(data.toString('binary'))
+            })
+         }
+      //
+      // close port
+      //
+      else if (msg.type == 'close') {
+         var device = msg.device
+         console.log('close '+device)
+         ws.send('serial port closed')
+         port.close()
+         port = null
+         }
+      //
+      // send string
+      //
+      else if (msg.type == 'string') {
+         console.log(msg.string)
+         port.write(msg.string,function(){
+            port.drain(function(err){
+               if (err)
+                  ws.send(err.message)
+               })
+            })
+         }
+      //
+      // send command
+      //
+      else if (msg.type == 'command') {
+         console.log(msg.contents)
+         port.write(msg.contents,function(){
+            port.drain(function(err){
+               if (err)
+                  ws.send(err.message)
+               else
+                  ws.send('done')
+               })
+            })
+         }
+      //
+      // cancel job
+      //
+      if (msg.type == 'cancel') {
+         cancel = true
+         }
+      //
+      // send file
+      //
+      else if (msg.type == 'file') {
+         var count = 0
+         console.log('writing '+msg.name+' length '+msg.contents.length)
+         cancel = false
+         write_char()
+         //
+         // character writer
+         //
+         function write_char() {
+            //
+            // cancel
+            //
+            if (cancel) {
+               console.log('cancel')
+               ws.send('cancel')
+               }
+            //
+            // continue
+            //
+            else {
+               port.write(msg.contents[count],function(){
+                  port.drain(function(err){
+                     if (err)
+                        ws.send('error '+err.message)
+                     else {
+                        ws.send((count+1)+'/'+msg.contents.length)
+                        count += 1
+                        if (count < msg.contents.length)
+                           write_char()
+                        else {
+                           console.log('done')
+                           ws.send('done')
+                           }
+                        }
+
+                     })
+                  })
+               }
+            }
+         }
+      })
+   //
+   // close
+   //
+   ws.on("close",function() {
+      console.log("connection closed")
+      if (port != null)
+         port.close()
+      port = null
+      })
+   })