Example #1
0
func (b *buffers) Read(num uint32, buf []byte) (int, error) {
	b.lck.Lock()

	chBuf, found := b.buffers[num]
	if !found {
		b.lck.Unlock()
		return 0, e.New(ErrStreamNotFound)
	}
	b.lck.Unlock()

	delta := b.deadline.Sub(time.Now())
	if b.deadline.IsZero() {
		n, err := chBuf.Read(buf)
		if err != nil {
			return 0, e.Push(err, "conn close")
		}
		return n, nil
	}
	select {
	case ret := <-chBuf.ReadChan(buf):
		if ret.Err != nil {
			return 0, e.Push(ret.Err, "conn close")
		}
		// TODO: reenviar o error para a fila em caso de conn close.
		return ret.N, nil
	case <-time.After(delta):
		return 0, errors.New("io read timeout")
	}
}
Example #2
0
func (p *protoSession) NamedInstance(inst string) (connInst, error) {
	s, err := p.newstream()
	if err != nil {
		return nil, e.Push(err, "can't initiate a new connection with the server")
	}
	enc := msgpack.NewEncoder(s)
	dec := msgpack.NewDecoder(s)
	err = enc.Encode(&ReqInst{
		Inst: inst,
	})
	if err != nil {
		return nil, e.Push(err, "can't request instance")
	}
	var resp RespInst
	err = dec.Decode(&resp)
	if err != nil {
		return nil, e.Push(err, "can't request instance")
	}
	if resp.Err != nil {
		return nil, e.Push(err, "instance init failed")
	}
	return &protoInst{
		s:    s,
		inst: resp.Inst,
		enc:  msgpack.NewEncoder(s),
		dec:  msgpack.NewDecoder(s),
	}, nil
}
Example #3
0
File: http.go Project: fcavani/ping
// PingHttp connect a http or https server and try to
// receive something. If the server return a code different
// of 2xx, it will fail. Ignores insecure certificates.
func PingHttp(url *url.URL) error {
	resp, err := httpClient.Get(url.String())
	if e.Contains(err, "connection refused") {
		return e.Push(e.New(err), "get failed: connection refused")
	} else if err != nil {
		return e.Push(e.New(err), "get failed")
	}
	defer resp.Body.Close()
	buf := make([]byte, 4096)
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		n, err := resp.Body.Read(buf)
		if err != nil && err != io.EOF {
			return e.Forward(err)
		}
		buf = buf[:n]
		//status.Log(status.Protocol, "PingHttp status code is %v and received it from server: %v", resp.StatusCode, string(buf))
		log.ProtoLevel().Printf("PingHttp status code is %v and received it from server: %v", resp.StatusCode, string(buf))
		return e.New("returned status code %v, expected 2xx", resp.StatusCode)
	}
	_, err = resp.Body.Read(buf)
	if err != nil && err != io.EOF {
		return e.Forward(err)
	}
	return nil
}
Example #4
0
func CheckUrl(rawurl string, min, max int) error {
	if len(rawurl) < min || len(rawurl) > max {
		return e.Push(e.New(ErrInvUrl), e.New("invalid url length"))
	}
	for _, v := range rawurl {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != '/' && v != ':' && v != '[' && v != ']' && v != '?' && v != '@' && v != '.' && v != '-' && v != '_' && v != ' ' && v != '+' && v != '%' && v != '#' {
			return e.Push(e.New(ErrInvUrl), e.New("the character '%v' in redirect is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #5
0
func (c *Client) encode(typ msgType, val interface{}, dst *net.UDPAddr) error {
	log.ProtoLevel().Tag("client", "discover").Printf("Send request (%v) to %v from %v.", typ, dst, c.conn.LocalAddr())

	reqBuf := bytes.NewBuffer([]byte{})

	buf := make([]byte, binary.MaxVarintLen16)
	binary.PutUvarint(buf, uint64(typ))
	n, err := reqBuf.Write(buf)
	if err != nil {
		return e.Push(err, "error enconding message type")
	}
	if n != len(buf) {
		return e.Push(err, "error enconding message type")
	}

	enc := gob.NewEncoder(reqBuf)
	err = enc.Encode(val)
	if err != nil {
		return e.Push(err, e.New("error encoding"))
	}

	msg, err := NewMsg(c.Name, c.ServerName, c.PrivateKey, c.ServerKey, reqBuf.Bytes())
	if err != nil {
		return e.Push(err, "erro cryptographing the value")
	}

	reqBuf = bytes.NewBuffer([]byte{})
	enc = gob.NewEncoder(reqBuf)
	err = enc.Encode(msg)
	if err != nil {
		return e.Push(err, e.New("error encoding"))
	}

	if reqBuf.Len() > c.BufSize {
		return e.New("value to encode is too big %v", reqBuf.Len())
	}
	err = c.conn.SetDeadline(time.Now().Add(c.Deadline))
	if err != nil {
		return e.New(err)
	}
	_, _, err = c.conn.WriteMsgUDP(reqBuf.Bytes(), nil, dst)
	if err != nil {
		return e.New(err)
	}
	err = c.conn.SetDeadline(time.Time{})
	if err != nil {
		return e.New(err)
	}
	return nil
}
Example #6
0
func (t *TestExportClient) TestRetval() (arg0 ResultInt) {
	_err_ := t.init()
	if _err_ != nil {
		t.log(e.Trace(e.Forward(_err_)))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	_err_ = t.client.Call("TestRetval", []reflect.Value{}, []reflect.Value{reflect.ValueOf(&arg0)})
	if _err_ != nil {
		t.log(e.Trace(_err_))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	return
}
Example #7
0
func (r *ResultClient) Calc() (arg0 int) {
	_err_ := r.init()
	if _err_ != nil {
		r.log(e.Trace(e.Forward(_err_)))
		r._err_ = e.Push(r._err_, _err_)
		return
	}
	_err_ = r.client.Call("Calc", []reflect.Value{}, []reflect.Value{reflect.ValueOf(&arg0)})
	if _err_ != nil {
		r.log(e.Trace(_err_))
		r._err_ = e.Push(r._err_, _err_)
		return
	}
	return
}
Example #8
0
func (t *TestChannelClient) Recv(x <-chan int) (arg0 int) {
	_err_ := t.init()
	if _err_ != nil {
		t.log(e.Trace(e.Forward(_err_)))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	_err_ = t.client.Call("Recv", []reflect.Value{reflect.ValueOf(x)}, []reflect.Value{reflect.ValueOf(&arg0)})
	if _err_ != nil {
		t.log(e.Trace(_err_))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	return
}
Example #9
0
func (t *TestChannelClient) Send(x chan<- int) {
	_err_ := t.init()
	if _err_ != nil {
		t.log(e.Trace(e.Forward(_err_)))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	_err_ = t.client.Call("Send", []reflect.Value{reflect.ValueOf(x)}, []reflect.Value{})
	if _err_ != nil {
		t.log(e.Trace(_err_))
		t._err_ = e.Push(t._err_, _err_)
		return
	}
	return
}
Example #10
0
func (a *Server) sendResp(resp *Response, to string, tokey *rsa.PublicKey, addr *net.UDPAddr) {
	log.ProtoLevel().Tag("server", "discover").Printf("Send response from %v to %v", a.conn.LocalAddr(), addr)
	respBuf := bytes.NewBuffer([]byte{})
	enc := gob.NewEncoder(respBuf)
	err := enc.Encode(resp)
	if err != nil {
		log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err)))
		a.sendErr(addr, e.Push(err, e.New("error enconding response")))
		return
	}

	msg, err := NewMsg(a.Name, to, a.PrivateKey, tokey, respBuf.Bytes())
	if err != nil {
		log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err)))
		a.sendErr(addr, e.Push(err, e.New("error creating new response message")))
		return
	}

	respBuf = bytes.NewBuffer([]byte{})
	enc = gob.NewEncoder(respBuf)
	err = enc.Encode(msg)
	if err != nil {
		log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err)))
		a.sendErr(addr, e.Push(err, e.New("error enconding response")))
		return
	}

	if respBuf.Len() > a.BufSize {
		log.Tag("discover", "server").Printf("Server - Protocol fail for %v message is too big (%v).", addr, respBuf.Len())
		a.sendErr(addr, e.Push(err, e.New("response is too long %v", respBuf.Len())))
		return
	}
	n, oob, err := a.conn.WriteMsgUDP(respBuf.Bytes(), nil, addr)
	if e.Contains(err, "use of closed network connection") {
		return
	} else if err != nil {
		log.Tag("discover", "server").Printf("Server - WriteMsgUDP (%v) failed: %v", addr, e.Trace(e.New(err)))
		return
	}
	if oob != 0 {
		log.Tag("discover", "server").Printf("Server - WriteMsgUDP to %v failed: %v, %v", addr, n, oob)
		return
	}
	if n != respBuf.Len() {
		log.Tag("discover", "server").Printf("Server - WriteMsgUDP to %v failed: %v, %v", addr, n, oob)
		return
	}
}
Example #11
0
func (c *Client) response() (*Response, error) {
	log.ProtoLevel().Tag("client", "discover").Printf("Waiting response...")
	buf := make([]byte, c.BufSize)
	err := c.conn.SetDeadline(time.Now().Add(c.Deadline))
	if err != nil {
		return nil, e.New(err)
	}
	n, addr, err := c.conn.ReadFromUDP(buf)
	if err != nil {
		return nil, e.New(err)
	}
	log.ProtoLevel().Tag("client", "discover").Printf("Response from %v with size %v.", addr, n)
	err = c.conn.SetDeadline(time.Time{})
	if err != nil {
		return nil, e.New(err)
	}

	dec := gob.NewDecoder(bytes.NewReader(buf[:n]))
	var msg Msg
	err = dec.Decode(&msg)
	if err != nil {
		return nil, e.Push(err, e.New("error decoding response"))
	}

	if msg.Err != nil {
		return nil, e.Forward(msg.Err)
	}

	if msg.From != c.ServerName {
		return nil, e.New("wrong server name")
	}
	if msg.To != c.Name {
		return nil, e.New("message isn't for me")
	}

	buf, err = msg.Message(c.ServerKey, c.PrivateKey)
	if err != nil {
		return nil, e.Push(err, e.New("error decrypting response"))
	}

	dec = gob.NewDecoder(bytes.NewReader(buf))
	var resp Response
	err = dec.Decode(&resp)
	if err != nil {
		return nil, e.Push(err, e.New("error decoding response"))
	}
	return &resp, nil
}
Example #12
0
func (c *client) do(method, path, params string, body []byte) (int, []byte, error) {
	url := utilUrl.Copy(c.url)
	url.Path += path
	url.RawQuery = params

	var buf io.Reader
	if len(body) > 0 {
		buf = bytes.NewBuffer(body)
	}

	req, err := http.NewRequest(method, url.String(), buf)
	if err != nil {
		return 0, nil, e.New("can't create request")
	}

	if c.url.User != nil {
		req.Header.Set("Authorization", authorizationHeader(url.User.String()))
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := HttpClient.Do(req)
	if err != nil {
		return 0, nil, e.Push(err, "can't put")
	}
	defer resp.Body.Close()

	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		return resp.StatusCode, nil, e.New("wrong status code - %v: %v", resp.StatusCode, resp.Status)
	}

	var data []byte
	data, _ = ioutil.ReadAll(resp.Body)

	return resp.StatusCode, data, nil
}
Example #13
0
func (i *Instances) NewChValueInstance(sess, inst string, ch reflect.Value, dir reflect.ChanDir, owners auth.Validator) error {
	i.lck.Lock()
	defer i.lck.Unlock()
	s, found := i.Insts[sess]
	if !found {
		s = &Session{
			Insts: map[string]Valuer{
				inst: &ChannelValue{
					ch:  ch,
					dir: dir,
				},
			},
			Owners: owners,
		}
		i.Insts[sess] = s
		return nil
	}
	if err := s.Owners.Equal(owners); err != nil {
		return e.Push(err, ErrOwnerNotMatch)
	}
	_, found = s.Insts[inst]
	if !found {
		s.Insts[inst] = &ChannelValue{
			ch:  ch,
			dir: dir,
		}
		return nil
	}
	return e.New(ErrInstExists)
}
Example #14
0
func (d *Daemon) restartProcess() error {
	d.status.Log(status.Verbose, "Process %v is about to restart.", d.DaemonName)
	err := d.exec(d.RestartCmd, d.RestartArgs...)
	if e.Contains(err, "exit status") {
		d.status.Log(status.Verbose, "Restart command %v failed for %v with error: %v.", d.RestartCmd, d.DaemonName, e.Trace(e.Forward(err)))
		if d.ForceKillCmd != "" {
			err := d.forceKill()
			if err != nil {
				return e.Push(err, ErrGiveUpRestart)
			}
		} else {
			err := d.kill(syscall.SIGTERM)
			if e.Equal(err, ErrNoPid) {
				d.status.Log(status.Verbose, "Starting force kill for %v.", d.DaemonName)
				err := d.forceKill()
				if err != nil {
					return e.Push(err, ErrGiveUpRestart)
				}
			} else if err != nil {
				err := d.kill(syscall.SIGKILL)
				if err != nil {
					d.status.Log(status.Verbose, "Starting force kill for %v.", d.DaemonName)
					err := d.forceKill()
					if err != nil {
						return e.Push(err, ErrGiveUpRestart)
					}
				}
			}
		}
		d.status.Log(status.Verbose, "Process %v is about to restart.", d.DaemonName)
		err = d.exec(d.RestartCmd, d.RestartArgs...)
		if err != nil {
			err := d.forceKill()
			if err != nil {
				return e.Push(err, ErrGiveUpRestart)
			}
			d.status.Log(status.Verbose, "Process %v is about to restart, for the last time.", d.DaemonName)
			err = d.exec(d.RestartCmd, d.RestartArgs...)
			if err != nil {
				return e.Push(err, ErrGiveUpRestart)
			}
		}
	} else if err != nil {
		return e.Forward(err)
	}
	return nil
}
Example #15
0
func CheckObjectName(name string) error {
	for _, v := range name {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != '-' && v != '_' && v != '*' && v != '{' && v != '}' && v != '/' && v != '.' && v != '[' && v != ']' {
			return e.Push(e.New(text.ErrInvCharacter), e.New("the character '%v' in object name is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #16
0
File: tags.go Project: fcavani/tags
// Check if a tag is formed with the corrects characters
func CheckTag(tag string) error {
	for _, v := range tag {
		if !u.IsLetter(v) && !unicode.IsDigit(v) && v != ' ' && v != '-' && v != '_' && v != '.' && v != '/' && v != ':' {
			return e.Push(e.New(ErrInvalidTagChar), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #17
0
// Get the document id from the database and put it in
// the struct point by v. rev is the revision and is optional.
func (c *Couch) Get(id, rev string, v interface{}) error {
	if rev != "" {
		rev = "rev=" + rev
	}
	code, data, err := c.get(id, rev, nil)
	if err != nil {
		return e.Push(err, ErrCantGetDoc)
	}
	if code != http.StatusOK {
		return e.New("can't get the document, wrong code: %v", code)
	}
	err = json.Unmarshal(data, v)
	if err != nil {
		return e.Push(err, "can't unserialize the document")
	}
	return nil
}
Example #18
0
// CheckHash the hash of a password.
func CheckHash(name string) error {
	for _, v := range name {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != '-' && v != '_' && v != '.' && v != '=' {
			return e.Push(e.New(text.ErrInvCharacter), e.New("the character '%v' in instance name is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #19
0
func CheckDomain(domain string) error {
	for _, v := range domain {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != '.' {
			return e.Push(e.New("invalid domain name"), e.New("the character '%v' in redirect is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #20
0
// Put inserts in the database the struct in v, v must have the fild _id and
// the field _rev both strings. Like the TestStruct struct.
func (c *Couch) Put(v interface{}) (id, rev string, err error) {
	data, err := json.Marshal(v)
	if err != nil {
		return "", "", e.Push(err, "can't serialize the data")
	}
	id = grepId(data)
	if id == "" {
		return "", "", e.New("document have no id")
	}
	code, resp, err := c.put(id, "", data)
	if err != nil && code == 409 {
		return "", "", e.Push(err, ErrDocConflict)
	} else if err != nil {
		return "", "", e.Push(err, "can't put the document")
	}
	if code == http.StatusCreated {
		ir := new(response)
		err := json.Unmarshal(resp, ir)
		if err != nil {
			return "", "", e.Push(e.Push(err, "can't desserialize returned data"), "can't put the document")
		}
		if !ir.Ok {
			return "", "", e.New("put failed")
		}
		return ir.Id, ir.Rev, nil
	}
	return "", "", e.Push(e.Push(err, e.New("received wrong response code, %v", code)), "can't put the document")
}
Example #21
0
func (m MultiEncodeGob) EncodeValue(val reflect.Value) (err error) {
	i := 0
	var allerrors error
	for conn, encoder := range m {
		err := encoder.EncodeValue(val)
		if err != nil {
			conn.Close()
			delete(m, conn)
			allerrors = e.Push(allerrors, err)
			continue
		}
		i++
	}
	if i == 0 {
		return e.Push(allerrors, "encode failed")
	}
	return nil
}
Example #22
0
func (m MultiEncodeGob) Encode(val interface{}) error {
	i := 0
	var allerrors error
	for conn, encoder := range m {
		err := encoder.Encode(val)
		if err != nil {
			conn.Close()
			delete(m, conn)
			allerrors = e.Push(allerrors, err)
			continue
		}
		i++
	}
	if i == 0 {
		return e.Push(allerrors, "encode failed")
	}
	return nil
}
Example #23
0
// InfoDB reports the status of the database.
// url is the url for the database and dbname is the name of the new database.
func InfoDB(url *url.URL, dbname string) (*DatabaseInfo, error) {
	c := &client{url}
	code, data, err := c.get(dbname, "", nil)
	if e.Contains(err, Err404) {
		return nil, e.Push(err, ErrDbNotFound)
	} else if err != nil {
		return nil, e.Push(err, "can't get database information")
	}
	if code != http.StatusOK {
		return nil, e.New("can't get database information, wrong response code: %v", code)
	}
	di := new(DatabaseInfo)
	err = json.Unmarshal(data, di)
	if err != nil {
		return nil, e.Push(err, "can't get database information")
	}
	return di, nil
}
Example #24
0
File: net.go Project: fcavani/net
// SplitHostPort splits a string with a ipv6, ipv4 or hostname with a port number.
func SplitHostPort(hp string) (host, port string, err error) {
	if len(hp) == 0 {
		return "", "", e.New("invalid host length")
	}
	if hp[0] == '[' {
		// ipv6 - [2001:db8:1f70::999:de8:7648:6e8]:100
		x := reCompIpv6Port.FindAllStringSubmatch(hp, -1)
		if len(x) == 0 {
			if IsValidIpv6(hp) {
				host = strings.TrimSuffix(strings.TrimPrefix(hp, "["), "]")
				port = ""
			} else {
				return "", "", e.New(ErrCantGetIp)
			}
		} else {
			if len(x[0]) >= 3 {
				host = x[0][1]
				port = x[0][len(x[0])-1] //Last is the port
			} else if len(x[0]) >= 2 {
				host = x[0][1]
				port = ""
			} else {
				return "", "", e.New(ErrCantGetIp)
			}
		}
	} else {
		//ip4 and host name
		ipport := strings.SplitN(hp, ":", 2)
		if len(ipport) == 1 {
			host = ipport[0]
			port = ""
		} else if len(ipport) == 2 {
			host = ipport[0]
			port = ipport[1]
		} else {
			return "", "", e.New(ErrCantSplitHostPort)
		}
		if !IsValidIpv4(host) {
			err := text.CheckDomain(host)
			if err != nil {
				return "", "", e.New("invalid domain name or ipv4")
			}
		}
	}
	if host == "" {
		return "", "", e.New(ErrCantFindHost)
	}
	if port == "" {
		return host, "", e.New(ErrCantFindPort)
	}
	_, err = strconv.ParseUint(port, 10, 16)
	if err != nil {
		return "", "", e.Push(e.New(err), "invalid port number")
	}
	host = strings.ToLower(host)
	return
}
Example #25
0
func CheckText(text string, min, max int) error {
	if len(text) < min || len(text) > max {
		return e.New(ErrInvNumberChars)
	}
	for _, v := range text {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != '\n' && v != ' ' && v != '`' && v != '~' && v != '!' && v != '@' && v != '#' && v != '$' && v != '%' && v != '^' && v != '&' && v != '*' && v != '(' && v != ')' && v != '_' && v != '-' && v != '+' && v != '=' && v != '{' && v != '}' && v != '[' && v != ']' && v != '|' && v != '\\' && v != ':' && v != ';' && v != '"' && v != '\'' && v != '?' && v != '/' && v != ',' && v != '.' {
			return e.Push(e.New(ErrInvCharacter), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #26
0
func CheckLettersNumber(text string, min, max uint64) error {
	if uint64(len(text)) < min || uint64(len(text)) > max {
		return e.New(ErrInvNumberChars)
	}
	for _, v := range text {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) {
			return e.Push(e.New(ErrInvCharacter), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #27
0
func CheckLetters(text string, min, max int) error {
	if len(text) < min || len(text) > max {
		return e.New(ErrInvNumberChars)
	}
	for _, v := range text {
		if !uni.IsLetter(v) {
			return e.Push(e.New(ErrInvCharacter), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #28
0
func CheckFileName(nome string, min, max int) error {
	if len(nome) < min || len(nome) > max {
		return e.New(ErrInvNumberChars)
	}
	for _, v := range nome {
		if !unicode.IsGraphic(v) {
			return e.Push(e.New(ErrInvCharacter), e.New("the character '%v' in filename is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #29
0
func CheckNameWithoutSpecials(name string, min, max int) error {
	if len(name) < min || len(name) > max {
		return e.New(ErrInvNumberChars)
	}
	for _, v := range name {
		if !uni.IsLetter(v) && !unicode.IsDigit(v) && v != ' ' && v != '&' && v != '(' && v != ')' && v != '-' && v != ':' && v != '/' && v != ',' && v != '.' && v != '_' {
			return e.Push(e.New(ErrInvCharacter), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}
Example #30
0
File: tags.go Project: fcavani/tags
// Check if a set of tags are correctly formated.
func CheckTags(tags string) error {
	if len(tags) <= TagStringMin && len(tags) >= TagStringMax {
		return e.New(ErrInvalidTagsLength)
	}
	for _, v := range tags {
		if !u.IsLetter(v) && !unicode.IsDigit(v) && v != ',' && v != ' ' && v != '-' && v != '_' && v != '.' && v != '/' && v != ':' {
			return e.Push(e.New(ErrInvalidTagChar), e.New("the character '%v' is invalid", string([]byte{byte(v)})))
		}
	}
	return nil
}