Add verify_client_certificates to the config

This commit is contained in:
Ken-Håvard Lieng 2016-01-14 06:17:53 +01:00
parent 13a3d96b44
commit 796bbd834e
6 changed files with 24 additions and 26 deletions

View File

@ -80,7 +80,7 @@ func bundleCssGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "bundle.css.gz", size: 1944, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "bundle.css.gz", size: 1944, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -100,12 +100,12 @@ func bundleJsGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "bundle.js.gz", size: 116657, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "bundle.js.gz", size: 116657, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
var _configDefaultToml = "\x70\x6f\x72\x74\x20\x3d\x20\x38\x30\x0a\x0a\x5b\x68\x74\x74\x70\x73\x5d\x0a\x65\x6e\x61\x62\x6c\x65\x64\x20\x3d\x20\x66\x61\x6c\x73\x65\x0a\x70\x6f\x72\x74\x20\x3d\x20\x34\x34\x33\x0a\x23\x20\x52\x65\x64\x69\x72\x65\x63\x74\x20\x61\x6c\x6c\x20\x68\x74\x74\x70\x20\x74\x72\x61\x66\x66\x69\x63\x20\x74\x6f\x20\x68\x74\x74\x70\x73\x0a\x72\x65\x64\x69\x72\x65\x63\x74\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x50\x61\x74\x68\x20\x74\x6f\x20\x79\x6f\x75\x72\x20\x63\x65\x72\x74\x20\x61\x6e\x64\x20\x70\x72\x69\x76\x61\x74\x65\x20\x6b\x65\x79\x20\x69\x66\x20\x79\x6f\x75\x20\x61\x72\x65\x20\x6e\x6f\x74\x20\x75\x73\x69\x6e\x67\x0a\x23\x20\x74\x68\x65\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x69\x6e\x74\x65\x67\x72\x61\x74\x69\x6f\x6e\x0a\x63\x65\x72\x74\x20\x3d\x20\x22\x22\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x6c\x65\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x5d\x0a\x23\x20\x59\x6f\x75\x72\x20\x64\x6f\x6d\x61\x69\x6e\x20\x6f\x72\x20\x73\x75\x62\x64\x6f\x6d\x61\x69\x6e\x0a\x64\x6f\x6d\x61\x69\x6e\x20\x3d\x20\x22\x22\x0a\x23\x20\x41\x6e\x20\x65\x6d\x61\x69\x6c\x20\x61\x64\x64\x72\x65\x73\x73\x20\x6c\x65\x74\x73\x20\x79\x6f\x75\x20\x72\x65\x63\x6f\x76\x65\x72\x20\x79\x6f\x75\x72\x20\x61\x63\x63\x6f\x75\x6e\x74\x73\x20\x70\x72\x69\x76\x61\x74\x65\x20\x6b\x65\x79\x0a\x65\x6d\x61\x69\x6c\x20\x3d\x20\x22\x22\x0a\x23\x20\x54\x68\x65\x20\x70\x6f\x72\x74\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x6c\x69\x73\x74\x65\x6e\x73\x20\x6f\x6e\x2c\x20\x63\x6f\x6d\x6d\x65\x6e\x74\x20\x74\x68\x69\x73\x20\x6f\x75\x74\x20\x74\x6f\x20\x6c\x65\x74\x20\x69\x74\x20\x62\x69\x6e\x64\x0a\x23\x20\x74\x6f\x20\x70\x6f\x72\x74\x20\x38\x30\x20\x61\x73\x20\x6e\x65\x65\x64\x65\x64\x2c\x20\x64\x6f\x69\x6e\x67\x20\x73\x6f\x20\x6d\x65\x61\x6e\x73\x20\x64\x69\x73\x70\x61\x74\x63\x68\x20\x69\x74\x73\x65\x6c\x66\x20\x63\x61\x6e\x6e\x6f\x74\x20\x75\x73\x65\x20\x70\x6f\x72\x74\x20\x38\x30\x0a\x70\x6f\x72\x74\x20\x3d\x20\x35\x30\x30\x31\x0a\x23\x20\x48\x61\x76\x65\x20\x64\x69\x73\x70\x61\x74\x63\x68\x20\x70\x72\x6f\x78\x79\x20\x74\x72\x61\x66\x66\x69\x63\x20\x66\x72\x6f\x6d\x20\x70\x6f\x72\x74\x20\x38\x30\x20\x74\x6f\x20\x74\x68\x65\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x70\x6f\x72\x74\x0a\x70\x72\x6f\x78\x79\x20\x3d\x20\x74\x72\x75\x65\x0a\x0a\x23\x20\x4e\x6f\x74\x20\x69\x6d\x70\x6c\x65\x6d\x65\x6e\x74\x65\x64\x0a\x5b\x61\x75\x74\x68\x5d\x0a\x23\x20\x41\x6c\x6c\x6f\x77\x20\x75\x73\x61\x67\x65\x20\x77\x69\x74\x68\x6f\x75\x74\x20\x62\x65\x69\x6e\x67\x20\x6c\x6f\x67\x67\x65\x64\x20\x69\x6e\x2c\x20\x61\x6c\x6c\x20\x63\x68\x61\x6e\x6e\x65\x6c\x73\x20\x61\x6e\x64\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x67\x65\x74\x0a\x23\x20\x74\x72\x61\x6e\x73\x66\x65\x72\x72\x65\x64\x20\x77\x68\x65\x6e\x20\x6c\x6f\x67\x67\x69\x6e\x67\x20\x69\x6e\x20\x6f\x72\x20\x72\x65\x67\x69\x73\x74\x65\x72\x69\x6e\x67\x0a\x61\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x45\x6e\x61\x62\x6c\x65\x20\x75\x73\x65\x72\x6e\x61\x6d\x65\x2f\x70\x61\x73\x73\x77\x6f\x72\x64\x20\x6c\x6f\x67\x69\x6e\x0a\x6c\x6f\x67\x69\x6e\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x45\x6e\x61\x62\x6c\x65\x20\x75\x73\x65\x72\x6e\x61\x6d\x65\x2f\x70\x61\x73\x73\x77\x6f\x72\x64\x20\x72\x65\x67\x69\x73\x74\x72\x61\x74\x69\x6f\x6e\x0a\x72\x65\x67\x69\x73\x74\x72\x61\x74\x69\x6f\x6e\x20\x3d\x20\x74\x72\x75\x65\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x67\x69\x74\x68\x75\x62\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x66\x61\x63\x65\x62\x6f\x6f\x6b\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x67\x6f\x6f\x67\x6c\x65\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x74\x77\x69\x74\x74\x65\x72\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a" var _configDefaultToml = "\x70\x6f\x72\x74\x20\x3d\x20\x38\x30\x0a\x76\x65\x72\x69\x66\x79\x5f\x63\x6c\x69\x65\x6e\x74\x5f\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x73\x20\x3d\x20\x74\x72\x75\x65\x0a\x0a\x5b\x68\x74\x74\x70\x73\x5d\x0a\x65\x6e\x61\x62\x6c\x65\x64\x20\x3d\x20\x66\x61\x6c\x73\x65\x0a\x70\x6f\x72\x74\x20\x3d\x20\x34\x34\x33\x0a\x23\x20\x52\x65\x64\x69\x72\x65\x63\x74\x20\x61\x6c\x6c\x20\x68\x74\x74\x70\x20\x74\x72\x61\x66\x66\x69\x63\x20\x74\x6f\x20\x68\x74\x74\x70\x73\x0a\x72\x65\x64\x69\x72\x65\x63\x74\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x50\x61\x74\x68\x20\x74\x6f\x20\x79\x6f\x75\x72\x20\x63\x65\x72\x74\x20\x61\x6e\x64\x20\x70\x72\x69\x76\x61\x74\x65\x20\x6b\x65\x79\x20\x69\x66\x20\x79\x6f\x75\x20\x61\x72\x65\x20\x6e\x6f\x74\x20\x75\x73\x69\x6e\x67\x0a\x23\x20\x74\x68\x65\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x69\x6e\x74\x65\x67\x72\x61\x74\x69\x6f\x6e\x0a\x63\x65\x72\x74\x20\x3d\x20\x22\x22\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x6c\x65\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x5d\x0a\x23\x20\x59\x6f\x75\x72\x20\x64\x6f\x6d\x61\x69\x6e\x20\x6f\x72\x20\x73\x75\x62\x64\x6f\x6d\x61\x69\x6e\x0a\x64\x6f\x6d\x61\x69\x6e\x20\x3d\x20\x22\x22\x0a\x23\x20\x41\x6e\x20\x65\x6d\x61\x69\x6c\x20\x61\x64\x64\x72\x65\x73\x73\x20\x6c\x65\x74\x73\x20\x79\x6f\x75\x20\x72\x65\x63\x6f\x76\x65\x72\x20\x79\x6f\x75\x72\x20\x61\x63\x63\x6f\x75\x6e\x74\x73\x20\x70\x72\x69\x76\x61\x74\x65\x20\x6b\x65\x79\x0a\x65\x6d\x61\x69\x6c\x20\x3d\x20\x22\x22\x0a\x23\x20\x54\x68\x65\x20\x70\x6f\x72\x74\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x6c\x69\x73\x74\x65\x6e\x73\x20\x6f\x6e\x2c\x20\x63\x6f\x6d\x6d\x65\x6e\x74\x20\x74\x68\x69\x73\x20\x6f\x75\x74\x20\x74\x6f\x20\x6c\x65\x74\x20\x69\x74\x20\x62\x69\x6e\x64\x0a\x23\x20\x74\x6f\x20\x70\x6f\x72\x74\x20\x38\x30\x20\x61\x73\x20\x6e\x65\x65\x64\x65\x64\x2c\x20\x64\x6f\x69\x6e\x67\x20\x73\x6f\x20\x6d\x65\x61\x6e\x73\x20\x64\x69\x73\x70\x61\x74\x63\x68\x20\x69\x74\x73\x65\x6c\x66\x20\x63\x61\x6e\x6e\x6f\x74\x20\x75\x73\x65\x20\x70\x6f\x72\x74\x20\x38\x30\x0a\x70\x6f\x72\x74\x20\x3d\x20\x35\x30\x30\x31\x0a\x23\x20\x48\x61\x76\x65\x20\x64\x69\x73\x70\x61\x74\x63\x68\x20\x70\x72\x6f\x78\x79\x20\x74\x72\x61\x66\x66\x69\x63\x20\x66\x72\x6f\x6d\x20\x70\x6f\x72\x74\x20\x38\x30\x20\x74\x6f\x20\x74\x68\x65\x20\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x20\x70\x6f\x72\x74\x0a\x70\x72\x6f\x78\x79\x20\x3d\x20\x74\x72\x75\x65\x0a\x0a\x23\x20\x4e\x6f\x74\x20\x69\x6d\x70\x6c\x65\x6d\x65\x6e\x74\x65\x64\x0a\x5b\x61\x75\x74\x68\x5d\x0a\x23\x20\x41\x6c\x6c\x6f\x77\x20\x75\x73\x61\x67\x65\x20\x77\x69\x74\x68\x6f\x75\x74\x20\x62\x65\x69\x6e\x67\x20\x6c\x6f\x67\x67\x65\x64\x20\x69\x6e\x2c\x20\x61\x6c\x6c\x20\x63\x68\x61\x6e\x6e\x65\x6c\x73\x20\x61\x6e\x64\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x20\x67\x65\x74\x0a\x23\x20\x74\x72\x61\x6e\x73\x66\x65\x72\x72\x65\x64\x20\x77\x68\x65\x6e\x20\x6c\x6f\x67\x67\x69\x6e\x67\x20\x69\x6e\x20\x6f\x72\x20\x72\x65\x67\x69\x73\x74\x65\x72\x69\x6e\x67\x0a\x61\x6e\x6f\x6e\x79\x6d\x6f\x75\x73\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x45\x6e\x61\x62\x6c\x65\x20\x75\x73\x65\x72\x6e\x61\x6d\x65\x2f\x70\x61\x73\x73\x77\x6f\x72\x64\x20\x6c\x6f\x67\x69\x6e\x0a\x6c\x6f\x67\x69\x6e\x20\x3d\x20\x74\x72\x75\x65\x0a\x23\x20\x45\x6e\x61\x62\x6c\x65\x20\x75\x73\x65\x72\x6e\x61\x6d\x65\x2f\x70\x61\x73\x73\x77\x6f\x72\x64\x20\x72\x65\x67\x69\x73\x74\x72\x61\x74\x69\x6f\x6e\x0a\x72\x65\x67\x69\x73\x74\x72\x61\x74\x69\x6f\x6e\x20\x3d\x20\x74\x72\x75\x65\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x67\x69\x74\x68\x75\x62\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x66\x61\x63\x65\x62\x6f\x6f\x6b\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x67\x6f\x6f\x67\x6c\x65\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a\x0a\x5b\x61\x75\x74\x68\x2e\x74\x77\x69\x74\x74\x65\x72\x5d\x0a\x6b\x65\x79\x20\x3d\x20\x22\x22\x0a\x73\x65\x63\x72\x65\x74\x20\x3d\x20\x22\x22\x0a"
func configDefaultTomlBytes() ([]byte, error) { func configDefaultTomlBytes() ([]byte, error) {
return bindataRead( return bindataRead(
@ -120,7 +120,7 @@ func configDefaultToml() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "config.default.toml", size: 981, mode: os.FileMode(436), modTime: time.Unix(1452747271, 0)} info := bindataFileInfo{name: "config.default.toml", size: 1015, mode: os.FileMode(436), modTime: time.Unix(1452748586, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -140,7 +140,7 @@ func fontFontelloEotGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "font/fontello.eot.gz", size: 3543, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "font/fontello.eot.gz", size: 3543, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -160,7 +160,7 @@ func fontFontelloSvgGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "font/fontello.svg.gz", size: 1707, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "font/fontello.svg.gz", size: 1707, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -180,7 +180,7 @@ func fontFontelloTtfGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "font/fontello.ttf.gz", size: 3490, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "font/fontello.ttf.gz", size: 3490, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -200,7 +200,7 @@ func fontFontelloWoffGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "font/fontello.woff.gz", size: 3701, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "font/fontello.woff.gz", size: 3701, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }
@ -220,7 +220,7 @@ func indexHtmlGz() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "index.html.gz", size: 266, mode: os.FileMode(436), modTime: time.Unix(1452747308, 0)} info := bindataFileInfo{name: "index.html.gz", size: 266, mode: os.FileMode(436), modTime: time.Unix(1452748622, 0)}
a := &asset{bytes: bytes, info: info} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }

View File

@ -1,4 +1,5 @@
port = 80 port = 80
verify_client_certificates = true
[https] [https]
enabled = false enabled = false

View File

@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"log"
"net" "net"
"strings" "strings"
"time" "time"
@ -51,12 +50,6 @@ func (c *Client) connect() error {
defer c.lock.Unlock() defer c.lock.Unlock()
if c.TLS { if c.TLS {
if c.TLSConfig == nil {
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
conn, err := tls.DialWithDialer(c.dialer, "tcp", c.Server, c.TLSConfig) conn, err := tls.DialWithDialer(c.dialer, "tcp", c.Server, c.TLSConfig)
if err != nil { if err != nil {
return err return err
@ -100,7 +93,6 @@ func (c *Client) tryConnect() {
return return
} }
log.Println(err)
time.Sleep(c.backoff.Duration()) time.Sleep(c.backoff.Duration())
} }
} }

View File

@ -88,6 +88,9 @@ func TestConnect(t *testing.T) {
func TestConnectTLS(t *testing.T) { func TestConnectTLS(t *testing.T) {
c := testClient() c := testClient()
c.TLS = true c.TLS = true
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
c.Connect("127.0.0.1:45679") c.Connect("127.0.0.1:45679")
assert.Equal(t, c.Host, "127.0.0.1") assert.Equal(t, c.Host, "127.0.0.1")
assert.Equal(t, c.Server, "127.0.0.1:45679") assert.Equal(t, c.Server, "127.0.0.1:45679")

View File

@ -7,6 +7,7 @@ import (
"net" "net"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/gorilla/websocket" "github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/gorilla/websocket"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/spf13/viper"
"github.com/khlieng/dispatch/irc" "github.com/khlieng/dispatch/irc"
"github.com/khlieng/dispatch/storage" "github.com/khlieng/dispatch/storage"
@ -113,7 +114,8 @@ func (h *wsHandler) connect(b []byte) {
if cert := h.session.user.GetCertificate(); cert != nil { if cert := h.session.user.GetCertificate(); cert != nil {
i.TLSConfig = &tls.Config{ i.TLSConfig = &tls.Config{
Certificates: []tls.Certificate{*cert}, Certificates: []tls.Certificate{*cert},
InsecureSkipVerify: !viper.GetBool("verify_client_certificates"),
} }
} }

View File

@ -17,16 +17,16 @@ func TestUser(t *testing.T) {
Open() Open()
srv := Server{ srv := Server{
Name: "Freenode", Name: "Freenode",
Address: "irc.freenode.net", Host: "irc.freenode.net",
Nick: "test", Nick: "test",
} }
chan1 := Channel{ chan1 := Channel{
Server: srv.Address, Server: srv.Host,
Name: "#test", Name: "#test",
} }
chan2 := Channel{ chan2 := Channel{
Server: srv.Address, Server: srv.Host,
Name: "#testing", Name: "#testing",
} }
@ -51,15 +51,15 @@ func TestUser(t *testing.T) {
assert.Equal(t, chan1, channels[0]) assert.Equal(t, chan1, channels[0])
assert.Equal(t, chan2, channels[1]) assert.Equal(t, chan2, channels[1])
user.SetNick("bob", srv.Address) user.SetNick("bob", srv.Host)
assert.Equal(t, "bob", user.GetServers()[0].Nick) assert.Equal(t, "bob", user.GetServers()[0].Nick)
user.RemoveChannel(srv.Address, chan1.Name) user.RemoveChannel(srv.Host, chan1.Name)
channels = user.GetChannels() channels = user.GetChannels()
assert.Len(t, channels, 1) assert.Len(t, channels, 1)
assert.Equal(t, chan2, channels[0]) assert.Equal(t, chan2, channels[0])
user.RemoveServer(srv.Address) user.RemoveServer(srv.Host)
assert.Len(t, user.GetServers(), 0) assert.Len(t, user.GetServers(), 0)
assert.Len(t, user.GetChannels(), 0) assert.Len(t, user.GetChannels(), 0)
} }