<commit_before>package wd

import "fmt"

type trieNode struct {
	Value               int
	Cb                  byte
	Left, Middle, Right *trieNode
}

func put(node *trieNode, key string, value, d int) *trieNode {
	c := key[d]
	if node == nil {
		node = &trieNode{Cb: c}
	}
	if c < node.Cb {
		// go to left node
		fmt.Printf("node.Cb: %c, and c:%c, go to left\n", node.Cb, c)
		node.Left = put(node.Left, key, value, d)
	} else if c > node.Cb {
		// go to right node
		fmt.Printf("node.Cb:%c, c: %c go to right\n", node.Cb, c)
		node.Right = put(node.Right, key, value, d)
	} else if d < len(key)-1 {
		fmt.Printf("node.Cb:%c c: %c goto middle\n", node.Cb, c)
		node.Middle = put(node.Middle, key, value, d+1)
	} else {
		// reach the end of key
		fmt.Printf("update node's value:%v, c:%c, d:%d, len(key)=%d\n", value, c, d, len(key))
		node.Value = value
	}
	return node
}

func get(node *trieNode, key string, d int) bool {
	if key == "" || node == nil {
		return false
	}
	if d == len(key) {
		fmt.Printf("reach the end, with node.Val:%d\n", node.Value)
		return node.Value == len(key)
	}
	c := key[d]
	fmt.Printf("node.Cb:%c, c:%c, d:%d\n", node.Cb, c, d)
	if c != '.' {
		if c < node.Cb {
			return get(node.Left, key, d)
		} else if c > node.Cb {
			return get(node.Right, key, d)
		} else if d < len(key)-1 {
			return get(node.Middle, key, d+1)
		} else {
			return node.Value == len(key)
		}
	} else {
		// this is the bottle neck.
		// maybe.. just maybe tst is not the proper choice for this fuzzy search.
		if d < len(key)-1 {
			return get(node.Left, key, d+1) || get(node.Right, key, d+1) || get(node.Middle, key, d+1) || get(node.Left, key, d) || get(node.Right, key, d) || get(node.Middle, key, d)
		}
		return node.Value == len(key)
	}
	return false
}

type WordDict struct {
	root *trieNode
}

func Constructor() *WordDict {
	return &WordDict{}
}

func (this *WordDict) AddWord(word string) {
	this.root = put(this.root, word, len(word), 0)
}

func (this *WordDict) Search(word string) bool {
	return get(this.root, word, 0)
}
<commit_msg>solve 211 use normal trie<commit_after>package wd

import "fmt"

type trieNode struct {
	Value               int
	Cb                  byte
	Left, Middle, Right *trieNode
}

func put(node *trieNode, key string, value, d int) *trieNode {
	c := key[d]
	if node == nil {
		node = &trieNode{Cb: c}
	}
	if c < node.Cb {
		// go to left node
		fmt.Printf("node.Cb: %c, and c:%c, go to left\n", node.Cb, c)
		node.Left = put(node.Left, key, value, d)
	} else if c > node.Cb {
		// go to right node
		fmt.Printf("node.Cb:%c, c: %c go to right\n", node.Cb, c)
		node.Right = put(node.Right, key, value, d)
	} else if d < len(key)-1 {
		fmt.Printf("node.Cb:%c c: %c goto middle\n", node.Cb, c)
		node.Middle = put(node.Middle, key, value, d+1)
	} else {
		// reach the end of key
		fmt.Printf("update node's value:%v, c:%c, d:%d, len(key)=%d\n", value, c, d, len(key))
		node.Value = value
	}
	return node
}

func get(node *trieNode, key string, d int) bool {
	if key == "" || node == nil {
		return false
	}
	if d == len(key) {
		fmt.Printf("reach the end, with node.Val:%d\n", node.Value)
		return node.Value == len(key)
	}
	c := key[d]
	fmt.Printf("node.Cb:%c, c:%c, d:%d\n", node.Cb, c, d)
	if c != '.' {
		if c < node.Cb {
			return get(node.Left, key, d)
		} else if c > node.Cb {
			return get(node.Right, key, d)
		} else if d < len(key)-1 {
			return get(node.Middle, key, d+1)
		} else {
			return node.Value == len(key)
		}
	} else {
		// this is the bottle neck.
		// maybe.. just maybe tst is not the proper choice for this fuzzy search.
		if d < len(key)-1 {
			return get(node.Left, key, d+1) || get(node.Right, key, d+1) || get(node.Middle, key, d+1) || get(node.Left, key, d) || get(node.Right, key, d) || get(node.Middle, key, d)
		}
		return node.Value == len(key)
	}
	return false
}

type normalTrieNode struct {
	children []*normalTrieNode
	item     string
}

type WordDict struct {
	root *normalTrieNode
}

func Constructor() *WordDict {
	return &WordDict{
		root: &normalTrieNode{
			children: make([]*normalTrieNode, 26),
		},
	}
}

func (this *WordDict) AddWord(word string) {
	// this.root = put(this.root, word, len(word), 0)
	node := this.root
	for _, c := range word {
		if node.children[c-'a'] == nil {
			node.children[c-'a'] = &normalTrieNode{
				children: make([]*normalTrieNode, 26),
			}
		}
		node = node.children[c-'a']
	}
	node.item = word
}

func (this *WordDict) Search(word string) bool {
	return match(word, 0, this.root)
}

func match(word string, k int, node *normalTrieNode) bool {
	if k == len(word) {
		return node.item != ""
	}
	if word[k] != '.' {
		return node.children[word[k]-'a'] != nil && match(word, k+1, node.children[word[k]-'a'])
	} else {
		for _, child := range node.children {
			if child != nil {
				if match(word, k+1, child) {
					return true
				}
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright © 2016 Mark Bates <mark@markbates.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package generate

import (
	"errors"
	"path/filepath"

	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

// GothCmd generates a actions/goth.go file configured to the specified providers.
var GothCmd = &cobra.Command{
	Use:   "goth [provider provider...]",
	Short: "Generates a actions/goth.go file configured to the specified providers.",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return errors.New("You must specifiy at least one provider!")
		}
		return NewGothGenerator().Run(".", gentronics.Data{
			"providers": args,
		})
	},
}

// NewGothGenerator a actions/goth.go file configured to the specified providers.
func NewGothGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile(filepath.Join("actions", "goth.go"), gGoth))
	g.Add(Fmt)
	return g
}

var gGoth = `package actions

import (
	"fmt"
	"os"

	"github.com/gobuffalo/buffalo"
	"github.com/markbates/goth"
	"github.com/markbates/goth/gothic"
	{{#each providers}}
	"github.com/markbates/goth/providers/{{ downcase . }}"
	{{/each}}
)

func init() {
	gothic.Store = App().SessionStore

	goth.UseProviders(
		{{#each providers}}
		{{downcase .}}.New(os.Getenv("{{upcase .}}_KEY"), os.Getenv("{{upcase .}}_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/{{downcase .}}/callback")),
		{{/each}}
	)

	app := App().Group("/auth")
	app.GET("/{provider}", buffalo.WrapHandlerFunc(gothic.BeginAuthHandler))
	app.GET("/{provider}/callback", AuthCallback)
}

func AuthCallback(c buffalo.Context) error {
	user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
	if err != nil {
		return c.Error(401, err)
	}
	// Do something with the user, maybe register them/sign them in
	return c.Render(200, r.JSON(user))
}
`
<commit_msg>Goth generator installs required dependencies via go get<commit_after>// Copyright © 2016 Mark Bates <mark@markbates.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package generate

import (
	"errors"
	"path/filepath"

	"github.com/markbates/gentronics"
	"github.com/spf13/cobra"
)

// GothCmd generates a actions/goth.go file configured to the specified providers.
var GothCmd = &cobra.Command{
	Use:   "goth [provider provider...]",
	Short: "Generates a actions/goth.go file configured to the specified providers.",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return errors.New("You must specifiy at least one provider!")
		}
		return NewGothGenerator().Run(".", gentronics.Data{
			"providers": args,
		})
	},
}

// NewGothGenerator a actions/goth.go file configured to the specified providers.
func NewGothGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile(filepath.Join("actions", "goth.go"), gGoth))
	g.Add(gentronics.NewCommand(GoGet("github.com/markbates/goth")))
	g.Add(gentronics.NewCommand(GoGet("github.com/mrjones/oauth")))
	g.Add(Fmt)
	return g
}

var gGoth = `package actions

import (
	"fmt"
	"os"

	"github.com/gobuffalo/buffalo"
	"github.com/markbates/goth"
	"github.com/markbates/goth/gothic"
	{{#each providers}}
	"github.com/markbates/goth/providers/{{ downcase . }}"
	{{/each}}
)

func init() {
	gothic.Store = App().SessionStore

	goth.UseProviders(
		{{#each providers}}
		{{downcase .}}.New(os.Getenv("{{upcase .}}_KEY"), os.Getenv("{{upcase .}}_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/{{downcase .}}/callback")),
		{{/each}}
	)

	app := App().Group("/auth")
	app.GET("/{provider}", buffalo.WrapHandlerFunc(gothic.BeginAuthHandler))
	app.GET("/{provider}/callback", AuthCallback)
}

func AuthCallback(c buffalo.Context) error {
	user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
	if err != nil {
		return c.Error(401, err)
	}
	// Do something with the user, maybe register them/sign them in
	return c.Render(200, r.JSON(user))
}
`
<|endoftext|>


<commit_before>package gateway

import (
	"time"

	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/user"
)

type Monitor struct{}

func (Monitor) Enabled() bool {
	return config.Global().Monitor.EnableTriggerMonitors
}

func (Monitor) Fire(sessionData *user.SessionState, key string, triggerLimit, usagePercentage float64) {
	em := config.EventMessage{
		Type: EventTriggerExceeded,
		Meta: EventTriggerExceededMeta{
			EventMetaDefault: EventMetaDefault{Message: "Quota trigger reached"},
			OrgID:            sessionData.OrgID,
			Key:              key,
			TriggerLimit:     int64(triggerLimit),
			UsagePercentage:  int64(usagePercentage),
		},
		TimeStamp: time.Now().String(),
	}

	go MonitoringHandler.HandleEvent(em)
}

func (m Monitor) Check(sessionData *user.SessionState, key string) {
	if !m.Enabled() {
		return
	}

	if m.checkLimit(sessionData, key, sessionData.QuotaMax, sessionData.QuotaRemaining, sessionData.QuotaRenews) {
		return
	}

	for _, ac := range sessionData.AccessRights {
		if m.checkLimit(sessionData, key, ac.Limit.QuotaMax, ac.Limit.QuotaRemaining, ac.Limit.QuotaRenews) {
			return
		}
	}
}

func (m Monitor) checkLimit(sessionData *user.SessionState, key string, quotaMax, quotaRemaining, quotaRenews int64) bool {
	if quotaMax <= 0 {
		return false
	}

	remainder := quotaMax - quotaRemaining
	usagePerc := (float64(remainder) / float64(quotaMax)) * 100.0

	log.Debug("Perc is: ", usagePerc)
	renewalDate := time.Unix(quotaRenews, 0)

	log.Debug("Now is: ", time.Now())
	log.Debug("Renewal is: ", renewalDate)
	if time.Now().After(renewalDate) {
		// Make sure that renewal is still in the future, If renewal is in the past,
		// then the quota can expire and will auto-renew
		log.Debug("Renewal date is in the past, skipping")
		return false
	}

	if config.Global().Monitor.GlobalTriggerLimit > 0.0 && usagePerc >= config.Global().Monitor.GlobalTriggerLimit {
		log.Info("Firing...")
		m.Fire(sessionData, key, config.Global().Monitor.GlobalTriggerLimit, usagePerc)
		return true
	}

	for _, triggerLimit := range sessionData.Monitor.TriggerLimits {
		if usagePerc >= triggerLimit && triggerLimit != config.Global().Monitor.GlobalTriggerLimit {
			log.Info("Firing...")
			m.Fire(sessionData, key, triggerLimit, usagePerc)
			return true
		}
	}

	return false
}
<commit_msg>Check limit is nil on monitoring (#3140)<commit_after>package gateway

import (
	"time"

	"github.com/TykTechnologies/tyk/config"
	"github.com/TykTechnologies/tyk/user"
)

type Monitor struct{}

func (Monitor) Enabled() bool {
	return config.Global().Monitor.EnableTriggerMonitors
}

func (Monitor) Fire(sessionData *user.SessionState, key string, triggerLimit, usagePercentage float64) {
	em := config.EventMessage{
		Type: EventTriggerExceeded,
		Meta: EventTriggerExceededMeta{
			EventMetaDefault: EventMetaDefault{Message: "Quota trigger reached"},
			OrgID:            sessionData.OrgID,
			Key:              key,
			TriggerLimit:     int64(triggerLimit),
			UsagePercentage:  int64(usagePercentage),
		},
		TimeStamp: time.Now().String(),
	}

	go MonitoringHandler.HandleEvent(em)
}

func (m Monitor) Check(sessionData *user.SessionState, key string) {
	if !m.Enabled() {
		return
	}

	if m.checkLimit(sessionData, key, sessionData.QuotaMax, sessionData.QuotaRemaining, sessionData.QuotaRenews) {
		return
	}

	for _, ac := range sessionData.AccessRights {
		if ac.Limit == nil {
			continue
		}

		if m.checkLimit(sessionData, key, ac.Limit.QuotaMax, ac.Limit.QuotaRemaining, ac.Limit.QuotaRenews) {
			return
		}
	}
}

func (m Monitor) checkLimit(sessionData *user.SessionState, key string, quotaMax, quotaRemaining, quotaRenews int64) bool {
	if quotaMax <= 0 {
		return false
	}

	remainder := quotaMax - quotaRemaining
	usagePerc := (float64(remainder) / float64(quotaMax)) * 100.0

	log.Debug("Perc is: ", usagePerc)
	renewalDate := time.Unix(quotaRenews, 0)

	log.Debug("Now is: ", time.Now())
	log.Debug("Renewal is: ", renewalDate)
	if time.Now().After(renewalDate) {
		// Make sure that renewal is still in the future, If renewal is in the past,
		// then the quota can expire and will auto-renew
		log.Debug("Renewal date is in the past, skipping")
		return false
	}

	if config.Global().Monitor.GlobalTriggerLimit > 0.0 && usagePerc >= config.Global().Monitor.GlobalTriggerLimit {
		log.Info("Firing...")
		m.Fire(sessionData, key, config.Global().Monitor.GlobalTriggerLimit, usagePerc)
		return true
	}

	for _, triggerLimit := range sessionData.Monitor.TriggerLimits {
		if usagePerc >= triggerLimit && triggerLimit != config.Global().Monitor.GlobalTriggerLimit {
			log.Info("Firing...")
			m.Fire(sessionData, key, triggerLimit, usagePerc)
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package generator

import (
	"strings"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/tcncloud/protoc-gen-persist/persist"
)

func IsMethodEnabled(method *descriptor.MethodDescriptorProto) bool {
	if method != nil && method.GetOptions() != nil && proto.HasExtension(method.Options, persist.E_Ql) {
		return true
	}
	return false
}

func GetMethodExtensionData(method *descriptor.MethodDescriptorProto) *persist.QLImpl {
	if IsMethodEnabled(method) {
		ex, err := proto.GetExtension(method.Options, persist.E_Ql)
		if err != nil {
			return nil
		}
		return ex.(*persist.QLImpl)
	}
	return nil
}

// check if a service has at least one method that has the persist.ql extension defined
func IsServicePersistEnabled(service *descriptor.ServiceDescriptorProto) bool {
	if service.Method != nil {
		for _, method := range service.Method {
			if IsMethodEnabled(method) {
				return true
			}
		}
	}
	return false
}

func splitType(typ string) (string, string) {
	typeName := typ[strings.LastIndex(typ, ".")+1 : len(typ)]
	pkgName := typ[1:strings.LastIndex(typ, ".")]
	return typeName, pkgName
}

func FindMessage(files []*descriptor.FileDescriptorProto, typeString string) *descriptor.DescriptorProto {
	typeName, pkgName := splitType(typeString)
	for _, file := range files {
		if pkgName == file.GetPackage() {
			for _, message := range file.MessageType {
				if typeName == message.GetName() {
					return message
				}
			}
		}
	}
	return nil
}
<commit_msg>add FindEnum function<commit_after>// Copyright 2017, TCN Inc.
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of TCN Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package generator

import (
	"strings"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/tcncloud/protoc-gen-persist/persist"
)

func IsMethodEnabled(method *descriptor.MethodDescriptorProto) bool {
	if method != nil && method.GetOptions() != nil && proto.HasExtension(method.Options, persist.E_Ql) {
		return true
	}
	return false
}

func GetMethodExtensionData(method *descriptor.MethodDescriptorProto) *persist.QLImpl {
	if IsMethodEnabled(method) {
		ex, err := proto.GetExtension(method.Options, persist.E_Ql)
		if err != nil {
			return nil
		}
		return ex.(*persist.QLImpl)
	}
	return nil
}

// check if a service has at least one method that has the persist.ql extension defined
func IsServicePersistEnabled(service *descriptor.ServiceDescriptorProto) bool {
	if service.Method != nil {
		for _, method := range service.Method {
			if IsMethodEnabled(method) {
				return true
			}
		}
	}
	return false
}

func splitType(typ string) (string, string) {
	typeName := typ[strings.LastIndex(typ, ".")+1 : len(typ)]
	pkgName := typ[1:strings.LastIndex(typ, ".")]
	return typeName, pkgName
}

func FindMessage(files []*descriptor.FileDescriptorProto, typeString string) *descriptor.DescriptorProto {
	typeName, pkgName := splitType(typeString)
	for _, file := range files {
		if pkgName == file.GetPackage() {
			for _, message := range file.MessageType {
				if typeName == message.GetName() {
					return message
				}
			}
		}
	}
	return nil
}

func FindEnum(files []*descriptor.FileDescriptorProto, enumString string) *descriptor.EnumDescriptorProto {
	enumName, pkgName := splitType(enumString)
	for _, file := range files {
		if pkgName == file.GetPackage() {
			for _, enum := range file.GetEnumType() {
				if enumName == enum.GetName() {
					return enum
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package genesis

import (
	"errors"
	"fmt"
	"time"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils/codec"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/json"
	"github.com/ava-labs/gecko/utils/units"
	"github.com/ava-labs/gecko/utils/wrappers"
	"github.com/ava-labs/gecko/vms/avm"
	"github.com/ava-labs/gecko/vms/nftfx"
	"github.com/ava-labs/gecko/vms/platformvm"
	"github.com/ava-labs/gecko/vms/propertyfx"
	"github.com/ava-labs/gecko/vms/secp256k1fx"
	"github.com/ava-labs/gecko/vms/spchainvm"
	"github.com/ava-labs/gecko/vms/spdagvm"
	"github.com/ava-labs/gecko/vms/timestampvm"
)

// ID of the EVM VM
var (
	EVMID = ids.NewID([32]byte{'e', 'v', 'm'})
)

// Genesis returns the genesis data of the Platform Chain.
// Since an AVA network has exactly one Platform Chain, and the Platform Chain
// defines the genesis state of the network (who is staking, which chains exist,
// etc.), defining the genesis state of the Platform Chain is the same as
// defining the genesis state of the network.
// The ID of the new network is [networkID].

// FromConfig ...
func FromConfig(networkID uint32, config *Config) ([]byte, error) {
	if err := config.init(); err != nil {
		return nil, err
	}

	// Specify the genesis state of the AVM
	avmArgs := avm.BuildGenesisArgs{}
	{
		ava := avm.AssetDefinition{
			Name:         "AVA",
			Symbol:       "AVA",
			Denomination: 9,
			InitialState: map[string][]interface{}{},
		}

		if len(config.MintAddresses) > 0 {
			ava.InitialState["variableCap"] = []interface{}{avm.Owners{
				Threshold: 1,
				Minters:   config.MintAddresses,
			}}
		}
		for _, addr := range config.FundedAddresses {
			ava.InitialState["fixedCap"] = append(ava.InitialState["fixedCap"], avm.Holder{
				Amount:  json.Uint64(45 * units.MegaAva),
				Address: addr,
			})
		}

		avmArgs.GenesisData = map[string]avm.AssetDefinition{
			// The AVM starts out with one asset, $AVA
			"AVA": ava,
		}
	}
	avmReply := avm.BuildGenesisReply{}

	avmSS := avm.StaticService{}
	err := avmSS.BuildGenesis(nil, &avmArgs, &avmReply)
	if err != nil {
		return nil, err
	}

	// Specify the genesis state of the simple payments DAG
	spdagvmArgs := spdagvm.BuildGenesisArgs{}
	for _, addr := range config.ParsedFundedAddresses {
		spdagvmArgs.Outputs = append(spdagvmArgs.Outputs,
			spdagvm.APIOutput{
				Amount:    json.Uint64(20 * units.KiloAva),
				Threshold: 1,
				Addresses: []ids.ShortID{addr},
			},
		)
	}

	spdagvmReply := spdagvm.BuildGenesisReply{}
	spdagvmSS := spdagvm.StaticService{}
	if err := spdagvmSS.BuildGenesis(nil, &spdagvmArgs, &spdagvmReply); err != nil {
		return nil, fmt.Errorf("problem creating simple payments DAG: %w", err)
	}

	// Specify the genesis state of the simple payments chain
	spchainvmArgs := spchainvm.BuildGenesisArgs{}
	for _, addr := range config.ParsedFundedAddresses {
		spchainvmArgs.Accounts = append(spchainvmArgs.Accounts,
			spchainvm.APIAccount{
				Address: addr,
				Balance: json.Uint64(20 * units.KiloAva),
			},
		)
	}
	spchainvmReply := spchainvm.BuildGenesisReply{}

	spchainvmSS := spchainvm.StaticService{}
	if err := spchainvmSS.BuildGenesis(nil, &spchainvmArgs, &spchainvmReply); err != nil {
		return nil, fmt.Errorf("problem creating simple payments chain: %w", err)
	}

	// Specify the initial state of the Platform Chain
	platformvmArgs := platformvm.BuildGenesisArgs{
		NetworkID: json.Uint32(networkID),
	}
	for _, addr := range config.ParsedFundedAddresses {
		platformvmArgs.Accounts = append(platformvmArgs.Accounts,
			platformvm.APIAccount{
				Address: addr,
				Balance: json.Uint64(20 * units.KiloAva),
			},
		)
	}

	genesisTime := time.Date(
		/*year=*/ 2019,
		/*month=*/ time.November,
		/*day=*/ 1,
		/*hour=*/ 0,
		/*minute=*/ 0,
		/*second=*/ 0,
		/*nano-second=*/ 0,
		/*location=*/ time.UTC,
	)
	stakingDuration := 365 * 24 * time.Hour // ~ 1 year
	endStakingTime := genesisTime.Add(stakingDuration)

	for i, validatorID := range config.ParsedStakerIDs {
		weight := json.Uint64(20 * units.KiloAva)
		platformvmArgs.Validators = append(platformvmArgs.Validators,
			platformvm.APIDefaultSubnetValidator{
				APIValidator: platformvm.APIValidator{
					StartTime: json.Uint64(genesisTime.Unix()),
					EndTime:   json.Uint64(endStakingTime.Unix()),
					Weight:    &weight,
					ID:        validatorID,
				},
				Destination: config.ParsedFundedAddresses[i%len(config.ParsedFundedAddresses)],
			},
		)
	}

	// Specify the chains that exist upon this network's creation
	platformvmArgs.Chains = []platformvm.APIChain{
		{
			GenesisData: avmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        avm.ID,
			FxIDs: []ids.ID{
				secp256k1fx.ID,
				nftfx.ID,
				propertyfx.ID,
			},
			Name: "X-Chain",
		},
		{
			GenesisData: formatting.CB58{Bytes: config.EVMBytes},
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        EVMID,
			Name:        "C-Chain",
		},
		{
			GenesisData: spdagvmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        spdagvm.ID,
			Name:        "Simple DAG Payments",
		},
		{
			GenesisData: spchainvmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        spchainvm.ID,
			Name:        "Simple Chain Payments",
		},
		{
			GenesisData: formatting.CB58{Bytes: []byte{}}, // There is no genesis data
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        timestampvm.ID,
			Name:        "Simple Timestamp Server",
		},
	}

	platformvmArgs.Time = json.Uint64(genesisTime.Unix())
	platformvmReply := platformvm.BuildGenesisReply{}

	platformvmSS := platformvm.StaticService{}
	if err := platformvmSS.BuildGenesis(nil, &platformvmArgs, &platformvmReply); err != nil {
		return nil, fmt.Errorf("problem while building platform chain's genesis state: %w", err)
	}

	return platformvmReply.Bytes.Bytes, nil
}

// Genesis ...
func Genesis(networkID uint32) ([]byte, error) { return FromConfig(networkID, GetConfig(networkID)) }

// VMGenesis ...
func VMGenesis(networkID uint32, vmID ids.ID) (*platformvm.CreateChainTx, error) {
	genesisBytes, err := Genesis(networkID)
	if err != nil {
		return nil, err
	}
	genesis := platformvm.Genesis{}
	platformvm.Codec.Unmarshal(genesisBytes, &genesis)
	if err := genesis.Initialize(); err != nil {
		return nil, err
	}
	for _, chain := range genesis.Chains {
		if chain.VMID.Equals(vmID) {
			return chain, nil
		}
	}
	return nil, fmt.Errorf("couldn't find subnet with VM ID %s", vmID)
}

// AVAAssetID ...
func AVAAssetID(networkID uint32) (ids.ID, error) {
	createAVM, err := VMGenesis(networkID, avm.ID)
	if err != nil {
		return ids.ID{}, err
	}

	c := codec.NewDefault()
	errs := wrappers.Errs{}
	errs.Add(
		c.RegisterType(&avm.BaseTx{}),
		c.RegisterType(&avm.CreateAssetTx{}),
		c.RegisterType(&avm.OperationTx{}),
		c.RegisterType(&avm.ImportTx{}),
		c.RegisterType(&avm.ExportTx{}),
		c.RegisterType(&secp256k1fx.TransferInput{}),
		c.RegisterType(&secp256k1fx.MintOutput{}),
		c.RegisterType(&secp256k1fx.TransferOutput{}),
		c.RegisterType(&secp256k1fx.MintOperation{}),
		c.RegisterType(&secp256k1fx.Credential{}),
	)
	if errs.Errored() {
		return ids.ID{}, errs.Err
	}

	genesis := avm.Genesis{}
	if err := c.Unmarshal(createAVM.GenesisData, &genesis); err != nil {
		return ids.ID{}, err
	}

	if len(genesis.Txs) == 0 {
		return ids.ID{}, errors.New("genesis creates no transactions")
	}
	genesisTx := genesis.Txs[0]

	tx := avm.Tx{UnsignedTx: &genesisTx.CreateAssetTx}
	txBytes, err := c.Marshal(&tx)
	if err != nil {
		return ids.ID{}, err
	}
	tx.Initialize(txBytes)

	return tx.ID(), nil
}
<commit_msg>Handle potential error when unmarshalling genesis bytes<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package genesis

import (
	"errors"
	"fmt"
	"time"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils/codec"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/json"
	"github.com/ava-labs/gecko/utils/units"
	"github.com/ava-labs/gecko/utils/wrappers"
	"github.com/ava-labs/gecko/vms/avm"
	"github.com/ava-labs/gecko/vms/nftfx"
	"github.com/ava-labs/gecko/vms/platformvm"
	"github.com/ava-labs/gecko/vms/propertyfx"
	"github.com/ava-labs/gecko/vms/secp256k1fx"
	"github.com/ava-labs/gecko/vms/spchainvm"
	"github.com/ava-labs/gecko/vms/spdagvm"
	"github.com/ava-labs/gecko/vms/timestampvm"
)

// ID of the EVM VM
var (
	EVMID = ids.NewID([32]byte{'e', 'v', 'm'})
)

// Genesis returns the genesis data of the Platform Chain.
// Since an AVA network has exactly one Platform Chain, and the Platform Chain
// defines the genesis state of the network (who is staking, which chains exist,
// etc.), defining the genesis state of the Platform Chain is the same as
// defining the genesis state of the network.
// The ID of the new network is [networkID].

// FromConfig ...
func FromConfig(networkID uint32, config *Config) ([]byte, error) {
	if err := config.init(); err != nil {
		return nil, err
	}

	// Specify the genesis state of the AVM
	avmArgs := avm.BuildGenesisArgs{}
	{
		ava := avm.AssetDefinition{
			Name:         "AVA",
			Symbol:       "AVA",
			Denomination: 9,
			InitialState: map[string][]interface{}{},
		}

		if len(config.MintAddresses) > 0 {
			ava.InitialState["variableCap"] = []interface{}{avm.Owners{
				Threshold: 1,
				Minters:   config.MintAddresses,
			}}
		}
		for _, addr := range config.FundedAddresses {
			ava.InitialState["fixedCap"] = append(ava.InitialState["fixedCap"], avm.Holder{
				Amount:  json.Uint64(45 * units.MegaAva),
				Address: addr,
			})
		}

		avmArgs.GenesisData = map[string]avm.AssetDefinition{
			// The AVM starts out with one asset, $AVA
			"AVA": ava,
		}
	}
	avmReply := avm.BuildGenesisReply{}

	avmSS := avm.StaticService{}
	err := avmSS.BuildGenesis(nil, &avmArgs, &avmReply)
	if err != nil {
		return nil, err
	}

	// Specify the genesis state of the simple payments DAG
	spdagvmArgs := spdagvm.BuildGenesisArgs{}
	for _, addr := range config.ParsedFundedAddresses {
		spdagvmArgs.Outputs = append(spdagvmArgs.Outputs,
			spdagvm.APIOutput{
				Amount:    json.Uint64(20 * units.KiloAva),
				Threshold: 1,
				Addresses: []ids.ShortID{addr},
			},
		)
	}

	spdagvmReply := spdagvm.BuildGenesisReply{}
	spdagvmSS := spdagvm.StaticService{}
	if err := spdagvmSS.BuildGenesis(nil, &spdagvmArgs, &spdagvmReply); err != nil {
		return nil, fmt.Errorf("problem creating simple payments DAG: %w", err)
	}

	// Specify the genesis state of the simple payments chain
	spchainvmArgs := spchainvm.BuildGenesisArgs{}
	for _, addr := range config.ParsedFundedAddresses {
		spchainvmArgs.Accounts = append(spchainvmArgs.Accounts,
			spchainvm.APIAccount{
				Address: addr,
				Balance: json.Uint64(20 * units.KiloAva),
			},
		)
	}
	spchainvmReply := spchainvm.BuildGenesisReply{}

	spchainvmSS := spchainvm.StaticService{}
	if err := spchainvmSS.BuildGenesis(nil, &spchainvmArgs, &spchainvmReply); err != nil {
		return nil, fmt.Errorf("problem creating simple payments chain: %w", err)
	}

	// Specify the initial state of the Platform Chain
	platformvmArgs := platformvm.BuildGenesisArgs{
		NetworkID: json.Uint32(networkID),
	}
	for _, addr := range config.ParsedFundedAddresses {
		platformvmArgs.Accounts = append(platformvmArgs.Accounts,
			platformvm.APIAccount{
				Address: addr,
				Balance: json.Uint64(20 * units.KiloAva),
			},
		)
	}

	genesisTime := time.Date(
		/*year=*/ 2019,
		/*month=*/ time.November,
		/*day=*/ 1,
		/*hour=*/ 0,
		/*minute=*/ 0,
		/*second=*/ 0,
		/*nano-second=*/ 0,
		/*location=*/ time.UTC,
	)
	stakingDuration := 365 * 24 * time.Hour // ~ 1 year
	endStakingTime := genesisTime.Add(stakingDuration)

	for i, validatorID := range config.ParsedStakerIDs {
		weight := json.Uint64(20 * units.KiloAva)
		platformvmArgs.Validators = append(platformvmArgs.Validators,
			platformvm.APIDefaultSubnetValidator{
				APIValidator: platformvm.APIValidator{
					StartTime: json.Uint64(genesisTime.Unix()),
					EndTime:   json.Uint64(endStakingTime.Unix()),
					Weight:    &weight,
					ID:        validatorID,
				},
				Destination: config.ParsedFundedAddresses[i%len(config.ParsedFundedAddresses)],
			},
		)
	}

	// Specify the chains that exist upon this network's creation
	platformvmArgs.Chains = []platformvm.APIChain{
		{
			GenesisData: avmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        avm.ID,
			FxIDs: []ids.ID{
				secp256k1fx.ID,
				nftfx.ID,
				propertyfx.ID,
			},
			Name: "X-Chain",
		},
		{
			GenesisData: formatting.CB58{Bytes: config.EVMBytes},
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        EVMID,
			Name:        "C-Chain",
		},
		{
			GenesisData: spdagvmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        spdagvm.ID,
			Name:        "Simple DAG Payments",
		},
		{
			GenesisData: spchainvmReply.Bytes,
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        spchainvm.ID,
			Name:        "Simple Chain Payments",
		},
		{
			GenesisData: formatting.CB58{Bytes: []byte{}}, // There is no genesis data
			SubnetID:    platformvm.DefaultSubnetID,
			VMID:        timestampvm.ID,
			Name:        "Simple Timestamp Server",
		},
	}

	platformvmArgs.Time = json.Uint64(genesisTime.Unix())
	platformvmReply := platformvm.BuildGenesisReply{}

	platformvmSS := platformvm.StaticService{}
	if err := platformvmSS.BuildGenesis(nil, &platformvmArgs, &platformvmReply); err != nil {
		return nil, fmt.Errorf("problem while building platform chain's genesis state: %w", err)
	}

	return platformvmReply.Bytes.Bytes, nil
}

// Genesis ...
func Genesis(networkID uint32) ([]byte, error) { return FromConfig(networkID, GetConfig(networkID)) }

// VMGenesis ...
func VMGenesis(networkID uint32, vmID ids.ID) (*platformvm.CreateChainTx, error) {
	genesisBytes, err := Genesis(networkID)
	if err != nil {
		return nil, err
	}
	genesis := platformvm.Genesis{}
	if err := platformvm.Codec.Unmarshal(genesisBytes, &genesis); err != nil {
		return nil, fmt.Errorf("couldn't unmarshal genesis bytes due to: %s", err)
	}
	if err := genesis.Initialize(); err != nil {
		return nil, err
	}
	for _, chain := range genesis.Chains {
		if chain.VMID.Equals(vmID) {
			return chain, nil
		}
	}
	return nil, fmt.Errorf("couldn't find subnet with VM ID %s", vmID)
}

// AVAAssetID ...
func AVAAssetID(networkID uint32) (ids.ID, error) {
	createAVM, err := VMGenesis(networkID, avm.ID)
	if err != nil {
		return ids.ID{}, err
	}

	c := codec.NewDefault()
	errs := wrappers.Errs{}
	errs.Add(
		c.RegisterType(&avm.BaseTx{}),
		c.RegisterType(&avm.CreateAssetTx{}),
		c.RegisterType(&avm.OperationTx{}),
		c.RegisterType(&avm.ImportTx{}),
		c.RegisterType(&avm.ExportTx{}),
		c.RegisterType(&secp256k1fx.TransferInput{}),
		c.RegisterType(&secp256k1fx.MintOutput{}),
		c.RegisterType(&secp256k1fx.TransferOutput{}),
		c.RegisterType(&secp256k1fx.MintOperation{}),
		c.RegisterType(&secp256k1fx.Credential{}),
	)
	if errs.Errored() {
		return ids.ID{}, errs.Err
	}

	genesis := avm.Genesis{}
	if err := c.Unmarshal(createAVM.GenesisData, &genesis); err != nil {
		return ids.ID{}, err
	}

	if len(genesis.Txs) == 0 {
		return ids.ID{}, errors.New("genesis creates no transactions")
	}
	genesisTx := genesis.Txs[0]

	tx := avm.Tx{UnsignedTx: &genesisTx.CreateAssetTx}
	txBytes, err := c.Marshal(&tx)
	if err != nil {
		return ids.ID{}, err
	}
	tx.Initialize(txBytes)

	return tx.ID(), nil
}
<|endoftext|>


<commit_before><commit_msg>Add parent_id field to new build response, rename recipe to patch<commit_after><|endoftext|>


<commit_before>package talentioutil

import (
	"sync"

	"github.com/kaneshin/go-talentio/talentio"
)

type (
	_Candidates struct{}

	// CandidatesListOptions represents list of candidates.
	CandidatesListOptions struct {
		Status  string
		Sort    string
		MaxPage int
	}
)

// Candidates is.
var Candidates _Candidates

func (c _Candidates) List(client *talentio.Client, opt *CandidatesListOptions) ([]*talentio.Candidate, error) {
	if opt == nil {
		opt = &CandidatesListOptions{}
	}
	if opt.MaxPage == 0 {
		// default value of max page.
		opt.MaxPage = 10
	}

	var candidates []*talentio.Candidate
	for page := 1; page <= opt.MaxPage; page++ {
		cands, resp, err := client.Candidates.List(
			&talentio.CandidatesListOptions{
				Page:   page,
				Status: opt.Status,
				Sort:   opt.Sort,
			},
		)
		if err != nil {
			return nil, err
		}
		candidates = append(candidates, cands...)

		if resp.Total <= len(candidates) {
			break
		}
	}

	return candidates, nil
}

func (c _Candidates) ApplyDetails(client *talentio.Client, list []*talentio.Candidate) error {

	var (
		e    error
		errc = make(chan error)
		wg   sync.WaitGroup
	)
	tmp := list
	for i, c := range tmp {
		wg.Add(1)
		go func(i int, c *talentio.Candidate) {
			defer wg.Done()

			var err error
			c, _, err = client.Candidates.Get(c.ID)
			if err != nil {
				errc <- err
				return
			}
			list[i] = c
		}(i, c)
	}
	go func() {
		for {
			select {
			case err := <-errc:
				e = err
			}
		}
	}()

	wg.Wait()
	return e
}

func (c _Candidates) Map(list []*talentio.Candidate, f func(*talentio.Candidate) bool) []*talentio.Candidate {

	var candidates []*talentio.Candidate
	for _, v := range list {
		v := v
		if f(v) {
			candidates = append(candidates, v)
		}
	}

	return candidates
}

// NoResume returns new candidates.
func (c _Candidates) NoResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		return len(c.Stages) == 0
	})
}

// OngoingResume returns candidates' status is ongoing resume.
func (c _Candidates) OngoingResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Type != talentio.TypeResume {
				return false
			}

			if s.Status == talentio.StatusOngoing {
				return true
			}
		}

		return false
	})
}

// PassResume returns candidates' status is pass of resume.
func (c _Candidates) PassResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		if len(c.Stages) == 0 {
			return false
		}

		for _, s := range c.Stages {
			if s.Type != talentio.TypeResume {
				return false
			}

			if s.Status != talentio.StatusPass {
				return false
			}
		}

		return true
	})
}

// OngoingInterview returns candidates' status is ongoing of interview.
func (c _Candidates) OngoingInterview(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Type != talentio.TypeInterview {
				continue
			}

			if s.Status == talentio.StatusOngoing {
				return true
			}
		}

		return false
	})
}

// PassInterview returns candidates' status is pass of interview.
func (c _Candidates) PassInterview(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Status != talentio.StatusPass {
				return false
			}

			if s.Type == talentio.TypeInterview {
				return true
			}
		}

		return false
	})
}
<commit_msg>Fix goroutine leak<commit_after>package talentioutil

import (
	"sync"

	"github.com/kaneshin/go-talentio/talentio"
)

type (
	_Candidates struct{}

	// CandidatesListOptions represents list of candidates.
	CandidatesListOptions struct {
		Status  string
		Sort    string
		MaxPage int
	}
)

// Candidates is.
var Candidates _Candidates

func (c _Candidates) List(client *talentio.Client, opt *CandidatesListOptions) ([]*talentio.Candidate, error) {
	if opt == nil {
		opt = &CandidatesListOptions{}
	}
	if opt.MaxPage == 0 {
		// default value of max page.
		opt.MaxPage = 10
	}

	var candidates []*talentio.Candidate
	for page := 1; page <= opt.MaxPage; page++ {
		cands, resp, err := client.Candidates.List(
			&talentio.CandidatesListOptions{
				Page:   page,
				Status: opt.Status,
				Sort:   opt.Sort,
			},
		)
		if err != nil {
			return nil, err
		}
		candidates = append(candidates, cands...)

		if resp.Total <= len(candidates) {
			break
		}
	}

	return candidates, nil
}

func (c _Candidates) ApplyDetails(client *talentio.Client, list []*talentio.Candidate) error {

	var (
		e  error
		wg sync.WaitGroup
	)
	tmp := list
	for i, c := range tmp {
		wg.Add(1)
		go func(i int, c *talentio.Candidate) {
			defer wg.Done()

			var err error
			c, _, err = client.Candidates.Get(c.ID)
			if err != nil {
				e = err
				return
			}
			list[i] = c
		}(i, c)
	}

	wg.Wait()
	return e
}

func (c _Candidates) Map(list []*talentio.Candidate, f func(*talentio.Candidate) bool) []*talentio.Candidate {

	var candidates []*talentio.Candidate
	for _, v := range list {
		v := v
		if f(v) {
			candidates = append(candidates, v)
		}
	}

	return candidates
}

// NoResume returns new candidates.
func (c _Candidates) NoResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		return len(c.Stages) == 0
	})
}

// OngoingResume returns candidates' status is ongoing resume.
func (c _Candidates) OngoingResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Type != talentio.TypeResume {
				return false
			}

			if s.Status == talentio.StatusOngoing {
				return true
			}
		}

		return false
	})
}

// PassResume returns candidates' status is pass of resume.
func (c _Candidates) PassResume(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		if len(c.Stages) == 0 {
			return false
		}

		for _, s := range c.Stages {
			if s.Type != talentio.TypeResume {
				return false
			}

			if s.Status != talentio.StatusPass {
				return false
			}
		}

		return true
	})
}

// OngoingInterview returns candidates' status is ongoing of interview.
func (c _Candidates) OngoingInterview(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Type != talentio.TypeInterview {
				continue
			}

			if s.Status == talentio.StatusOngoing {
				return true
			}
		}

		return false
	})
}

// PassInterview returns candidates' status is pass of interview.
func (c _Candidates) PassInterview(list []*talentio.Candidate) []*talentio.Candidate {

	return c.Map(list, func(c *talentio.Candidate) bool {

		for _, s := range c.Stages {
			if s.Status != talentio.StatusPass {
				return false
			}

			if s.Type == talentio.TypeInterview {
				return true
			}
		}

		return false
	})
}
<|endoftext|>


<commit_before>package sphinx

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

func newTestRoute(numHops int) ([]*Router, *OnionPacket, error) {
	nodes := make([]*Router, numHops)

	// Create numMaxHops random sphinx nodes.
	for i := 0; i < len(nodes); i++ {
		privKey, err := btcec.NewPrivateKey(btcec.S256())
		if err != nil {
			return nil, nil, fmt.Errorf("Unable to generate random "+
				"key for sphinx node: %v", err)
		}

		nodes[i] = NewRouter(privKey, &chaincfg.MainNetParams)
	}

	// Gather all the pub keys in the path.
	route := make([]*btcec.PublicKey, len(nodes))
	for i := 0; i < len(nodes); i++ {
		route[i] = nodes[i].onionKey.PubKey()
	}

	var hopPayloads [][]byte
	for i := 0; i < len(nodes); i++ {
		payload := bytes.Repeat([]byte{byte('A' + i)}, HopPayloadSize)
		hopPayloads = append(hopPayloads, payload)
	}

	// Generate a forwarding message to route to the final node via the
	// generated intermdiates nodes above.  Destination should be Hash160,
	// adding padding so parsing still works.
	sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))
	fwdMsg, err := NewOnionPacket(route, sessionKey, hopPayloads, nil)
	if err != nil {
		return nil, nil, fmt.Errorf("Unable to create forwarding "+
			"message: %#v", err)
	}

	return nodes, fwdMsg, nil
}

func TestSphinxCorrectness(t *testing.T) {
	nodes, fwdMsg, err := newTestRoute(NumMaxHops)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Now simulate the message propagating through the mix net eventually
	// reaching the final destination.
	for i := 0; i < len(nodes); i++ {
		hop := nodes[i]

		log.Printf("Processing at hop: %v \n", i)
		processAction, err := hop.ProcessOnionPacket(fwdMsg, nil)
		if err != nil {
			t.Fatalf("Node %v was unabled to process the forwarding message: %v", i, err)
		}

		// If this is the last hop on the path, the node should
		// recognize that it's the exit node.
		if i == len(nodes)-1 {
			if processAction.Action != ExitNode {
				t.Fatalf("Processing error, node %v is the last hop in "+
					"the path, yet it doesn't recognize so", i)
			}

		} else {
			// If this isn't the last node in the path, then the returned
			// action should indicate that there are more hops to go.
			if processAction.Action != MoreHops {
				t.Fatalf("Processing error, node %v is not the final"+
					" hop, yet thinks it is.", i)
			}

			// The next hop should have been parsed as node[i+1].
			parsedNextHop := processAction.NextHop[:]
			if !bytes.Equal(parsedNextHop, nodes[i+1].nodeID[:]) {
				t.Fatalf("Processing error, next hop parsed incorrectly."+
					" next hop shoud be %v, was instead parsed as %v",
					hex.EncodeToString(nodes[i+1].nodeID[:]),
					hex.EncodeToString(parsedNextHop))
			}

			fwdMsg = processAction.Packet
		}
	}
}

func TestSphinxSingleHop(t *testing.T) {
	// We'd like to test the proper behavior of the correctness of onion
	// packet processing for "single-hop" payments which bare a full onion
	// packet.

	nodes, fwdMsg, err := newTestRoute(1)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Simulating a direct single-hop payment, send the sphinx packet to
	// the destination node, making it process the packet fully.
	processedPacket, err := nodes[0].ProcessOnionPacket(fwdMsg, nil)
	if err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// The destination node should detect that the packet is destined for
	// itself.
	if processedPacket.Action != ExitNode {
		t.Fatalf("processed action is correct, is %v should be %v",
			processedPacket.Action, ExitNode)
	}
}

func TestSphinxNodeRelpay(t *testing.T) {
	// We'd like to ensure that the sphinx node itself rejects all replayed
	// packets which share the same shared secret.
	nodes, fwdMsg, err := newTestRoute(NumMaxHops)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Allow the node to process the initial packet, this should proceed
	// without any failures.
	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, nil); err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// Now, force the node to process the packet a second time, this should
	// fail with a detected replay error.
	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, nil); err != ErrReplayedPacket {
		t.Fatalf("sphinx packet replay should be rejected, instead error is %v", err)
	}
}

func TestSphinxAssocData(t *testing.T) {
	// We want to make sure that the associated data is considered in the
	// HMAC creation
	nodes, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, []byte("somethingelse")); err == nil {
		t.Fatalf("we should fail when associated data changes")
	}

}

func TestSphinxEncodeDecode(t *testing.T) {
	// Create some test data with a randomly populated, yet valid onion
	// forwarding message.
	_, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Encode the created onion packet into an empty buffer. This should
	// succeeed without any errors.
	var b bytes.Buffer
	if err := fwdMsg.Encode(&b); err != nil {
		t.Fatalf("unable to encode message: %v", err)
	}

	// Now decode the bytes encoded above. Again, this should succeeed
	// without any errors.
	newFwdMsg := &OnionPacket{}
	if err := newFwdMsg.Decode(&b); err != nil {
		t.Fatalf("unable to decode message: %v", err)
	}

	// The two forwarding messages should now be identical.
	if !reflect.DeepEqual(fwdMsg, newFwdMsg) {
		t.Fatalf("forwarding messages don't match, %v vs %v",
			spew.Sdump(fwdMsg), spew.Sdump(newFwdMsg))
	}
}
<commit_msg>test: fix minor formatting issue<commit_after>package sphinx

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

func newTestRoute(numHops int) ([]*Router, *OnionPacket, error) {
	nodes := make([]*Router, numHops)

	// Create numMaxHops random sphinx nodes.
	for i := 0; i < len(nodes); i++ {
		privKey, err := btcec.NewPrivateKey(btcec.S256())
		if err != nil {
			return nil, nil, fmt.Errorf("Unable to generate random "+
				"key for sphinx node: %v", err)
		}

		nodes[i] = NewRouter(privKey, &chaincfg.MainNetParams)
	}

	// Gather all the pub keys in the path.
	route := make([]*btcec.PublicKey, len(nodes))
	for i := 0; i < len(nodes); i++ {
		route[i] = nodes[i].onionKey.PubKey()
	}

	var hopPayloads [][]byte
	for i := 0; i < len(nodes); i++ {
		payload := bytes.Repeat([]byte{byte('A' + i)}, HopPayloadSize)
		hopPayloads = append(hopPayloads, payload)
	}

	// Generate a forwarding message to route to the final node via the
	// generated intermdiates nodes above.  Destination should be Hash160,
	// adding padding so parsing still works.
	sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))
	fwdMsg, err := NewOnionPacket(route, sessionKey, hopPayloads, nil)
	if err != nil {
		return nil, nil, fmt.Errorf("Unable to create forwarding "+
			"message: %#v", err)
	}

	return nodes, fwdMsg, nil
}

func TestSphinxCorrectness(t *testing.T) {
	nodes, fwdMsg, err := newTestRoute(NumMaxHops)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Now simulate the message propagating through the mix net eventually
	// reaching the final destination.
	for i := 0; i < len(nodes); i++ {
		hop := nodes[i]

		log.Printf("Processing at hop: %v \n", i)
		processAction, err := hop.ProcessOnionPacket(fwdMsg, nil)
		if err != nil {
			t.Fatalf("Node %v was unable to process the "+
				"forwarding message: %v", i, err)
		}

		// If this is the last hop on the path, the node should
		// recognize that it's the exit node.
		if i == len(nodes)-1 {
			if processAction.Action != ExitNode {
				t.Fatalf("Processing error, node %v is the last hop in "+
					"the path, yet it doesn't recognize so", i)
			}

		} else {
			// If this isn't the last node in the path, then the returned
			// action should indicate that there are more hops to go.
			if processAction.Action != MoreHops {
				t.Fatalf("Processing error, node %v is not the final"+
					" hop, yet thinks it is.", i)
			}

			// The next hop should have been parsed as node[i+1].
			parsedNextHop := processAction.NextHop[:]
			if !bytes.Equal(parsedNextHop, nodes[i+1].nodeID[:]) {
				t.Fatalf("Processing error, next hop parsed incorrectly."+
					" next hop shoud be %v, was instead parsed as %v",
					hex.EncodeToString(nodes[i+1].nodeID[:]),
					hex.EncodeToString(parsedNextHop))
			}

			fwdMsg = processAction.Packet
		}
	}
}

func TestSphinxSingleHop(t *testing.T) {
	// We'd like to test the proper behavior of the correctness of onion
	// packet processing for "single-hop" payments which bare a full onion
	// packet.

	nodes, fwdMsg, err := newTestRoute(1)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Simulating a direct single-hop payment, send the sphinx packet to
	// the destination node, making it process the packet fully.
	processedPacket, err := nodes[0].ProcessOnionPacket(fwdMsg, nil)
	if err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// The destination node should detect that the packet is destined for
	// itself.
	if processedPacket.Action != ExitNode {
		t.Fatalf("processed action is correct, is %v should be %v",
			processedPacket.Action, ExitNode)
	}
}

func TestSphinxNodeRelpay(t *testing.T) {
	// We'd like to ensure that the sphinx node itself rejects all replayed
	// packets which share the same shared secret.
	nodes, fwdMsg, err := newTestRoute(NumMaxHops)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Allow the node to process the initial packet, this should proceed
	// without any failures.
	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, nil); err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// Now, force the node to process the packet a second time, this should
	// fail with a detected replay error.
	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, nil); err != ErrReplayedPacket {
		t.Fatalf("sphinx packet replay should be rejected, instead error is %v", err)
	}
}

func TestSphinxAssocData(t *testing.T) {
	// We want to make sure that the associated data is considered in the
	// HMAC creation
	nodes, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	if _, err := nodes[0].ProcessOnionPacket(fwdMsg, []byte("somethingelse")); err == nil {
		t.Fatalf("we should fail when associated data changes")
	}

}

func TestSphinxEncodeDecode(t *testing.T) {
	// Create some test data with a randomly populated, yet valid onion
	// forwarding message.
	_, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Encode the created onion packet into an empty buffer. This should
	// succeeed without any errors.
	var b bytes.Buffer
	if err := fwdMsg.Encode(&b); err != nil {
		t.Fatalf("unable to encode message: %v", err)
	}

	// Now decode the bytes encoded above. Again, this should succeeed
	// without any errors.
	newFwdMsg := &OnionPacket{}
	if err := newFwdMsg.Decode(&b); err != nil {
		t.Fatalf("unable to decode message: %v", err)
	}

	// The two forwarding messages should now be identical.
	if !reflect.DeepEqual(fwdMsg, newFwdMsg) {
		t.Fatalf("forwarding messages don't match, %v vs %v",
			spew.Sdump(fwdMsg), spew.Sdump(newFwdMsg))
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2022 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 		http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package geo

import (
	"encoding/json"
	"sync"

	index "github.com/blevesearch/bleve_index_api"

	"github.com/blevesearch/geo/geojson"
	"github.com/blevesearch/geo/s2"
)

const (
	PointType              = "point"
	MultiPointType         = "multipoint"
	LineStringType         = "linestring"
	MultiLineStringType    = "multilinestring"
	PolygonType            = "polygon"
	MultiPolygonType       = "multipolygon"
	GeometryCollectionType = "geometrycollection"
	CircleType             = "circle"
	EnvelopeType           = "envelope"
)

// spatialPluginsMap is spatial plugin cache.
var (
	spatialPluginsMap = make(map[string]index.SpatialAnalyzerPlugin)
	pluginsMapLock    = sync.RWMutex{}
)

func init() {
	registerS2RegionTermIndexer()
}

func registerS2RegionTermIndexer() {
	spatialPlugin := S2SpatialAnalyzerPlugin{
		s2Indexer:  s2.NewRegionTermIndexerWithOptions(initS2IndexerOptions()),
		s2Searcher: s2.NewRegionTermIndexerWithOptions(initS2SearcherOptions()),
	}

	RegisterSpatialAnalyzerPlugin(&spatialPlugin)
}

// RegisterSpatialAnalyzerPlugin registers the given plugin implementation.
func RegisterSpatialAnalyzerPlugin(plugin index.SpatialAnalyzerPlugin) {
	pluginsMapLock.Lock()
	spatialPluginsMap[plugin.Type()] = plugin
	pluginsMapLock.Unlock()
}

// GetSpatialAnalyzerPlugin retrieves the given implementation type.
func GetSpatialAnalyzerPlugin(typ string) index.SpatialAnalyzerPlugin {
	pluginsMapLock.RLock()
	rv := spatialPluginsMap[typ]
	pluginsMapLock.RUnlock()
	return rv
}

func initS2IndexerOptions() s2.Options {
	options := s2.Options{}
	// maxLevel control the maximum size of the
	// S2Cells used to approximate regions.
	options.SetMaxLevel(16)

	// minLevel control the minimum size of the
	// S2Cells used to approximate regions.
	options.SetMinLevel(2)

	// levelMod value greater than 1 increases the effective branching
	// factor of the S2Cell hierarchy by skipping some levels.
	options.SetLevelMod(1)

	// maxCells controls the maximum number of cells
	// when approximating each s2 region.
	options.SetMaxCells(20)

	return options
}

func initS2SearcherOptions() s2.Options {
	options := s2.Options{}
	// maxLevel control the maximum size of the
	// S2Cells used to approximate regions.
	options.SetMaxLevel(16)

	// minLevel control the minimum size of the
	// S2Cells used to approximate regions.
	options.SetMinLevel(2)

	// levelMod value greater than 1 increases the effective branching
	// factor of the S2Cell hierarchy by skipping some levels.
	options.SetLevelMod(1)

	// maxCells controls the maximum number of cells
	// when approximating each s2 region.
	options.SetMaxCells(8)

	return options
}

// S2SpatialAnalyzerPlugin is an implementation of
// the index.SpatialAnalyzerPlugin interface.
type S2SpatialAnalyzerPlugin struct {
	s2Indexer  *s2.RegionTermIndexer
	s2Searcher *s2.RegionTermIndexer
}

func (s *S2SpatialAnalyzerPlugin) Type() string {
	return "s2"
}

func (s *S2SpatialAnalyzerPlugin) GetIndexTokens(queryShape index.GeoJSON) []string {
	var rv []string
	shapes := []index.GeoJSON{queryShape}
	if gc, ok := queryShape.(*geojson.GeometryCollection); ok {
		shapes = gc.Shapes
	}

	for _, shape := range shapes {
		if s2t, ok := shape.(s2Tokenizable); ok {
			rv = append(rv, s2t.IndexTokens(s.s2Indexer)...)
		}
	}

	return geojson.DeduplicateTerms(rv)
}

func (s *S2SpatialAnalyzerPlugin) GetQueryTokens(queryShape index.GeoJSON) []string {
	var rv []string
	shapes := []index.GeoJSON{queryShape}
	if gc, ok := queryShape.(*geojson.GeometryCollection); ok {
		shapes = gc.Shapes
	}

	for _, shape := range shapes {
		if s2t, ok := shape.(s2Tokenizable); ok {
			rv = append(rv, s2t.QueryTokens(s.s2Searcher)...)
		}
	}

	return geojson.DeduplicateTerms(rv)
}

// ------------------------------------------------------------------------
// s2Tokenizable is an optional interface for shapes that support
// the generation of s2 based tokens that can be used for both
// indexing and querying.

type s2Tokenizable interface {
	// IndexTokens returns the tokens for indexing.
	IndexTokens(*s2.RegionTermIndexer) []string

	// QueryTokens returns the tokens for searching.
	QueryTokens(*s2.RegionTermIndexer) []string
}

//----------------------------------------------------------------------------------

func (p *Point) Type() string {
	return PointType
}

func (p *Point) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *Point) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *Point) IndexTokens(s *s2.RegionTermIndexer) []string {
	return s.GetIndexTermsForPoint(s2.PointFromLatLng(
		s2.LatLngFromDegrees(p.Lat, p.Lon)), "")
}

func (p *Point) QueryTokens(s *s2.RegionTermIndexer) []string {
	return nil
}

//----------------------------------------------------------------------------------

type boundedRectangle struct {
	minLat float64
	maxLat float64
	minLon float64
	maxLon float64
}

func NewBoundedRectangle(minLat, minLon, maxLat,
	maxLon float64) *boundedRectangle {
	return &boundedRectangle{minLat: minLat,
		maxLat: maxLat, minLon: minLon, maxLon: maxLon}
}

func (br *boundedRectangle) Type() string {
	// placeholder implementation
	return "boundedRectangle"
}

func (p *boundedRectangle) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *boundedRectangle) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (br *boundedRectangle) IndexTokens(s *s2.RegionTermIndexer) []string {
	return nil
}

func (br *boundedRectangle) QueryTokens(s *s2.RegionTermIndexer) []string {
	rect := s2.RectFromDegrees(br.minLat, br.minLon, br.maxLat, br.maxLon)

	// obtain the terms to be searched for the given bounding box.
	terms := s.GetQueryTermsForRegion(rect, "")

	return geojson.StripCoveringTerms(terms)
}

//----------------------------------------------------------------------------------

type boundedPolygon struct {
	coordinates []Point
}

func NewBoundedPolygon(coordinates []Point) *boundedPolygon {
	return &boundedPolygon{coordinates: coordinates}
}

func (bp *boundedPolygon) Type() string {
	// placeholder implementation
	return "boundedPolygon"
}

func (p *boundedPolygon) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *boundedPolygon) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (bp *boundedPolygon) IndexTokens(s *s2.RegionTermIndexer) []string {
	return nil
}

func (bp *boundedPolygon) QueryTokens(s *s2.RegionTermIndexer) []string {
	vertices := make([]s2.Point, len(bp.coordinates))
	for i, point := range bp.coordinates {
		vertices[i] = s2.PointFromLatLng(
			s2.LatLngFromDegrees(point.Lat, point.Lon))
	}
	s2polygon := s2.PolygonFromOrientedLoops([]*s2.Loop{s2.LoopFromPoints(vertices)})

	// obtain the terms to be searched for the given polygon.
	terms := s.GetQueryTermsForRegion(
		s2polygon.CapBound(), "")

	return geojson.StripCoveringTerms(terms)
}

//----------------------------------------------------------------------------------

type pointDistance struct {
	dist      float64
	centerLat float64
	centerLon float64
}

func (p *pointDistance) Type() string {
	// placeholder implementation
	return "pointDistance"
}

func NewPointDistance(centerLat, centerLon,
	dist float64) *pointDistance {
	return &pointDistance{centerLat: centerLat,
		centerLon: centerLon, dist: dist}
}

func (p *pointDistance) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *pointDistance) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (pd *pointDistance) IndexTokens(s *s2.RegionTermIndexer) []string {
	return nil
}

func (pd *pointDistance) QueryTokens(s *s2.RegionTermIndexer) []string {
	// obtain the covering query region from the given points.
	queryRegion := s2.CapFromCenterAndRadius(pd.centerLat,
		pd.centerLon, pd.dist)

	// obtain the query terms for the query region.
	terms := s.GetQueryTermsForRegion(queryRegion, "")

	return geojson.StripCoveringTerms(terms)
}

// ------------------------------------------------------------------------

// NewGeometryCollection instantiate a geometrycollection
// and prefix the byte contents with certain glue bytes that
// can be used later while filering the doc values.
func NewGeometryCollection(coordinates [][][][][]float64,
	typs []string) (index.GeoJSON, []byte, error) {

	return geojson.NewGeometryCollection(coordinates, typs)
}

// NewGeoCircleShape instantiate a circle shape and
// prefix the byte contents with certain glue bytes that
// can be used later while filering the doc values.
func NewGeoCircleShape(cp []float64,
	radiusInMeter float64) (index.GeoJSON, []byte, error) {
	return geojson.NewGeoCircleShape(cp, radiusInMeter)
}

func NewGeoJsonShape(coordinates [][][][]float64, typ string) (
	index.GeoJSON, []byte, error) {
	return geojson.NewGeoJsonShape(coordinates, typ)
}

func NewGeoJsonPoint(points []float64) index.GeoJSON {
	return geojson.NewGeoJsonPoint(points)
}

func NewGeoJsonMultiPoint(points [][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultiPoint(points)
}

func NewGeoJsonLinestring(points [][]float64) index.GeoJSON {
	return geojson.NewGeoJsonLinestring(points)
}

func NewGeoJsonMultilinestring(points [][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultilinestring(points)
}

func NewGeoJsonPolygon(points [][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonPolygon(points)
}

func NewGeoJsonMultiPolygon(points [][][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultiPolygon(points)
}

func NewGeoCircle(points []float64, radius float64) index.GeoJSON {
	return geojson.NewGeoCircle(points, radius)
}

func NewGeoEnvelope(points [][]float64) index.GeoJSON {
	return geojson.NewGeoEnvelope(points)
}

func ParseGeoJSONShape(input json.RawMessage) (index.GeoJSON, error) {
	return geojson.ParseGeoJSONShape(input)
}
<commit_msg>Updating the geopoint options for s2's region term indexer (#1693)<commit_after>//  Copyright (c) 2022 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 		http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package geo

import (
	"encoding/json"
	"sync"

	index "github.com/blevesearch/bleve_index_api"

	"github.com/blevesearch/geo/geojson"
	"github.com/blevesearch/geo/s2"
)

const (
	PointType              = "point"
	MultiPointType         = "multipoint"
	LineStringType         = "linestring"
	MultiLineStringType    = "multilinestring"
	PolygonType            = "polygon"
	MultiPolygonType       = "multipolygon"
	GeometryCollectionType = "geometrycollection"
	CircleType             = "circle"
	EnvelopeType           = "envelope"
)

// spatialPluginsMap is spatial plugin cache.
var (
	spatialPluginsMap = make(map[string]index.SpatialAnalyzerPlugin)
	pluginsMapLock    = sync.RWMutex{}
)

func init() {
	registerS2RegionTermIndexer()
}

func registerS2RegionTermIndexer() {
	spatialPlugin := S2SpatialAnalyzerPlugin{
		s2Indexer:                    s2.NewRegionTermIndexerWithOptions(initS2IndexerOptions()),
		s2Searcher:                   s2.NewRegionTermIndexerWithOptions(initS2SearcherOptions()),
		s2GeoPointsRegionTermIndexer: s2.NewRegionTermIndexerWithOptions(initS2OptionsForGeoPoints()),
	}

	RegisterSpatialAnalyzerPlugin(&spatialPlugin)
}

// RegisterSpatialAnalyzerPlugin registers the given plugin implementation.
func RegisterSpatialAnalyzerPlugin(plugin index.SpatialAnalyzerPlugin) {
	pluginsMapLock.Lock()
	spatialPluginsMap[plugin.Type()] = plugin
	pluginsMapLock.Unlock()
}

// GetSpatialAnalyzerPlugin retrieves the given implementation type.
func GetSpatialAnalyzerPlugin(typ string) index.SpatialAnalyzerPlugin {
	pluginsMapLock.RLock()
	rv := spatialPluginsMap[typ]
	pluginsMapLock.RUnlock()
	return rv
}

// initS2IndexerOptions returns the options for s2's region
// term indexer for the index time tokens of geojson shapes.
func initS2IndexerOptions() s2.Options {
	options := s2.Options{}
	// maxLevel control the maximum size of the
	// S2Cells used to approximate regions.
	options.SetMaxLevel(16)

	// minLevel control the minimum size of the
	// S2Cells used to approximate regions.
	options.SetMinLevel(2)

	// levelMod value greater than 1 increases the effective branching
	// factor of the S2Cell hierarchy by skipping some levels.
	options.SetLevelMod(1)

	// maxCells controls the maximum number of cells
	// when approximating each s2 region.
	options.SetMaxCells(20)

	return options
}

// initS2SearcherOptions returns the options for s2's region
// term indexer for the query time tokens of geojson shapes.
func initS2SearcherOptions() s2.Options {
	options := s2.Options{}
	// maxLevel control the maximum size of the
	// S2Cells used to approximate regions.
	options.SetMaxLevel(16)

	// minLevel control the minimum size of the
	// S2Cells used to approximate regions.
	options.SetMinLevel(2)

	// levelMod value greater than 1 increases the effective branching
	// factor of the S2Cell hierarchy by skipping some levels.
	options.SetLevelMod(1)

	// maxCells controls the maximum number of cells
	// when approximating each s2 region.
	options.SetMaxCells(8)

	return options
}

// initS2OptionsForGeoPoints returns the options for
// s2's region term indexer for the original geopoints.
func initS2OptionsForGeoPoints() s2.Options {
	options := s2.Options{}
	// maxLevel control the maximum size of the
	// S2Cells used to approximate regions.
	options.SetMaxLevel(16)

	// minLevel control the minimum size of the
	// S2Cells used to approximate regions.
	options.SetMinLevel(4)

	// levelMod value greater than 1 increases the effective branching
	// factor of the S2Cell hierarchy by skipping some levels.
	options.SetLevelMod(2)

	// maxCells controls the maximum number of cells
	// when approximating each s2 region.
	options.SetMaxCells(8)

	// explicit for geo points.
	options.SetPointsOnly(true)

	return options
}

// S2SpatialAnalyzerPlugin is an implementation of
// the index.SpatialAnalyzerPlugin interface.
type S2SpatialAnalyzerPlugin struct {
	s2Indexer                    *s2.RegionTermIndexer
	s2Searcher                   *s2.RegionTermIndexer
	s2GeoPointsRegionTermIndexer *s2.RegionTermIndexer
}

func (s *S2SpatialAnalyzerPlugin) Type() string {
	return "s2"
}

func (s *S2SpatialAnalyzerPlugin) GetIndexTokens(queryShape index.GeoJSON) []string {
	var rv []string
	shapes := []index.GeoJSON{queryShape}
	if gc, ok := queryShape.(*geojson.GeometryCollection); ok {
		shapes = gc.Shapes
	}

	for _, shape := range shapes {
		if s2t, ok := shape.(s2Tokenizable); ok {
			rv = append(rv, s2t.IndexTokens(s.s2Indexer)...)
		} else if s2t, ok := shape.(s2TokenizableEx); ok {
			rv = append(rv, s2t.IndexTokens(s)...)
		}
	}

	return geojson.DeduplicateTerms(rv)
}

func (s *S2SpatialAnalyzerPlugin) GetQueryTokens(queryShape index.GeoJSON) []string {
	var rv []string
	shapes := []index.GeoJSON{queryShape}
	if gc, ok := queryShape.(*geojson.GeometryCollection); ok {
		shapes = gc.Shapes
	}

	for _, shape := range shapes {
		if s2t, ok := shape.(s2Tokenizable); ok {
			rv = append(rv, s2t.QueryTokens(s.s2Searcher)...)
		} else if s2t, ok := shape.(s2TokenizableEx); ok {
			rv = append(rv, s2t.QueryTokens(s)...)
		}
	}

	return geojson.DeduplicateTerms(rv)
}

// ------------------------------------------------------------------------
// s2Tokenizable is an optional interface for shapes that support
// the generation of s2 based tokens that can be used for both
// indexing and querying.

type s2Tokenizable interface {
	// IndexTokens returns the tokens for indexing.
	IndexTokens(*s2.RegionTermIndexer) []string

	// QueryTokens returns the tokens for searching.
	QueryTokens(*s2.RegionTermIndexer) []string
}

// ------------------------------------------------------------------------
// s2TokenizableEx is an optional interface for shapes that support
// the generation of s2 based tokens that can be used for both
// indexing and querying. This is intended for the older geopoint
// indexing and querying.
type s2TokenizableEx interface {
	// IndexTokens returns the tokens for indexing.
	IndexTokens(*S2SpatialAnalyzerPlugin) []string

	// QueryTokens returns the tokens for searching.
	QueryTokens(*S2SpatialAnalyzerPlugin) []string
}

//----------------------------------------------------------------------------------

func (p *Point) Type() string {
	return PointType
}

func (p *Point) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *Point) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *Point) IndexTokens(s *S2SpatialAnalyzerPlugin) []string {
	return s.s2GeoPointsRegionTermIndexer.GetIndexTermsForPoint(s2.PointFromLatLng(
		s2.LatLngFromDegrees(p.Lat, p.Lon)), "")
}

func (p *Point) QueryTokens(s *S2SpatialAnalyzerPlugin) []string {
	return nil
}

//----------------------------------------------------------------------------------

type boundedRectangle struct {
	minLat float64
	maxLat float64
	minLon float64
	maxLon float64
}

func NewBoundedRectangle(minLat, minLon, maxLat,
	maxLon float64) *boundedRectangle {
	return &boundedRectangle{minLat: minLat,
		maxLat: maxLat, minLon: minLon, maxLon: maxLon}
}

func (br *boundedRectangle) Type() string {
	// placeholder implementation
	return "boundedRectangle"
}

func (p *boundedRectangle) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *boundedRectangle) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (br *boundedRectangle) IndexTokens(s *S2SpatialAnalyzerPlugin) []string {
	return nil
}

func (br *boundedRectangle) QueryTokens(s *S2SpatialAnalyzerPlugin) []string {
	rect := s2.RectFromDegrees(br.minLat, br.minLon, br.maxLat, br.maxLon)

	// obtain the terms to be searched for the given bounding box.
	terms := s.s2GeoPointsRegionTermIndexer.GetQueryTermsForRegion(rect, "")

	return geojson.StripCoveringTerms(terms)
}

//----------------------------------------------------------------------------------

type boundedPolygon struct {
	coordinates []Point
}

func NewBoundedPolygon(coordinates []Point) *boundedPolygon {
	return &boundedPolygon{coordinates: coordinates}
}

func (bp *boundedPolygon) Type() string {
	// placeholder implementation
	return "boundedPolygon"
}

func (p *boundedPolygon) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *boundedPolygon) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (bp *boundedPolygon) IndexTokens(s *S2SpatialAnalyzerPlugin) []string {
	return nil
}

func (bp *boundedPolygon) QueryTokens(s *S2SpatialAnalyzerPlugin) []string {
	vertices := make([]s2.Point, len(bp.coordinates))
	for i, point := range bp.coordinates {
		vertices[i] = s2.PointFromLatLng(
			s2.LatLngFromDegrees(point.Lat, point.Lon))
	}
	s2polygon := s2.PolygonFromOrientedLoops([]*s2.Loop{s2.LoopFromPoints(vertices)})

	// obtain the terms to be searched for the given polygon.
	terms := s.s2GeoPointsRegionTermIndexer.GetQueryTermsForRegion(
		s2polygon.CapBound(), "")

	return geojson.StripCoveringTerms(terms)
}

//----------------------------------------------------------------------------------

type pointDistance struct {
	dist      float64
	centerLat float64
	centerLon float64
}

func (p *pointDistance) Type() string {
	// placeholder implementation
	return "pointDistance"
}

func NewPointDistance(centerLat, centerLon,
	dist float64) *pointDistance {
	return &pointDistance{centerLat: centerLat,
		centerLon: centerLon, dist: dist}
}

func (p *pointDistance) Intersects(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (p *pointDistance) Contains(s index.GeoJSON) (bool, error) {
	// placeholder implementation
	return false, nil
}

func (pd *pointDistance) IndexTokens(s *S2SpatialAnalyzerPlugin) []string {
	return nil
}

func (pd *pointDistance) QueryTokens(s *S2SpatialAnalyzerPlugin) []string {
	// obtain the covering query region from the given points.
	queryRegion := s2.CapFromCenterAndRadius(pd.centerLat,
		pd.centerLon, pd.dist)

	// obtain the query terms for the query region.
	terms := s.s2GeoPointsRegionTermIndexer.GetQueryTermsForRegion(queryRegion, "")

	return geojson.StripCoveringTerms(terms)
}

// ------------------------------------------------------------------------

// NewGeometryCollection instantiate a geometrycollection
// and prefix the byte contents with certain glue bytes that
// can be used later while filering the doc values.
func NewGeometryCollection(coordinates [][][][][]float64,
	typs []string) (index.GeoJSON, []byte, error) {

	return geojson.NewGeometryCollection(coordinates, typs)
}

// NewGeoCircleShape instantiate a circle shape and
// prefix the byte contents with certain glue bytes that
// can be used later while filering the doc values.
func NewGeoCircleShape(cp []float64,
	radiusInMeter float64) (index.GeoJSON, []byte, error) {
	return geojson.NewGeoCircleShape(cp, radiusInMeter)
}

func NewGeoJsonShape(coordinates [][][][]float64, typ string) (
	index.GeoJSON, []byte, error) {
	return geojson.NewGeoJsonShape(coordinates, typ)
}

func NewGeoJsonPoint(points []float64) index.GeoJSON {
	return geojson.NewGeoJsonPoint(points)
}

func NewGeoJsonMultiPoint(points [][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultiPoint(points)
}

func NewGeoJsonLinestring(points [][]float64) index.GeoJSON {
	return geojson.NewGeoJsonLinestring(points)
}

func NewGeoJsonMultilinestring(points [][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultilinestring(points)
}

func NewGeoJsonPolygon(points [][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonPolygon(points)
}

func NewGeoJsonMultiPolygon(points [][][][]float64) index.GeoJSON {
	return geojson.NewGeoJsonMultiPolygon(points)
}

func NewGeoCircle(points []float64, radius float64) index.GeoJSON {
	return geojson.NewGeoCircle(points, radius)
}

func NewGeoEnvelope(points [][]float64) index.GeoJSON {
	return geojson.NewGeoEnvelope(points)
}

func ParseGeoJSONShape(input json.RawMessage) (index.GeoJSON, error) {
	return geojson.ParseGeoJSONShape(input)
}
<|endoftext|>


<commit_before>// Main package wraps sprite_sass tool for use with the command line
// See -h for list of available options
package main

/*
#cgo LDFLAGS: -Llibsass -lsass -lstdc++ -lm
#cgo CFLAGS: -Ilibsass

#include <stdlib.h>
#include <sass_context.h>
*/
import "C"

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"

	sprite "github.com/drewwells/sprite_sass"
)

const version = `v0.1.0`

var (
	Dir, Gen, Input, Output, Includes string
	MainFile, Style                   string
	Comments                          bool
	cpuprofile                        string
	ShowVersion                       bool
	BuildDir                          string
)

func init() {
	flag.StringVar(&Output, "output", "", "Output file")
	flag.StringVar(&Output, "o", "", "Output file")
	flag.StringVar(&BuildDir, "b", "", "Build Directory")
	flag.StringVar(&Includes, "p", "", "SASS import path")
	flag.StringVar(&Dir, "dir", "", "Image directory")
	flag.StringVar(&Dir, "d", "", "Image directory")
	flag.StringVar(&Gen, "gen", ".", "Directory for generated images")
	flag.StringVar(&Style, "style", "nested", "CSS nested style")
	flag.StringVar(&Style, "s", "nested", "CSS nested style")
	flag.BoolVar(&Comments, "comment", true, "Turn on source comments")
	flag.BoolVar(&Comments, "c", true, "Turn on source comments")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.BoolVar(&ShowVersion, "version", false, "Show the app version")
}

func main() {
	flag.Parse()

	if ShowVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Profiling code
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer func() {
			err := f.Close()
			if err != nil {
				log.Fatal(err)
			}
			pprof.StopCPUProfile()
		}()
	}

	for _, v := range flag.Args() {
		if strings.HasPrefix(v, "-") {
			log.Fatalf("Please specify flags before other arguments: %s", v)
		}
	}

	if len(flag.Args()) == 0 {
		fmt.Println("Please specify input filepath.")
		fmt.Println("\nAvailable options:")
		flag.PrintDefaults()
		return
	}

	style, ok := sprite.Style[Style]

	if !ok {
		style = sprite.NESTED_STYLE
	}
	for _, f := range flag.Args() {
		// Remove partials
		if strings.HasPrefix(filepath.Base(f), "_") {
			continue
		}
		log.Println("Open:", f)

		// If no imagedir specified, assume relative to the input file
		if Dir == "" {
			Dir = filepath.Dir(f)
		}
		rel, _ := filepath.Rel(Includes, filepath.Dir(f))
		filename := strings.Replace(filepath.Base(f), ".scss", ".css", 1)
		output := filepath.Join(BuildDir, rel, filename)
		ctx := sprite.Context{
			OutputStyle: style,
			ImageDir:    Dir,
			// Assumption that output is a file
			BuildDir:     filepath.Dir(output),
			GenImgDir:    Gen,
			MainFile:     f,
			Comments:     Comments,
			IncludePaths: []string{filepath.Dir(f)},
		}
		if Includes != "" {
			ctx.IncludePaths = append(ctx.IncludePaths,
				strings.Split(Includes, ",")...)
		}
		fRead, err := os.Open(f)
		if err != nil {
			panic(err)
		}

		var out io.WriteCloser

		if output == "" {
			out = os.Stdout
		} else {
			dir := filepath.Dir(output)
			err := os.MkdirAll(dir, 0755)
			if err != nil {
				log.Fatalf("Failed to create directory: %s", dir)
			}

			out, err = os.Create(output)
			log.Println("Created:", output)
			if err != nil {
				log.Fatalf("Failed to create file: %s", Output)
			}
		}

		err = ctx.Run(fRead, out, filepath.Dir(Input))
		if err != nil {
			log.Println(err)
		}
	}
}
<commit_msg>cli path<commit_after>// Main package wraps sprite_sass tool for use with the command line
// See -h for list of available options
package main

/*
#cgo LDFLAGS: -Llibsass/lib -lsass -lstdc++ -lm
#cgo CFLAGS: -Ilibsass

#include <stdlib.h>
#include <sass_context.h>
*/
import "C"

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"

	sprite "github.com/drewwells/sprite_sass"
)

const version = `v0.1.0`

var (
	Dir, Gen, Input, Output, Includes string
	MainFile, Style                   string
	Comments                          bool
	cpuprofile                        string
	ShowVersion                       bool
	BuildDir                          string
)

func init() {
	flag.StringVar(&Output, "output", "", "Output file")
	flag.StringVar(&Output, "o", "", "Output file")
	flag.StringVar(&BuildDir, "b", "", "Build Directory")
	flag.StringVar(&Includes, "p", "", "SASS import path")
	flag.StringVar(&Dir, "dir", "", "Image directory")
	flag.StringVar(&Dir, "d", "", "Image directory")
	flag.StringVar(&Gen, "gen", ".", "Directory for generated images")
	flag.StringVar(&Style, "style", "nested", "CSS nested style")
	flag.StringVar(&Style, "s", "nested", "CSS nested style")
	flag.BoolVar(&Comments, "comment", true, "Turn on source comments")
	flag.BoolVar(&Comments, "c", true, "Turn on source comments")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.BoolVar(&ShowVersion, "version", false, "Show the app version")
}

func main() {
	flag.Parse()

	if ShowVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Profiling code
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer func() {
			err := f.Close()
			if err != nil {
				log.Fatal(err)
			}
			pprof.StopCPUProfile()
		}()
	}

	for _, v := range flag.Args() {
		if strings.HasPrefix(v, "-") {
			log.Fatalf("Please specify flags before other arguments: %s", v)
		}
	}

	if len(flag.Args()) == 0 {
		fmt.Println("Please specify input filepath.")
		fmt.Println("\nAvailable options:")
		flag.PrintDefaults()
		return
	}

	style, ok := sprite.Style[Style]

	if !ok {
		style = sprite.NESTED_STYLE
	}
	for _, f := range flag.Args() {
		// Remove partials
		if strings.HasPrefix(filepath.Base(f), "_") {
			continue
		}
		log.Println("Open:", f)

		// If no imagedir specified, assume relative to the input file
		if Dir == "" {
			Dir = filepath.Dir(f)
		}
		rel, _ := filepath.Rel(Includes, filepath.Dir(f))
		filename := strings.Replace(filepath.Base(f), ".scss", ".css", 1)
		output := filepath.Join(BuildDir, rel, filename)
		ctx := sprite.Context{
			OutputStyle: style,
			ImageDir:    Dir,
			// Assumption that output is a file
			BuildDir:     filepath.Dir(output),
			GenImgDir:    Gen,
			MainFile:     f,
			Comments:     Comments,
			IncludePaths: []string{filepath.Dir(f)},
		}
		if Includes != "" {
			ctx.IncludePaths = append(ctx.IncludePaths,
				strings.Split(Includes, ",")...)
		}
		fRead, err := os.Open(f)
		if err != nil {
			panic(err)
		}

		var out io.WriteCloser

		if output == "" {
			out = os.Stdout
		} else {
			dir := filepath.Dir(output)
			err := os.MkdirAll(dir, 0755)
			if err != nil {
				log.Fatalf("Failed to create directory: %s", dir)
			}

			out, err = os.Create(output)
			log.Println("Created:", output)
			if err != nil {
				log.Fatalf("Failed to create file: %s", Output)
			}
		}

		err = ctx.Run(fRead, out, filepath.Dir(Input))
		if err != nil {
			log.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>// Main package wraps sprite_sass tool for use with the command line
// See -h for list of available options
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"

	"github.com/drewwells/sprite_sass/context"

	sprite "github.com/drewwells/sprite_sass"
)

const version = `v0.2.1`

var (
	Dir, Gen, Input, Includes string
	MainFile, Style           string
	Comments                  bool
	cpuprofile                string
	Help, ShowVersion         bool
	BuildDir                  string
)

func init() {
	flag.StringVar(&BuildDir, "b", "", "Build Directory")
	flag.StringVar(&Includes, "p", "", "SASS import path")
	flag.BoolVar(&Help, "help", false, "this help")
	flag.BoolVar(&Help, "h", false, "this help")
	flag.StringVar(&Dir, "dir", "", "Image directory")
	flag.StringVar(&Dir, "d", "", "Image directory")
	flag.StringVar(&Gen, "gen", ".", "Directory for generated images")
	flag.StringVar(&Style, "style", "nested", "CSS nested style")
	flag.StringVar(&Style, "s", "nested", "CSS nested style")
	flag.BoolVar(&Comments, "comment", true, "Turn on source comments")
	flag.BoolVar(&Comments, "c", true, "Turn on source comments")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.BoolVar(&ShowVersion, "version", false, "Show the app version")
}

func main() {
	flag.Parse()

	if ShowVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Profiling code
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer func() {
			err := f.Close()
			if err != nil {
				log.Fatal(err)
			}
			pprof.StopCPUProfile()
		}()
	}

	for _, v := range flag.Args() {
		if strings.HasPrefix(v, "-") {
			log.Fatalf("Please specify flags before other arguments: %s", v)
		}
	}

	if Help {
		fmt.Println("Please specify input filepath.")
		fmt.Println("\nAvailable options:")
		flag.PrintDefaults()
		return
	}

	style, ok := context.Style[Style]

	if !ok {
		style = context.NESTED_STYLE
	}

	if len(flag.Args()) == 0 {
		// Read from stdin
		log.Print("Reading from stdin, -h for help")
		out := os.Stdout
		in := os.Stdin

		var pout bytes.Buffer
		ctx := context.Context{}
		err := startParser(ctx, in, &pout, "")
		if err != nil {
			log.Println(err)
		}
		err = ctx.Compile(&pout, out)

		if err != nil {
			log.Println(err)
		}
	}

	for _, f := range flag.Args() {
		// Remove partials
		if strings.HasPrefix(filepath.Base(f), "_") {
			continue
		}
		log.Println("Open:", f)

		// If no imagedir specified, assume relative to the input file
		if Dir == "" {
			Dir = filepath.Dir(f)
		}
		var (
			out  io.WriteCloser
			fout string
		)
		if BuildDir != "" {
			// Build output file based off build directory and input filename
			rel, _ := filepath.Rel(Includes, filepath.Dir(f))
			filename := strings.Replace(filepath.Base(f), ".scss", ".css", 1)
			fout = filepath.Join(BuildDir, rel, filename)
		} else {
			out = os.Stdout
		}

		ctx := context.Context{
			// TODO: Most of these fields are no longer used
			OutputStyle: style,
			ImageDir:    Dir,
			// Assumption that output is a file
			BuildDir:     BuildDir,
			GenImgDir:    Gen,
			MainFile:     f,
			Comments:     Comments,
			IncludePaths: []string{filepath.Dir(f)},
		}
		if Includes != "" {
			ctx.IncludePaths = append(ctx.IncludePaths,
				strings.Split(Includes, ",")...)
		}
		fRead, err := os.Open(f)
		if err != nil {
			log.Fatal(err)
		}
		if fout != "" {
			dir := filepath.Dir(fout)
			err := os.MkdirAll(dir, 0755)
			if err != nil {
				log.Fatalf("Failed to create directory: %s", dir)
			}

			out, err = os.Create(fout)
			if err != nil {
				log.Fatalf("Failed to create file: %s", f)
			}
			log.Println("Created:", fout)
		}

		var pout bytes.Buffer
		err = startParser(ctx, fRead, &pout, filepath.Dir(Input))
		if err != nil {
			log.Println(err)
			continue
		}
		err = ctx.Compile(&pout, out)

		if err != nil {
			log.Println(err)
		}
	}
}

func startParser(ctx context.Context, in io.Reader, out io.Writer, pkgdir string) error {
	// Run the sprite_sass parser prior to passing to libsass
	parser := sprite.Parser{
		ImageDir:  ctx.ImageDir,
		Includes:  ctx.IncludePaths,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	// Save reference to parser in context
	bs, err := parser.Start(in, pkgdir)
	if err != nil {
		return err
	}
	out.Write(bs)
	return err
}
<commit_msg>Context expects sprite array<commit_after>// Main package wraps sprite_sass tool for use with the command line
// See -h for list of available options
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"
	"strings"

	"github.com/drewwells/sprite_sass/context"
	"github.com/drewwells/spritewell"

	sprite "github.com/drewwells/sprite_sass"
)

const version = `v0.2.1`

var (
	Dir, Gen, Input, Includes string
	MainFile, Style           string
	Comments                  bool
	cpuprofile                string
	Help, ShowVersion         bool
	BuildDir                  string
)

func init() {
	flag.StringVar(&BuildDir, "b", "", "Build Directory")
	flag.StringVar(&Includes, "p", "", "SASS import path")
	flag.BoolVar(&Help, "help", false, "this help")
	flag.BoolVar(&Help, "h", false, "this help")
	flag.StringVar(&Dir, "dir", "", "Image directory")
	flag.StringVar(&Dir, "d", "", "Image directory")
	flag.StringVar(&Gen, "gen", ".", "Directory for generated images")
	flag.StringVar(&Style, "style", "nested", "CSS nested style")
	flag.StringVar(&Style, "s", "nested", "CSS nested style")
	flag.BoolVar(&Comments, "comment", true, "Turn on source comments")
	flag.BoolVar(&Comments, "c", true, "Turn on source comments")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
	flag.BoolVar(&ShowVersion, "version", false, "Show the app version")
}

func main() {
	flag.Parse()

	if ShowVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Profiling code
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer func() {
			err := f.Close()
			if err != nil {
				log.Fatal(err)
			}
			pprof.StopCPUProfile()
		}()
	}

	for _, v := range flag.Args() {
		if strings.HasPrefix(v, "-") {
			log.Fatalf("Please specify flags before other arguments: %s", v)
		}
	}

	if Help {
		fmt.Println("Please specify input filepath.")
		fmt.Println("\nAvailable options:")
		flag.PrintDefaults()
		return
	}

	style, ok := context.Style[Style]

	if !ok {
		style = context.NESTED_STYLE
	}

	if len(flag.Args()) == 0 {
		// Read from stdin
		log.Print("Reading from stdin, -h for help")
		out := os.Stdout
		in := os.Stdin

		var pout bytes.Buffer
		ctx := context.Context{}
		err := startParser(ctx, in, &pout, "")
		if err != nil {
			log.Println(err)
		}
		err = ctx.Compile(&pout, out)

		if err != nil {
			log.Println(err)
		}
	}

	for _, f := range flag.Args() {
		// Remove partials
		if strings.HasPrefix(filepath.Base(f), "_") {
			continue
		}
		log.Println("Open:", f)

		// If no imagedir specified, assume relative to the input file
		if Dir == "" {
			Dir = filepath.Dir(f)
		}
		var (
			out  io.WriteCloser
			fout string
		)
		if BuildDir != "" {
			// Build output file based off build directory and input filename
			rel, _ := filepath.Rel(Includes, filepath.Dir(f))
			filename := strings.Replace(filepath.Base(f), ".scss", ".css", 1)
			fout = filepath.Join(BuildDir, rel, filename)
		} else {
			out = os.Stdout
		}

		ctx := context.Context{
			// TODO: Most of these fields are no longer used
			Sprites:     make(map[string]spritewell.ImageList),
			OutputStyle: style,
			ImageDir:    Dir,
			// Assumption that output is a file
			BuildDir:     BuildDir,
			GenImgDir:    Gen,
			MainFile:     f,
			Comments:     Comments,
			IncludePaths: []string{filepath.Dir(f)},
		}
		if Includes != "" {
			ctx.IncludePaths = append(ctx.IncludePaths,
				strings.Split(Includes, ",")...)
		}
		fRead, err := os.Open(f)
		if err != nil {
			log.Fatal(err)
		}
		if fout != "" {
			dir := filepath.Dir(fout)
			err := os.MkdirAll(dir, 0755)
			if err != nil {
				log.Fatalf("Failed to create directory: %s", dir)
			}

			out, err = os.Create(fout)
			if err != nil {
				log.Fatalf("Failed to create file: %s", f)
			}
			log.Println("Created:", fout)
		}

		var pout bytes.Buffer
		err = startParser(ctx, fRead, &pout, filepath.Dir(Input))
		if err != nil {
			log.Println(err)
			continue
		}
		err = ctx.Compile(&pout, out)

		if err != nil {
			log.Println(err)
		}
	}
}

func startParser(ctx context.Context, in io.Reader, out io.Writer, pkgdir string) error {
	// Run the sprite_sass parser prior to passing to libsass
	parser := sprite.Parser{
		ImageDir:  ctx.ImageDir,
		Includes:  ctx.IncludePaths,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	// Save reference to parser in context
	bs, err := parser.Start(in, pkgdir)
	if err != nil {
		return err
	}
	out.Write(bs)
	return err
}
<|endoftext|>


<commit_before><commit_msg>Update files<commit_after><|endoftext|>