   }
   
   func handleMessage(_ message:String) {
-    self.log("<< \(message)")
-    let parts = message.components(separatedBy: " ")
-    if parts.count >= 2 {
-      let id = parts[0]
-      let message = parts[1].lowercased()
-      var response = "OK"
+    self.log("<< \(message.replacingOccurrences(of: "\t", with: " "))")
+    let parts = message.components(separatedBy: "\t")
+    if parts.count >= 1 {
+      var id = ""
+      var message = ""
+      let idParts = parts[0].components(separatedBy: ":")
+      if idParts.count > 1 {
+        id = idParts[0]
+        message = idParts[1].lowercased()
+      } else {
+        message = idParts[0].lowercased()
+      }
+      var data:String?
+      if parts.count > 1 {
+        data = parts[1]
+      }
+      let messageParts = message.components(separatedBy: ".")
+      if messageParts.count > 1 {
+        message = messageParts[0]
+        for i in 1..<messageParts.count {
+          switch messageParts[i] {
+            case "encoded":
+              if data != nil {
+                data = data!.base64Decoded()
+              }
+            default:
+              self.log("Unknown command option: \(messageParts[i])")
+          }
+        }
+      }
       switch message {
-        case "clearcache":
-          clearCache()
-        case "startbrowser":
-          startBrowser()
-        case "closebrowser":
-          closeBrowser()
+        case "clearcache": clearCache(id:id)
+        case "startbrowser": startBrowser(id:id)
+        case "closebrowser", "stopbrowser": closeBrowser(id:id)
         case "navigate":
-          if parts.count >= 3 {
-            let url = parts[2]
-            navigate(url)
+          if data != nil {
+            navigate(id:id, to:data!)
           } else {
-            response = "ERROR"
+            sendMessage(id:id, message:"ERROR", data:"Missing URL for navigation")
+          }
+        case "addorange", "setorange": addOrange(id:id)
+        case "exec":
+          if data != nil {
+            execScript(id:id, script:data!)
+          } else {
+            sendMessage(id:id, message:"ERROR", data:"Missing script for exec")
           }
         default:
-          response = "ERROR"
-      }
-      sendMessage(id:id, message:response)
+          sendMessage(id:id, message:"ERROR", data:"Unknown command: \(message)")
+      }
     }
   }
   
   /*************************************************************************************
                                   browser operations
    *************************************************************************************/
-  func clearCache() {
-  }
-  
-  func startBrowser() {
-    if webView != nil {
-      self.closeBrowser()
+  func clearCache(id:String) {
+    sendMessage(id:id, message:"OK")
+  }
+  
+  func startBrowser(id:String) {
+    if webView != nil {
+      webView!.navigationDelegate = nil
+      webView!.removeFromSuperview()
+      webView = nil
     }
     webView = WKWebView()
     webView!.frame = self.view.bounds
     self.view.addSubview(webView!)
     webView!.loadHTMLString(startPage, baseURL: URL(string: "http://www.webpagetest.org"))
+    hasOrange = true
     webView!.navigationDelegate = self
-  }
-  
-  func closeBrowser() {
+    title = ""
+    sendMessage(id:id, message:"OK")
+  }
+  
+  func closeBrowser(id:String) {
     if webView != nil {
       webView!.navigationDelegate = nil
       webView!.removeFromSuperview()
       webView = nil
     }
-  }
-  
-  func navigate(_ to:String) {
+    hasOrange = false
+    title = "iWptBrowser"
+    sendMessage(id:id, message:"OK")
+  }
+  
+  func navigate(id:String, to:String) {
     if webView != nil {
       var url = to
       if !url.hasPrefix("http") {
         url = "http://" + url
       }
+      title = "Loading..."
       webView!.load(URLRequest(url: URL(string:url)!))
+      sendMessage(id:id, message:"OK")
+    } else {
+      sendMessage(id:id, message:"ERROR", data:"Browser not started")
+    }
+  }
+  
+  func addOrange(id:String) {
+    if webView != nil {
+      webView!.evaluateJavaScript(showOrange) { (result, error) in
+        self.sendMessage(id:id, message:"OK")
+      }
+    } else {
+      sendMessage(id:id, message:"ERROR", data:"Browser not started")
+    }
+  }
+  
+  func execScript(id:String, script:String) {
+    if webView != nil {
+      webView!.evaluateJavaScript(script) { (result, error) in
+        var ok = "OK"
+        var returned = ""
+        if error != nil {
+          ok = "ERROR"
+          returned = "\(error!)"
+        }
+        if result != nil {
+          returned = "\(result!)"
+        }
+        if returned.range(of: "\t") != nil {
+          ok += ".encoded"
+          returned = returned.base64Encoded()!
+        }
+        self.sendMessage(id:id, message:ok, data:returned)
+      }
+    } else {
+      sendMessage(id:id, message:"ERROR", data:"Browser not started")
     }
   }
   

                                Agent socket interface
   *************************************************************************************/
  func sendNotification(message:String) {
    sendMessage(id:"0", message:message, data:"")
  }
  
  func sendNotification(message:String, data:String) {
    sendMessage(id:"0", message:message, data:data)
  }
  
  func sendMessage(id:String, message:String) {

        }
      } catch let err {
        self.log("\(id): Socket Read error: \(err)")
        cont = socket.isConnected
      }
    } while cont
    socket.close()
