Best K6 code snippet using log.WriteTo
logger.go
Source:logger.go  
1package logger2import (3	"fmt"4	"io"5	"os"6	"sync"7	"time"8)9// Level is the importance of a logged event10type Level uint811// log message importance12const (13	Debug   Level = iota // passed through without prepending timestamp14	Fatal                // irrecoverable error15	Error                // non-fatal but permanent degradation16	Warning              // temporary degradation or transient IO error or client error17	Info                 // unimportant but noteworthy18	Ignore               // don't print19)20// fatalExitCode is the code Logger will abort the process with if a fatal-level message is printed21const fatalExitCode int = 322// Logger is an utility for thread-safe and periodic logging.23// Use .Log() or one of its wrappers for issues that can be caught as they happen,24// PeriodicLogger for statistics and.25// Use .Compose() to make sure multi-statement messages get written as one.26// Should not be dereferenced or moved as it contains mutexes27type Logger struct {28	writeTo   io.WriteCloser29	writeLock sync.Mutex30	Treshold  Level31	p         periodic32}33// NewLogger creates a new logger with a minimum importance level and the interval to check the periodic loggers34// Even though Logger implements WriteCloser, Loggers should not be nested.35func NewLogger(writeTo io.WriteCloser, treshold Level) *Logger {36	l := &Logger{37		p:         newPeriodic(),38		writeLock: sync.Mutex{},39		writeTo:   writeTo,40		Treshold:  treshold,41	}42	go periodicRunner(l)43	return l44}45// Close the underlying Writer46func (l *Logger) Close() {47	l.writeLock.Lock()48	l.p.Close()49	// Might return an error, but where should the error message be written?50	_ = l.writeTo.Close()51	l.writeTo = nil52	// Dereferencing a nil is better than silently waiting forever on a lock.53	l.writeLock.Unlock()54}55func (l *Logger) prefixMessage(level Level) {56	if l.Treshold < Debug {57		fmt.Fprint(l.writeTo, time.Now().Format("2006-01-02 15:04:05: "))58	}59	if level == Warning {60		fmt.Fprint(l.writeTo, "WARNING: ")61	} else if level == Error {62		fmt.Fprint(l.writeTo, "ERROR: ")63	} else if level == Fatal && l.Treshold != Debug {64		fmt.Fprint(l.writeTo, "FATAL: ")65	}66}67// Compose allows holding the lock between multiple print68func (l *Logger) Compose(level Level) Composer {69	if level > l.Treshold {70		return Composer{71			writeTo:  nil,72			heldLock: nil,73			fatal:    false,74		}75	}76	l.writeLock.Lock()77	l.prefixMessage(level)78	return Composer{79		writeTo:  l.writeTo,80		heldLock: &l.writeLock,81		fatal:    level == Fatal,82	}83}84// Log writes the message if it passes the loggers importance treshold85func (l *Logger) Log(level Level, format string, args ...interface{}) {86	if level <= l.Treshold {87		l.writeLock.Lock()88		defer l.writeLock.Unlock()89		l.prefixMessage(level)90		if len(args) == 0 {91			fmt.Fprintln(l.writeTo, format)92		} else {93			fmt.Fprintf(l.writeTo, format, args...)94			fmt.Fprintln(l.writeTo)95		}96		if level == Fatal {97			os.Exit(fatalExitCode)98		}99	}100}101// WriteAdapter returns a Writer that writes through this logger with the given level.102// Writes that don't end in a newline are buffered to not split messages, but103// Composer-written messages might get split.104// The adapter is not synchronized because both the standard log.Logger and other instances105// of this type serializes writes, and the underlying Logger is synchronized.106func (l *Logger) WriteAdapter(level Level) io.Writer {107	if level > l.Treshold {108		return nil // faster and uses less memory109	}110	return &writeAdapter{111		logger: l,112		level:  level,113	}114}115// Wrappers around Log()116// Debug prints possibly interesting information, and is never filtered.117// Calls to this should probably not be committed.118func (l *Logger) Debug(format string, args ...interface{}) {119	l.Log(Debug, format, args...)120}121// Info prints unimportant but noteworthy events or information122func (l *Logger) Info(format string, args ...interface{}) {123	l.Log(Info, format, args...)124}125// Warning prints an error that might be recovered from126func (l *Logger) Warning(format string, args ...interface{}) {127	l.Log(Warning, format, args...)128}129// Error prints a non-fatal but permanent error130func (l *Logger) Error(format string, args ...interface{}) {131	l.Log(Error, format, args...)132}133// Fatal prints an error message and exits the program134func (l *Logger) Fatal(format string, args ...interface{}) {135	l.Log(Fatal, format, args...)136}137// FatalIf does nothing if cond is false, but otherwise prints the message and aborts the process.138func (l *Logger) FatalIf(cond bool, format string, args ...interface{}) {139	if cond {140		l.Fatal(format, args...)141	}142}143// FatalIfErr does nothing if err is nil, but otherwise prints "Failed to <..>: $err.Error()" and aborts the process.144func (l *Logger) FatalIfErr(err error, format string, args ...interface{}) {145	if err != nil {146		args = append(args, err.Error())147		l.Fatal("Failed to "+format+": %s", args...)148	}149}150// Composer lets you split a long message into multiple write statements151// End the message by calling Finish() or Close()152type Composer struct {153	fatal    bool154	writeTo  io.Writer // nil if level is ignored155	heldLock *sync.Mutex156}157// Write writes formatted text without a newline158func (c *Composer) Write(format string, args ...interface{}) {159	if c.writeTo != nil {160		if len(args) == 0 {161			fmt.Fprint(c.writeTo, format)162		} else {163			fmt.Fprintf(c.writeTo, format, args...)164		}165	}166}167// Writeln writes a formatted string plus a newline.168// This is identical to what Logger.Log() does.169func (c *Composer) Writeln(format string, args ...interface{}) {170	if c.writeTo != nil {171		if len(args) == 0 {172			fmt.Fprintln(c.writeTo, format)173		} else {174			fmt.Fprintf(c.writeTo, format, args...)175			fmt.Fprintln(c.writeTo)176		}177	}178}179// Finish writes a formatted line and then closes the composer.180func (c *Composer) Finish(format string, args ...interface{}) {181	c.Writeln(format, args...)182	c.Close()183}184// Close releases the mutex on the logger and exits the process for `Fatal` errors.185func (c *Composer) Close() {186	if c.writeTo != nil {187		c.heldLock.Unlock()188		c.writeTo = nil189		if c.fatal {190			os.Exit(fatalExitCode)191		}192	}193}194// See documentation on WriteAdapter195type writeAdapter struct {196	logger *Logger197	buf    []byte198	level  Level199}200// Always returns len(message), nil201func (wa *writeAdapter) Write(message []byte) (int, error) {202	if len(message) > 0 {203		wa.buf = append(wa.buf, message...)204		if wa.buf[len(wa.buf)-1] == byte('\n') { // flush it205			noTrailingNewline := wa.buf[:len(wa.buf)-1] // Log appends a newline206			wa.logger.Log(wa.level, "%s", string(noTrailingNewline))207			wa.buf = []byte{} // restart208		}209	}210	return len(message), nil211}...loginfo_model.go
Source:loginfo_model.go  
1package log2import (3	"bytes"4	"fmt"5	"io"6	"os"7	"runtime"8	"strconv"9)10const delim = ": "11// helpers for constructor12const (13	// NONE no logging14	NONE = 015	// INFO level16	INFO = 117	// WARN level18	WARN = 219	// DEBUG level20	DEBUG = 321)22var logLevels = []string{"NONE", "INFO", "WARN", "DEBUG"}23type Logger struct {24	logLevel int25	writeTo  io.Writer26	// for shorter form in case do not need caller file.27	withCaller bool28}29// New Constructor with levels 0 - no logging, 1 - info, 2 - warn, 3 - debug.30func NewLogger(level int, writeTo io.Writer, withCaller bool) *Logger {31	lev := convertLevel(level)32	if writeTo == nil {33		writeTo = os.Stdout34	}35	res := Logger{36		logLevel:   lev,37		writeTo:    writeTo,38		withCaller: withCaller,39	}40	res.Printf("Created logger, level %v.", logLevels[lev])41	return &res42}43func (i *Logger) Print(args ...interface{}) {44	buf := bufPool.Get().(*bytes.Buffer)45	buf.Reset()46	buf.WriteString(timestamp() + " " + fmt.Sprint(args...) + "\n")47	i.writeTo.Write(buf.Bytes())48	bufPool.Put(buf)49}50func (i *Logger) Printf(format string, args ...interface{}) {51	buf := bufPool.Get().(*bytes.Buffer)52	buf.Reset()53	buf.WriteString(timestamp() + " " + fmt.Sprintf(format, args...) + "\n")54	i.writeTo.Write(buf.Bytes())55	bufPool.Put(buf)56}57func (i *Logger) Info(args ...interface{}) {58	if i.logLevel == 0 {59		return60	}61	buf := bufPool.Get().(*bytes.Buffer)62	defer bufPool.Put(buf)63	buf.Reset()64	if i.withCaller {65		_, file, line, _ := runtime.Caller(1)66		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + logLevels[1] + delim + fmt.Sprint(args...) + "\n")67		i.writeTo.Write(buf.Bytes())68		return69	}70	buf.WriteString(timestamp() + " " + logLevels[1] + delim + fmt.Sprint(args...) + "\n")71	i.writeTo.Write(buf.Bytes())72}73func (i *Logger) Infof(format string, args ...interface{}) {74	if i.logLevel == 0 {75		return76	}77	buf := bufPool.Get().(*bytes.Buffer)78	defer bufPool.Put(buf)79	buf.Reset()80	if i.withCaller {81		_, file, line, _ := runtime.Caller(1)82		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + logLevels[1] + delim + fmt.Sprintf(format, args...) + "\n")83		i.writeTo.Write(buf.Bytes())84		return85	}86	buf.WriteString(timestamp() + " " + logLevels[1] + delim + fmt.Sprintf(format, args...) + "\n")87	i.writeTo.Write(buf.Bytes())88}89func (i *Logger) Warn(args ...interface{}) {90	if i.logLevel < 2 {91		return92	}93	buf := bufPool.Get().(*bytes.Buffer)94	defer bufPool.Put(buf)95	buf.Reset()96	if i.withCaller {97		_, file, line, _ := runtime.Caller(1)98		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + colorWarn()(logLevels[2]) + delim + fmt.Sprint(args...) + "\n")99		i.writeTo.Write(buf.Bytes())100		return101	}102	buf.WriteString(timestamp() + " " + colorWarn()(logLevels[2]) + delim + fmt.Sprint(args...) + "\n")103	i.writeTo.Write(buf.Bytes())104}105func (i *Logger) Warnf(format string, args ...interface{}) {106	if i.logLevel < 2 {107		return108	}109	buf := bufPool.Get().(*bytes.Buffer)110	defer bufPool.Put(buf)111	buf.Reset()112	if i.withCaller {113		_, file, line, _ := runtime.Caller(1)114		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + colorWarn()(logLevels[2]) + delim + fmt.Sprintf(format, args...) + "\n")115		i.writeTo.Write(buf.Bytes())116		return117	}118	buf.WriteString(timestamp() + " " + colorWarn()(logLevels[2]) + delim + fmt.Sprintf(format, args...) + "\n")119	i.writeTo.Write(buf.Bytes())120}121func (i *Logger) Debug(args ...interface{}) {122	if i.logLevel < 3 {123		return124	}125	buf := bufPool.Get().(*bytes.Buffer)126	defer bufPool.Put(buf)127	buf.Reset()128	if i.withCaller {129		_, file, line, _ := runtime.Caller(1)130		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + colorDebug()(logLevels[3]) + delim + fmt.Sprint(args...) + "\n")131		i.writeTo.Write(buf.Bytes())132		return133	}134	buf.WriteString(timestamp() + " " + colorDebug()(logLevels[3]) + delim + fmt.Sprint(args...) + "\n")135	i.writeTo.Write(buf.Bytes())136}137func (i *Logger) Debugf(format string, args ...interface{}) {138	if i.logLevel < 3 {139		return140	}141	buf := bufPool.Get().(*bytes.Buffer)142	defer bufPool.Put(buf)143	buf.Reset()144	if i.withCaller {145		_, file, line, _ := runtime.Caller(1)146		buf.WriteString(timestamp() + " " + file + " Line" + delim + strconv.FormatInt(int64(line), 10) + " " + colorDebug()(logLevels[3]) + delim + fmt.Sprintf(format, args...) + "\n")147		i.writeTo.Write(buf.Bytes())148		return149	}150	buf.WriteString(timestamp() + " " + colorDebug()(logLevels[3]) + delim + fmt.Sprintf(format, args...) + "\n")151	i.writeTo.Write(buf.Bytes())152}153func (i *Logger) Fatal(args ...interface{}) {154	i.Print(args...)155	os.Exit(1)156}157func (i *Logger) GetLogLevel() int {158	return i.logLevel159}160func (i *Logger) SetLogLevel(level int) {161	i.logLevel = level162}...model.go
Source:model.go  
1package logs2import (3	"bufio"4	"fmt"5	"os"6)7/*8æ¥å¿æ¥å£9*/10type Logs interface {11	DeBug(logMsg error)12	Trace(logMsg error)13	Info(logMsg error)14	Warring(logmsg error)15	Error(logMsg error)16	Fatal(logMsg error)	17}18/*19æ¥å¿æä»¶20*/21type FileLog struct {22	Logpath string `json:logpath`23}24/*25ç»ç«¯æ¥å¿26*/27type ConsoleLog struct {28}29/*30å®ä¹ç»ç«¯æ¥å¿åæä»¶æ¥å¿ç常é31*/32const (33	CONSOLE = iota34	FILE35)36/*37è¿åä¸ä¸ªæ¥å£38*/39func NewLogger(style int, path string) Logs {40	switch style {41	case CONSOLE:42		var logs Logs43		consolelog := newConsoleLog()44		logs = consolelog45		return logs46	case FILE:47		var logs Logs48		if path == "" {49			path = "/var/log/TennetlDB.log"50		}51		fileLog := newFileLog(path)52		logs = fileLog53		return logs54	default:55		return nil56	}57}58/*59å建ä¸ä¸ªæä»¶æ¥å¿60*/61func newFileLog(path string) *FileLog {62	return &FileLog{63		Logpath: path,64	}65}66/*67å建ä¸ä¸ªç»ç«¯æ¥å¿68*/69func newConsoleLog() *ConsoleLog {70	return &ConsoleLog{}71}72func (flog *FileLog)writeTo(level int,logMsg error){73	timeStr := logtime()74	file, err := os.OpenFile(flog.Logpath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)75	if err != nil {76		return77	}78	writer := bufio.NewWriter(file)79	levelstr := getLevel(level)80	str := fmt.Sprintf("%s: [%s] -%v\n", timeStr, levelstr, logMsg)81	_,err = writer.Write([]byte(str))82	if err !=nil {83		return84	}85	err = writer.Flush()86	if err != nil {87		return88	}89	defer file.Close()90}91/*92filelog 93*/94func (flog *FileLog)DeBug(errMsg error) {95	flog.writeTo(DEBUG,errMsg)96}97func (flog *FileLog)Trace(errMsg error){98	flog.writeTo(TRACE,errMsg)99}100func (flog *FileLog)Info(errMgs error){101	flog.writeTo(INFO,errMgs)102}103func (flog *FileLog)Warring(errMsg error){104	flog.writeTo(WARRING,errMsg)105}106func (flog *FileLog)Error(errMsg error){107	flog.writeTo(ERROR,errMsg)108}109func (flog *FileLog)Fatal(errMsg error) {110	flog.writeTo(FATAL,errMsg)		111}112/*consloelog*/113func (clog *ConsoleLog)DeBug(errMsg error){114	clog.writeTo(DEBUG,errMsg)115}116func (clog *ConsoleLog)Trace(errMsg error){117	clog.writeTo(TRACE,errMsg)118}119func (clog *ConsoleLog)Info(errMsg error){120	clog.writeTo(TRACE,errMsg)121}122func (clog *ConsoleLog)Warring(errMsg error){123	clog.writeTo(WARRING,errMsg)124}125func (clog *ConsoleLog)Error(errMsg error){126	clog.writeTo(ERROR,errMsg)127}128func (clog *ConsoleLog)Fatal(errMgs error){129	clog.writeTo(FATAL,errMgs)130}131/*132ç»ç«¯æ¥å¿æå°133*/134func (clog *ConsoleLog)writeTo(level int,errMsg error){135	timeStr := logtime()136	levelstr := getLevel(level)137	fmt.Fprintf(os.Stdout, "%s: [%s] -%v\n", timeStr, levelstr, errMsg)138}...WriteTo
Using AI Code Generation
1import (2func main() {3    f, err := os.OpenFile("test.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)4    if err != nil {5        log.Fatalf("error opening file: %v", err)6    }7    defer f.Close()8    log.SetOutput(f)9    log.Println("This is a test log entry")10}11import (12func main() {13    f, err := os.OpenFile("test.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)14    if err != nil {15        log.Fatalf("error opening file: %v", err)16    }17    defer f.Close()18    log.SetOutput(f)19    log.Println("This is a test log entry")20}21import (22func main() {23    f, err := os.OpenFile("test.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)24    if err != nil {25        log.Fatalf("error opening file: %v", err)26    }27    defer f.Close()28    log.SetOutput(f)29    log.Println("This is a test log entry")30}31import (32func main() {33    f, err := os.OpenFile("test.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)34    if err != nil {35        log.Fatalf("error opening file: %v", err)36    }37    defer f.Close()38    log.SetOutput(f)39    log.Println("This is a test log entry")40}41import (42func main() {43    f, err := os.OpenFile("test.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)44    if err != nil {45        log.Fatalf("error opening file: %v", err)WriteTo
Using AI Code Generation
1import (2func main() {3	f, err := os.Create("test.txt")4	if err != nil {5		log.Fatal(err)6	}7	defer f.Close()8	log.SetOutput(f)9	log.Println("This is a test log entry")10}WriteTo
Using AI Code Generation
1import (2func main() {3	file, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)4	if err != nil {5		log.Fatalln("Failed to open log file:", err)6	}7	defer file.Close()8	logger := log.New(file, "logger: ", log.Lshortfile)9	logger.Println("This is a regular message.")10	logger.Fatalln("This is a fatal error.")11}12import (13func main() {14	file, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)15	if err != nil {16		log.Fatalln("Failed to open log file:", err)17	}18	defer file.Close()19	log.SetOutput(file)20	log.Println("This is a regular message.")21	log.Fatalln("This is a fatal error.")22}23import (24func main() {25	log.SetFlags(log.Lshortfile)26	log.Println("This is a regular message.")27	log.Fatalln("This is a fatal error.")28}29import (30func main() {31	log.SetPrefix("logger: ")32	log.Println("This is a regular message.")33	log.Fatalln("This is a fatal error.")34}WriteTo
Using AI Code Generation
1import (2func main() {3	logfile, err := os.Create("logfile.txt")4	if err != nil {5		log.Fatal(err)6	}7	defer logfile.Close()8	log.SetOutput(logfile)9	log.Println("This is a test log entry")10}WriteTo
Using AI Code Generation
1import (2func main() {3	f, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY, 0666)4	if err != nil {5		log.Fatalln("failed to open file: ", err)6	}7	defer f.Close()8	log.SetOutput(f)9	log.Println("This is a regular message")10	log.Fatalln("This is a fatal message")11}12import (13func main() {14	f, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY, 0666)15	if err != nil {16		log.Fatalln("failed to open file: ", err)17	}18	defer f.Close()19	log.SetOutput(f)20	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)21	log.Println("This is a regular message")22	log.Fatalln("This is a fatal message")23}24import (25func main() {26	f, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY, 0666)27	if err != nil {28		log.Fatalln("failed to open file: ", err)29	}30	defer f.Close()31	log.SetOutput(f)32	log.SetPrefix("TRACE: ")33	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)34	log.Println("This is a regular message")35	log.Fatalln("This is a fatal message")36}37import (38func main() {39	log.Panicln("This is a panic message")40}41import (42func main() {43	log.Panicf("Hello, %s", name)44}45import (46func main() {47	log.Panic("This is a panic message")48}WriteTo
Using AI Code Generation
1import (2func main() {3	log.SetOutput(os.Stdout)4	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)5	log.Println("This is a log message")6}7import (8func main() {9	log.SetOutput(os.Stdout)10	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)11	log.Println("This is a log message")12}13How to use log.Fatal() in Go?14How to use log.Panic() in Go?WriteTo
Using AI Code Generation
1import (2func main() {3	log.SetOutput(os.Stdout)4	log.Println("This is a standard message")5	log.Fatalln("This is a fatal message")6	log.Panicln("This is a panic message")7}8log.Panicln(0xc20800a030, 0x1, 0x1)9main.main()WriteTo
Using AI Code Generation
1import (2func main() {3	log.SetOutput(os.Stdout)4	log.SetFlags(log.LstdFlags | log.Lshortfile)5	log.Println("This is a test log entry")6	file, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)7	if err == nil {8		log.SetOutput(file)9	} else {10		log.Fatalln("failed to open test.log file for writing")11	}12	log.Println("This is a test log entry")13	log.SetOutput(os.Stdout)14	log.Println("This is a test log entry")15}16func (l *Logger) ReadFrom(r io.Reader) (n int64, err error)17import (18func main() {19	log.SetOutput(os.Stdout)20	log.SetFlags(log.LstdFlags | log.Lshortfile)21	log.Println("This is a test log entry")22	file, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)23	if err == nil {24		log.SetOutput(file)WriteTo
Using AI Code Generation
1import (2func main() {3	log.SetFlags(0)4	log.SetOutput(os.Stdout)5	log.Println("Hello World")6}7import (8func main() {9	log.SetFlags(0)10	log.SetOutput(os.Stdout)11	log.Println("Hello World")12}13import (14func main() {15	log.SetFlags(0)16	log.SetOutput(os.Stdout)17	log.Println("Hello World")18}19import (20func main() {21	log.SetFlags(0)22	log.SetOutput(os.Stdout)23	log.SetPrefix("Log: ")24	log.Println("Hello World")25}26import (27func main() {28	log.SetFlags(0)29	log.SetOutput(os.Stdout)30	log.SetPrefix("Log: ")31	log.Fatal("Hello World")32}33import (34func main() {35	log.SetFlags(0)36	log.SetOutput(os.Stdout)37	log.SetPrefix("Log: ")38	log.Panic("Hello World")39}40log.Panic(0xc4200b1f78, 0x1, 0x1)Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
