<commit_before>package sixpack

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
)

const pattern string = `^[a-z0-9][a-z0-9\-_ ]*$`

var BaseUrl string = "http://localhost:5000"

type Options struct {
	ClientID  []byte
	BaseUrl   *url.URL
	IP        string
	UserAgent string
}

func (opts *Options) Values() url.Values {
	v := url.Values{}

	if opts.IP != "" {
		v.Set("ip_address", opts.IP)
	}

	if opts.UserAgent != "" {
		v.Set("user_agent", opts.UserAgent)
	}

	return v
}

type Alternative struct {
	Name string `json:"name"`
}

type Experiment struct {
	Version int    `json:"version"`
	Name    string `json:"name"`
}

type Response struct {
	Status      string      `json:"status"`
	ClientID    string      `json:"client_id"`
	Alternative Alternative `json:"alternative"`
	Experiment  Experiment  `json:"experiment"`
}

type Session struct {
	Client  *http.Client
	Options *Options
}

func NewSession(opts Options) (*Session, error) {
	if len(opts.ClientID) == 0 {
		id, err := GenerateClientID()
		if err != nil {
			return nil, err
		}
		opts.ClientID = id
	}

	if opts.BaseUrl == nil {
		u, err := url.Parse(BaseUrl)
		if err != nil {
			return nil, err
		}
		opts.BaseUrl = u
	}

	return &Session{Client: &http.Client{}, Options: &opts}, nil
}

func (s *Session) Participate(name string, alternatives []string, force string) (r *Response, err error) {
	rex := regexp.MustCompile(pattern)
	if !rex.MatchString(name) {
		return nil, errors.New("Bad experiment name")<commit_msg>add timeout<commit_after>package sixpack

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"time"
)

const pattern string = `^[a-z0-9][a-z0-9\-_ ]*$`

var BaseUrl string = "http://localhost:5000"

type Options struct {
	ClientID  []byte
	BaseUrl   *url.URL
	IP        string
	UserAgent string
}

func (opts *Options) Values() url.Values {
	v := url.Values{}

	if opts.IP != "" {
		v.Set("ip_address", opts.IP)
	}

	if opts.UserAgent != "" {
		v.Set("user_agent", opts.UserAgent)
	}

	return v
}

type Alternative struct {
	Name string `json:"name"`
}

type Experiment struct {
	Version int    `json:"version"`
	Name    string `json:"name"`
}

type Response struct {
	Status      string      `json:"status"`
	ClientID    string      `json:"client_id"`
	Alternative Alternative `json:"alternative"`
	Experiment  Experiment  `json:"experiment"`
}

type Session struct {
	Client  *http.Client
	Options *Options
}

func NewSession(opts Options) (*Session, error) {
	if len(opts.ClientID) == 0 {
		id, err := GenerateClientID()
		if err != nil {
			return nil, err
		}
		opts.ClientID = id
	}

	if opts.BaseUrl == nil {
		u, err := url.Parse(BaseUrl)
		if err != nil {
			return nil, err
		}
		opts.BaseUrl = u
	}

	timeout := time.Duration(250 * time.Millisecond)
	transport := http.Transport{
		Dial: func(network, addr string) (net.Conn, error) {
			return net.DialTimeout(network, addr, timeout)
		},
	}

	return &Session{
		Client: &http.Client{
			Transport: &transport,
		},
		Options: &opts,
	}, nil
}

func (s *Session) Participate(name string, alternatives []string, force string) (r *Response, err error) {
	rex := regexp.MustCompile(pattern)
	if !rex.MatchString(name) {
		return nil, errors.New("Bad experiment name")
{'fraction_non_alphanumeric': 0.1478787878787879, 'fraction_numerical': 0.006363636363636364, 'mean_word_length': 3.534340659340659, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1157377', 'n_tokens_mistral': 1265, 'n_tokens_neox': 1186, 'n_words': 308}