func (m *MycatPartitionMurmurHashShard) FindForKey(key interface{}) (int, error) {
	keyStr := GetString(key)
	hashKey := m.hashFunction.HashUnencodedChars(keyStr)
	_, ret := m.bucketMap.Ceiling(int(hashKey))
	if ret != nil {
		return ret.(int), nil
	}
	k, v := m.bucketMap.Min()
	if k == nil {
		return 0, errors.New("bucket map is empty")
	}
	return v.(int), nil
}
FindForKey return MycatPartitionMurmurHashShard calculated result
package router
import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"github.com/emirpasic/gods/maps/treemap"
	"github.com/nooncall/shazam/util"
	"github.com/nooncall/shazam/util/hack"
)
type MycatPartitionModShard struct {
	ShardNum int
}
func NewMycatPartitionModShard(shardNum int) *MycatPartitionModShard {
	return &MycatPartitionModShard{
		ShardNum: shardNum,
	}
}
func (m *MycatPartitionModShard) FindForKey(key interface{}) (int, error) {
	h := hack.Abs(NumValue(key))
	return int(h % int64(m.ShardNum)), nil
}
const (
	PartitionLength = 1024
	andValue        = PartitionLength - 1
)
type MycatPartitionLongShard struct {
	shardNum  int
	countStr  string
	lengthStr string
	count     []int
	length    []int
	segment   []int
}
func NewMycatPartitionLongShard(shardNum int, partitionCount, partitionLength string) *MycatPartitionLongShard {
	return &MycatPartitionLongShard{
		shardNum:  shardNum,
		countStr:  partitionCount,
		lengthStr: partitionLength,
		count:     make([]int, 0, 10),
		length:    make([]int, 0, 10),
		segment:   make([]int, 0, PartitionLength),
	}
}
func (m *MycatPartitionLongShard) Init() error {
	countList, err := toIntArray(m.countStr)
	if err != nil {
		return err
	}
	lengthList, err := toIntArray(m.lengthStr)
	if err != nil {
		return err
	}
	countSize := len(countList)
	lengthSize := len(lengthList)
	if countSize != lengthSize {
		return errors.New("error, check your scope & scopeLength definition")
	}
	segmentLength := 0
	for i := 0; i < countSize; i++ {
		segmentLength += countList[i]
	}
	if segmentLength != m.shardNum {
		return errors.New("segmentLength is not equal to shardNum")
	}
	ai := make([]int, segmentLength+1)
	index := 0
	for i := 0; i < countSize; i++ {
		for j := 0; j < countList[i]; j++ {
			ai[index+1] = ai[index] + lengthList[i]
			index++
		}
	}
	if ai[len(ai)-1] != PartitionLength {
		return errors.New("error, check your partitionScope definition")
	}
	segment := make([]int, PartitionLength)
	for i := 1; i < len(ai); i++ {
		for j := ai[i-1]; j < ai[i]; j++ {
			segment[j] = i - 1
		}
	}
	m.count = countList
	m.length = lengthList
	m.segment = segment
	return nil
}
func toIntArray(str string) ([]int, error) {
	str = strings.Replace(str, " ", "", -1)
	strList := strings.Split(str, ",")
	ret := make([]int, 0, len(strList))
	for _, s := range strList {
		num, err := strconv.Atoi(s)
		if err != nil {
			return ret, err
		}
		ret = append(ret, num)
	}
	return ret, nil
}
func (m *MycatPartitionLongShard) FindForKey(key interface{}) (int, error) {
	h := NumValue(key)
	return m.segment[int(h)&andValue], nil
}
type MycatPartitionStringShard struct {
	*MycatPartitionLongShard
	hashSliceStr   string
	hashSliceStart int
	hashSliceEnd   int
}
func NewMycatPartitionStringShard(shardNum int, partitionCount, partitionLength string, hashSliceStr string) *MycatPartitionStringShard {
	longShard := NewMycatPartitionLongShard(shardNum, partitionCount, partitionLength)
	stringShard := &MycatPartitionStringShard{
		MycatPartitionLongShard: longShard,
		hashSliceStr:            hashSliceStr,
	}
	return stringShard
}
func (m *MycatPartitionStringShard) Init() error {
	if err := m.MycatPartitionLongShard.Init(); err != nil {
		return err
	}
	start, end, err := parseHashSliceStartEnd(m.hashSliceStr)
	if err != nil {
		return err
	}
	m.hashSliceStart = start
	m.hashSliceEnd = end
	return nil
}
func parseHashSliceStartEnd(hashSliceStr string) (int, int, error) {
	hashSliceStr = strings.TrimSpace(hashSliceStr)
	strs := strings.Split(hashSliceStr, ":")
	if len(strs) == 1 {
		v, err := strconv.Atoi(strs[0])
		if err != nil {
			return -1, -1, err
		}
		if v >= 0 {
			return 0, v, nil
		}
		return v, 0, nil
	}
	if len(strs) == 2 {
		start, err := parseHashSliceValue(strs[0])
		if err != nil {
			return -1, -1, fmt.Errorf("parse hash slice start error: %v", err)
		}
		end, err := parseHashSliceValue(strs[1])
		if err != nil {
			return -1, -1, fmt.Errorf("parse hash slice end error: %v", err)
		}
		return start, end, nil
	}
	return -1, -1, fmt.Errorf("invalid hash slice str")
}
func parseHashSliceValue(str string) (int, error) {
	if str == "" {
		return 0, nil
	}
	v, err := strconv.Atoi(str)
	return v, err
}
func (m *MycatPartitionStringShard) FindForKey(key interface{}) (int, error) {
	keyStr := GetString(key)
	var start int
	if m.hashSliceStart >= 0 {
		start = m.hashSliceStart
	} else {
		start = len(keyStr) + m.hashSliceStart
	}
	var end int
	if m.hashSliceEnd > 0 {
		end = m.hashSliceEnd
	} else {
		end = len(keyStr) + m.hashSliceEnd
	}
	h := stringHash(keyStr, start, end)
	return m.segment[int(h)&andValue], nil
}
func stringHash(s string, start, end int) int64 {
	input := []rune(s)
	if start < 0 {
		start = 0
	}
	if end > len(input) {
		end = len(input)
	}
	var h int64
	for i := start; i < end; i++ {
		h = (h << 5) - h + int64(input[i])
	}
	return h
}
const (
	defaultWeight = 1
)
type MycatPartitionMurmurHashShard struct {
	seed               int
	count              int
	virtualBucketTimes int
	weightMap          map[int]int
	bucketMap          *treemap.Map
	hashFunction       *util.MurmurHash
}
func NewMycatPartitionMurmurHashShard(seedStr, virtualBucketTimesStr string, count int) (*MycatPartitionMurmurHashShard, error) {
	seed, err := strconv.Atoi(seedStr)
	if err != nil {
		return nil, err
	}
	if virtualBucketTimesStr == "" {
		virtualBucketTimesStr = "160"
	}
	virtualBucketTimes, err := strconv.Atoi(virtualBucketTimesStr)
	if err != nil {
		return nil, err
	}
	return &MycatPartitionMurmurHashShard{
		seed:               seed,
		count:              count,
		virtualBucketTimes: virtualBucketTimes,
	}, nil
}
func (m *MycatPartitionMurmurHashShard) Init() error {
	m.bucketMap = treemap.NewWithIntComparator()
	m.hashFunction = util.NewMurmurHash(m.seed)  
	if err := m.generateBucketMap(); err != nil {
		return fmt.Errorf("murmur hash error, %v", err)
	}
	m.weightMap = make(map[int]int)
	return nil
}