This commit is contained in:
kayos@tcp.direct 2021-09-28 02:30:11 -07:00
commit 3fba6e6295
9 changed files with 624 additions and 0 deletions

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# durnkb0t
```
<soyak> .drinkin
<durnkb0t> _.._..,_,_
<durnkb0t> ( )
<durnkb0t> ]~,"-.-~~[
<durnkb0t> .=])' (; ([
<durnkb0t> | ]:: ' [ the following lovely chatters
<durnkb0t> '=]): .) ([ are trying their absolute best
<durnkb0t> |:: ' | to get fuckin lit in 2021
<durnkb0t> ~~----~~
<durnkb0t> -------> kayos[m]1 d soyak
```
```
<&kayos> Where r u working now Oh, yes, I've just been to see The Exorcism of Emily Rose and may never sleep again!
<&kayos> They are going to mush!
<&kayos> Bad days give u happiness.
<&kayos> So, Wish u a very Happy New Year and I wanted to ask ü to wait 4 me there ar?
<&kayos> Then r we meeting tmr?
<&kayos> Try SPEEDCHAT, txt SPEEDCHAT to 80155, if you don't mind, as doing that nxt wk.
<&kayos> See you in the library?
<&kayos> Bring it if you got it I'm in a meeting, call me later at Oh wow thats gay.
<&kayos> Do have a fantastic year and all the best. ttyl 1.20 that call cost.
<&kayos> I know this is a challenging time for you also but i have hundreds of handsomes and beauties to wish.
<&kayos> If not then let this text give you a special treat if you keep the secret.
<&kayos> At home by the way it comes!
<&kayos> Just got some gas money, any chance you and the gang want to go to taunton if you still need to loose weight.```

45
config.go Normal file
View File

@ -0,0 +1,45 @@
package main
/////////////
/////////
/// RPC
var RPCPort string = "4321"
var RPCHost string = "127.0.0.1"
var cowPipe string = "/tmp/sh0rtbus.cowrie.fifo"
/////////
/// IRC
var ircHost string = "br3ircdrchatmfsk.onion"
var ircPort int = 6667
var ircSSL bool = false
var ircFlood bool = true
var ircDebug uintptr = 0 //os.Stdout
var ircVersion string = "sh0rtbus 0.2 fun edition"
// Bot
var ircHome string = "#tcpdirect"
var ircOwner string = "kayos"
var ircNick string = "durnkb0t"
var ircUser string
var ircPass string // username:pasword defined in auth.text
// Proxy
var proxyProto string = "SOCKS5" // "false" to disable proxy
var proxyHost string = "127.0.0.1"
var proxyPort string = "9050"
//// Cowrie
var cowVerbose int = 0
var cowLogs string = "/home/cowrie/cowrie/var/log/cowrie"
var cowPings string = "kayos hgc Civil Xair nameless moony Glock kuntz w00dsman"
// Cowrie SQL
//var sqlHost string = "127.0.0.1"
//var sqlPort string = "3306"
//var sqlDB string = "cowrie"
//var sqlUser string = "sh0rtbus"
//var sqlPass string = "Eir4OcertEutpyfryWadbiwobJaphAlf"
///////////////////
//var db *sql.DB
var err error
var cowSesh []string
//////////////////
var soberStrings []string

96
cowrie.go Normal file
View File

@ -0,0 +1,96 @@
package main
import(
"syscall"
"os"
"bytes"
"fmt"
"io"
"strings"
"github.com/lrstanley/girc"
)
//func stainSelect(query string) {
// db, err = sql.Open("mysql","user:"+sqlUser+"@"+sqlHost+"("+sqlHost+":"+sqlPort+")/"+sqlDB)
// defer db.Close()
// if err != nil {
// fmt.Println("[SQL] Fatal error when opening the MySQL database: ", err.Error())
// }
// err = db.Ping()
// if err != nil {
// fmt.Println("[SQL] Fatal error when pinging the MySQL database: ", err.Error())
// }
//}
func Cowrie(c *girc.Client) error {
syscall.Mkfifo(cowPipe, 0600)
for {
// fmt.Println("[IPC] Opening named pipe for reading")
stdout, err := os.OpenFile(cowPipe, os.O_RDONLY, 0600)
var buff bytes.Buffer
if err != nil {
fmt.Println("[IPC] FATAL! Cannot open named pipe!")
return err
os.Exit(2)
}
io.Copy(&buff, stdout)
stdout.Close()
dataStr := buff.String()
if (cowVerbose == 1 && strings.Contains(dataStr, "CMD:")) {
fmt.Println("CMD detected!")
cowSlice := strings.Split(dataStr,"]")
cowPrefix := cowSlice[0]
cowString := strings.Split(cowPrefix, ")")
cowString = strings.Split(cowString[0], ")")
cowSession := cowString[0]
cowIPstr := strings.Split(cowPrefix,",")
cowIP := cowIPstr[0]
cowCmd := "["+cowIP+"]["+cowSession+"] " + cowSlice[1]
fmt.Println(cowCmd)
if !contains(cowSesh,cowSession) {
Phone(c,"(new) Retard alert! Attn:")
PhoneOwner(c,"Retard alert!")
Phone(c,cowPings)
Phone(c,"-----------------")
cowSesh = append(cowSesh,cowSession)
printSlice(cowSesh)
}
Phone(c,dataStr)
}
if cowVerbose == 2 {
fmt.Printf("[IPC] sending data to [IRC]: %s\n", dataStr)
Phone(c,dataStr)
}
}
}
func cowSay(c *girc.Client, str0 string, str1 string, str2 string) {
Phone(c," __,._{i} " + str0)
Phone(c," / _ \\ ")
if (cowVerbose == 0) {
Phone(c," | 6 \\ \\ {red}oo{c} ")
} else if cowVerbose == 1 {
Phone(c," | 6 \\ \\ {green}oo{c} ")
} else {
Phone(c," {yellow}REEE{c} | 6 \\ \\ {green}$${c} ")
}
Phone(c," \\___/ .|__|| ")
Phone(c," __,..=\"^ . , \" ,\\ ")
Phone(c,"<.__________________/ ")
Phone(c,"{white}" + str1)
if str2 != "0" {
Phone(c,"{white}" + str2)
}
}

47
drunkbot.go Normal file
View File

@ -0,0 +1,47 @@
package main
import (
// "database/sql"
"github.com/lrstanley/girc"
"math/rand"
"time"
////////
// _ "github.com/go-sql-driver/mysql"
)
func Phone(c *girc.Client, Msg string) {
target := ircHome
c.Cmd.Message(target, girc.Fmt(Msg))
}
func PhoneOwner(c *girc.Client, Msg string) {
target := ircOwner
c.Cmd.Message(target, girc.Fmt(Msg))
}
func ircBanner(c *girc.Client) {
c.Cmd.Message(ircHome, girc.Fmt("{purple,black} {green,black} ___ {purple,black} {c}"))
c.Cmd.Message(ircHome, girc.Fmt("{purple,black} | {green,black}| /|{purple,black} | | {gold,black}v0.2{c}{green,black}fun{c}"))
c.Cmd.Message(ircHome, girc.Fmt("{purple,black} - |- {green,black}| + |{purple,black} |- -+- |- - {c}"))
c.Cmd.Message(ircHome, girc.Fmt("{purple,black} \\ | | {green,black}|/ |{purple,black} | | | | | | \\ {c}"))
c.Cmd.Message(ircHome, girc.Fmt("{purple,black} - {green,black} --- {purple,black} - - -- - {c}"))
return
}
func ircDrinkin(c *girc.Client) {
c.Cmd.Message(ircHome, girc.Fmt(" _.._..,_,_ "))
c.Cmd.Message(ircHome, girc.Fmt(" ({black,white} {c})"))
c.Cmd.Message(ircHome, girc.Fmt(" ]{white,gold}~,\"-.-~~{c}[" ))
c.Cmd.Message(ircHome, girc.Fmt(".=]{white,gold})' (; ({c}["))
c.Cmd.Message(ircHome, girc.Fmt("| ]{white,gold}:: ' {c}[ the following lovely chatters"))
c.Cmd.Message(ircHome, girc.Fmt("'=]{white,gold}): .) ({c}[ are trying their absolute best"))
c.Cmd.Message(ircHome, girc.Fmt(" |{white,gold}:: ' {c}| to get fuckin {orange}lit{c} in 2021"))
c.Cmd.Message(ircHome, girc.Fmt(" ~~----~~ "))
}
func soberString() string {
rand.Seed(time.Now().Unix())
choice := soberStrings[rand.Intn(len(soberStrings))]
return choice
}

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module drunkb0t
go 1.17
require (
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
)

9
go.sum Normal file
View File

@ -0,0 +1,9 @@
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b h1:jrLvME7VuLW6NRysbiZtenTB9QcNlR9RPKK4LFfZn60=
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

339
ircbot.go Normal file
View File

@ -0,0 +1,339 @@
package main
import(
"github.com/lrstanley/girc"
"golang.org/x/net/proxy"
"strconv"
"strings"
"net/url"
"bufio"
"time"
"fmt"
"net"
"os"
)
var drinkin []string
var smokin []string
var speedin []string
var vapin []string
var drinkyBoys string
func ircbot() {
soberStrings = []string {
" wakes up confused (sober)",
" sobers up and questions their entire life",
" is straight edge because drugs and alcohol are for LOSERS (sober)",
" doesn't wanna talk about it (sober)",
}
//////////////////////////////////
//////////////////////////////////
///////////////// TCP Server
//inbound, err := net.ListenTCP("tcp", Host+":"+Port) // Define TCP Listener
//if err != nil { //logr.Fatal("RPC Listener error! " + err) }
//psad := new(psadRPC) // Create a new handler of type psadRPC
//rpc.Register(psad)// Adds all relevant functions to RPC registry (gives client options)
//rpc.Accept(inbound) // Begins listening on socket and offering functions
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//logr := //logr.WithContext("IRC")
if (len(os.Args) > 1) {
ircNick = os.Args[1]
}
var SASLbool bool = false
var client *girc.Client
var ircSASL *girc.SASLPlain
fmt.Println("[IRC] Opening auth file for nickserv creds...")
f, err := os.Open("auth.txt")
if err != nil {
fmt.Println("[IRC] Error opening auth.txt file!")
fmt.Println("[IRC] Proceeding without authentication...")
ircUser = ircNick
ircPass = ""
} else {
defer f.Close()
scanner := bufio.NewScanner(f)
scanner.Scan()
line := scanner.Text()
auth := strings.Split(line, ":")
ircUser = auth[0]
ircPass = auth[1]
ircSASL = &girc.SASLPlain{User: ircUser, Pass: ircPass}
SASLbool = true
f.Close()
}
if SASLbool == true {
client = girc.New(girc.Config{
Server: ircHost,
Port: ircPort,
Nick: ircNick,
Name: ircNick,
User: ircUser,
SSL: ircSSL,
SASL: ircSASL,
AllowFlood: ircFlood,
Out: os.Stdout,
Version: ircVersion,
})
} else {
client = girc.New(girc.Config{
Server: ircHost,
Port: ircPort,
Nick: ircNick,
Name: ircNick,
User: ircUser,
SSL: ircSSL,
AllowFlood: ircFlood,
Out: os.Stdout,
Version: ircVersion,
})
}
client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
fmt.Println("[IRC] Successfully connected to: " + ircHost)
c.Cmd.Join(ircHome)
fmt.Println("[IRC] Joining channel: " + ircHome)
err = Cowrie(c)
if err != nil {
fmt.Println("[IPC] Error: " + err.Error())
c.Cmd.Message(ircOwner, "IPC Error: err.Error()")
os.Exit(2)
}
})
client.Handlers.Add(girc.INVITE, func(c *girc.Client, e girc.Event) {
c.Cmd.Join(e.Last())
})
client.Handlers.Add(girc.ERR_CANNOTSENDTOCHAN, func(c *girc.Client, e girc.Event) {
Target := ircHome
if (strings.Contains(girc.Fmt(e.String()), ircHome)) {
Target = ircOwner
}
c.Cmd.Message(Target, "ERR_INVITEONLYCHAN:")
c.Cmd.Message(Target, girc.Fmt(e.String()))
})
client.Handlers.Add(girc.ERR_INVITEONLYCHAN, func(c *girc.Client, e girc.Event) {
Phone(c,"ERR_INVITEONLYCHAN:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISUSER, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISUSER:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISOPERATOR, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISOPERATOR:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISIDLE, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISIDLE:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISSERVER, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISSERVER:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISCHANOP, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISCHANOP:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISCHANOP, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_LINKS:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISCHANOP, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_STATSLINKINFO:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_WHOISCHANOP, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_TRACELINK:")
Phone(c,girc.Fmt(e.String()))
})
client.Handlers.Add(girc.RPL_TOPICWHOTIME, func(c *girc.Client, e girc.Event) {
Chan := strings.Split(e.String(), " ")[4]
if Chan != ircHome {
Phone(c,"Joined " + Chan + " on " + e.Source.ID())
Phone(c,girc.Fmt(e.String()))
}
})
/* client.Handlers.Add(girc.RPL_NAMREPLY, func(c *girc.Client, e girc.Event) {
reply := strings.Split(e.String(), " ")
if reply[5] != ircHome {
for i, h := range reply {
if i < 4 { continue }
Phone(c,h)
}
} else {
ircBanner(c)
Phone(c,ircVersion)
}
})*/
client.Handlers.Add(girc.RPL_WHOISCHANNELS, func(c *girc.Client, e girc.Event) {
Phone(c,"RPL_WHOISCHANNELS:")
Phone(c,e.String())
})
client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
Sender := e.Source.Name
if Sender == "NickServ" {
fmt.Println("[IRC] NickServ response: " + e.Last())
}
if (strings.HasPrefix(e.Last(), ".")) {
fmt.Println("[IRC] "+e.String())
thyWill := strings.Split(e.Last(), " ")
switch thyWill[0] {
case ".whois":
if len(thyWill) == 1 {
c.Cmd.ReplyTo(e, girc.Fmt("Usage: !whois nick"))
return
}
fmt.Println("[IRC] <"+string(Sender)+"> !spider " + thyWill[1])
if girc.IsValidNick(thyWill[1]) {
c.Cmd.Whois(thyWill[1])
return
} else {
fmt.Println("[IRC] ERROR: Bad whois target!")
Phone(c,"Bad Target! Wtf is that shit?")
return
}
case ".spider":
if Sender != ircOwner {
c.Cmd.Kick(ircHome,Sender,"lol r3kt")
return
}
thyWill := strings.Split(e.Last(), " ")
var thyMark string
if len(thyWill) == 1 {
c.Cmd.ReplyTo(e, girc.Fmt("Usage: !spider #channel"))
return
}
thyMark = thyWill[1]
fmt.Println("[IRC] <"+string(Sender)+"> !spider " + thyMark)
if girc.IsValidChannel(thyMark) {
fmt.Println("[IRC][SPIDER] Joining target " + thyMark)
Phone(c,"Joining " + thyMark)
c.Cmd.Join(thyMark)
return
} else {
fmt.Println("[IRC][SPIDER] Bad scan target! " + thyMark)
Phone(c,"Bad Target! Wtf is that shit?")
return
}
case ".stop":
if Sender == ircOwner {
c.Close()
return
} else {
c.Cmd.Kick(ircHome,Sender,"yeah okay retard")
}
case ".motd":
ircBanner(c)
case ".cowrie":
if (len(thyWill) < 3) {
cowSay(c,"snail","snailyboi","Cowrie is disabled on this instance, but i hope you like this cute snail :)")
return
}
case ".drinkin":
if !contains(drinkin,Sender) {
fmt.Println("[IRC][drinkin] New drinker! " + Sender)
drinkin = append(drinkin, Sender)
} else {
fmt.Println("[IRC][drinkin] Existing drinker " + Sender)
drinkyBoys = strings.Join(drinkin, " ")
drinkyBoys = strings.Replace(drinkyBoys, "nil", "", -1)
drinkyBoys = strings.Replace(drinkyBoys, " ", "", -1)
Phone(c, Sender + " takes another swig ;D")
Phone(c, " 🍺 ------> " + drinkyBoys)
return
}
ircDrinkin(c)
drinkyBoys = strings.Join(drinkin," ")
drinkyBoys = strings.Replace(drinkyBoys, "nil ", "", -1)
drinkyBoys = strings.Replace(drinkyBoys, " ", "", -1)
Phone(c," -------> "+drinkyBoys)
case ".sober":
if contains(drinkin,Sender) {
for i, v := range drinkin {
if v == Sender {
drinkin[i] = "nil"
}
}
}
Phone(c, Sender + soberString())
default:
fmt.Println("[IRC] Unknown bot command issued: " + thyWill[0])
}
}
})
sslString := " "
////logr.Debug("Parsing proxy URI: " + ProxyURI)
//logr.Debug("Validating " + proxyProto + " proxy at host " + proxyHost + " on port " + proxyPort)
if ircSSL == true {
sslString = "-ssl"
}
if proxyProto != "false" {
ProxyUrl, err := url.Parse(proxyProto + "://" + proxyHost + ":" + proxyPort)
if err != nil {
fmt.Println("Proxy URI is malformed!")
panic(err)
}
dialer, _ := proxy.FromURL(ProxyUrl, &net.Dialer{Timeout: 5 * time.Second})
for {
fmt.Println("[IRC] Dialing through a " + proxyProto + " proxy at host " + proxyHost + " on port " + proxyPort)
fmt.Println("[IRC] Connecting to " + ircHost + "/" + strconv.Itoa(ircPort) + " " + sslString)
if err := client.DialerConnect(dialer); err != nil {
fmt.Println("[IRC] Connection error! " + err.Error())
fmt.Println("[IRC] reconnecting...")
time.Sleep(1)
} else {
return
}
}
} else {
for {
fmt.Println("[IRC] Connecting to " + ircHost + "/" + strconv.Itoa(ircPort) + " " + sslString)
if err := client.Connect(); err != nil {
fmt.Println("[IRC] Connection error! " + err.Error())
fmt.Println("[IRC] reconnecting...")
time.Sleep(1)
} else {
return
}
}
}
}

18
main.go Normal file
View File

@ -0,0 +1,18 @@
package main
import "os"
import "fmt"
func init() {
fmt.Println("yeet")
}
func main() {
if (len(os.Args) > 2 && os.Args[1] == "client") {
//fmt.Println("Starting client...")
} else {
conBanner()
ircbot()
}
}

32
util.go Normal file
View File

@ -0,0 +1,32 @@
package main
import "encoding/base64"
import "fmt"
func b64d(str string) string {
data, err := base64.StdEncoding.DecodeString(str)
if err != nil {
return err.Error()
}
return string(data)
}
func conBanner() {
data := "ICAgICAgICAg4paI4paIICAgICAgIOKWiOKWiOKWiOKWiCAgICAgICAgICAg4paI4paIICAg4paI4paIICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg4paR4paI4paIICAgICAg4paI4paR4paR4paR4paI4paIICAgICAgICAg4paR4paI4paIICDilpHilojiloggICAgICAgICAgICAgICAgICAgICAKICDilojilojilojilojilojilojilpHilojiloggICAgIOKWkeKWiCAg4paI4paR4paIIOKWiOKWiOKWiOKWiOKWiOKWiCDilojilojilojilojilojilojilpHilojiloggICAgICDilojiloggICDilojiloggIOKWiOKWiOKWiOKWiOKWiOKWiAog4paI4paI4paR4paR4paR4paRIOKWkeKWiOKWiOKWiOKWiOKWiOKWiCDilpHilogg4paIIOKWkeKWiOKWkeKWkeKWiOKWiOKWkeKWkeKWiOKWkeKWkeKWkeKWiOKWiOKWkSDilpHilojilojilojilojilojilogg4paR4paI4paIICDilpHilojilogg4paI4paI4paR4paR4paR4paRIArilpHilpHilojilojilojilojilogg4paR4paI4paI4paR4paR4paR4paI4paI4paR4paI4paIICDilpHilogg4paR4paI4paIIOKWkSAgIOKWkeKWiOKWiCAg4paR4paI4paI4paR4paR4paR4paI4paI4paR4paI4paIICDilpHilojilojilpHilpHilojilojilojilojiloggCiDilpHilpHilpHilpHilpHilojilojilpHilojiloggIOKWkeKWiOKWiOKWkeKWiCAgIOKWkeKWiCDilpHilojiloggICAgIOKWkeKWiOKWiCAg4paR4paI4paIICDilpHilojilojilpHilojiloggIOKWkeKWiOKWiCDilpHilpHilpHilpHilpHilojilogKIOKWiOKWiOKWiOKWiOKWiOKWiCDilpHilojiloggIOKWkeKWiOKWiOKWkSDilojilojilojilogg4paR4paI4paI4paIICAgICDilpHilpHilojilogg4paR4paI4paI4paI4paI4paI4paIIOKWkeKWkeKWiOKWiOKWiOKWiOKWiOKWiCDilojilojilojilojilojiloggCuKWkeKWkeKWkeKWkeKWkeKWkSAg4paR4paRICAg4paR4paRICDilpHilpHilpHilpEgIOKWkeKWkeKWkSAgICAgICDilpHilpEgIOKWkeKWkeKWkeKWkeKWkSAgICDilpHilpHilpHilpHilpHilpEg4paR4paR4paR4paR4paR4paRICAK"
fmt.Println(b64d(data))
return
}
func contains(s []string, v string) bool {
for _, a := range s {
if a == v {
return true
}
}
return false
}
func printSlice(s []string) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}