<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

const url string = "https://%s/api/v1/incidents?since=%sT00%%3A00%%3A00SGT&until=%sT23%%3A59%%3A59SGT&time_zone=%s&offset=%d"

type IncidentsResponse struct {
	Incidents []Incident `json:"incidents"`
	Limit     int        `json:"limit"`
	Offset    int        `json:"offset"`
	Total     int        `json:"total"`
}

type Incident struct {
	ID             string        `json:"id"`
	IncidentNumber int           `json:"incident_number"`
	CreatedOn      time.Time     `json:"created_on"`
	Status         string        `json:"status"`
	PendingActions []interface{} `json:"pending_actions"`
	HTMLURL        string        `json:"html_url"`
	IncidentKey    string        `json:"incident_key"`
	Service        struct {
		ID          string      `json:"id"`
		Name        string      `json:"name"`
		HTMLURL     string      `json:"html_url"`
		DeletedAt   interface{} `json:"deleted_at"`
		Description string      `json:"description"`
	} `json:"service"`
	EscalationPolicy struct {
		ID        string      `json:"id"`
		Name      string      `json:"name"`
		DeletedAt interface{} `json:"deleted_at"`
	} `json:"escalation_policy"`
	AssignedToUser     interface{} `json:"assigned_to_user"`
	TriggerSummaryData struct {
		Description string `json:"description"`
	} `json:"trigger_summary_data"`
	TriggerDetailsHTMLURL string        `json:"trigger_details_html_url"`
	TriggerType           string        `json:"trigger_type"`
	LastStatusChangeOn    time.Time     `json:"last_status_change_on"`
	LastStatusChangeBy    interface{}   `json:"last_status_change_by"`
	NumberOfEscalations   int           `json:"number_of_escalations"`
	ResolvedByUser        interface{}   `json:"resolved_by_user,omitempty"`
	AssignedTo            []interface{} `json:"assigned_to"`
	Urgency               string        `json:"urgency"`
	Acknowledgers         []struct {
		At     time.Time `json:"at"`
		Object struct {
			ID      string `json:"id"`
			Name    string `json:"name"`
			Email   string `json:"email"`
			HTMLURL string `json:"html_url"`
			Type    string `json:"type"`
		} `json:"object"`
	} `json:"acknowledgers,omitempty"`
}

func writeIncident(key string, incident Incident) {
	status := incident.Status
	resolution := incident.ResolvedByUser
	if status == "resolved" {
		if resolution == nil {
			resolution = "API"
		} else {
			resolution = fmt.Sprintf("resolved by: %s", incident.ResolvedByUser)
		}
	} else if status == "acknowledged" {
		var buffer bytes.Buffer
		//just print the first Acknowledger
		buffer.WriteString(fmt.Sprintf("%s - %s", incident.Acknowledgers[0].Object.Name, incident.Acknowledgers[0].At))
		resolution = buffer.String()
	} else if status == "triggered" {
		resolution = "open"
	}

	fmt.Printf("%s,%d,%s,%s,%s,%s,%s\n", key, incident.IncidentNumber, incident.TriggerSummaryData.Description, incident.CreatedOn, incident.LastStatusChangeOn, status, resolution)
}

func callApi(endpoint string, timeZone string, token string, startDate string, endDate string, offset int, respStruct *IncidentsResponse) {
	url := fmt.Sprintf(url, endpoint, startDate, endDate, timeZone, offset)
	client := &http.Client{}
	req, _ := http.NewRequest("GET", url, nil)

    tk := fmt.Sprintf("Token token=%s",  token)
    fmt.Printf("Token: ", tk)

	req.Header.Set("Authorization", tk)

	fmt.Println("about to call API with url:", url)
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Err: %s", err)
		os.Exit(-1)

	}

	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(contents, respStruct)

	if err != nil {
		panic(err)
	}

	//fmt.Printf("myVariable = %#v \n", respStruct)

}

//usage: ./pdreport -endpoint <<your org's pd endpoint>> -tz <<your time zone>> -token <<yourAPI Token>> -since=2016-04-28 -until=2016-04-28
func main() {

	endpoint := flag.String("endpoint", "", "pagerduty endpoint for your organization")
	timeZone := flag.String("tz", "", "tz db timezone e.g: Singapore")
	token := flag.String("token", "", "PD assigned API token")
	startDate := flag.String("since", "", "date in format: 2016-04-27")
	endDate := flag.String("until", "", "date in format: 2016-04-27")
	flag.Parse()
	fmt.Printf("Called with params: since:%s until:%s", *startDate, *endDate)

	respStruct := new(IncidentsResponse)
	groupedByServiceMap := make(map[string][]Incident)
	offset := 0
	callcount := 1

	//API call paginates so call repeatedly until there are no items left
	for {
		fmt.Println("Starting call: ", callcount)
		callApi(*endpoint, *timeZone, *token, *startDate, *endDate, offset, respStruct)
		if len(respStruct.Incidents) == 0 {
			fmt.Println("No more items.")
			break
		}
		for _, incident := range respStruct.Incidents {
			arr, present := groupedByServiceMap[incident.Service.Name]
			if !present {
				groupedByServiceMap[incident.Service.Name] = make([]Incident, 1)
			}
			newslice := append(arr, incident)
			groupedByServiceMap[incident.Service.Name] = newslice
		}
		//fmt.Println("offset:", respStruct.Offset)
		if respStruct.Total <= respStruct.Limit {
			break
		}
		if offset == 0 {
			offset = respStruct.Limit
		} else {
			offset = respStruct.Offset + len(respStruct.Incidents)
		}
		fmt.Println("finished call: ", callcount)
		callcount++
	}

	for key, valarr := range groupedByServiceMap {
		//fmt.Printf("%#v->\n", key)
		fmt.Printf("Category %s: count: %d\n", string(key), len(groupedByServiceMap[key]))
		for _, incident := range valarr {
			writeIncident(key, incident)
			//fmt.Printf("%#v \n", incident)
			//fmt.Printf("%#v \n", incident)
		}
	}
	//fmt.Printf("map = %#v \n", groupedByServiceMap)
	//fmt.Printf("map = %#v \n", groupedByServiceMap)
}
<commit_msg>fixed logging<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

const url string = "https://%s/api/v1/incidents?since=%sT00%%3A00%%3A00SGT&until=%sT23%%3A59%%3A59SGT&time_zone=%s&offset=%d"

type IncidentsResponse struct {
	Incidents []Incident `json:"incidents"`
	Limit     int        `json:"limit"`
	Offset    int        `json:"offset"`
	Total     int        `json:"total"`
}

type Incident struct {
	ID             string        `json:"id"`
	IncidentNumber int           `json:"incident_number"`
	CreatedOn      time.Time     `json:"created_on"`
	Status         string        `json:"status"`
	PendingActions []interface{} `json:"pending_actions"`
	HTMLURL        string        `json:"html_url"`
	IncidentKey    string        `json:"incident_key"`
	Service        struct {
		ID          string      `json:"id"`
		Name        string      `json:"name"`
		HTMLURL     string      `json:"html_url"`
		DeletedAt   interface{} `json:"deleted_at"`
		Description string      `json:"description"`
	} `json:"service"`
	EscalationPolicy struct {
		ID        string      `json:"id"`
		Name      string      `json:"name"`
		DeletedAt interface{} `json:"deleted_at"`
	} `json:"escalation_policy"`
	AssignedToUser     interface{} `json:"assigned_to_user"`
	TriggerSummaryData struct {
		Description string `json:"description"`
	} `json:"trigger_summary_data"`
	TriggerDetailsHTMLURL string        `json:"trigger_details_html_url"`
	TriggerType           string        `json:"trigger_type"`
	LastStatusChangeOn    time.Time     `json:"last_status_change_on"`
	LastStatusChangeBy    interface{}   `json:"last_status_change_by"`
	NumberOfEscalations   int           `json:"number_of_escalations"`
	ResolvedByUser        interface{}   `json:"resolved_by_user,omitempty"`
	AssignedTo            []interface{} `json:"assigned_to"`
	Urgency               string        `json:"urgency"`
	Acknowledgers         []struct {
		At     time.Time `json:"at"`
		Object struct {
			ID      string `json:"id"`
			Name    string `json:"name"`
			Email   string `json:"email"`
			HTMLURL string `json:"html_url"`
			Type    string `json:"type"`
		} `json:"object"`
	} `json:"acknowledgers,omitempty"`
}

func writeIncident(key string, incident Incident) {
	status := incident.Status
	resolution := incident.ResolvedByUser
	if status == "resolved" {
		if resolution == nil {
			resolution = "API"
		} else {
			resolution = fmt.Sprintf("resolved by: %s", incident.ResolvedByUser)
		}
	} else if status == "acknowledged" {
		var buffer bytes.Buffer
		//just print the first Acknowledger
		buffer.WriteString(fmt.Sprintf("%s - %s", incident.Acknowledgers[0].Object.Name, incident.Acknowledgers[0].At))
		resolution = buffer.String()
	} else if status == "triggered" {
		resolution = "open"
	}

	fmt.Printf("%s,%d,%s,%s,%s,%s,%s\n", key, incident.IncidentNumber, incident.TriggerSummaryData.Description, incident.CreatedOn, incident.LastStatusChangeOn, status, resolution)
}

func callApi(endpoint string, timeZone string, token string, startDate string, endDate string, offset int, respStruct *IncidentsResponse) {
	url := fmt.Sprintf(url, endpoint, startDate, endDate, timeZone, offset)
	client := &http.Client{}
	req, _ := http.NewRequest("GET", url, nil)

    tk := fmt.Sprintf("Token token=%s",  token)
    fmt.Printf("Token: ", tk)

	req.Header.Set("Authorization", tk)

	fmt.Println("about to call API with url:", url)
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("Err: %s", err)
		os.Exit(-1)

	}

	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(contents, respStruct)

	if err != nil {
		panic(err)
	}

	//fmt.Printf("myVariable = %#v \n", respStruct)

}

//usage: ./pdreport -endpoint <<your org's pd endpoint>> -tz <<your time zone>> -token <<yourAPI Token>> -since=2016-04-28 -until=2016-04-28
func main() {

	endpoint := flag.String("endpoint", "", "pagerduty endpoint for your organization")
	timeZone := flag.String("tz", "", "tz db timezone e.g: Singapore")
	token := flag.String("token", "", "PD assigned API token")
	startDate := flag.String("since", "", "date in format: 2016-04-27")
	endDate := flag.String("until", "", "date in format: 2016-04-27")
	flag.Parse()
	fmt.Printf("Called with params: endpoint: %s tz: %s token: %s, since:%s until:%s\n", *endpoint, *timeZone, *token, *startDate, *endDate)

	respStruct := new(IncidentsResponse)
	groupedByServiceMap := make(map[string][]Incident)
	offset := 0
	callcount := 1

	//API call paginates so call repeatedly until there are no items left
	for {
		fmt.Println("Starting call: ", callcount)
		callApi(*endpoint, *timeZone, *token, *startDate, *endDate, offset, respStruct)
		if len(respStruct.Incidents) == 0 {
			fmt.Println("No more items.")
			break
		}
		for _, incident := range respStruct.Incidents {
			arr, present := groupedByServiceMap[incident.Service.Name]
			if !present {
				groupedByServiceMap[incident.Service.Name] = make([]Incident, 1)
			}
			newslice := append(arr, incident)
			groupedByServiceMap[incident.Service.Name] = newslice
		}
		//fmt.Println("offset:", respStruct.Offset)
		if respStruct.Total <= respStruct.Limit {
			break
		}
		if offset == 0 {
			offset = respStruct.Limit
		} else {
			offset = respStruct.Offset + len(respStruct.Incidents)
		}
		fmt.Println("finished call: ", callcount)
		callcount++
	}

	for key, valarr := range groupedByServiceMap {
		//fmt.Printf("%#v->\n", key)
		fmt.Printf("Category %s: count: %d\n", string(key), len(groupedByServiceMap[key]))
		for _, incident := range valarr {
			writeIncident(key, incident)
			//fmt.Printf("%#v \n", incident)
			//fmt.Printf("%#v \n", incident)
		}
	}
	//fmt.Printf("map = %#v \n", groupedByServiceMap)
	//fmt.Printf("map = %#v \n", groupedByServiceMap)
}
<|endoftext|>


<commit_before>package match

var UseSse41 bool
var UseSse42 bool

// Match4 will return start indeces of all matches of a 4 byte needle
// in a haystack that is a multiple of 16 in length.
// Indeces are returned ordered from index 0 and upwards.
func Match4(needle, haystack []byte, indices []int) []int {
	if len(needle) != 4 {
		panic("length not 4")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint16, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find4(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&1 == 1 {
				indices = append(indices, i*16+j)
			}
			v >>= 1
			j++
		}
	}
	return indices
}

// Match4String performs the same operation as Match4 on strings
func Match4String(needle, haystack string, indices []int) []int {
	if len(needle) != 4 {
		panic("length not 4")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint16, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find4string(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&1 == 1 {
				indices = append(indices, i*16+j)
			}
			v >>= 1
			j++
		}
	}
	return indices
}

func find4(needle, haystack []byte, dst []uint16) {
	if UseSse41 {
		find4SSE4(needle, haystack, dst)
		return
	}
	find4Go(needle, haystack, dst)
}

func find4string(needle, haystack string, dst []uint16) {
	if UseSse41 {
		find4SSE4s(needle, haystack, dst)
		return
	}
	find4Go([]byte(needle), []byte(haystack), dst)
}

// find4Go is the reference implementation that mimmics the SSE4
// implemenation.
func find4Go(needle, haystack []byte, dst []uint16) {
	end := uint(len(haystack) - 3)
	for i := uint(0); i < end; i++ {
		if needle[0] == haystack[i] {
			if needle[1] == haystack[i+1] && needle[2] == haystack[i+2] && needle[3] == haystack[i+3] {
				dst[i>>4] |= 1 << (i & 15)
			}
		}
	}
}

// Match8 will return start indeces of all matches of a 8 byte needle
// in a haystack that is a multiple of 16 in length.
// Indeces are returned ordered from index 0 and upwards.
func Match8(needle, haystack []byte, indices []int) []int {
	if len(needle) != 8 {
		panic("length not 8")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint32, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find8(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&3 == 3 {
				indices = append(indices, i*16+j)
			}
			v >>= 2
			j++
		}
	}
	return indices
}

// Match4And8 will return start indeces of all matches of a 8 byte needle
// in a haystack that is a multiple of 16 in length.
// Matches for the first four bytes are returned in the first index, and 8
// byte matches are returned in the second. An index that is an 8 byte match will
// not be present in the 4-byte matches.
// Indeces are returned ordered from index 0 and upwards.
func Match8And4(needle, haystack []byte, indices8 []int, indices4 []int) ([]int, []int) {
	if len(needle) != 8 {
		panic("length not 8")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint32, len(haystack)/16)
	if indices8 == nil {
		indices8 = make([]int, 0, 10)
	} else {
		indices8 = indices8[:0]
	}
	if indices4 == nil {
		indices4 = make([]int, 0, 10)
	} else {
		indices4 = indices4[:0]
	}
	find8(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&3 == 3 {
				indices8 = append(indices8, i*16+j)
			} else if v&1 == 1 {
				indices4 = append(indices4, i*16+j)
			}
			v >>= 2
			j++
		}
	}
	return indices8, indices4
}

func find8(needle, haystack []byte, dst []uint32) {
	if UseSse41 {
		find8SSE4(needle, haystack, dst)
		return
	}
	find8Go(needle, haystack, dst)
}

// find8Go is the reference implementation that mimmics the SSE4
// implemenation.
func find8Go(needle, haystack []byte, dst []uint32) {
	end := uint(len(haystack) - 7)
	for i := uint(0); i < end; i++ {
		if needle[0] == haystack[i] && needle[1] == haystack[i+1] && needle[2] == haystack[i+2] && needle[3] == haystack[i+3] {
			dst[i>>4] |= 1 << ((i & 15) << 1)
		}
		if needle[4] == haystack[i+4] && needle[5] == haystack[i+5] && needle[6] == haystack[i+6] && needle[7] == haystack[i+7] {
			dst[i>>4] |= 2 << ((i & 15) << 1)
		}
	}
}

var MatchLen func([]byte, []byte, int) int

func init() {
	MatchLen = matchLenSSE4
}

func matchLen(a, b []byte, max int) int {
	/*	if len(a) < max {
			panic("a too short")
		}
		if len(b) < max {
			panic("a too short")
		}
		if UseSse42 {
			return matchLenSSE4(a, b, max)
		}*/
	a = a[:max]
	b = b[:max]
	for i, av := range a {
		if b[i] != av {
			return i
		}
	}
	return max
}
<commit_msg>Use SSE 4.2 detection for MatchLen.<commit_after>package match

var UseSse41 bool
var UseSse42 bool

// Match4 will return start indeces of all matches of a 4 byte needle
// in a haystack that is a multiple of 16 in length.
// Indeces are returned ordered from index 0 and upwards.
func Match4(needle, haystack []byte, indices []int) []int {
	if len(needle) != 4 {
		panic("length not 4")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint16, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find4(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&1 == 1 {
				indices = append(indices, i*16+j)
			}
			v >>= 1
			j++
		}
	}
	return indices
}

// Match4String performs the same operation as Match4 on strings
func Match4String(needle, haystack string, indices []int) []int {
	if len(needle) != 4 {
		panic("length not 4")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint16, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find4string(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&1 == 1 {
				indices = append(indices, i*16+j)
			}
			v >>= 1
			j++
		}
	}
	return indices
}

func find4(needle, haystack []byte, dst []uint16) {
	if UseSse41 {
		find4SSE4(needle, haystack, dst)
		return
	}
	find4Go(needle, haystack, dst)
}

func find4string(needle, haystack string, dst []uint16) {
	if UseSse41 {
		find4SSE4s(needle, haystack, dst)
		return
	}
	find4Go([]byte(needle), []byte(haystack), dst)
}

// find4Go is the reference implementation that mimmics the SSE4
// implemenation.
func find4Go(needle, haystack []byte, dst []uint16) {
	end := uint(len(haystack) - 3)
	for i := uint(0); i < end; i++ {
		if needle[0] == haystack[i] {
			if needle[1] == haystack[i+1] && needle[2] == haystack[i+2] && needle[3] == haystack[i+3] {
				dst[i>>4] |= 1 << (i & 15)
			}
		}
	}
}

// Match8 will return start indeces of all matches of a 8 byte needle
// in a haystack that is a multiple of 16 in length.
// Indeces are returned ordered from index 0 and upwards.
func Match8(needle, haystack []byte, indices []int) []int {
	if len(needle) != 8 {
		panic("length not 8")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint32, len(haystack)/16)
	if indices == nil {
		indices = make([]int, 0, 10)
	}
	find8(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&3 == 3 {
				indices = append(indices, i*16+j)
			}
			v >>= 2
			j++
		}
	}
	return indices
}

// Match4And8 will return start indeces of all matches of a 8 byte needle
// in a haystack that is a multiple of 16 in length.
// Matches for the first four bytes are returned in the first index, and 8
// byte matches are returned in the second. An index that is an 8 byte match will
// not be present in the 4-byte matches.
// Indeces are returned ordered from index 0 and upwards.
func Match8And4(needle, haystack []byte, indices8 []int, indices4 []int) ([]int, []int) {
	if len(needle) != 8 {
		panic("length not 8")
	}
	if len(haystack)&15 != 0 {
		panic("haystack must be dividable by 16")
	}
	dst := make([]uint32, len(haystack)/16)
	if indices8 == nil {
		indices8 = make([]int, 0, 10)
	} else {
		indices8 = indices8[:0]
	}
	if indices4 == nil {
		indices4 = make([]int, 0, 10)
	} else {
		indices4 = indices4[:0]
	}
	find8(needle, haystack, dst)
	for i, v := range dst {
		j := 0
		for v != 0 {
			if v&3 == 3 {
				indices8 = append(indices8, i*16+j)
			} else if v&1 == 1 {
				indices4 = append(indices4, i*16+j)
			}
			v >>= 2
			j++
		}
	}
	return indices8, indices4
}

func find8(needle, haystack []byte, dst []uint32) {
	if UseSse41 {
		find8SSE4(needle, haystack, dst)
		return
	}
	find8Go(needle, haystack, dst)
}

// find8Go is the reference implementation that mimmics the SSE4
// implemenation.
func find8Go(needle, haystack []byte, dst []uint32) {
	end := uint(len(haystack) - 7)
	for i := uint(0); i < end; i++ {
		if needle[0] == haystack[i] && needle[1] == haystack[i+1] && needle[2] == haystack[i+2] && needle[3] == haystack[i+3] {
			dst[i>>4] |= 1 << ((i & 15) << 1)
		}
		if needle[4] == haystack[i+4] && needle[5] == haystack[i+5] && needle[6] == haystack[i+6] && needle[7] == haystack[i+7] {
			dst[i>>4] |= 2 << ((i & 15) << 1)
		}
	}
}

func MatchLen(a []byte, b []byte, max int) int {
	if UseSse42 {
		return matchLenSSE4(a, b, max)
	}
	return matchLen(a, b, max)
}

func matchLen(a, b []byte, max int) int {
	a = a[:max]
	b = b[:max]
	for i, av := range a {
		if b[i] != av {
			return i
		}
	}
	return max
}
<|endoftext|>


<commit_before>package ucfg

import "reflect"

func (c *Config) Merge(from interface{}) error {
	other, err := normalize(from)
	if err != nil {
		return err
	}
	return mergeConfig(c.fields, other.fields)
}

func mergeConfig(to, from map[string]value) error {
	for k, v := range from {
		old, ok := to[k]
		if !ok {
			to[k] = v
			continue
		}

		subOld, ok := old.(cfgSub)
		if !ok {
			to[k] = v
			continue
		}

		subFrom, ok := v.(cfgSub)
		if !ok {
			to[k] = v
			continue
		}

		err := mergeConfig(subOld.c.fields, subFrom.c.fields)
		if err != nil {
			return err
		}
	}
	return nil
}

// convert from into normalized *Config checking for errors
// before merging generated(normalized) config with current config
func normalize(from interface{}) (*Config, error) {
	vFrom := chaseValue(reflect.ValueOf(from))

	switch vFrom.Type() {
	case tConfig:
		return vFrom.Addr().Interface().(*Config), nil
	case tConfigMap:
		return normalizeMap(vFrom)
	default:
		switch vFrom.Kind() {
		case reflect.Struct:
			return normalizeStruct(vFrom)
		case reflect.Map:
			return normalizeMap(vFrom)
		}
	}

	return nil, ErrTypeMismatch
}

func normalizeMap(from reflect.Value) (*Config, error) {
	cfg := New()
	if err := normalizeMapInto(cfg, from); err != nil {
		return nil, err
	}
	return cfg, nil
}

func normalizeMapInto(cfg *Config, from reflect.Value) error {
	k := from.Type().Key().Kind()
	if k != reflect.String && k != reflect.Interface {
		return ErrTypeMismatch
	}

	for _, k := range from.MapKeys() {
		k = chaseValueInterfaces(k)
		if k.Kind() != reflect.String {
			return ErrKeyTypeNotString
		}

		name := k.String()
		if cfg.HasField(name) {
			return errDuplicateKey(name)
		}

		v, err := normalizeValue(from.MapIndex(k))
		if err != nil {
			return err
		}
		cfg.fields[name] = v
	}
	return nil
}

func normalizeStruct(from reflect.Value) (*Config, error) {
	cfg := New()
	if err := normalizeStructInto(cfg, from); err != nil {
		return nil, err
	}
	return cfg, nil
}

func normalizeStructInto(cfg *Config, from reflect.Value) error {
	v := chaseValue(from)
	numField := v.NumField()

	for i := 0; i < numField; i++ {
		stField := v.Type().Field(i)
		name, opts := parseTags(stField.Tag.Get("config"))

		if opts.squash {
			var err error

			vField := chaseValue(v.Field(i))
			switch vField.Kind() {
			case reflect.Struct:
				err = normalizeStructInto(cfg, vField)
			case reflect.Map:
				err = normalizeMapInto(cfg, vField)
			default:
				err = ErrTypeMismatch
			}

			if err != nil {
				return err
			}
		} else {
			v, err := normalizeValue(v.Field(i))
			if err != nil {
				return err
			}

			name = fieldName(name, stField.Name)
			if cfg.HasField(name) {
				return errDuplicateKey(name)
			}

			cfg.fields[name] = v
		}
	}
	return nil
}

func normalizeStructValue(from reflect.Value) (value, error) {
	sub, err := normalizeStruct(from)
	if err != nil {
		return nil, err
	}
	return cfgSub{sub}, nil
}

func normalizeMapValue(from reflect.Value) (value, error) {
	sub, err := normalizeMap(from)
	if err != nil {
		return nil, err
	}
	return cfgSub{sub}, nil
}

func normalizeArray(v reflect.Value) (value, error) {
	l := v.Len()
	out := make([]value, 0, l)
	for i := 0; i < l; i++ {
		tmp, err := normalizeValue(v.Index(i))
		if err != nil {
			return nil, err
		}
		out = append(out, tmp)
	}
	return &cfgArray{arr: out}, nil
}

func normalizeValue(v reflect.Value) (value, error) {
	v = chaseValue(v)

	// handle primitives
	switch v.Kind() {
	case reflect.Bool:
		return &cfgBool{b: v.Bool()}, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return &cfgInt{i: v.Int()}, nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return &cfgInt{i: int64(v.Uint())}, nil
	case reflect.Float32, reflect.Float64:
		return &cfgFloat{f: v.Float()}, nil
	case reflect.String:
		return &cfgString{s: v.String()}, nil
	case reflect.Array, reflect.Slice:
		return normalizeArray(v)
	case reflect.Map:
		return normalizeMapValue(v)
	case reflect.Struct:
		if v.Type().ConvertibleTo(tConfig) {
			var c *Config
			if !v.CanAddr() {
				vTmp := reflect.New(tConfig)
				vTmp.Elem().Set(v)
				c = vTmp.Interface().(*Config)
			} else {
				c = v.Addr().Interface().(*Config)
			}
			return cfgSub{c}, nil
		}
		return normalizeStructValue(v)
	default:
		return nil, ErrTypeMismatch
	}
}
<commit_msg>Add merge options<commit_after>package ucfg

import "reflect"

type MergeOption func(mergeOpts) mergeOpts

type mergeOpts struct {
	tag string
}

func StructTag(tag string) MergeOption {
	return func(opts mergeOpts) mergeOpts {
		opts.tag = tag
		return opts
	}
}

func makeMergeOpts(options []MergeOption) mergeOpts {
	opts := mergeOpts{
		tag: "config",
	}
	for _, opt := range options {
		opts = opt(opts)
	}
	return opts
}

func (c *Config) Merge(from interface{}, options ...MergeOption) error {
	opts := makeMergeOpts(options)
	other, err := normalize(opts, from)
	if err != nil {
		return err
	}
	return mergeConfig(c.fields, other.fields)
}

func mergeConfig(to, from map[string]value) error {
	for k, v := range from {
		old, ok := to[k]
		if !ok {
			to[k] = v
			continue
		}

		subOld, ok := old.(cfgSub)
		if !ok {
			to[k] = v
			continue
		}

		subFrom, ok := v.(cfgSub)
		if !ok {
			to[k] = v
			continue
		}

		err := mergeConfig(subOld.c.fields, subFrom.c.fields)
		if err != nil {
			return err
		}
	}
	return nil
}

// convert from into normalized *Config checking for errors
// before merging generated(normalized) config with current config
func normalize(opts mergeOpts, from interface{}) (*Config, error) {
	vFrom := chaseValue(reflect.ValueOf(from))

	switch vFrom.Type() {
	case tConfig:
		return vFrom.Addr().Interface().(*Config), nil
	case tConfigMap:
		return normalizeMap(opts, vFrom)
	default:
		switch vFrom.Kind() {
		case reflect.Struct:
			return normalizeStruct(opts, vFrom)
		case reflect.Map:
			return normalizeMap(opts, vFrom)
		}
	}

	return nil, ErrTypeMismatch
}

func normalizeMap(opts mergeOpts, from reflect.Value) (*Config, error) {
	cfg := New()
	if err := normalizeMapInto(cfg, opts, from); err != nil {
		return nil, err
	}
	return cfg, nil
}

func normalizeMapInto(cfg *Config, opts mergeOpts, from reflect.Value) error {
	k := from.Type().Key().Kind()
	if k != reflect.String && k != reflect.Interface {
		return ErrTypeMismatch
	}

	for _, k := range from.MapKeys() {
		k = chaseValueInterfaces(k)
		if k.Kind() != reflect.String {
			return ErrKeyTypeNotString
		}

		name := k.String()
		if cfg.HasField(name) {
			return errDuplicateKey(name)
		}

		v, err := normalizeValue(opts, from.MapIndex(k))
		if err != nil {
			return err
		}
		cfg.fields[name] = v
	}
	return nil
}

func normalizeStruct(opts mergeOpts, from reflect.Value) (*Config, error) {
	cfg := New()
	if err := normalizeStructInto(cfg, opts, from); err != nil {
		return nil, err
	}
	return cfg, nil
}

func normalizeStructInto(cfg *Config, opts mergeOpts, from reflect.Value) error {
	v := chaseValue(from)
	numField := v.NumField()

	for i := 0; i < numField; i++ {
		stField := v.Type().Field(i)
		name, tagOpts := parseTags(stField.Tag.Get(opts.tag))
		if tagOpts.squash {
			var err error

			vField := chaseValue(v.Field(i))
			switch vField.Kind() {
			case reflect.Struct:
				err = normalizeStructInto(cfg, opts, vField)
			case reflect.Map:
				err = normalizeMapInto(cfg, opts, vField)
			default:
				err = ErrTypeMismatch
			}

			if err != nil {
				return err
			}
		} else {
			v, err := normalizeValue(opts, v.Field(i))
			if err != nil {
				return err
			}

			name = fieldName(name, stField.Name)
			if cfg.HasField(name) {
				return errDuplicateKey(name)
			}

			cfg.fields[name] = v
		}
	}
	return nil
}

func normalizeStructValue(opts mergeOpts, from reflect.Value) (value, error) {
	sub, err := normalizeStruct(opts, from)
	if err != nil {
		return nil, err
	}
	return cfgSub{sub}, nil
}

func normalizeMapValue(opts mergeOpts, from reflect.Value) (value, error) {
	sub, err := normalizeMap(opts, from)
	if err != nil {
		return nil, err
	}
	return cfgSub{sub}, nil
}

func normalizeArray(opts mergeOpts, v reflect.Value) (value, error) {
	l := v.Len()
	out := make([]value, 0, l)
	for i := 0; i < l; i++ {
		tmp, err := normalizeValue(opts, v.Index(i))
		if err != nil {
			return nil, err
		}
		out = append(out, tmp)
	}
	return &cfgArray{arr: out}, nil
}

func normalizeValue(opts mergeOpts, v reflect.Value) (value, error) {
	v = chaseValue(v)

	// handle primitives
	switch v.Kind() {
	case reflect.Bool:
		return &cfgBool{b: v.Bool()}, nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return &cfgInt{i: v.Int()}, nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return &cfgInt{i: int64(v.Uint())}, nil
	case reflect.Float32, reflect.Float64:
		return &cfgFloat{f: v.Float()}, nil
	case reflect.String:
		return &cfgString{s: v.String()}, nil
	case reflect.Array, reflect.Slice:
		return normalizeArray(opts, v)
	case reflect.Map:
		return normalizeMapValue(opts, v)
	case reflect.Struct:
		if v.Type().ConvertibleTo(tConfig) {
			var c *Config
			if !v.CanAddr() {
				vTmp := reflect.New(tConfig)
				vTmp.Elem().Set(v)
				c = vTmp.Interface().(*Config)
			} else {
				c = v.Addr().Interface().(*Config)
			}
			return cfgSub{c}, nil
		}
		return normalizeStructValue(opts, v)
	default:
		return nil, ErrTypeMismatch
	}
}
<|endoftext|>


<commit_before>//
// daemon.go
//
package main

import (
  "bufio"
  "log"
  "net"
  "strconv"
  "strings"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store *ArticleStore
  api_caller *API
  listener net.Listener
  debug bool
  sync_on_start bool
  running bool
  feeds map[NNTPConnection]bool
  infeed chan string
}

func (self *NNTPDaemon) End() {
  self.listener.Close()
}

// register a new connection
// can be either inbound or outbound
func (self *NNTPDaemon) newConnection(conn net.Conn, inbound bool, policy *FeedPolicy) NNTPConnection {
  feed := NNTPConnection{conn, bufio.NewReader(conn), inbound, self.debug, new(ConnectionInfo), policy, make(chan *NNTPMessage)}
  self.feeds[feed] = ! inbound
  return feed
}

func (self *NNTPDaemon) persistFeed(conf FeedConfig) {
  for {
    if self.running {
      time.Sleep(1 * time.Second)
      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
          continue
        }
      }
      policy := &conf.policy
      nntp := self.newConnection(conn, false, policy)
      nntp.HandleOutbound(self)
      delete(self.feeds, nntp)
    }
  }
}

// run daemon
func (self *NNTPDaemon) Run() {
  err := self.Bind()
  if err != nil {
    log.Println("failed to bind:", err)
    return
  }
  defer self.listener.Close()

  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx])
  }
  go self.mainloop()

  if self.sync_on_start {
    log.Println("syncing on start")
    go self.syncAll()
  }

  // loop over messages
  for {
    message := <- self.infeed
    // load message
    nntp := self.store.GetMessage(message, false)
    // send to all outfeeds
    for feed , use := range self.feeds {
      if use {
        feed.send <- nntp
      }
    }
  }
}

func (self *NNTPDaemon) syncAll() {
  self.store.IterateAllArticles(func(messageID string) {
    msg := self.store.GetMessage(messageID, false)
    for feed , use := range self.feeds {
      if use {
        feed.send <- msg
     }
    }
  })
}

func (self *NNTPDaemon) mainloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := self.newConnection(conn, true, nil)
    go self.RunConnection(nntp)
  }
}

func (self *NNTPDaemon) RunConnection(nntp NNTPConnection) {
  nntp.HandleInbound(self)
  delete(self.feeds, nntp)
}

// bind to address
func (self *NNTPDaemon) Bind() error {
  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Println("failed to bind to", self.bind_addr, err)
    return err
  }
  self.listener = listener
  log.Println("SRNd NNTPD bound at", listener.Addr())
  return nil
}

// load configuration
// bind to interface
func (self *NNTPDaemon) Init() bool {
  CheckConfig()
  log.Println("load config")
  self.conf = ReadConf()
  if self.conf == nil {
    log.Println("cannot load config")
    return false
  }
  self.infeed = make(chan string, 20)
  self.feeds = make(map[NNTPConnection]bool)
  self.store = new(ArticleStore)
  self.store.directory = self.conf.store["base_dir"]
  self.store.Init()
  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  self.bind_addr = self.conf.daemon["bind"]
  self.debug = self.conf.daemon["log"] == "debug"
  if self.debug {
    log.Println("debug mode activated")
  }

  return true
}
<commit_msg>fix outfeed sync on start<commit_after>//
// daemon.go
//
package main

import (
  "bufio"
  "log"
  "net"
  "strconv"
  "strings"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store *ArticleStore
  api_caller *API
  listener net.Listener
  debug bool
  sync_on_start bool
  running bool
  feeds map[NNTPConnection]bool
  infeed chan string
}

func (self *NNTPDaemon) End() {
  self.listener.Close()
}

// register a new connection
// can be either inbound or outbound
func (self *NNTPDaemon) newConnection(conn net.Conn, inbound bool, policy *FeedPolicy) NNTPConnection {
  feed := NNTPConnection{conn, bufio.NewReader(conn), inbound, self.debug, new(ConnectionInfo), policy, make(chan *NNTPMessage)}
  self.feeds[feed] = ! inbound
  return feed
}

func (self *NNTPDaemon) persistFeed(conf FeedConfig) {
  for {
    if self.running {
      time.Sleep(1 * time.Second)
      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
          continue
        }
      }
      policy := &conf.policy
      nntp := self.newConnection(conn, false, policy)
      nntp.HandleOutbound(self)
      delete(self.feeds, nntp)
    }
  }
}

// run daemon
func (self *NNTPDaemon) Run() {
  err := self.Bind()
  if err != nil {
    log.Println("failed to bind:", err)
    return
  }
  defer self.listener.Close()

  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx])
  }
  go self.mainloop()

  // loop over messages
  for {
    message := <- self.infeed
    // load message
    nntp := self.store.GetMessage(message, false)
    // send to all outfeeds
    for feed , use := range self.feeds {
      if use {
        feed.send <- nntp
      }
    }
  }
}

func (self *NNTPDaemon) mainloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := self.newConnection(conn, true, nil)
    go self.RunConnection(nntp)
  }
}

func (self *NNTPDaemon) RunConnection(nntp NNTPConnection) {
  nntp.HandleInbound(self)
  delete(self.feeds, nntp)
}

// bind to address
func (self *NNTPDaemon) Bind() error {
  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Println("failed to bind to", self.bind_addr, err)
    return err
  }
  self.listener = listener
  log.Println("SRNd NNTPD bound at", listener.Addr())
  return nil
}

// load configuration
// bind to interface
func (self *NNTPDaemon) Init() bool {
  CheckConfig()
  log.Println("load config")
  self.conf = ReadConf()
  if self.conf == nil {
    log.Println("cannot load config")
    return false
  }
  self.infeed = make(chan string, 20)
  self.feeds = make(map[NNTPConnection]bool)
  self.store = new(ArticleStore)
  self.store.directory = self.conf.store["base_dir"]
  self.store.Init()
  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  self.bind_addr = self.conf.daemon["bind"]
  self.debug = self.conf.daemon["log"] == "debug"
  if self.debug {
    log.Println("debug mode activated")
  }

  return true
}
<|endoftext|>


<commit_before>// +build go1.8 go1.9

/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import "crypto/tls"

var SupportedTLSVersions = map[string]int{
	"ssl3.0": tls.VersionSSL30,
	"tls1.0": tls.VersionTLS10,
	"tls1.1": tls.VersionTLS11,
	"tls1.2": tls.VersionTLS12,
}

var SupportedTLSCipherSuites = map[string]uint16{
	"TLS_RSA_WITH_RC4_128_SHA":                tls.TLS_RSA_WITH_RC4_128_SHA,
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":           tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,
	"TLS_RSA_WITH_AES_256_CBC_SHA":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
	"TLS_RSA_WITH_AES_128_GCM_SHA256":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_RSA_WITH_AES_256_GCM_SHA384":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":     tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
<commit_msg>Removed redundant 1.9 tag from tlsconfig_go1_8.go<commit_after>// +build go1.8

/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import "crypto/tls"

var SupportedTLSVersions = map[string]int{
	"ssl3.0": tls.VersionSSL30,
	"tls1.0": tls.VersionTLS10,
	"tls1.1": tls.VersionTLS11,
	"tls1.2": tls.VersionTLS12,
}

var SupportedTLSCipherSuites = map[string]uint16{
	"TLS_RSA_WITH_RC4_128_SHA":                tls.TLS_RSA_WITH_RC4_128_SHA,
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":           tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,
	"TLS_RSA_WITH_AES_256_CBC_SHA":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
	"TLS_RSA_WITH_AES_128_GCM_SHA256":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_RSA_WITH_AES_256_GCM_SHA384":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":     tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Rocky Bernstein.

// Package repl is a simple REPL (read-eval-print loop) for GO using
// http://github.com/0xfaded/eval to the heavy lifting to implement
// the eval() part.
//
// Inside this package we provide two front-ends, one which uses GNU
// Readline (http://code.google.com/p/go-gnureadline) and one which doesn't.
// Feel free to add patches to support other kinds of readline support.
//
package repl

// We separate this from the main package so that the main package
// can provide its own readline function. This could be, for example,
// GNU Readline, lineedit or something else.
import (
	"bufio"
	"flag"
	"fmt"
	"go/parser"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"

	"github.com/0xfaded/eval"
)

var Highlight = flag.Bool("highlight", true, `use syntax highlighting in output`)

// Maxwidth is the size of the line. We will try to wrap text that is
// longer than this. It like the COLS environment variable
var Maxwidth int = 80

// ReadLineFnType is function signature for a common read line
// interface that we support.
type ReadLineFnType func(prompt string, add_history ... bool) (string, error)
var  readLineFn ReadLineFnType

// HistoryFile returns a string file name to use for saving command
// history entries.
func HistoryFile(history_basename string) string {
	home_dir := os.Getenv("HOME")
	if home_dir == "" {
		// FIXME: also try ~ ?
		fmt.Println("ignoring history file; environment variable HOME not set")
		return ""
	}
	history_file := filepath.Join(home_dir, history_basename)
	if fi, err := os.Stat(history_file); err != nil {
		fmt.Println("No history file found to read in: ", err.Error())
	} else {
		if fi.IsDir() {
			fmt.Printf("Ignoring history file %s; is a directory, should be a file",
				history_file)
			return ""
		}
	}
	return history_file
}

// SetReadLineFn is used to set a specific readline function to be used
// as the "read" part of the read/eval/print loop.
func SetReadLineFn(fn ReadLineFnType) {
	readLineFn = fn
}

// GetReadLineFn returns the current readline function in effect for
// the "read" part of the read/eval/print loop.
func GetReadLineFn() ReadLineFnType {
	return readLineFn
}

// Input is a workaround for the fact that ReadLineFnType doesn't have
// an input parameter, but SimpleReadLine below needs a
// *bufioReader. So set this global variable beforehand if you are using
// SimpleReadLine.
var Input *bufio.Reader

// SimpleReadLine is simple replacement for GNU readline.
// prompt is the command prompt to print before reading input.
// add_history is ignored, but provided as a parameter to match
// those readline interfaces that do support saving command history.
func SimpleReadLine(prompt string, add_history ... bool) (string, error) {
	fmt.Printf(prompt)
	line, err := Input.ReadString('\n')
	if err == nil {
		line = strings.TrimRight(line, "\r\n")
	}
	return line, err
}

func init() {
	readLineFn = SimpleReadLine
}

// MakeEvalEnv creates an environment to use in evaluation.  The
// environment is exactly that environment needed by eval
// automatically extracted from the package eval
// (http://github.com/0xfaded/eval).
func MakeEvalEnv() eval.Env {
	var pkgs map[string] eval.Pkg = make(map[string] eval.Pkg)
	EvalEnvironment(pkgs)

	env := eval.Env {
		Name:   ".",
		Vars:   make(map[string] reflect.Value),
		Consts: make(map[string] reflect.Value),
		Funcs:  make(map[string] reflect.Value),
		Types:  make(map[string] reflect.Type),
		Pkgs:   pkgs,
	}
	return env
}

// LeaveREPL is set when we want to quit.
var LeaveREPL bool = false

// ExitCode is the exit code this program will set on exit.
var ExitCode  int  = 0

// Env is the evaluation environment we are working with.
var Env *eval.Env

// REPL is the read, eval, and print loop.
func REPL(env *eval.Env, results *([]interface{})) {

	var err error
	Env = env
	exprs := 0
	line, err := readLineFn("gofish> ", true)
	for true {
		if err != nil {
			if err == io.EOF { break }
			panic(err)
		}
		if wasProcessed(line) {
			if LeaveREPL {break}
			line, err = readLineFn("gofish> ", true)
			continue
		}
		ctx := &eval.Ctx{line}
		if expr, err := parser.ParseExpr(line); err != nil {
			fmt.Printf("parse error: %s\n", err)
		} else if cexpr, errs := eval.CheckExpr(ctx, expr, env); len(errs) != 0 {
			for _, cerr := range errs {
				fmt.Printf("%v\n", cerr)
			}
		} else if vals, _, err := eval.EvalExpr(ctx, cexpr, env); err != nil {
			fmt.Printf("eval error: %s\n", err)
		} else if vals == nil {
			fmt.Printf("Kind=nil\nnil\n")
		} else if len(*vals) == 0 {
			fmt.Printf("Kind=Slice\nvoid\n")
		} else if len(*vals) == 1 {
			value := (*vals)[0]
			kind := value.Kind().String()
			typ  := value.Type().String()
			if typ != kind {
				fmt.Printf("Kind = %v\n", kind)
				fmt.Printf("Type = %v\n", typ)
			} else {
				fmt.Printf("Kind = Type = %v\n", kind)
			}
			if kind == "string" {
				fmt.Printf("results[%d] = %s\n", exprs,
					strconv.QuoteToASCII(value.String()))
			} else {
				fmt.Printf("results[%d] = %v\n", exprs, (value.Interface()))
			}
			exprs  += 1
			*results = append(*results, (*vals)[0].Interface())
		} else {
			fmt.Printf("Kind = Multi-Value\n")
			size := len(*vals)
			for i, v := range *vals {
				if v.Interface() == nil {
					fmt.Printf("nil")
				} else {
					fmt.Printf("%v", v.Interface())
				}
				if i < size-1 { fmt.Printf(", ") }
			}
			fmt.Printf("\n")
			exprs  += 1
			*results = append(*results, (*vals))
		}

		line, err = readLineFn("gofish> ", true)
	}
}
<commit_msg>Set Maxwidth more properly.<commit_after>// Copyright 2013-2014 Rocky Bernstein.

// Package repl is a simple REPL (read-eval-print loop) for GO using
// http://github.com/0xfaded/eval to the heavy lifting to implement
// the eval() part.
//
// Inside this package we provide two front-ends, one which uses GNU
// Readline (http://code.google.com/p/go-gnureadline) and one which doesn't.
// Feel free to add patches to support other kinds of readline support.
//
package repl

// We separate this from the main package so that the main package
// can provide its own readline function. This could be, for example,
// GNU Readline, lineedit or something else.
import (
	"bufio"
	"flag"
	"fmt"
	"go/parser"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"

	"github.com/0xfaded/eval"
)

var Highlight = flag.Bool("highlight", true, `use syntax highlighting in output`)

// Maxwidth is the size of the line. We will try to wrap text that is
// longer than this. It like the COLUMNS environment variable
var Maxwidth int

// ReadLineFnType is function signature for a common read line
// interface that we support.
type ReadLineFnType func(prompt string, add_history ... bool) (string, error)
var  readLineFn ReadLineFnType

var initial_cwd string

// GOFISH_RESTART_CMD is a string that was used to invoke gofish.
//If we want to restart gofish, this is what we'll use.
var GOFISH_RESTART_CMD string

// HistoryFile returns a string file name to use for saving command
// history entries.
func HistoryFile(history_basename string) string {
	home_dir := os.Getenv("HOME")
	if home_dir == "" {
		// FIXME: also try ~ ?
		fmt.Println("ignoring history file; environment variable HOME not set")
		return ""
	}
	history_file := filepath.Join(home_dir, history_basename)
	if fi, err := os.Stat(history_file); err != nil {
		fmt.Println("No history file found to read in: ", err.Error())
	} else {
		if fi.IsDir() {
			fmt.Printf("Ignoring history file %s; is a directory, should be a file",
				history_file)
			return ""
		}
	}
	return history_file
}

// SetReadLineFn is used to set a specific readline function to be used
// as the "read" part of the read/eval/print loop.
func SetReadLineFn(fn ReadLineFnType) {
	readLineFn = fn
}

// GetReadLineFn returns the current readline function in effect for
// the "read" part of the read/eval/print loop.
func GetReadLineFn() ReadLineFnType {
	return readLineFn
}

// Input is a workaround for the fact that ReadLineFnType doesn't have
// an input parameter, but SimpleReadLine below needs a
// *bufioReader. So set this global variable beforehand if you are using
// SimpleReadLine.
var Input *bufio.Reader

// SimpleReadLine is simple replacement for GNU readline.
// prompt is the command prompt to print before reading input.
// add_history is ignored, but provided as a parameter to match
// those readline interfaces that do support saving command history.
func SimpleReadLine(prompt string, add_history ... bool) (string, error) {
	fmt.Printf(prompt)
	line, err := Input.ReadString('\n')
	if err == nil {
		line = strings.TrimRight(line, "\r\n")
	}
	return line, err
}

func init() {
	readLineFn = SimpleReadLine
	widthstr := os.Getenv("COLUMNS")
	initial_cwd, _ = os.Getwd()
	GOFISH_RESTART_CMD = os.Getenv("GOFISH_RESTART_CMD")
	if len(widthstr) == 0 {
		Maxwidth = 80
	} else if i, err := strconv.Atoi(widthstr); err == nil {
		Maxwidth = i
	}
}

// MakeEvalEnv creates an environment to use in evaluation.  The
// environment is exactly that environment needed by eval
// automatically extracted from the package eval
// (http://github.com/0xfaded/eval).
func MakeEvalEnv() eval.Env {
	var pkgs map[string] eval.Pkg = make(map[string] eval.Pkg)
	EvalEnvironment(pkgs)

	env := eval.Env {
		Name:   ".",
		Vars:   make(map[string] reflect.Value),
		Consts: make(map[string] reflect.Value),
		Funcs:  make(map[string] reflect.Value),
		Types:  make(map[string] reflect.Type),
		Pkgs:   pkgs,
	}
	return env
}

// LeaveREPL is set when we want to quit.
var LeaveREPL bool = false

// ExitCode is the exit code this program will set on exit.
var ExitCode  int  = 0

// Env is the evaluation environment we are working with.
var Env *eval.Env

// REPL is the read, eval, and print loop.
func REPL(env *eval.Env, results *([]interface{})) {

	var err error
	Env = env
	exprs := 0
	line, err := readLineFn("gofish> ", true)
	for true {
		if err != nil {
			if err == io.EOF { break }
			panic(err)
		}
		if wasProcessed(line) {
			if LeaveREPL {break}
			line, err = readLineFn("gofish> ", true)
			continue
		}
		ctx := &eval.Ctx{line}
		if expr, err := parser.ParseExpr(line); err != nil {
			fmt.Printf("parse error: %s\n", err)
		} else if cexpr, errs := eval.CheckExpr(ctx, expr, env); len(errs) != 0 {
			for _, cerr := range errs {
				fmt.Printf("%v\n", cerr)
			}
		} else if vals, _, err := eval.EvalExpr(ctx, cexpr, env); err != nil {
			fmt.Printf("eval error: %s\n", err)
		} else if vals == nil {
			fmt.Printf("Kind=nil\nnil\n")
		} else if len(*vals) == 0 {
			fmt.Printf("Kind=Slice\nvoid\n")
		} else if len(*vals) == 1 {
			value := (*vals)[0]
			kind := value.Kind().String()
			typ  := value.Type().String()
			if typ != kind {
				fmt.Printf("Kind = %v\n", kind)
				fmt.Printf("Type = %v\n", typ)
			} else {
				fmt.Printf("Kind = Type = %v\n", kind)
			}
			if kind == "string" {
				fmt.Printf("results[%d] = %s\n", exprs,
					strconv.QuoteToASCII(value.String()))
			} else {
				fmt.Printf("results[%d] = %v\n", exprs, (value.Interface()))
			}
			exprs  += 1
			*results = append(*results, (*vals)[0].Interface())
		} else {
			fmt.Printf("Kind = Multi-Value\n")
			size := len(*vals)
			for i, v := range *vals {
				if v.Interface() == nil {
					fmt.Printf("nil")
				} else {
					fmt.Printf("%v", v.Interface())
				}
				if i < size-1 { fmt.Printf(", ") }
			}
			fmt.Printf("\n")
			exprs  += 1
			*results = append(*results, (*vals))
		}

		line, err = readLineFn("gofish> ", true)
	}
}
<|endoftext|>


<commit_before>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     October 22, 2020
;       related version of root zone:     2020102201
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<commit_msg>root zone update for November 11, 2020<commit_after>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     November 11, 2020
;       related version of root zone:     2020111101
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<|endoftext|>


<commit_before>package orm

import (
	"fmt"
	"gnd.la/orm/driver"
	"gnd.la/orm/index"
	"gnd.la/orm/query"
	"reflect"
	"strings"
)

type JoinType int

const (
	InnerJoin JoinType = JoinType(driver.InnerJoin)
	OuterJoin JoinType = JoinType(driver.OuterJoin)
	LeftJoin  JoinType = JoinType(driver.LeftJoin)
	RightJoin JoinType = JoinType(driver.RightJoin)
)

func (j JoinType) String() string {
	switch j {
	case InnerJoin:
		return "INNER JOIN"
	case OuterJoin:
		return "OUTER JOIN"
	case LeftJoin:
		return "LEFT OUTER JOIN"
	case RightJoin:
		return "OUTER JOIN"
	}
	return "unknown JoinType"
}

type reference struct {
	model string
	field string
}

type model struct {
	options         *Options
	name            string
	shortName       string
	table           string
	fields          *driver.Fields
	tags            string
	references      map[string]*reference
	modelReferences map[*model][]*join
	namedReferences map[string]*model
}

func (m *model) Type() reflect.Type {
	return m.fields.Type
}

func (m *model) Table() string {
	return m.table
}

func (m *model) Fields() *driver.Fields {
	return m.fields
}

func (m *model) Indexes() []*index.Index {
	var indexes []*index.Index
	if m.options != nil {
		indexes = append(indexes, m.options.Indexes...)
	}
	// Add indexes declared in the fields
	for ii, v := range m.fields.Tags {
		if v.Has("index") {
			dir := v.Value("index")
			if dir == "" || dir == "asc" || dir == "both" {
				indexes = append(indexes, &index.Index{
					Fields: []string{m.fields.QNames[ii]},
					Unique: v.Has("unique"),
				})
			}
			if dir == "desc" || dir == "both" {
				name := m.fields.QNames[ii]
				idx := &index.Index{
					Fields: []string{name},
					Unique: v.Has("unique"),
				}
				indexes = append(indexes, idx.Set(index.DESC, name))
			}
		}
	}
	return indexes
}

func (m *model) Map(qname string) (string, reflect.Type, error) {
	sep := strings.IndexByte(qname, '|')
	if sep >= 0 {
		name := qname[:sep]
		if name != m.name && name != m.shortName {
			return "", nil, errNotThisModel(name)
		}
		qname = qname[sep+1:]
	}
	if n, ok := m.fields.QNameMap[qname]; ok {
		return m.fields.QuotedNames[n], m.fields.Types[n], nil
	}
	return "", nil, errCantMap(qname)
}

func (m *model) Skip() bool {
	return false
}

func (m *model) Join() driver.Join {
	return nil
}

func (m *model) String() string {
	return m.name
}

func (m *model) fullName(qname string) string {
	return m.name + "|" + qname
}

type join struct {
	model *joinModel
	jtype JoinType
	q     query.Q
}

func (j *join) Model() driver.Model {
	return j.model
}

func (j *join) Type() driver.JoinType {
	return driver.JoinType(j.jtype)
}

func (j *join) Query() query.Q {
	return j.q
}

func (j *join) clone() *join {
	return &join{
		model: j.model.clone(),
		jtype: j.jtype,
		q:     j.q,
	}
}

type joinModel struct {
	*model
	skip bool
	join *join
}

func (j *joinModel) clone() *joinModel {
	nj := &joinModel{
		model: j.model,
		skip:  j.skip,
	}
	if j.join != nil {
		nj.join = j.join.clone()
	}
	return nj
}

func (j *joinModel) Fields() *driver.Fields {
	if j.skip {
		return nil
	}
	return j.model.Fields()
}

func (j *joinModel) Skip() bool {
	return j.skip
}

func (j *joinModel) Join() driver.Join {
	// This workarounds a gotcha in Go which
	// generates an interface which points to nil
	// when returning a nil variable, thus making
	// the caller think it got a non-nil object if
	// it just checks for x != nil. The caller can
	// check for this using reflect, but it seems
	// easier and less error prone to circumvent the
	// problem right here.
	if j.join == nil {
		return nil
	}
	return j.join
}

func (j *joinModel) String() string {
	s := []string{j.model.name}
	if j.skip {
		s = append(s, "(Skipped)")
	}
	if j.join != nil {
		s = append(s, " JOIN ")
		s = append(s, j.join.model.String())
		s = append(s, " ON ")
		s = append(s, fmt.Sprintf("%+v", j.join.q))
	}
	return strings.Join(s, "")
}

func (j *joinModel) joinWith(model *model, q query.Q, jt JoinType) (*joinModel, error) {
	if j.model == nil {
		j.model = model
		return j, nil
	}
	m := j
	if q == nil {
		var candidates []*join
		// Implicit join
		for {
			candidates = append(candidates, m.modelReferences[model]...)
			if m.join == nil {
				break
			}
			m = m.join.model
		}
		if len(candidates) > 1 {
			// Check if all the candidates point to the same
			// model and field. In that case, pick the first one.
			first := candidates[0]
			if eq, ok := first.q.(*query.Eq); ok {
				equal := true
				for _, v := range candidates[1:] {
					if veq, ok := v.q.(*query.Eq); !ok || first.model.model != v.model.model || !reflect.DeepEqual(eq.Value, veq.Value) {
						equal = false
						break
					}
				}
				if equal {
					candidates = candidates[:1]
				}
			}
		}
		switch len(candidates) {
		case 1:
			m.join = candidates[0].clone()
			m.join.jtype = jt
		case 0:
			return nil, fmt.Errorf("can't join %s with model %s", j, model)
		default:
			return nil, fmt.Errorf("joining %s with model %s is ambiguous using query %+v", j, model, q)
		}
	} else {
		for m.join != nil {
			m = m.join.model
		}
		m.join = &join{
			model: &joinModel{model: model},
			jtype: jt,
			q:     q,
		}
	}
	return m.join.model, nil
}

func (j *joinModel) joinWithField(field string, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	pipe := strings.IndexByte(field, '|')
	if pipe < 0 {
		return nil
	}
	typ := field[:pipe]
	m := j
	for {
		if model := m.model.namedReferences[typ]; model != nil {
			// Check if we're already joined to this model
			if _, ok := models[model]; ok {
				break
			}
			// Joins derived from queries are always implicit
			// and skipped, since we're only joining to check
			// against the value of the joined model.
			last, err := j.joinWith(model, nil, jt)
			if err != nil {
				return err
			}
			last.skip = true
			models[model] = struct{}{}
			*methods = append(*methods, model.fields.Methods)
			break
		}
		join := m.join
		if join == nil {
			break
		}
		m = join.model
	}
	return nil
}

func (j *joinModel) joinWithSort(sort []driver.Sort, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	for _, v := range sort {
		if err := j.joinWithField(v.Field(), jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) joinWithQuery(q query.Q, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	if err := j.joinWithField(q.FieldName(), jt, models, methods); err != nil {
		return err
	}
	for _, sq := range q.SubQ() {
		if err := j.joinWithQuery(sq, jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) Map(qname string) (string, reflect.Type, error) {
	var candidates []mapCandidate
	for cur := j; ; {
		n, t, err := cur.model.Map(qname)
		if err == nil {
			candidates = append(candidates, mapCandidate{n, t})
		}
		if cur.join == nil {
			break
		}
		cur = cur.join.model
	}
	switch len(candidates) {
	case 0:
		return "", nil, errCantMap(qname)
	case 1:
		c := candidates[0]
		return c.name, c.typ, nil
	default:
		return "", nil, errAmbiguous(qname)
	}
	panic("unreachable")
}

type mapCandidate struct {
	name string
	typ  reflect.Type
}

type sortModels []driver.Model

func (s sortModels) Len() int {
	return len(s)
}

func (s sortModels) less(mi, mj driver.Model) bool {
	for _, v := range mi.Fields().References {
		if v.Model == mj {
			return false
		}
		if v.Model != mi && !s.less(v.Model, mj) {
			return false
		}
	}
	return true
}

func (s sortModels) Less(i, j int) bool {
	return s.less(s[i], s[j])
}

func (s sortModels) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

type errCantMap string

func (e errCantMap) Error() string {
	return fmt.Sprintf("can't map field %q to a database name", string(e))
}

type errNotThisModel string

func (e errNotThisModel) Error() string {
	return fmt.Sprintf("name %q does not correspond to this model", string(e))
}

type errAmbiguous string

func (e errAmbiguous) Error() string {
	return fmt.Sprintf("field name %q is ambiguous. Please, indicate the type like e.g. Type|Field", string(e))
}
<commit_msg>Format imports<commit_after>package orm

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"

	"gnd.la/orm/driver"
	"gnd.la/orm/index"
	"gnd.la/orm/query"
)

type JoinType int

const (
	InnerJoin JoinType = JoinType(driver.InnerJoin)
	OuterJoin JoinType = JoinType(driver.OuterJoin)
	LeftJoin  JoinType = JoinType(driver.LeftJoin)
	RightJoin JoinType = JoinType(driver.RightJoin)
)

func (j JoinType) String() string {
	switch j {
	case InnerJoin:
		return "INNER JOIN"
	case OuterJoin:
		return "OUTER JOIN"
	case LeftJoin:
		return "LEFT OUTER JOIN"
	case RightJoin:
		return "OUTER JOIN"
	}
	return "unknown JoinType"
}

type reference struct {
	model string
	field string
}

type model struct {
	options         *Options
	name            string
	shortName       string
	table           string
	fields          *driver.Fields
	tags            string
	references      map[string]*reference
	modelReferences map[*model][]*join
	namedReferences map[string]*model
}

func (m *model) Type() reflect.Type {
	return m.fields.Type
}

func (m *model) Table() string {
	return m.table
}

func (m *model) Fields() *driver.Fields {
	return m.fields
}

func (m *model) Indexes() []*index.Index {
	var indexes []*index.Index
	if m.options != nil {
		indexes = append(indexes, m.options.Indexes...)
	}
	// Add indexes declared in the fields
	for ii, v := range m.fields.Tags {
		if v.Has("index") {
			dir := v.Value("index")
			if dir == "" || dir == "asc" || dir == "both" {
				indexes = append(indexes, &index.Index{
					Fields: []string{m.fields.QNames[ii]},
					Unique: v.Has("unique"),
				})
			}
			if dir == "desc" || dir == "both" {
				name := m.fields.QNames[ii]
				idx := &index.Index{
					Fields: []string{name},
					Unique: v.Has("unique"),
				}
				indexes = append(indexes, idx.Set(index.DESC, name))
			}
		}
	}
	return indexes
}

func (m *model) Map(qname string) (string, reflect.Type, error) {
	sep := strings.IndexByte(qname, '|')
	if sep >= 0 {
		name := qname[:sep]
		if name != m.name && name != m.shortName {
			return "", nil, errNotThisModel(name)
		}
		qname = qname[sep+1:]
	}
	if n, ok := m.fields.QNameMap[qname]; ok {
		return m.fields.QuotedNames[n], m.fields.Types[n], nil
	}
	return "", nil, errCantMap(qname)
}

func (m *model) Skip() bool {
	return false
}

func (m *model) Join() driver.Join {
	return nil
}

func (m *model) String() string {
	return m.name
}

func (m *model) fullName(qname string) string {
	return m.name + "|" + qname
}

type join struct {
	model *joinModel
	jtype JoinType
	q     query.Q
}

func (j *join) Model() driver.Model {
	return j.model
}

func (j *join) Type() driver.JoinType {
	return driver.JoinType(j.jtype)
}

func (j *join) Query() query.Q {
	return j.q
}

func (j *join) clone() *join {
	return &join{
		model: j.model.clone(),
		jtype: j.jtype,
		q:     j.q,
	}
}

type joinModel struct {
	*model
	skip bool
	join *join
}

func (j *joinModel) clone() *joinModel {
	nj := &joinModel{
		model: j.model,
		skip:  j.skip,
	}
	if j.join != nil {
		nj.join = j.join.clone()
	}
	return nj
}

func (j *joinModel) Fields() *driver.Fields {
	if j.skip {
		return nil
	}
	return j.model.Fields()
}

func (j *joinModel) Skip() bool {
	return j.skip
}

func (j *joinModel) Join() driver.Join {
	// This workarounds a gotcha in Go which
	// generates an interface which points to nil
	// when returning a nil variable, thus making
	// the caller think it got a non-nil object if
	// it just checks for x != nil. The caller can
	// check for this using reflect, but it seems
	// easier and less error prone to circumvent the
	// problem right here.
	if j.join == nil {
		return nil
	}
	return j.join
}

func (j *joinModel) String() string {
	s := []string{j.model.name}
	if j.skip {
		s = append(s, "(Skipped)")
	}
	if j.join != nil {
		s = append(s, " JOIN ")
		s = append(s, j.join.model.String())
		s = append(s, " ON ")
		s = append(s, fmt.Sprintf("%+v", j.join.q))
	}
	return strings.Join(s, "")
}

func (j *joinModel) joinWith(model *model, q query.Q, jt JoinType) (*joinModel, error) {
	if j.model == nil {
		j.model = model
		return j, nil
	}
	m := j
	if q == nil {
		var candidates []*join
		// Implicit join
		for {
			candidates = append(candidates, m.modelReferences[model]...)
			if m.join == nil {
				break
			}
			m = m.join.model
		}
		if len(candidates) > 1 {
			// Check if all the candidates point to the same
			// model and field. In that case, pick the first one.
			first := candidates[0]
			if eq, ok := first.q.(*query.Eq); ok {
				equal := true
				for _, v := range candidates[1:] {
					if veq, ok := v.q.(*query.Eq); !ok || first.model.model != v.model.model || !reflect.DeepEqual(eq.Value, veq.Value) {
						equal = false
						break
					}
				}
				if equal {
					candidates = candidates[:1]
				}
			}
		}
		switch len(candidates) {
		case 1:
			m.join = candidates[0].clone()
			m.join.jtype = jt
		case 0:
			return nil, fmt.Errorf("can't join %s with model %s", j, model)
		default:
			return nil, fmt.Errorf("joining %s with model %s is ambiguous using query %+v", j, model, q)
		}
	} else {
		for m.join != nil {
			m = m.join.model
		}
		m.join = &join{
			model: &joinModel{model: model},
			jtype: jt,
			q:     q,
		}
	}
	return m.join.model, nil
}

func (j *joinModel) joinWithField(field string, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	pipe := strings.IndexByte(field, '|')
	if pipe < 0 {
		return nil
	}
	typ := field[:pipe]
	m := j
	for {
		if model := m.model.namedReferences[typ]; model != nil {
			// Check if we're already joined to this model
			if _, ok := models[model]; ok {
				break
			}
			// Joins derived from queries are always implicit
			// and skipped, since we're only joining to check
			// against the value of the joined model.
			last, err := j.joinWith(model, nil, jt)
			if err != nil {
				return err
			}
			last.skip = true
			models[model] = struct{}{}
			*methods = append(*methods, model.fields.Methods)
			break
		}
		join := m.join
		if join == nil {
			break
		}
		m = join.model
	}
	return nil
}

func (j *joinModel) joinWithSort(sort []driver.Sort, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	for _, v := range sort {
		if err := j.joinWithField(v.Field(), jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) joinWithQuery(q query.Q, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	if err := j.joinWithField(q.FieldName(), jt, models, methods); err != nil {
		return err
	}
	for _, sq := range q.SubQ() {
		if err := j.joinWithQuery(sq, jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) Map(qname string) (string, reflect.Type, error) {
	var candidates []mapCandidate
	for cur := j; ; {
		n, t, err := cur.model.Map(qname)
		if err == nil {
			candidates = append(candidates, mapCandidate{n, t})
		}
		if cur.join == nil {
			break
		}
		cur = cur.join.model
	}
	switch len(candidates) {
	case 0:
		return "", nil, errCantMap(qname)
	case 1:
		c := candidates[0]
		return c.name, c.typ, nil
	default:
		return "", nil, errAmbiguous(qname)
	}
	panic("unreachable")
}

type mapCandidate struct {
	name string
	typ  reflect.Type
}

type sortModels []driver.Model

func (s sortModels) Len() int {
	return len(s)
}

func (s sortModels) less(mi, mj driver.Model) bool {
	for _, v := range mi.Fields().References {
		if v.Model == mj {
			return false
		}
		if v.Model != mi && !s.less(v.Model, mj) {
			return false
		}
	}
	return true
}

func (s sortModels) Less(i, j int) bool {
	return s.less(s[i], s[j])
}

func (s sortModels) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

type errCantMap string

func (e errCantMap) Error() string {
	return fmt.Sprintf("can't map field %q to a database name", string(e))
}

type errNotThisModel string

func (e errNotThisModel) Error() string {
	return fmt.Sprintf("name %q does not correspond to this model", string(e))
}

type errAmbiguous string

func (e errAmbiguous) Error() string {
	return fmt.Sprintf("field name %q is ambiguous. Please, indicate the type like e.g. Type|Field", string(e))
}
<|endoftext|>


<commit_before>package orm

import (
	"fmt"
	"gnd.la/orm/driver"
	"gnd.la/orm/index"
	"gnd.la/orm/query"
	"reflect"
	"strings"
)

type JoinType int

const (
	InnerJoin JoinType = JoinType(driver.InnerJoin)
	OuterJoin JoinType = JoinType(driver.OuterJoin)
	LeftJoin  JoinType = JoinType(driver.LeftJoin)
	RightJoin JoinType = JoinType(driver.RightJoin)
)

func (j JoinType) String() string {
	switch j {
	case InnerJoin:
		return "INNER JOIN"
	case OuterJoin:
		return "OUTER JOIN"
	case LeftJoin:
		return "LEFT OUTER JOIN"
	case RightJoin:
		return "OUTER JOIN"
	}
	return "unknown JoinType"
}

type reference struct {
	model string
	field string
}

type model struct {
	options         *Options
	name            string
	shortName       string
	table           string
	fields          *driver.Fields
	tags            string
	references      map[string]*reference
	modelReferences map[*model][]*join
	namedReferences map[string]*model
}

func (m *model) Type() reflect.Type {
	return m.fields.Type
}

func (m *model) Table() string {
	return m.table
}

func (m *model) Fields() *driver.Fields {
	return m.fields
}

func (m *model) Indexes() []*index.Index {
	var indexes []*index.Index
	if m.options != nil {
		indexes = append(indexes, m.options.Indexes...)
	}
	// Add indexes declared in the fields
	for ii, v := range m.fields.Tags {
		if v.Has("index") {
			indexes = append(indexes, &index.Index{
				Fields: []string{m.fields.QNames[ii]},
				Unique: v.Has("unique"),
			})
		}
	}
	return indexes
}

func (m *model) Map(qname string) (string, reflect.Type, error) {
	sep := strings.IndexByte(qname, '|')
	if sep >= 0 {
		name := qname[:sep]
		if name != m.name && name != m.shortName {
			return "", nil, errNotThisModel(name)
		}
		qname = qname[sep+1:]
	}
	if n, ok := m.fields.QNameMap[qname]; ok {
		return m.fields.QuotedNames[n], m.fields.Types[n], nil
	}
	return "", nil, errCantMap(qname)
}

func (m *model) Skip() bool {
	return false
}

func (m *model) Join() driver.Join {
	return nil
}

func (m *model) String() string {
	return m.name
}

func (m *model) fullName(qname string) string {
	return m.name + "|" + qname
}

type join struct {
	model *joinModel
	jtype JoinType
	q     query.Q
}

func (j *join) Model() driver.Model {
	return j.model
}

func (j *join) Type() driver.JoinType {
	return driver.JoinType(j.jtype)
}

func (j *join) Query() query.Q {
	return j.q
}

func (j *join) clone() *join {
	return &join{
		model: j.model.clone(),
		jtype: j.jtype,
		q:     j.q,
	}
}

type joinModel struct {
	*model
	skip bool
	join *join
}

func (j *joinModel) clone() *joinModel {
	nj := &joinModel{
		model: j.model,
		skip:  j.skip,
	}
	if j.join != nil {
		nj.join = j.join.clone()
	}
	return nj
}

func (j *joinModel) Fields() *driver.Fields {
	if j.skip {
		return nil
	}
	return j.model.Fields()
}

func (j *joinModel) Skip() bool {
	return j.skip
}

func (j *joinModel) Join() driver.Join {
	// This workarounds a gotcha in Go which
	// generates an interface which points to nil
	// when returning a nil variable, thus making
	// the caller think it got a non-nil object if
	// it just checks for x != nil. The caller can
	// check for this using reflect, but it seems
	// easier and less error prone to circumvent the
	// problem right here.
	if j.join == nil {
		return nil
	}
	return j.join
}

func (j *joinModel) String() string {
	s := []string{j.model.name}
	for cur := j; cur.join != nil; cur = cur.join.model {
		s = append(s, " JOIN ")
		s = append(s, cur.join.model.name)
		s = append(s, " ON ")
		s = append(s, fmt.Sprintf("%+v", cur.join.q))
	}
	return strings.Join(s, "")
}

func (j *joinModel) joinWith(model *model, q query.Q, jt JoinType) (*joinModel, error) {
	if j.model == nil {
		j.model = model
		return j, nil
	}
	m := j
	if q == nil {
		var candidates []*join
		// Implicit join
		for {
			candidates = append(candidates, m.modelReferences[model]...)
			if m.join == nil {
				break
			}
			m = m.join.model
		}
		if len(candidates) > 1 {
			// Check if all the candidates point to the same
			// model and field. In that case, pick the first one.
			first := candidates[0]
			if eq, ok := first.q.(*query.Eq); ok {
				equal := true
				for _, v := range candidates[1:] {
					if veq, ok := v.q.(*query.Eq); !ok || first.model.model != v.model.model || !reflect.DeepEqual(eq.Value, veq.Value) {
						equal = false
						break
					}
				}
				if equal {
					candidates = candidates[:1]
				}
			}
		}
		switch len(candidates) {
		case 1:
			m.join = candidates[0].clone()
			m.join.jtype = jt
		case 0:
			return nil, fmt.Errorf("can't join %s with model %s", j, model)
		default:
			return nil, fmt.Errorf("joining %s with model %s is ambiguous using query %+v", j, model, q)
		}
	} else {
		for m.join != nil {
			m = m.join.model
		}
		m.join = &join{
			model: &joinModel{model: model},
			jtype: jt,
			q:     q,
		}
	}
	return m.join.model, nil
}

func (j *joinModel) joinWithField(field string, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	pipe := strings.IndexByte(field, '|')
	if pipe < 0 {
		return nil
	}
	typ := field[:pipe]
	m := j
	for {
		if model := m.model.namedReferences[typ]; model != nil {
			// Check if we're already joined to this model
			if _, ok := models[model]; ok {
				break
			}
			// Joins derived from queries are always implicit
			// and skipped, since we're only joining to check
			// against the value of the joined model.
			last, err := j.joinWith(model, nil, jt)
			if err != nil {
				return err
			}
			last.skip = true
			models[model] = struct{}{}
			*methods = append(*methods, model.fields.Methods)
			break
		}
		join := m.join
		if join == nil {
			break
		}
		m = join.model
	}
	return nil
}

func (j *joinModel) joinWithSort(sort []driver.Sort, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	for _, v := range sort {
		if err := j.joinWithField(v.Field(), jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) joinWithQuery(q query.Q, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	if err := j.joinWithField(q.FieldName(), jt, models, methods); err != nil {
		return err
	}
	for _, sq := range q.SubQ() {
		if err := j.joinWithQuery(sq, jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) Map(qname string) (string, reflect.Type, error) {
	var candidates []mapCandidate
	for cur := j; ; {
		n, t, err := cur.model.Map(qname)
		if err == nil {
			candidates = append(candidates, mapCandidate{n, t})
		}
		if cur.join == nil {
			break
		}
		cur = cur.join.model
	}
	switch len(candidates) {
	case 0:
		return "", nil, errCantMap(qname)
	case 1:
		c := candidates[0]
		return c.name, c.typ, nil
	default:
		return "", nil, errAmbiguous(qname)
	}
	panic("unreachable")
}

type mapCandidate struct {
	name string
	typ  reflect.Type
}

type sortModels []driver.Model

func (s sortModels) Len() int {
	return len(s)
}

func (s sortModels) less(mi, mj driver.Model) bool {
	for _, v := range mi.Fields().References {
		if v.Model == mj {
			return false
		}
		if v.Model != mi && !s.less(v.Model, mj) {
			return false
		}
	}
	return true
}

func (s sortModels) Less(i, j int) bool {
	return s.less(s[i], s[j])
}

func (s sortModels) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

type errCantMap string

func (e errCantMap) Error() string {
	return fmt.Sprintf("can't map field %q to a database name", string(e))
}

type errNotThisModel string

func (e errNotThisModel) Error() string {
	return fmt.Sprintf("name %q does not correspond to this model", string(e))
}

type errAmbiguous string

func (e errAmbiguous) Error() string {
	return fmt.Sprintf("field name %q is ambiguous. Please, indicate the type like e.g. Type|Field", string(e))
}
<commit_msg>Show skipped models in joinModel's String()<commit_after>package orm

import (
	"fmt"
	"gnd.la/orm/driver"
	"gnd.la/orm/index"
	"gnd.la/orm/query"
	"reflect"
	"strings"
)

type JoinType int

const (
	InnerJoin JoinType = JoinType(driver.InnerJoin)
	OuterJoin JoinType = JoinType(driver.OuterJoin)
	LeftJoin  JoinType = JoinType(driver.LeftJoin)
	RightJoin JoinType = JoinType(driver.RightJoin)
)

func (j JoinType) String() string {
	switch j {
	case InnerJoin:
		return "INNER JOIN"
	case OuterJoin:
		return "OUTER JOIN"
	case LeftJoin:
		return "LEFT OUTER JOIN"
	case RightJoin:
		return "OUTER JOIN"
	}
	return "unknown JoinType"
}

type reference struct {
	model string
	field string
}

type model struct {
	options         *Options
	name            string
	shortName       string
	table           string
	fields          *driver.Fields
	tags            string
	references      map[string]*reference
	modelReferences map[*model][]*join
	namedReferences map[string]*model
}

func (m *model) Type() reflect.Type {
	return m.fields.Type
}

func (m *model) Table() string {
	return m.table
}

func (m *model) Fields() *driver.Fields {
	return m.fields
}

func (m *model) Indexes() []*index.Index {
	var indexes []*index.Index
	if m.options != nil {
		indexes = append(indexes, m.options.Indexes...)
	}
	// Add indexes declared in the fields
	for ii, v := range m.fields.Tags {
		if v.Has("index") {
			indexes = append(indexes, &index.Index{
				Fields: []string{m.fields.QNames[ii]},
				Unique: v.Has("unique"),
			})
		}
	}
	return indexes
}

func (m *model) Map(qname string) (string, reflect.Type, error) {
	sep := strings.IndexByte(qname, '|')
	if sep >= 0 {
		name := qname[:sep]
		if name != m.name && name != m.shortName {
			return "", nil, errNotThisModel(name)
		}
		qname = qname[sep+1:]
	}
	if n, ok := m.fields.QNameMap[qname]; ok {
		return m.fields.QuotedNames[n], m.fields.Types[n], nil
	}
	return "", nil, errCantMap(qname)
}

func (m *model) Skip() bool {
	return false
}

func (m *model) Join() driver.Join {
	return nil
}

func (m *model) String() string {
	return m.name
}

func (m *model) fullName(qname string) string {
	return m.name + "|" + qname
}

type join struct {
	model *joinModel
	jtype JoinType
	q     query.Q
}

func (j *join) Model() driver.Model {
	return j.model
}

func (j *join) Type() driver.JoinType {
	return driver.JoinType(j.jtype)
}

func (j *join) Query() query.Q {
	return j.q
}

func (j *join) clone() *join {
	return &join{
		model: j.model.clone(),
		jtype: j.jtype,
		q:     j.q,
	}
}

type joinModel struct {
	*model
	skip bool
	join *join
}

func (j *joinModel) clone() *joinModel {
	nj := &joinModel{
		model: j.model,
		skip:  j.skip,
	}
	if j.join != nil {
		nj.join = j.join.clone()
	}
	return nj
}

func (j *joinModel) Fields() *driver.Fields {
	if j.skip {
		return nil
	}
	return j.model.Fields()
}

func (j *joinModel) Skip() bool {
	return j.skip
}

func (j *joinModel) Join() driver.Join {
	// This workarounds a gotcha in Go which
	// generates an interface which points to nil
	// when returning a nil variable, thus making
	// the caller think it got a non-nil object if
	// it just checks for x != nil. The caller can
	// check for this using reflect, but it seems
	// easier and less error prone to circumvent the
	// problem right here.
	if j.join == nil {
		return nil
	}
	return j.join
}

func (j *joinModel) String() string {
	s := []string{j.model.name}
	if j.skip {
		s = append(s, "(Skipped)")
	}
	if j.join != nil {
		s = append(s, " JOIN ")
		s = append(s, j.join.model.String())
		s = append(s, " ON ")
		s = append(s, fmt.Sprintf("%+v", j.join.q))
	}
	return strings.Join(s, "")
}

func (j *joinModel) joinWith(model *model, q query.Q, jt JoinType) (*joinModel, error) {
	if j.model == nil {
		j.model = model
		return j, nil
	}
	m := j
	if q == nil {
		var candidates []*join
		// Implicit join
		for {
			candidates = append(candidates, m.modelReferences[model]...)
			if m.join == nil {
				break
			}
			m = m.join.model
		}
		if len(candidates) > 1 {
			// Check if all the candidates point to the same
			// model and field. In that case, pick the first one.
			first := candidates[0]
			if eq, ok := first.q.(*query.Eq); ok {
				equal := true
				for _, v := range candidates[1:] {
					if veq, ok := v.q.(*query.Eq); !ok || first.model.model != v.model.model || !reflect.DeepEqual(eq.Value, veq.Value) {
						equal = false
						break
					}
				}
				if equal {
					candidates = candidates[:1]
				}
			}
		}
		switch len(candidates) {
		case 1:
			m.join = candidates[0].clone()
			m.join.jtype = jt
		case 0:
			return nil, fmt.Errorf("can't join %s with model %s", j, model)
		default:
			return nil, fmt.Errorf("joining %s with model %s is ambiguous using query %+v", j, model, q)
		}
	} else {
		for m.join != nil {
			m = m.join.model
		}
		m.join = &join{
			model: &joinModel{model: model},
			jtype: jt,
			q:     q,
		}
	}
	return m.join.model, nil
}

func (j *joinModel) joinWithField(field string, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	pipe := strings.IndexByte(field, '|')
	if pipe < 0 {
		return nil
	}
	typ := field[:pipe]
	m := j
	for {
		if model := m.model.namedReferences[typ]; model != nil {
			// Check if we're already joined to this model
			if _, ok := models[model]; ok {
				break
			}
			// Joins derived from queries are always implicit
			// and skipped, since we're only joining to check
			// against the value of the joined model.
			last, err := j.joinWith(model, nil, jt)
			if err != nil {
				return err
			}
			last.skip = true
			models[model] = struct{}{}
			*methods = append(*methods, model.fields.Methods)
			break
		}
		join := m.join
		if join == nil {
			break
		}
		m = join.model
	}
	return nil
}

func (j *joinModel) joinWithSort(sort []driver.Sort, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	for _, v := range sort {
		if err := j.joinWithField(v.Field(), jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) joinWithQuery(q query.Q, jt JoinType, models map[*model]struct{}, methods *[]*driver.Methods) error {
	if err := j.joinWithField(q.FieldName(), jt, models, methods); err != nil {
		return err
	}
	for _, sq := range q.SubQ() {
		if err := j.joinWithQuery(sq, jt, models, methods); err != nil {
			return err
		}
	}
	return nil
}

func (j *joinModel) Map(qname string) (string, reflect.Type, error) {
	var candidates []mapCandidate
	for cur := j; ; {
		n, t, err := cur.model.Map(qname)
		if err == nil {
			candidates = append(candidates, mapCandidate{n, t})
		}
		if cur.join == nil {
			break
		}
		cur = cur.join.model
	}
	switch len(candidates) {
	case 0:
		return "", nil, errCantMap(qname)
	case 1:
		c := candidates[0]
		return c.name, c.typ, nil
	default:
		return "", nil, errAmbiguous(qname)
	}
	panic("unreachable")
}

type mapCandidate struct {
	name string
	typ  reflect.Type
}

type sortModels []driver.Model

func (s sortModels) Len() int {
	return len(s)
}

func (s sortModels) less(mi, mj driver.Model) bool {
	for _, v := range mi.Fields().References {
		if v.Model == mj {
			return false
		}
		if v.Model != mi && !s.less(v.Model, mj) {
			return false
		}
	}
	return true
}

func (s sortModels) Less(i, j int) bool {
	return s.less(s[i], s[j])
}

func (s sortModels) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

type errCantMap string

func (e errCantMap) Error() string {
	return fmt.Sprintf("can't map field %q to a database name", string(e))
}

type errNotThisModel string

func (e errNotThisModel) Error() string {
	return fmt.Sprintf("name %q does not correspond to this model", string(e))
}

type errAmbiguous string

func (e errAmbiguous) Error() string {
	return fmt.Sprintf("field name %q is ambiguous. Please, indicate the type like e.g. Type|Field", string(e))
}
<|endoftext|>