| 
					
				 | 
			
			
				@@ -1,39 +1,290 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package main
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import (
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"bytes"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"fmt"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"log"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"net"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	native "log"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"net/http"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	"regexp"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"os"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"time"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ws "github.com/gorilla/websocket"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"github.com/kelseyhightower/envconfig"
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var (
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	version string
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	date    string
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	logger  = native.New(os.Stdout, "", 0)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	errors  = native.New(os.Stderr, "", 0)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 )
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var upgrader = ws.Upgrader{
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ReadBufferSize:  1024,
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	WriteBufferSize: 1024,
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	CheckOrigin: func(r *http.Request) bool {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return true // disable CORS
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	},
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+type config struct {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Port   int64  `default:"8080"`
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Prefix string `default:"/"`
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func main() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var c config
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err := envconfig.Process("ws", &c); err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		errors.Fatal(err)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	mngr := manager{
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		clients:   make(map[*client]bool),
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		add:       make(chan *client),
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		remove:    make(chan *client),
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		broadcast: make(chan []byte),
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	go func() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		for {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			select {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			case client := <-mngr.add:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				mngr.clients[client] = true
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			case client := <-mngr.remove:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if _, ok := mngr.clients[client]; ok {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					delete(mngr.clients, client)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					close(client.send)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			case message := <-mngr.broadcast:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				for client := range mngr.clients {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					select {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					case client.send <- message:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					default:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						close(client.send)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						delete(mngr.clients, client)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http.HandleFunc(fmt.Sprintf("%sws", c.Prefix), func(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		conn, err := upgrader.Upgrade(w, r, nil)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			logger.Println(err)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		client := &client{
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			conn: conn,
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			send: make(chan []byte, 256),
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			mngr: mngr,
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		mngr.add <- client
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	http.HandleFunc("/Info", info)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	http.HandleFunc("/Ok", ok)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	http.HandleFunc("/Status", status)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	http.ListenAndServe(":8081", nil) // устанавливаем порт веб-сервера
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	err := http.ListenAndServe(":8081", nil)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		log.Fatal("ListenAndServe: ", err)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		go client.write()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		go client.read()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http.HandleFunc(c.Prefix, index(c.Prefix))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if c.Prefix != "/" {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			w.WriteHeader(http.StatusForbidden)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http.HandleFunc(fmt.Sprintf("%sversion", c.Prefix), func(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if len(version) > 0 && len(date) > 0 {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			fmt.Fprintf(w, "version: %s (built at %s)", version, date)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			w.WriteHeader(http.StatusOK)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w.WriteHeader(http.StatusOK)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	logger.Printf("[service] listening on port %d", c.Port)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err := http.ListenAndServe(fmt.Sprintf(":%d", c.Port), nil); err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		errors.Fatal(err)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func info(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fmt.Fprint(w, "HTTP-status 200")
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+type manager struct {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	clients   map[*client]bool
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	add       chan *client
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	remove    chan *client
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	broadcast chan []byte
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func ok(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fmt.Fprint(w, "Kruglov Kirill,792")
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+type client struct {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn *ws.Conn
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	send chan []byte
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	mngr manager
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func status(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	ip, _, _ := net.SplitHostPort(r.RemoteAddr) // SHP на выходе дает 3 переменные
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	re := regexp.MustCompile(`[.].*[.]`)        // MC библиотека для работы с регулярками;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// [.] - Соответствует одному символу из содержащихся в квадратных скобках
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fmt.Fprintln(w, re.ReplaceAllString(ip, ".*.*.")) // В реплейс загоняем необработанный текст, он на выходе выдает обработанный с помощью регулярки
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fmt.Fprintf(w, "Kruglov Kirill,792"+"\n")
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	fmt.Fprintln(w, time.Now().Format("2006-01-02 3:4:5 pm"))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const (
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	maxMessageSize = 512
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	readDeadline   = 60 * time.Second
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writeDeadline  = 10 * time.Second
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	pingPeriod     = (writeDeadline * 9) / 10
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var (
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	newline = []byte{'\n'}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	space   = []byte{' '}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (c *client) read() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer func() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		c.mngr.remove <- c
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		c.conn.Close()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	c.conn.SetReadLimit(maxMessageSize)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	c.conn.SetReadDeadline(time.Now().Add(readDeadline))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	c.conn.SetPongHandler(func(string) error {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		c.conn.SetReadDeadline(time.Now().Add(readDeadline))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return nil
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_, message, err := c.conn.ReadMessage()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if ws.IsUnexpectedCloseError(err, ws.CloseGoingAway, ws.CloseAbnormalClosure) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				logger.Printf("error: %v", err)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			break
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		c.mngr.broadcast <- message
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (c *client) write() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ticker := time.NewTicker(pingPeriod)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer func() {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		ticker.Stop()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		c.conn.Close()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}()
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		select {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		case message, ok := <-c.send:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			c.conn.SetWriteDeadline(time.Now().Add(writeDeadline))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if !ok {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				c.conn.WriteMessage(ws.CloseMessage, []byte{})
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			w, err := c.conn.NextWriter(ws.TextMessage)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			w.Write(message)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			n := len(c.send)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			for i := 0; i < n; i++ {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				w.Write(newline)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				w.Write(<-c.send)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if err := w.Close(); err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		case <-ticker.C:
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			c.conn.SetWriteDeadline(time.Now().Add(writeDeadline))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if err := c.conn.WriteMessage(ws.PingMessage, nil); err != nil {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+var html = `<!DOCTYPE html>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<html lang="en">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<head>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <meta charset="UTF-8">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <title>Chat Example</title>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <script type="text/javascript">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    window.onload = function () {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var conn;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var msg = document.getElementById("msg");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var log = document.getElementById("log");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        function appendLog(item) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var doScroll = log.scrollTop > log.scrollHeight - log.clientHeight - 1;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            log.appendChild(item);
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (doScroll) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                log.scrollTop = log.scrollHeight - log.clientHeight;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        document.getElementById("form").onsubmit = function () {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!conn) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!msg.value) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            conn.send(msg.value);
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            msg.value = "";
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        };
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (window["WebSocket"]) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            conn = new WebSocket("ws://" + document.location.host + "%sws");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            conn.onclose = function (evt) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var item = document.createElement("div");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                item.innerHTML = "<b>Connection closed.</b>";
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                appendLog(item);
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            };
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            conn.onmessage = function (evt) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var messages = evt.data.split('\n');
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (var i = 0; i < messages.length; i++) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var item = document.createElement("div");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    item.innerText = messages[i];
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    appendLog(item);
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            };
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var item = document.createElement("div");
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            appendLog(item);
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    };
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </script>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <style type="text/css">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    html {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        overflow: hidden;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    body {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        overflow: hidden;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 0;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin: 0;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width: 100%%;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 100%%;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: blue;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #log {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: white;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin: 0;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 0.5em 0.5em 0.5em 0.5em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        position: absolute;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        top: 0.5em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        left: 0.5em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        right: 0.5em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bottom: 3em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        overflow: auto;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #form {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 0 0.5em 0 0.5em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin: 0;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        position: absolute;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bottom: 1em;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        left: 0px;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width: 100%;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        overflow: hidden;
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	</style>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</head>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<body>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div id="log"></div>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <form id="form">
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <input type="submit" value="Send" />
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <input type="text" id="msg" size="64" />
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </form>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</body>
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</html>`
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func index(prefix string) func(http.ResponseWriter, *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return func(w http.ResponseWriter, r *http.Request) {
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		fmt.Fprint(w, fmt.Sprintf(html, prefix))
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }
 
			 |