├── data ├── gua.data └── dayan.data ├── zoneinfo.zip ├── log.go ├── config ├── config_test.go ├── database.go └── config.go ├── zhouyi_test.go ├── zhouyi.go ├── god.go ├── error.go ├── nayin.go ├── regular ├── regular_test.go └── regular.go ├── bazi_test.go ├── martial.go ├── .gitignore ├── go.mod ├── cmd ├── console │ ├── main.go │ ├── name.go │ └── init.go └── strokefix │ ├── main.go │ ├── update.go │ ├── rule.go │ └── check.go ├── wuge_test.go ├── stroke.go ├── wuxing.go ├── yao.go ├── LICENSE ├── iterator.go ├── name_stroke.go ├── fate_test.go ├── sancai.go ├── xiyong.go ├── example └── create_a_name │ └── main.go ├── name.go ├── zodiac.go ├── database.go ├── README.md ├── character.go ├── information.go ├── bazi.go ├── wuge.go ├── dayan.go ├── fate.go └── statik └── statik.go /data/gua.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reed-hong/fate/HEAD/data/gua.data -------------------------------------------------------------------------------- /zoneinfo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reed-hong/fate/HEAD/zoneinfo.zip -------------------------------------------------------------------------------- /data/dayan.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reed-hong/fate/HEAD/data/dayan.data -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/goextension/log/zap" 5 | ) 6 | 7 | func init() { 8 | zap.InitZapSugar() 9 | } 10 | -------------------------------------------------------------------------------- /config/config_test.go: -------------------------------------------------------------------------------- 1 | package config_test 2 | 3 | import ( 4 | "testing" 5 | 6 | ) 7 | 8 | func TestLoad(t *testing.T) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /zhouyi_test.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import "testing" 4 | 5 | func TestQiGua(t *testing.T) { 6 | yi := QiGua(7, 7) 7 | get := yi.Get(0) 8 | t.Log(get) 9 | } 10 | -------------------------------------------------------------------------------- /zhouyi.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/godcong/yi" 5 | ) 6 | 7 | //QiGua 起卦 8 | func QiGua(xia, shang int) *yi.Yi { 9 | return yi.NumberQiGua(shang, xia) 10 | } 11 | -------------------------------------------------------------------------------- /god.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | // LikeUseGod ... 4 | type LikeUseGod struct { 5 | LikeGod string //喜神 6 | UseGod string //用神 7 | Gold string //五行:金 8 | Wood string //五行:木 9 | Water string //五行:水 10 | Fire string //五行:火 11 | Soil string //五行:土 12 | } 13 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // Wrap ... 9 | func Wrap(err error, msg ...string) error { 10 | if err != nil { 11 | m := strings.Join(msg, " ") 12 | return fmt.Errorf("%s:%w", m, err) 13 | } 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /nayin.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import "github.com/godcong/chronos" 4 | 5 | //NaYin 纳音 6 | type NaYin struct { 7 | calendar *chronos.Calendar 8 | } 9 | 10 | //NewNaYin 创建纳音 11 | func NewNaYin(calendar *chronos.Calendar) *NaYin { 12 | return &NaYin{ 13 | calendar: calendar, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /regular/regular_test.go: -------------------------------------------------------------------------------- 1 | package regular 2 | 3 | import ( 4 | "github.com/godcong/fate" 5 | "github.com/godcong/fate/config" 6 | "testing" 7 | ) 8 | 9 | func TestNew(t *testing.T) { 10 | c := config.LoadConfig() 11 | db := fate.InitDatabaseWithConfig(*c) 12 | regular := New(db) 13 | regular.Run() 14 | } 15 | -------------------------------------------------------------------------------- /bazi_test.go: -------------------------------------------------------------------------------- 1 | package fate_test 2 | 3 | import ( 4 | "github.com/godcong/chronos" 5 | "github.com/godcong/fate" 6 | "log" 7 | "testing" 8 | ) 9 | 10 | func TestPoint(t *testing.T) { 11 | t1 := chronos.New("2020/01/24 15:30") 12 | log.Println(t1.Lunar().EightCharacter()) 13 | 14 | bz := fate.NewBazi(t1) 15 | t.Log(bz.XiYong()) 16 | t.Log(bz.XiYongShen()) 17 | } 18 | -------------------------------------------------------------------------------- /martial.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | //Martial six martials 4 | type Martial struct { 5 | BiHua bool `bson:"bi_hua" json:"bi_hua"` //笔画 6 | SanCai bool `bson:"san_cai" json:"san_cai"` //三才 7 | BaZi bool `bson:"ba_zi" json:"ba_zi"` //八字 8 | GuaXiang bool `bson:"gua_xiang" json:"gua_xiang"` //卦象 9 | TianYun bool `bson:"tian_yun" json:"tian_yun"` //天运 10 | ShengXiao bool `bson:"sheng_xiao" json:"sheng_xiao"` //生肖 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | #[Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | /.idea 34 | go.sum -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/godcong/fate 2 | 3 | require ( 4 | github.com/go-sql-driver/mysql v1.4.1 5 | github.com/godcong/chronos v0.0.2 6 | github.com/godcong/yi v1.0.2 7 | github.com/goextension/log v0.0.2 8 | github.com/google/uuid v1.1.1 9 | github.com/rakyll/statik v0.1.6 10 | github.com/spf13/cobra v0.0.5 11 | github.com/xormsharp/builder v0.3.6 12 | github.com/xormsharp/xorm v1.0.0 13 | go.uber.org/zap v1.13.0 14 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect 15 | ) 16 | 17 | go 1.13 18 | -------------------------------------------------------------------------------- /cmd/console/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "github.com/spf13/cobra" 5 | 6 | const programName = `fate` 7 | 8 | var rootCmd = &cobra.Command{ 9 | Use: "fate [command]", 10 | Short: "call fate command", 11 | Version: "v0.0.1", 12 | Run: func(cmd *cobra.Command, args []string) { 13 | fmt.Println("arguments [command] was not inputted") 14 | }, 15 | DisableSuggestions: false, 16 | SuggestionsMinimumDistance: 1, 17 | } 18 | 19 | func main() { 20 | rootCmd.AddCommand(cmdInit(), cmdName()) 21 | e := rootCmd.Execute() 22 | if e != nil { 23 | panic(e) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /wuge_test.go: -------------------------------------------------------------------------------- 1 | package fate_test 2 | 3 | import ( 4 | "github.com/godcong/fate" 5 | "log" 6 | "testing" 7 | ) 8 | 9 | func TestWuGe_WaiGe(t *testing.T) { 10 | l1, l2, f1, f2 := 1, 1, 1, 1 11 | for i := 0; i < 80000; i++ { 12 | if f2 >= fate.WuGeMax { 13 | f1++ 14 | f2 = 1 15 | } 16 | if f1 >= fate.WuGeMax { 17 | l2++ 18 | f1 = 1 19 | } 20 | if l2 >= fate.WuGeMax { 21 | l1++ 22 | l2 = 1 23 | } 24 | wg := fate.CalcWuGe(l1, l2, f1, f2) 25 | sum := l1 + l2 + f1 + f2 26 | if wg.ZongGe() != sum { 27 | log.Println(wg.ZongGe() == sum, l1, l2, f1, f2, wg.ZongGe()) 28 | } 29 | f2++ 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cmd/strokefix/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/godcong/fate" 5 | "github.com/godcong/fate/config" 6 | "github.com/xormsharp/xorm" 7 | ) 8 | 9 | func main() { 10 | var e error 11 | 12 | cfg := config.DefaultConfig() 13 | db := fate.InitDatabaseWithConfig(*cfg) 14 | 15 | e = db.Sync(fate.Character{}) 16 | if e != nil { 17 | return 18 | } 19 | 20 | e = UpdateFix(db.Database().(*xorm.Engine)) 21 | if e != nil { 22 | panic(e) 23 | } 24 | e = CheckLoader(`E:\project\fate\cmd\strokefix\dict.json`) 25 | if e != nil { 26 | panic(e) 27 | } 28 | e = CheckVerify(db) 29 | if e != nil { 30 | panic(e) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/database.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Database struct { 4 | Host string `json:"host"` 5 | Port string `json:"port"` 6 | User string `json:"user"` 7 | Pwd string `json:"pwd"` 8 | Name string `json:"name"` 9 | MaxIdleCon int `json:"max_idle_con"` 10 | MaxOpenCon int `json:"max_open_con"` 11 | Driver string `json:"driver"` 12 | File string `json:"file"` 13 | Dsn string `json:"dsn"` 14 | ShowSQL bool `json:"show_sql"` 15 | ShowExecTime bool `json:"show_exec_time"` 16 | } 17 | 18 | func (d *Database) Addr() string { 19 | return d.Host + ":" + d.Port 20 | } 21 | -------------------------------------------------------------------------------- /stroke.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | //Strokes 推荐笔画数 4 | type Strokes struct { 5 | SimplifiedChinese int //简体中文 6 | TraditionalChinese int //繁体中文 7 | KangxiDictionary int //康熙字典 8 | GodBook int //神册 9 | } 10 | 11 | //FindCharacterStrokes 通过文字查询推荐笔画数 12 | func FindCharacterStrokes(char string) int { 13 | //TODO:find 14 | s := &Strokes{} 15 | if s.GodBook > 0 { 16 | return s.GodBook 17 | } 18 | if s.KangxiDictionary > 0 { 19 | return s.KangxiDictionary 20 | } 21 | if s.TraditionalChinese > 0 { 22 | return s.TraditionalChinese 23 | } 24 | if s.SimplifiedChinese > 0 { 25 | return s.SimplifiedChinese 26 | } 27 | return 0 28 | } 29 | -------------------------------------------------------------------------------- /cmd/strokefix/update.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/godcong/fate" 5 | "github.com/goextension/log" 6 | "github.com/xormsharp/xorm" 7 | ) 8 | 9 | func UpdateFix(engine *xorm.Engine) error { 10 | rows, e := engine.Rows(&fate.Character{}) 11 | if e != nil { 12 | return e 13 | } 14 | var ch *fate.Character 15 | for rows.Next() { 16 | ch = &fate.Character{} 17 | e := rows.Scan(ch) 18 | if e != nil { 19 | log.Errorw("fix", "charater", ch.Ch, "error", e) 20 | continue 21 | } 22 | if fixChar(ch) { 23 | _, e := engine.Where("hash = ?", ch.Hash).Cols("science_stroke").Update(ch) 24 | if e != nil { 25 | log.Errorw("update", "charater", ch.Ch, "error", e) 26 | continue 27 | } 28 | log.Infow("updated", "charater", ch.Ch, "stroke", ch.ScienceStroke) 29 | } 30 | } 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /wuxing.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "errors" 5 | "github.com/xormsharp/xorm" 6 | ) 7 | 8 | // Luck ... 9 | type Luck int 10 | 11 | var luckPoint = []string{"大凶", "凶", "凶多于吉", "吉凶参半", "吉多于凶", "吉", "大吉"} 12 | 13 | // Point ... 14 | func (l *Luck) Point() int { 15 | return int(*l) + 1 16 | } 17 | 18 | // ToLuck ... 19 | func ToLuck(s string) (l Luck, e error) { 20 | for i, luck := range luckPoint { 21 | if luck == s { 22 | return Luck(i), nil 23 | } 24 | } 25 | return Luck(0), errors.New("parse error") 26 | } 27 | 28 | //WuXing 五行:five elements of metal,wood,water,fire and earth 29 | type WuXing struct { 30 | WuXing string `json:"wu_xing"` 31 | Luck Luck `json:"luck"` 32 | Comment string `json:"comment"` 33 | } 34 | 35 | //FindWuXing find a wuxing 36 | func FindWuXing(engine *xorm.Engine, s ...string) *WuXing { 37 | var wx WuXing 38 | _, e := engine.Where("first = ?", s[0]).And("second = ?", s[1]).And("third = ?", s[2]).Get(&wx) 39 | if e != nil { 40 | return nil 41 | } 42 | return &wx 43 | } 44 | -------------------------------------------------------------------------------- /yao.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import "github.com/godcong/yi" 4 | 5 | // GuaYao ... 6 | type GuaYao struct { 7 | Yao string `bson:"er_yao"` //二爻 8 | JiXiong string `bson:"er_yao_ji_xiong"` //二爻吉凶 9 | } 10 | 11 | func getYao(xiang *yi.GuaXiang, yao int) GuaYao { 12 | switch yao { 13 | case 0: 14 | return GuaYao{Yao: xiang.ChuYao, JiXiong: xiang.ChuYaoJiXiong} 15 | case 1: 16 | return GuaYao{Yao: xiang.ErYao, JiXiong: xiang.ErYaoJiXiong} 17 | case 2: 18 | return GuaYao{Yao: xiang.SanYao, JiXiong: xiang.SanYaoJiXiong} 19 | case 3: 20 | return GuaYao{Yao: xiang.SiYao, JiXiong: xiang.SiYaoJiXiong} 21 | case 4: 22 | return GuaYao{Yao: xiang.WuYao, JiXiong: xiang.WuYaoJiXiong} 23 | case 5: 24 | return GuaYao{Yao: xiang.ShangYao, JiXiong: xiang.ShangYaoJiXiong} 25 | default: 26 | panic("wrong yao") 27 | } 28 | } 29 | 30 | func filterYao(y *yi.Yi, fs ...string) bool { 31 | yao := getYao(y.Get(yi.BianGua), y.BianYao()) 32 | for _, s := range fs { 33 | if yao.JiXiong == s { 34 | return false 35 | } 36 | } 37 | return true 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 godcong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /iterator.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | // IteratorFunc ... 4 | type IteratorFunc func(v interface{}) error 5 | 6 | type iterator struct { 7 | data []interface{} 8 | index int 9 | } 10 | 11 | // newIterator ... 12 | func newIterator() *iterator { 13 | return &iterator{ 14 | data: nil, 15 | index: 0, 16 | } 17 | } 18 | 19 | //HasNext check next 20 | func (i *iterator) HasNext() bool { 21 | return i.index < len(i.data) 22 | } 23 | 24 | //Next get next 25 | func (i *iterator) Next() interface{} { 26 | defer func() { 27 | i.index++ 28 | }() 29 | if i.index < len(i.data) { 30 | return i.data[i.index] 31 | } 32 | 33 | return nil 34 | } 35 | 36 | //Reset reset index 37 | func (i *iterator) Reset() { 38 | i.index = 0 39 | } 40 | 41 | //Add add radical 42 | func (i *iterator) Add(v interface{}) { 43 | i.data = append(i.data, v) 44 | } 45 | 46 | //Size iterator data size 47 | func (i *iterator) Size() int { 48 | return len(i.data) 49 | } 50 | 51 | //Iterator an default iterator 52 | func (i *iterator) Iterator(f IteratorFunc) error { 53 | i.Reset() 54 | for i.HasNext() { 55 | if err := f(i.Next()); err != nil { 56 | return err 57 | } 58 | } 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /name_stroke.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | // NameStroke ... 4 | type NameStroke struct { 5 | //ID bson.ObjectId `bson:"_id,omitempty"` 6 | Last1 int `bson:"last_1"` 7 | Last2 int `bson:"last_2"` 8 | First1 int `bson:"first_1"` 9 | First2 int `bson:"first_2"` 10 | } 11 | 12 | type nameStroke struct { 13 | *NameStroke 14 | *SanCai 15 | *WuGe 16 | } 17 | 18 | // SanCaiWuGe ... 19 | type SanCaiWuGe interface { 20 | } 21 | 22 | //SanCaiWuGe 三才五格 23 | func (s *NameStroke) SanCaiWuGe() SanCaiWuGe { 24 | l1, l2, f1, f2 := s.Last1, s.Last2, s.First1, s.First2 25 | wuGe := &WuGe{ 26 | tianGe: tianGe(l1, l2, f1, f2), 27 | renGe: renGe(l1, l2, f1, f2), 28 | diGe: diGe(l1, l2, f1, f2), 29 | waiGe: waiGe(l1, l2, f1, f2), 30 | zongGe: zongGe(l1, l2, f1, f2), 31 | } 32 | 33 | sanCai := &SanCai{ 34 | tianCai: sanCaiAttr(wuGe.TianGe()), 35 | tianCaiYinYang: yinYangAttr(wuGe.TianGe()), 36 | renCai: sanCaiAttr(wuGe.RenGe()), 37 | renCaiYinYang: yinYangAttr(wuGe.RenGe()), 38 | diCai: sanCaiAttr(wuGe.DiGe()), 39 | diCaiYingYang: yinYangAttr(wuGe.DiGe()), 40 | } 41 | 42 | return &nameStroke{ 43 | NameStroke: s, 44 | SanCai: sanCai, 45 | WuGe: wuGe, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /fate_test.go: -------------------------------------------------------------------------------- 1 | package fate_test 2 | 3 | import ( 4 | "context" 5 | "github.com/godcong/chronos" 6 | "github.com/godcong/fate" 7 | "github.com/godcong/fate/config" 8 | "testing" 9 | ) 10 | 11 | func init() { 12 | //trait.NewZapFileSugar("fate.log") 13 | } 14 | 15 | func TestFate_RunMakeName(t *testing.T) { 16 | born := chronos.New("2020/02/06 15:45").Solar().Time() 17 | last := "张" 18 | cfg := config.DefaultConfig() 19 | cfg.BaguaFilter = true 20 | cfg.ZodiacFilter = true 21 | cfg.SupplyFilter = true 22 | cfg.HardFilter = true 23 | cfg.StrokeMin = 3 24 | cfg.StrokeMax = 24 25 | cfg.Regular = true 26 | cfg.RunInit = false 27 | cfg.FileOutput = config.FileOutput{ 28 | OutputMode: config.OutputModeLog, 29 | Path: "name.log", 30 | } 31 | cfg.Database = config.Database{ 32 | Host: "localhost", 33 | Port: "3306", 34 | User: "root", 35 | Pwd: "111111", 36 | Name: "fate", 37 | MaxIdleCon: 0, 38 | MaxOpenCon: 0, 39 | Driver: "mysql", 40 | File: "", 41 | Dsn: "", 42 | ShowSQL: false, 43 | ShowExecTime: false, 44 | } 45 | f := fate.NewFate(last, born, fate.ConfigOption(cfg), fate.SexOption(fate.SexGirl)) 46 | 47 | //f.SetDB(eng) 48 | e := f.MakeName(context.Background()) 49 | if e != nil { 50 | t.Fatal(e) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cmd/console/name.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/godcong/chronos" 7 | "github.com/godcong/fate" 8 | "github.com/godcong/fate/config" 9 | "github.com/goextension/log" 10 | "github.com/spf13/cobra" 11 | "time" 12 | ) 13 | 14 | func cmdName() *cobra.Command { 15 | path := "" 16 | born := "" 17 | last := "" 18 | sex := false 19 | cmd := &cobra.Command{ 20 | Use: "name", 21 | Short: "output the name", 22 | Run: func(cmd *cobra.Command, args []string) { 23 | config.DefaultJSONPath = path 24 | cfg := config.LoadConfig() 25 | fmt.Printf("config loaded: %+v", cfg) 26 | bornTime, e := time.Parse(chronos.DateFormat, born) 27 | if e != nil { 28 | log.Fatalw("parseborn", "error", e) 29 | } 30 | f := fate.NewFate(last, bornTime, fate.ConfigOption(cfg), fate.SexOption(fate.Sex(sex))) 31 | 32 | e = f.MakeName(context.Background()) 33 | if e != nil { 34 | log.Fatalw("makename", "error", e) 35 | } 36 | }, 37 | } 38 | cmd.Flags().StringVarP(&last, "last", "l", "", "set lastname") 39 | cmd.Flags().StringVarP(&born, "born", "b", time.Now().Format(chronos.DateFormat), "set birth as 2016/01/02 15:04") 40 | cmd.Flags().StringVarP(&path, "path", "p", ".", "set the input path") 41 | cmd.Flags().BoolVarP(&sex, "sex", "s", false, "set sex of the baby") 42 | return cmd 43 | } 44 | -------------------------------------------------------------------------------- /sancai.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import "github.com/xormsharp/xorm" 4 | 5 | const sanCai = "水木木火火土土金金水" 6 | const yinYang = "阴阳" 7 | 8 | // SanCai ... 9 | type SanCai struct { 10 | tianCai string `bson:"tian_cai"` 11 | tianCaiYinYang string `bson:"tian_cai_yin_yang"` 12 | renCai string `bson:"ren_cai"` 13 | renCaiYinYang string `bson:"ren_cai_yin_yang"` 14 | diCai string `bson:"di_cai"` 15 | diCaiYingYang string `bson:"di_cai_ying_yang"` 16 | fortune string `bson:"fortune"` //吉凶 17 | comment string `bson:"comment"` //说明 18 | } 19 | 20 | //NewSanCai 新建一个三才对象 21 | func NewSanCai(tian, ren, di int) *SanCai { 22 | return &SanCai{ 23 | tianCai: sanCaiAttr(tian), 24 | tianCaiYinYang: yinYangAttr(tian), 25 | renCai: sanCaiAttr(ren), 26 | renCaiYinYang: yinYangAttr(ren), 27 | diCai: sanCaiAttr(di), 28 | diCaiYingYang: yinYangAttr(di), 29 | } 30 | } 31 | 32 | //Check 检查三才属性 33 | func Check(engine *xorm.Engine, cai *SanCai, point int) bool { 34 | wx := FindWuXing(engine, cai.tianCai, cai.renCai, cai.diCai) 35 | if wx.Luck.Point() >= point { 36 | return true 37 | } 38 | return false 39 | } 40 | 41 | // GenerateThreeTalent 计算字符的三才属性 42 | // 1-2木:1为阳木,2为阴木 3-4火:3为阳火,4为阴火 5-6土:5为阳土,6为阴土 7-8金:7为阳金,8为阴金 9-10水:9为阳水,10为阴水 43 | func sanCaiAttr(i int) string { 44 | return string([]rune(sanCai)[i%10]) 45 | } 46 | 47 | func yinYangAttr(i int) string { 48 | return string([]rune(yinYang)[i%2]) 49 | } 50 | -------------------------------------------------------------------------------- /xiyong.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | //XiYong 喜用神 4 | type XiYong struct { 5 | WuXingFen map[string]int 6 | Similar []string //同类 7 | SimilarPoint int 8 | Heterogeneous []string //异类 9 | HeterogeneousPoint int 10 | } 11 | 12 | var sheng = []string{"木", "火", "土", "金", "水"} 13 | var ke = []string{"木", "土", "水", "火", "金"} 14 | 15 | //AddFen 五行分 16 | func (xy *XiYong) AddFen(s string, point int) { 17 | if xy.WuXingFen == nil { 18 | xy.WuXingFen = make(map[string]int) 19 | } 20 | 21 | if v, b := xy.WuXingFen[s]; b { 22 | xy.WuXingFen[s] = v + point 23 | } else { 24 | xy.WuXingFen[s] = point 25 | } 26 | } 27 | 28 | //GetFen 取得分 29 | func (xy *XiYong) GetFen(s string) (point int) { 30 | if xy.WuXingFen == nil { 31 | return 0 32 | } 33 | if v, b := xy.WuXingFen[s]; b { 34 | return v 35 | } 36 | return 0 37 | } 38 | 39 | func (xy *XiYong) minFenWuXing(ss ...string) (wx string) { 40 | min := 9999 41 | for _, s := range ss { 42 | if xy.WuXingFen[s] < min { 43 | min = xy.WuXingFen[s] 44 | wx = s 45 | } else if xy.WuXingFen[s] == min { 46 | wx += s 47 | } 48 | } 49 | return 50 | } 51 | 52 | //Shen 喜用神 53 | func (xy *XiYong) Shen() string { 54 | if !xy.QiangRuo() { 55 | return xy.minFenWuXing(xy.Similar...) 56 | } 57 | return xy.minFenWuXing(xy.Heterogeneous...) 58 | } 59 | 60 | //QiangRuo 八字偏强(true)弱(false) 61 | func (xy *XiYong) QiangRuo() bool { 62 | return xy.SimilarPoint > xy.HeterogeneousPoint 63 | } 64 | 65 | func filterXiYong(yong string, cs ...*Character) (b bool) { 66 | for _, c := range cs { 67 | if c.WuXing == yong { 68 | return true 69 | } 70 | } 71 | return false 72 | } 73 | -------------------------------------------------------------------------------- /cmd/console/init.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/godcong/fate/config" 7 | "github.com/spf13/cobra" 8 | "io" 9 | "log" 10 | "os" 11 | "path/filepath" 12 | "runtime" 13 | ) 14 | 15 | func cmdInit() *cobra.Command { 16 | var path string 17 | cmd := &cobra.Command{ 18 | Use: "init", 19 | Short: "output the init config", 20 | Run: func(cmd *cobra.Command, args []string) { 21 | absPath, e := filepath.Abs(path) 22 | if e != nil { 23 | log.Fatalf("wrong path with:%v", e) 24 | } 25 | fmt.Printf("config will output to %s\n", filepath.Join(absPath, config.JSONName)) 26 | config.DefaultJSONPath = path 27 | 28 | e = config.OutputConfig(config.DefaultConfig()) 29 | if e != nil { 30 | log.Fatal(e) 31 | } 32 | 33 | e = zoneCheck() 34 | if e != nil { 35 | log.Fatal(e) 36 | } 37 | }, 38 | } 39 | cmd.Flags().StringVarP(&path, "path", "p", "", "set the output path") 40 | return cmd 41 | } 42 | 43 | func zoneCheck() error { 44 | path := runtime.GOROOT() + "/lib/time" 45 | info, e := os.Stat(path) 46 | if e != nil { 47 | if os.IsNotExist(e) { 48 | e = os.MkdirAll(path, 0755) 49 | if e != nil { 50 | return e 51 | } 52 | } else { 53 | return e 54 | } 55 | } 56 | if !info.IsDir() { 57 | return errors.New("destination file is not a directory") 58 | } 59 | 60 | filename := "zoneinfo.zip" 61 | 62 | src, e := os.Open(filename) 63 | if e != nil { 64 | return e 65 | } 66 | dst, e := os.OpenFile(filepath.Join(path, filename), os.O_CREATE|os.O_RDWR|os.O_SYNC|os.O_TRUNC, 0755) 67 | if e != nil { 68 | return e 69 | } 70 | if _, err := io.Copy(dst, src); err != nil { 71 | return err 72 | } 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /example/create_a_name/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/godcong/chronos" 6 | "github.com/godcong/fate" 7 | "github.com/godcong/fate/config" 8 | ) 9 | 10 | func main() { 11 | 12 | //cfg := config.DefaultConfig() 参数如下 13 | //config.Config{ 14 | // HardFilter: false, 15 | // //输出最大笔画数 16 | // StrokeMax: 3, 17 | // //输出最小笔画数 18 | // StrokeMin: 18, 19 | // //立春修正(出生日期为立春当日时间为已过立春八字需修正) 20 | // FixBazi: true, 21 | // //三才五格过滤 22 | // SupplyFilter: true, 23 | // //生肖过滤 24 | // ZodiacFilter: true, 25 | // //周易八卦过滤 26 | // BaguaFilter: true, 27 | // //连接DB: 28 | // Database: config.Database{ 29 | // Host: "localhost", 30 | // Port: "3306", 31 | // User: "root", 32 | // Pwd: "111111", 33 | // Name: "fate", 34 | // MaxIdleCon: 0, 35 | // MaxOpenCon: 0, 36 | // Driver: "mysql", 37 | // File: "", 38 | // Dsn: "", 39 | // ShowSQL: false, 40 | // ShowExecTime: false, 41 | // }, 42 | //}) 43 | //出生日期 44 | born := chronos.New("2020/01/14 02:45") 45 | //姓氏 46 | lastName := "张" 47 | cfg := config.DefaultConfig() 48 | cfg.BaguaFilter = true 49 | cfg.ZodiacFilter = true 50 | cfg.SupplyFilter = true 51 | cfg.HardFilter = true 52 | cfg.StrokeMin = 3 53 | cfg.StrokeMax = 24 54 | cfg.Database = config.Database{ 55 | Host: "localhost", 56 | Port: "3306", 57 | User: "root", 58 | Pwd: "111111", 59 | Name: "fate", 60 | MaxIdleCon: 0, 61 | MaxOpenCon: 0, 62 | Driver: "mysql", 63 | File: "", 64 | Dsn: "", 65 | ShowSQL: false, 66 | ShowExecTime: false, 67 | } 68 | cfg.FileOutput = config.FileOutput{ 69 | OutputMode: config.OutputModeLog, 70 | Path: "name.log", 71 | } 72 | 73 | f := fate.NewFate(lastName, born.Solar().Time(), fate.ConfigOption(cfg)) 74 | 75 | e := f.MakeName(context.Background()) 76 | if e != nil { 77 | panic(e) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /name.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/godcong/chronos" 5 | "github.com/godcong/yi" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | //Name 姓名 11 | type Name struct { 12 | FirstName []*Character //名姓 13 | LastName []*Character 14 | born *chronos.Calendar 15 | baZi *BaZi 16 | baGua *yi.Yi //周易八卦 17 | zodiac *Zodiac 18 | zodiacPoint int 19 | } 20 | 21 | // String ... 22 | func (n Name) String() string { 23 | var s string 24 | for _, l := range n.LastName { 25 | s += l.Ch 26 | } 27 | for _, f := range n.FirstName { 28 | s += f.Ch 29 | } 30 | return s 31 | } 32 | 33 | // Strokes ... 34 | func (n Name) Strokes() string { 35 | var s []string 36 | for _, l := range n.LastName { 37 | s = append(s, strconv.Itoa(l.ScienceStroke)) 38 | } 39 | 40 | for _, f := range n.FirstName { 41 | s = append(s, strconv.Itoa(f.ScienceStroke)) 42 | } 43 | return strings.Join(s, ",") 44 | } 45 | 46 | // PinYin ... 47 | func (n Name) PinYin() string { 48 | var s string 49 | for _, l := range n.LastName { 50 | s += "[" + strings.Join(l.PinYin, ",") + "]" 51 | } 52 | 53 | for _, f := range n.FirstName { 54 | s += "[" + strings.Join(f.PinYin, ",") + "]" 55 | } 56 | return s 57 | } 58 | 59 | // WuXing ... 60 | func (n Name) WuXing() string { 61 | var s string 62 | for _, l := range n.LastName { 63 | s += l.WuXing 64 | } 65 | for _, f := range n.FirstName { 66 | s += f.WuXing 67 | } 68 | return s 69 | } 70 | 71 | // XiYongShen ... 72 | func (n Name) XiYongShen() string { 73 | return n.baZi.XiYongShen() 74 | } 75 | 76 | func createName(impl *fateImpl, f1 *Character, f2 *Character) *Name { 77 | lastSize := len(impl.lastChar) 78 | last := make([]*Character, lastSize, lastSize) 79 | copy(last, impl.lastChar) 80 | ff1 := *f1 81 | ff2 := *f2 82 | first := []*Character{&ff1, &ff2} 83 | 84 | return &Name{ 85 | FirstName: first, 86 | LastName: last, 87 | } 88 | } 89 | 90 | // BaGua ... 91 | func (n *Name) BaGua() *yi.Yi { 92 | if n.baGua == nil { 93 | lastSize := len(n.LastName) 94 | shang := getStroke(n.LastName[0]) 95 | if lastSize > 1 { 96 | shang += getStroke(n.LastName[1]) 97 | } 98 | xia := getStroke(n.FirstName[0]) + getStroke(n.FirstName[1]) 99 | n.baGua = yi.NumberQiGua(xia, shang, shang+xia) 100 | } 101 | 102 | return n.baGua 103 | } 104 | 105 | // BaZi ... 106 | func (n Name) BaZi() string { 107 | return n.baZi.String() 108 | } 109 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | const JSONName = "config.json" 11 | 12 | type FilterMode int 13 | 14 | const ( 15 | FilterModeNormal FilterMode = iota 16 | FilterModeHard 17 | FilterModeCustom 18 | ) 19 | 20 | type OutputMode int 21 | 22 | const ( 23 | OutputModeLog OutputMode = iota 24 | OutputModeCSV 25 | OutputModelJSON 26 | ) 27 | 28 | type FileOutput struct { 29 | OutputMode OutputMode `json:"output_mode"` 30 | Path string `json:"path"` 31 | Heads []string `json:"heads"` 32 | } 33 | 34 | type Config struct { 35 | RunInit bool `json:"run_init"` 36 | FilterMode FilterMode `json:"filter_mode"` 37 | StrokeMax int `json:"stroke_max"` 38 | StrokeMin int `json:"stroke_min"` 39 | HardFilter bool `json:"hard_filter"` 40 | FixBazi bool `json:"fix_bazi"` //八字修正 41 | SupplyFilter bool `json:"supply_filter"` //过滤补八字 42 | ZodiacFilter bool `json:"zodiac_filter"` //过滤生肖 43 | BaguaFilter bool `json:"bagua_filter"` //过滤卦象 44 | Regular bool `json:"regular"` //常用 45 | Database Database `json:"database"` 46 | FileOutput FileOutput `json:"file_output"` 47 | } 48 | 49 | var DefaultJSONPath = "" 50 | var DefaultHeads = []string{"姓名", "笔画", "拼音", "喜用神", "八字"} 51 | 52 | func init() { 53 | if DefaultJSONPath == "" { 54 | dir, err := os.Getwd() 55 | if err != nil { 56 | panic(err) 57 | } 58 | s, err := filepath.Abs(dir) 59 | if err != nil { 60 | panic(err) 61 | } 62 | DefaultJSONPath = s 63 | } 64 | } 65 | 66 | func LoadConfig() (c *Config) { 67 | c = &Config{} 68 | def := DefaultConfig() 69 | f := filepath.Join(DefaultJSONPath, JSONName) 70 | bys, e := ioutil.ReadFile(f) 71 | if e != nil { 72 | return def 73 | } 74 | e = json.Unmarshal(bys, &c) 75 | if e != nil { 76 | return def 77 | } 78 | return c 79 | } 80 | 81 | func OutputConfig(config *Config) error { 82 | bys, e := json.MarshalIndent(config, "", " ") 83 | if e != nil { 84 | return e 85 | } 86 | 87 | return ioutil.WriteFile(filepath.Join(DefaultJSONPath, JSONName), bys, 0755) 88 | } 89 | 90 | func DefaultConfig() *Config { 91 | return &Config{ 92 | RunInit: false, 93 | FilterMode: 0, 94 | StrokeMax: 18, 95 | StrokeMin: 3, 96 | HardFilter: false, 97 | FixBazi: false, 98 | SupplyFilter: true, 99 | ZodiacFilter: true, 100 | BaguaFilter: true, 101 | Regular: true, 102 | Database: Database{ 103 | Host: "127.0.0.1", 104 | Port: "3306", 105 | User: "root", 106 | Pwd: "111111", 107 | Name: "fate", 108 | MaxIdleCon: 0, 109 | MaxOpenCon: 0, 110 | Driver: "mysql", 111 | File: "", 112 | Dsn: "", 113 | ShowSQL: false, 114 | ShowExecTime: false, 115 | }, 116 | FileOutput: FileOutput{ 117 | Heads: DefaultHeads, 118 | OutputMode: OutputModeLog, 119 | Path: "name.txt", 120 | }, 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /cmd/strokefix/rule.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/godcong/fate" 5 | "strings" 6 | ) 7 | 8 | var charCharList = []string{ 9 | `阧障陇陾階阾降隄隓陞隂陈隯陖隗陠阱陲阼隩阬陳陌隀阠陿隉陉隥陧陁陱阶陂陽陼陪陗陊阪阞陑隭阬陆隡陫陦陂阳防阽陔隄防隕陨陇陑陚隬陉隣陕隝` + 10 | `阺阫隢陹限附陰阮隚隥阪阭陏陳陜陸阦阷阞隫隞隘陒隴隍陶隀隔陀阤隤陬隨除陲降陮阽阩阴陋队隳隊隊隭陮隋隝隴陘阥隆陡陏陫陙陈隧阸陯隑隍` + 11 | `陡陛阸隔阻隑隯陘陃陊除陖隘隫阨阨隌陔阧陵附陟隞队随隌陙陃`, 12 | `邤酆那鄟郐邝邯酃邸邢郟鄧郤郕邚郫鄀郠郂鄝邩酈邽部郚鄽鄹鄚邲鄳郕郥邶邪鄡邡郿邠鄱邞邩邗鄯鄤邯郎鄐郸鄁邓酇郲鄽郩鄴郔郭郜鄻邦鄺郘鄋郦郡` + 13 | `鄷鄇都鄲鄂鄥郣郐郻鄧鄕邒郭郳鄣郷鄆邞鄶邿鄮鄗鄏郗鄒邬郪邷郲郈鄼鄄郙邰鄛邦郱郓邜鄈鄁鄵邮郮邨郠鄌郸阿邾郈鄝郛郄郂鄸邨郴鄲邴邵邥部` + 14 | `邴郧郞郟邘邟鄍郹郖郍鄿邺郰鄘鄶郙邭邛郏郡鄙鄺郑邸鄗鄉邠郀郬邼邖邼鄄郹鄤酁邽鄈鄩邔郦鄰鄇邳郴郝郀邲郃郞鄜邙邭郯邝郜鄑郝邟郣鄐邱鄛` + 15 | `邹郢邻鄷郆郅酂酄鄊郊邓郏郇郊邗郖鄭鄫鄖郉酆酄郵郁郋邧都邶邡`, 16 | } 17 | 18 | func CharChar(ch *fate.Character) bool { 19 | if i := strings.Index(charCharList[0], ch.Ch); i != -1 { 20 | if ch.Stroke != 0 { 21 | ch.ScienceStroke = ch.Stroke + 8 22 | return true 23 | } 24 | if ch.SimpleTotalStroke != 0 { 25 | ch.ScienceStroke = ch.SimpleTotalStroke + 8 26 | return true 27 | } 28 | } 29 | 30 | if i := strings.Index(charCharList[0], ch.Ch); i != -1 { 31 | if ch.Stroke != 0 { 32 | ch.ScienceStroke = ch.Stroke + 7 33 | return true 34 | } 35 | if ch.SimpleTotalStroke != 0 { 36 | ch.ScienceStroke = ch.SimpleTotalStroke + 7 37 | return true 38 | } 39 | } 40 | 41 | return false 42 | } 43 | 44 | var numberCharList = `一二三四五六七八九十` 45 | 46 | func NumberChar(ch *fate.Character) bool { 47 | if i := strings.Index(numberCharList, ch.Ch); i != -1 { 48 | if ch.Stroke != 0 { 49 | ch.ScienceStroke = ch.Stroke + i 50 | return true 51 | } 52 | if ch.SimpleTotalStroke != 0 { 53 | ch.ScienceStroke = ch.SimpleTotalStroke + i 54 | return true 55 | } 56 | } 57 | return false 58 | } 59 | 60 | var radicalCharList = map[string]int{ 61 | "扌": 1, 62 | "忄": 1, 63 | "氵": 1, 64 | "犭": 1, 65 | "礻": 1, 66 | "王": 1, 67 | "艹": 3, 68 | "衤": 1, 69 | "月": 3, 70 | "辶": 4, 71 | } 72 | 73 | func RadicalChar(ch *fate.Character) bool { 74 | for k, v := range radicalCharList { 75 | if strings.Compare(ch.Radical, k) == 0 { 76 | ch.ScienceStroke = ch.Stroke + v 77 | return true 78 | } 79 | if strings.Compare(ch.SimpleRadical, k) == 0 { 80 | ch.ScienceStroke = ch.SimpleTotalStroke + v 81 | return true 82 | } 83 | } 84 | return false 85 | } 86 | 87 | var fixTable = []func(character *fate.Character) bool{ 88 | RadicalChar, 89 | NumberChar, 90 | CharChar, 91 | DefaultChar, 92 | } 93 | 94 | func fixChar(character *fate.Character) bool { 95 | for _, f := range fixTable { 96 | if f(character) { 97 | return true 98 | } 99 | } 100 | return false 101 | } 102 | 103 | func DefaultChar(character *fate.Character) bool { 104 | if character.KangXiStroke != 0 { 105 | character.ScienceStroke = character.KangXiStroke 106 | } else if character.TraditionalTotalStroke != 0 { 107 | character.ScienceStroke = character.TraditionalTotalStroke 108 | } else if character.Stroke != 0 { 109 | character.ScienceStroke = character.Stroke 110 | } else if character.SimpleTotalStroke != 0 { 111 | character.ScienceStroke = character.SimpleTotalStroke 112 | } else { 113 | return false 114 | } 115 | return true 116 | } 117 | -------------------------------------------------------------------------------- /zodiac.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/godcong/chronos" 5 | "strings" 6 | ) 7 | 8 | // ZodiacPig ... 9 | const ( 10 | ZodiacPig = "猪" 11 | ZodiacMice = "鼠" 12 | ) 13 | 14 | //Zodiac 生肖 15 | type Zodiac struct { 16 | Name string 17 | Xi string //喜 18 | XiRadical string 19 | Ji string //忌 20 | JiRadical string 21 | } 22 | 23 | var zodiacList = map[string]Zodiac{ 24 | ZodiacPig: { 25 | Name: ZodiacPig, 26 | Xi: "", 27 | XiRadical: "", 28 | Ji: `一乙几刀力匕三上凡也土大川己已巳干弓之仁什今天太巴引戈支斤日比片牙王爿主乏代刊加功包卉占古召叱央它市布平弘弗旦玉申皮矛矢石示氾光列刑危夷妃州帆式戎早旨旭朵此虫血衣圮托汎伸佔但伯伶别判君呀坎壮希庇廷弟彤形杉系邑礽玖些依例刻券刷到制协卓卷呻坤奇奈宗宛延弦或戕旺易昌昆昂明昀昏昕昊昇枝欣版状直知社祀祁纠初采长忻玕佌旻炘炅罕泓泡泛玫表亮侯係前剋则勇垣奐宣巷帝帅建弭彦春昭映昧是星昱架柏矜祉祈祇禹穿竿紂红纪纫紇约紆羿虹衫风玡玠柰祅紈迅巡芝芽指珊玲珍珀玳倡候修刚奚孙家差席师庭时晋晏晃晁书核栩矩砷祕祐祠祟祖神祝祚纺纱纹素索纯纽级紜纳纸纷翁蚩袁袂衽讯託起躬珅倧扆祜紘紓衿衾邪邦那迎返近范茅苓班琉珮珠乾健凰副务勘曼唱唬婉婚将崇常张强彬彩彫旋晚晤晨曹勗桿烯祥票祭絃统扎绍紼细绅组终羚翌翎聆彪蛉被袒袖袍袋责玼珩埏紵紾袗邵述迦迪能情掛採捺涎浅琅球理现剴创劳喉场堤堠媛嵐巽帧弼彭斯普晰晴晶景智曾棕牌番短结绒绝紫絮丝络给绚絳翕蛟裁裂视诊费贵须邰琁珺牋矞絪絜軫陀郎郁送迷迺莫庄莉提扬琪琳琥琴琦琨勤势园戡暗暉暖暄会杨枫照煜牒祺禄禁经绢绥群蜀蛾蜕蜂裟裙补裘装裕试钾雉零琬琰琝媴絻郡通连速造透逢途準猿瑚瑟瑞瑙瑛瑜署僎划寥廖彰截畅碧禎福祸粽绽綰综绰綾绿紧缀网纲綺绸绵綵纶维绪緇綬臧蜜蜻裳裴裹裸製褚豪宾赶闽溒瑄瑋榬綪緁緆緋綖綦蜒裱魠郭都週逸进慢漫瑶琐玛瑰剧刘剑增审影暮槽桨毅奖莹稼缔练纬緻缄缅编缘缎缓緲緹翩蝴蝶褐复褓褊诞赏质辉驻鲁齿摎漻褌褋褙陈乡运游道达违遁撰潜澎璋璃瑾璀剂勋战历晓曇炽御縑縈县縝縉萤融褪裤褫讽醒骇璇璉縕螈錼阳邹远逊遣遥递蒋璟璞励弥戏戴曙墙矫禧禪绩繆缕总纵縴縵翼襄褸辕鍚鄔蟉襁适迁环璦璨断曜璧织缮绕繚绣繒蝉顏题蕥鎱际郑邓选迟薑璿嚥曝牘璽疆祷繫绎绳绘缴襠襟识赞譔还迈邀藏琼劝曦繽继耀腾龄繾饌邈瓏樱缠续边瓔弯禳衬鷚晒缨纤襴鷸蛮纘逻湾缆驪別壯協狀糾長則帥彥紅紀紉約風剛孫師時晉書紡紗紋純紐級納紙紛訊務將張強統紮紹細紳組終責淺現創勞場幀結絨絕絲絡給絢視診費貴須莊揚勢園會楊楓祿經絹綏蛻補裝試鉀連劃暢禍綻綜綽綠緊綴網綱綢綿綸維緒賓趕閩進瑤瑣瑪劇劉劍審槳獎瑩締練緯緘緬編緣緞緩複誕賞質輝駐魯齒陳鄉運遊達違潛劑勳戰曆曉熾禦縣螢褲諷駭陽鄒遠遜遙遞蔣勵彌戲牆矯績縷總縱轅適遷環斷織繕繞繡蟬題際鄭鄧選遲禱繹繩繪繳識贊還邁瓊勸繼騰齡櫻纏續邊彎襯曬纓纖蠻邏灣纜`, 29 | JiRadical: "", 30 | }, 31 | ZodiacMice: { 32 | Name: ZodiacMice, 33 | Xi: "", 34 | XiRadical: "", 35 | Ji: `丁二人士仁仃仇仍今介化午夭孔巴日火以付仕代仙仟卯央平旦未汀伙伊伍休仲件任仰仳份企光全印合地在圭妃寺早旨旬旭朴次竹羊臣行仵价伂位住伫伴佛何估佐佑伺伸似但作伯低伶余佈免坊址坍均坎壮孝宋巫志攸杜赤辛佟抑亚佯依侍佳使供例来佰佩仑佾侑兔味命坪坡坦妹岱幸旺易昌昆昂明昀昏昊昇东杵炎祀卧佼佶侄坵旻炅耵肖拒沫亭亮信侯侠保促俟俊俗俐係俞勉南哇型垠垣垢城姜姿宣封庠律徉春昭映昧是星昱柯柏柳炫为炳炬炯红美订酊香俋昶炷肯洋倍俸倩倖俩值倚倨俱倡候修倪俾伦冤冻卿埂埔埃姬娩宰差徐恙时晋晏晃晁书桓柴氧烊烈留羔耿袁袂酒钉马珋倢埕埒晟邦那迎胡苎苣茉英茆挽珠停假偃偌做伟健偶侦倏冕曼唱域坚堆埠基堵执婚张得从悠教晚晤曹勗欲焉烯瓷祥羚聊袋许顶偈偅偩偮娅欷欸羕邱迪悻傢傅备杰喜尧堪场堤堰报堡复普晰晴晶景智曾棚款焰然善翔贷距辜集冯傌媄焯羢郎郁脩莘莫荷提扬佣傲传仅僇吗塑塘涂塚塔填塌块坞妈微意暗晖暖暄会楠杨歇照煜焕义羡群详路钾铆驰驯渼羟郝连造逢菟署僧像侨境垫墅寿彻榴歌熙熊监绽台赫輓驳墉杩都逸进慢漾漫亿仪僵价侬俭刘墟增坠墩嬉德徵暮样槽楼欧羯蝴卖辉锌养驻驷驶驾驹鲁儆僾儌墡禡羬陈运道达潜骂儒傧壁垦坛壅曆晓昙炽燕熹笃糕羲谘醒骆嶪烨羱阳邹远优偿储壕壑壎曙营灿镁鍚骋骏鲜鲑邬蓨澲燨膳丛垒曜柠欤缮缯题骑镏骐郑邓选薑嚥垄坜曝羶羹辞鹏鄯薘繨邺迈壤曦耀议骞腾骝牺驱蓦欢鑑鞑骄骅惊驿验坝骤驞骥骊`, 36 | JiRadical: "", 37 | }, 38 | } 39 | 40 | // GetZodiac ... 41 | func GetZodiac(c chronos.Calendar) *Zodiac { 42 | z := chronos.GetZodiac(c.Lunar()) 43 | if v, b := zodiacList[z]; b { 44 | return &v 45 | } 46 | return nil 47 | } 48 | 49 | func (z *Zodiac) zodiacJi(character *Character) int { 50 | if strings.IndexRune(z.Ji, []rune(character.Ch)[0]) != -1 { 51 | return -3 52 | } 53 | return 0 54 | } 55 | 56 | func filterZodiac(c chronos.Calendar, chars ...*Character) bool { 57 | return GetZodiac(c).PointCheck(3, chars...) 58 | } 59 | 60 | //PointCheck 检查point 61 | func (z *Zodiac) PointCheck(limit int, chars ...*Character) bool { 62 | for _, c := range chars { 63 | if z.Point(c) < limit { 64 | return false 65 | } 66 | } 67 | return true 68 | } 69 | 70 | //Point 喜忌对冲,理论上喜忌都有的话,最好不要选给1,忌给0,喜给5,都没有给3 71 | func (z *Zodiac) Point(character *Character) int { 72 | dp := 3 73 | dp += z.zodiacJi(character) 74 | dp += z.zodiacXi(character) 75 | return dp 76 | } 77 | 78 | func (z *Zodiac) zodiacXi(character *Character) int { 79 | if strings.IndexRune(z.Xi, []rune(character.Ch)[0]) != -1 { 80 | return 2 81 | } 82 | return 0 83 | } 84 | -------------------------------------------------------------------------------- /database.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "fmt" 5 | "github.com/go-sql-driver/mysql" 6 | "github.com/godcong/fate/config" 7 | "github.com/goextension/log" 8 | 9 | "github.com/xormsharp/xorm" 10 | "net/url" 11 | ) 12 | 13 | const mysqlSource = "%s:%s@tcp(%s)/%s?loc=%s&charset=utf8mb4&parseTime=true" 14 | const createDatabase = "CREATE DATABASE `%s` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin'" 15 | 16 | var _ = mysql.Config{} 17 | 18 | // DefaultTableName ... 19 | var DefaultTableName = "fate" 20 | 21 | // Database ... 22 | type Database interface { 23 | Sync(v ...interface{}) error 24 | CountWuGeLucky() (n int64, e error) 25 | InsertOrUpdateWuGeLucky(lucky *WuGeLucky) (n int64, e error) 26 | GetCharacter(fn func(engine *xorm.Engine) *xorm.Session) (*Character, error) 27 | GetCharacters(fn func(engine *xorm.Engine) *xorm.Session) ([]*Character, error) 28 | FilterWuGe(last []*Character, wg chan<- *WuGeLucky) error 29 | Database() interface{} 30 | } 31 | 32 | type xormDatabase struct { 33 | *xorm.Engine 34 | } 35 | 36 | // Database ... 37 | func (db *xormDatabase) Database() interface{} { 38 | return db.Engine 39 | } 40 | 41 | // FilterWuGe ... 42 | func (db *xormDatabase) FilterWuGe(last []*Character, wg chan<- *WuGeLucky) error { 43 | return filterWuGe(db.Engine, last, wg) 44 | } 45 | 46 | // GetCharacters ... 47 | func (db *xormDatabase) GetCharacters(fn func(engine *xorm.Engine) *xorm.Session) ([]*Character, error) { 48 | return getCharacters(db.Engine, fn) 49 | } 50 | 51 | // Sync ... 52 | func (db *xormDatabase) Sync(v ...interface{}) error { 53 | return db.Engine.Sync2(v...) 54 | } 55 | 56 | // GetCharacter ... 57 | func (db *xormDatabase) GetCharacter(fn func(engine *xorm.Engine) *xorm.Session) (*Character, error) { 58 | return getCharacter(db.Engine, fn) 59 | } 60 | 61 | // InsertOrUpdateWuGeLucky ... 62 | func (db *xormDatabase) InsertOrUpdateWuGeLucky(lucky *WuGeLucky) (n int64, e error) { 63 | return insertOrUpdateWuGeLucky(db.Engine, lucky) 64 | } 65 | 66 | // CountWuGeLucky ... 67 | func (db *xormDatabase) CountWuGeLucky() (n int64, e error) { 68 | return countWuGeLucky(db.Engine) 69 | } 70 | 71 | // InitDatabaseWithConfig ... 72 | func InitDatabaseWithConfig(cfg config.Config) Database { 73 | return initDatabaseWithConfig(cfg.Database) 74 | } 75 | 76 | func initDatabaseWithConfig(db config.Database) Database { 77 | engine := initSQL(db) 78 | return &xormDatabase{ 79 | Engine: engine, 80 | } 81 | } 82 | 83 | func initSQL(database config.Database) *xorm.Engine { 84 | dbURL := fmt.Sprintf(mysqlSource, database.User, database.Pwd, database.Addr(), "", url.QueryEscape("Asia/Shanghai")) 85 | dbEngine, e := xorm.NewEngine(database.Driver, dbURL) 86 | if e != nil { 87 | log.Panicw("connect database failed", "error", e) 88 | } 89 | defer dbEngine.Close() 90 | 91 | sql := fmt.Sprintf(createDatabase, database.Name) 92 | 93 | _, e = dbEngine.DB().Exec(sql) 94 | if e == nil { 95 | log.Infow("create database failed", "database", DefaultTableName) 96 | } 97 | u := fmt.Sprintf(mysqlSource, database.User, database.Pwd, database.Addr(), database.Name, url.QueryEscape("Asia/Shanghai")) 98 | eng, e := xorm.NewEngine(database.Driver, u) 99 | if e != nil { 100 | log.Panicw("connect table failed", "error", e) 101 | } 102 | if database.ShowSQL { 103 | eng.ShowSQL(true) 104 | } 105 | 106 | if database.ShowExecTime { 107 | eng.ShowExecTime(true) 108 | } 109 | return eng 110 | } 111 | -------------------------------------------------------------------------------- /cmd/strokefix/check.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/godcong/fate" 8 | "github.com/goextension/log" 9 | "github.com/xormsharp/xorm" 10 | "io/ioutil" 11 | "strconv" 12 | ) 13 | 14 | type Dict struct { 15 | Jin map[string][]string `json:"jin"` 16 | Mu map[string][]string `json:"mu"` 17 | Huo map[string][]string `json:"huo"` 18 | Shui map[string][]string `json:"shui"` 19 | Tu map[string][]string `json:"tu"` 20 | } 21 | 22 | var dict Dict 23 | 24 | type WuXingFunc func(s string) bool 25 | 26 | func CheckLoader(s string) error { 27 | bytes, e := ioutil.ReadFile(s) 28 | if e != nil { 29 | return e 30 | } 31 | e = json.Unmarshal(bytes, &dict) 32 | if e != nil { 33 | return e 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func CheckVerify(db fate.Database) error { 40 | if err := verifySub(db, dict.Jin, "金"); err != nil { 41 | return err 42 | } 43 | if err := verifySub(db, dict.Mu, "木"); err != nil { 44 | return err 45 | } 46 | if err := verifySub(db, dict.Shui, "水"); err != nil { 47 | return err 48 | } 49 | if err := verifySub(db, dict.Huo, "火"); err != nil { 50 | return err 51 | } 52 | if err := verifySub(db, dict.Tu, "土"); err != nil { 53 | return err 54 | } 55 | 56 | return nil 57 | } 58 | 59 | func verifySub(db fate.Database, m map[string][]string, wx string) error { 60 | count := 0 61 | eng := db.Database().(*xorm.Engine) 62 | for k, v := range m { 63 | for _, vv := range v { 64 | count++ 65 | character, e := db.GetCharacter(func(eng *xorm.Engine) *xorm.Session { 66 | return eng.Where("ch = ?", vv) 67 | }) 68 | i, _ := strconv.Atoi(k) 69 | if e != nil { 70 | log.Errorw("get character error", "character", vv) 71 | ch := fate.Character{ 72 | Hash: hash(vv), 73 | PinYin: []string{"custom"}, 74 | Ch: vv, 75 | ScienceStroke: i, 76 | Radical: "", 77 | RadicalStroke: 0, 78 | Stroke: 0, 79 | IsKangXi: false, 80 | KangXi: "", 81 | KangXiStroke: 0, 82 | SimpleRadical: "", 83 | SimpleRadicalStroke: 0, 84 | SimpleTotalStroke: 0, 85 | TraditionalRadical: "", 86 | TraditionalRadicalStroke: 0, 87 | TraditionalTotalStroke: 0, 88 | NameScience: true, 89 | WuXing: wx, 90 | Lucky: "", 91 | Regular: false, 92 | TraditionalCharacter: nil, 93 | VariantCharacter: nil, 94 | Comment: []string{"custom"}, 95 | } 96 | _, e := eng.InsertOne(ch) 97 | if e != nil { 98 | log.Error("inser error", "character", ch.Ch) 99 | } 100 | continue 101 | } 102 | if character.WuXing != wx { 103 | if character.WuXing == "" { 104 | //fix wuxing 105 | character.WuXing = wx 106 | } else { 107 | log.Warnw("wrong wuxing", "character", vv, "charwuxing", character.WuXing, "dictwuxing", wx) 108 | } 109 | } 110 | if character.ScienceStroke != i { 111 | log.Warnw("check warning", "character", vv, "db", character.ScienceStroke, "need", k) 112 | //fix stroke 113 | character.ScienceStroke = i 114 | } 115 | update, e := eng.Where("hash = ?", character.Hash).Update(character) 116 | if e != nil { 117 | return e 118 | } 119 | if update != 1 { 120 | //log.Errorw("not updated", "update", update) 121 | } 122 | } 123 | } 124 | log.Infow("total", "count", count) 125 | return nil 126 | } 127 | 128 | func hash(char string) string { 129 | s := md5.Sum([]byte(char)) 130 | return fmt.Sprintf("%x", s) 131 | } 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 命运:现代科学取名工具 # 2 | FATE: A modern science chinese name create tool 3 | ## Github第一个开源的中文取名项目 ## 4 | The first chinese name create tool in github 5 | 6 | ## [起名算法搜索排第一位](https://www.google.com/search?q=%E8%B5%B7%E5%90%8D%E7%AE%97%E6%B3%95&oq=%E8%B5%B7%E5%90%8D%E7%AE%97%E6%B3%95&aqs=chrome..69i57.3721j0j8&sourceid=chrome&ie=UTF-8) ## 7 | 8 | # 最新Release版下载: [v3.1.1](https://github.com/godcong/fate/releases/tag/v3.1.1) # 9 | 10 | ## 简介 ## 11 | 一个好名字伴随人的一生,FATE让你取一个好名字: 12 | 本程序适用于单个姓或双个姓,起2个名的情况。(如:独孤**,李张**,张**,王**) 13 | 14 | ## 参考算法 ## 15 | 周易卦象 16 | 大衍之数 17 | 三才五格 18 | 喜用神(平衡用神) 19 | 生肖用字 20 | 八字吉凶 21 | 22 | ## 接口调用生成姓名 ## 23 | ``` 24 | 使用前请导入database的数据(测试字库已基本完善,保险起见生成姓名后可以去一些测名网站验证下) 25 | //加载配置(具体参数参考example/create_a_name) 26 | cfg := config.Default() 27 | //生日: 28 | born := chronos.New("2020/01/23 11:31") 29 | //姓氏: 30 | lastName := "张" 31 | //第一参数:姓氏 32 | //第二参数:生日 33 | f := fate.NewFate(lastName, born.Solar().Time(), fate.ConfigOption(cfg)) 34 | 35 | e := f.MakeName(context.Background()) 36 | if e != nil { 37 | t.Fatal(e) 38 | } 39 | ``` 40 | 41 | ## 可执行文件生成姓名 ## 42 | ``` 43 | //生成配置文件(可修改数据库,及一些基本参数): 44 | fate.exe init 45 | //输出姓名: 46 | fate.exe name -l 张 -b "2020/02/06 15:04" 47 | ``` 48 | 49 | ## 版本履历: 50 | ``` 51 | 第一版: 52 | 大部分是手动工作,现已废弃 53 | 54 | 第二版: 55 | 可自动生成名字字符 + 手工筛选 56 | 57 | 第三版(开发中): 58 | 每次生成一个名字,并目标喜用神,生肖喜忌,月历转换,生成八字等功能 59 | 八字计算: https://github.com/godcong/chronos 60 | 字典数据: https://github.com/godcong/excavator 61 | 数据库重新切回mysql,mongo虽然插入简单,检索语法太繁琐了... 62 | 63 | 起名算法: 64 | 算法(进度) 备注 65 | 五格(95%) 暂用字库已补全 66 | 三才(95%) 暂用字库已补全 67 | 八字(100%) 喜用神完成, 补八字完成 68 | 卦象(100%) 算法完成,起卦完成,吉凶过滤完成。 69 | 生肖(30%) 生肖获取完成,字库筛选待完成 70 | 天运(TODO) 71 | 72 | 第四版(计划): 73 | 通过AI,大数据匹配算法,取出更好更佳的名字. 74 | ``` 75 | 76 | 77 | 78 | 79 | ### 其他(补充资料) ### 80 | 81 | 立春: 82 | 2019年02月04日 11:14:14 83 | 2020年02月04日 17:03:12 84 | 2021年02月03日 22:58:39 85 | 2022年02月04日 04:50:36 86 | 2023年02月04日 10:42:21 87 | 2024年02月04日 16:26:53 88 | 2025年02月03日 22:10:13 89 | 生肖按八字算从立春开始算起,不到时间则为上一年。 90 | 91 | 1、配合八字命理的喜忌,是起名字的核心所在。 92 | 八字是每个人出生的年、月、日、时,小孩取名的第一步即是分析八字,了解命理五行所缺并找出喜用神,并且据此起名,这是最关键的核心,所有姓名的吉凶预测与取名,都以此为准。 93 | 2、名字用字字义务必吉祥 94 | 中国文字的魅力在于,每个方块字不仅都有其本身的含义,而且还有其特殊的周易诱导含义,名字在很多时候它还会影响到人性格的形成,正所谓“名如其人”。 95 | 所以一个好的名字,务必用字字义吉祥。 96 | 宝宝起名字确实需要考虑很多因素,不仅要考虑读音、字形以及各种禁忌更重要的是要考虑宝宝的生辰八字,因此给孩子起名还是找专家比较好。 97 | 现在这方面比较知名的应该是温雅居士了,温雅居士在宝宝起名方面有着十几年的经验独创易学起名法:排八字、看五行、测五格、配三才、合属相、想寓意、听音律、写字形,在业界目前应该是比较权威的了。 98 | 取名是需要非常系统考虑的,不能只考虑读音一个方面,温雅居士采用的排八字、看五行、测五格、配三才、想寓意、听音律、写字形的综合起名法非常喜欢。 99 | 3、五格数理,特别是主格的数理要为吉数。 100 | 在姓名学中,数理产生许多福祸吉凶的灵动力,对人生影响很大。 101 | 这跟单个姓名用字的笔划好坏无关,准确的福祸吉凶是按照特殊方式计算数理的。 102 | 4、三才配置一定不可以相克。 103 | 三才配置在姓名学中,占有很大的分量。三才配置指的是天格、人格、地格之间的关系。中国传统文化中有顺应天时、地利、人和的行事哲理; 104 | 测名过程中,有很多姓名数理不错,但是三才配置不佳,大多表现为运气反复,遇事受阻碍,且感情及财运不好。 105 | 三才配置相生相克的关系定吉凶,同样也影响着一个人事业成功率的高低。 106 | 5、五格配置在姓名学中占有主要位置。 107 | 五格配置是指天格、地格、人格、外格、总格共五格之间的关系。 108 | 天格是由祖先流传而来,单独出现对人生没有多大影响;人格是姓名剖象数理的中心所在,对人生的影响最大; 109 | 人格与地格结合的数理则为基础运。地格主要是36岁前的人生,也叫前运力,外格代表人的外围,吉凶无谓。总格是36岁以后的人生,也是后运力。 110 | 6、小孩取名字时还要结合命主的出生方位、父母资料等因素,以达到事半功倍的效果。 111 | 其实任何事情道理都是一样的,只有适合自己的才是最好的。 112 | 113 | 周易卦象编码参考: 114 | 115 | 六十四卦 116 | # ䷀ ䷁ ䷂ ䷃ ䷄ ䷅ ䷆ ䷇ ䷈ ䷉ ䷊ ䷋ ䷌ ䷍ ䷎ ䷏ 117 | # ䷐ ䷑ ䷒ ䷓ ䷔ ䷕ ䷖ ䷗ ䷘ ䷙ ䷚ ䷛ ䷜ ䷝ ䷞ ䷟ 118 | # ䷠ ䷡ ䷢ ䷣ ䷤ ䷥ ䷦ ䷧ ䷨ ䷩ ䷪ ䷫ ䷬ ䷭ ䷮ ䷯ 119 | # ䷰ ䷱ ䷲ ䷳ ䷴ ䷵ ䷶ ䷷ ䷸ ䷹ ䷺ ䷻ ䷼ ䷽ ䷾ ䷿ 120 | 121 | 八卦 122 | # ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ 123 | 124 | 四象 125 | # ⚌ ⚍ ⚎ ⚏ 126 | 127 | 两仪 128 | # ⚋⚊ 129 | 130 | 为什么要集六大派与一体? 131 | 看下下面这个统计,每一派的取名法其实都有其不足之处. 132 | • 笔划派: 认为笔划全吉,人生就大吉。其实准确度仅12.5 % 133 | • 三才派: 完全不管笔划吉凶,只认为天地人三才五行相生,人生就大吉。其实准确度仅56.6 %。 134 | • 补八字: 完全不管笔划吉凶,只认为名字补到先天八字命盘欠缺,人生就大吉。其实准确度非常低。 135 | • 卦象派: 完全不管笔划吉凶,只认为名字求出卦象漂亮,人生就大吉。其实准确度仅40.26 %。 136 | • 天运派: 完全不管笔划吉凶,只认为名字不要被出生年天运五行所剋,人生就大吉。其实准确度仅25.32 %。 137 | • 生肖派: 完全不管笔划吉凶,只认为生肖用对字形,人生就大吉。其实准确度仅27.55 %。 138 | 139 | PS:最近看到有人别出心裁说三才不准,并举了一些名人的例子. 140 | 然后他倒过来算,发现很符合,很正确. 141 | 那我也就呵呵了,按准确度来算,非正即反. 142 | 你倒过来算,不准的变准了.那原来准的那些不就不准了. 143 | 在我看来事分阴阳,而这接近一半的准确度则恰到其好处. 144 | 145 | 所以,遵照传统为自己的宝宝起一个中正平和的名字才是最好的. 146 | 从概率论的角度来讲,相交得到的最终结果.其准确度最高. 147 | 所以,单纯得拿一种或两种方法来取名是不可取的. 148 | 尽量符合多种的名字才是最佳,但并不一定需要全中. 149 | Fate的本意是让起名变得简单,且能取到一个好的名字. 150 | 有人会花个十几,几十万取一个名字(周围的真人真事), 151 | 但是这个名字好不好你却未必知道. 152 | 算法开源就是为了让每个人知道, 153 | 这个名字取名过程的来龙去脉. 154 | 155 | -------------------------------------------------------------------------------- /character.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "crypto/sha256" 5 | "fmt" 6 | "github.com/xormsharp/builder" 7 | "github.com/xormsharp/xorm" 8 | ) 9 | 10 | //Character 字符 11 | type Character struct { 12 | Hash string `xorm:"pk hash"` 13 | PinYin []string `xorm:"default() notnull pin_yin"` //拼音 14 | Ch string `xorm:"default() notnull ch"` //字符 15 | ScienceStroke int `xorm:"default(0) notnull science_stroke" json:"science_stroke"` //科学笔画 16 | Radical string `xorm:"default() notnull radical"` //部首 17 | RadicalStroke int `xorm:"default(0) notnull radical_stroke"` //部首笔画 18 | Stroke int `xorm:"default() notnull stroke"` //总笔画数 19 | IsKangXi bool `xorm:"default(0) notnull is_kang_xi"` //是否康熙字典 20 | KangXi string `xorm:"default() notnull kang_xi"` //康熙 21 | KangXiStroke int `xorm:"default(0) notnull kang_xi_stroke"` //康熙笔画 22 | SimpleRadical string `xorm:"default() notnull simple_radical"` //简体部首 23 | SimpleRadicalStroke int `xorm:"default(0) notnull simple_radical_stroke"` //简体部首笔画 24 | SimpleTotalStroke int `xorm:"default(0) notnull simple_total_stroke"` //简体笔画 25 | TraditionalRadical string `xorm:"default() notnull traditional_radical"` //繁体部首 26 | TraditionalRadicalStroke int `xorm:"default(0) notnull traditional_radical_stroke"` //繁体部首笔画 27 | TraditionalTotalStroke int `xorm:"default(0) notnull traditional_total_stroke"` //简体部首笔画 28 | NameScience bool `xorm:"default(0) notnull name_science"` //姓名学 29 | WuXing string `xorm:"default() notnull wu_xing"` //五行 30 | Lucky string `xorm:"default() notnull lucky"` //吉凶寓意 31 | Regular bool `xorm:"default(0) notnull regular"` //常用 32 | TraditionalCharacter []string `xorm:"default() notnull traditional_character"` //繁体字 33 | VariantCharacter []string `xorm:"default() notnull variant_character"` //异体字 34 | Comment []string `xorm:"default() notnull comment"` //解释 35 | } 36 | 37 | // InsertOrUpdateCharacter ... 38 | func InsertOrUpdateCharacter(engine *xorm.Engine, c *Character) (i int64, e error) { 39 | tmp := new(Character) 40 | b, e := engine.Where("hash = ?", Hash(c.Ch)).Get(tmp) 41 | if e != nil { 42 | return 0, e 43 | } 44 | if !b { 45 | i, e = engine.InsertOne(c) 46 | return 47 | } 48 | i, e = engine.Where("ch = ?", c.Ch).Update(c) 49 | return 50 | } 51 | 52 | func getCharacters(engine *xorm.Engine, fn func(engine *xorm.Engine) *xorm.Session) ([]*Character, error) { 53 | s := fn(engine) 54 | var c []*Character 55 | e := s.Find(&c) 56 | if e == nil { 57 | return c, nil 58 | } 59 | return nil, fmt.Errorf("character list get error:%w", e) 60 | } 61 | 62 | func getCharacter(eng *xorm.Engine, fn func(engine *xorm.Engine) *xorm.Session) (*Character, error) { 63 | s := fn(eng) 64 | var c Character 65 | b, e := s.Get(&c) 66 | if e == nil && b { 67 | return &c, nil 68 | } 69 | return nil, fmt.Errorf("character get error:%w", e) 70 | } 71 | 72 | // CharacterOptions ... 73 | type CharacterOptions func(session *xorm.Session) *xorm.Session 74 | 75 | // Regular ... 76 | func Regular() CharacterOptions { 77 | return func(session *xorm.Session) *xorm.Session { 78 | return session.And("regular = ?", 1) 79 | } 80 | } 81 | 82 | // Stoker ... 83 | func Stoker(s int, options ...CharacterOptions) func(engine *xorm.Engine) *xorm.Session { 84 | return func(engine *xorm.Engine) *xorm.Session { 85 | session := engine.Where("pin_yin IS NOT NULL"). 86 | And(builder.Eq{"science_stroke": s}) 87 | //Or(builder.Eq{"stroke": s}). 88 | //Or(builder.Eq{"kang_xi_stroke": s}). 89 | //Or(builder.Eq{"simple_total_stroke": s}). 90 | //Or(builder.Eq{"traditional_total_stroke": s})) 91 | for _, option := range options { 92 | session = option(session) 93 | } 94 | return session 95 | } 96 | 97 | } 98 | 99 | // Char ... 100 | func Char(name string) func(engine *xorm.Engine) *xorm.Session { 101 | return func(engine *xorm.Engine) *xorm.Session { 102 | return engine.Where(builder.Eq{"ch": name}. 103 | Or(builder.Eq{"kang_xi": name}). 104 | Or(builder.Eq{"traditional_character": name})) 105 | } 106 | } 107 | 108 | // Hash ... 109 | func Hash(url string) string { 110 | sum256 := sha256.Sum256([]byte(url)) 111 | return fmt.Sprintf("%x", sum256) 112 | } 113 | -------------------------------------------------------------------------------- /information.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "bufio" 5 | "encoding/csv" 6 | "encoding/json" 7 | "fmt" 8 | "github.com/godcong/fate/config" 9 | "go.uber.org/zap" 10 | "go.uber.org/zap/zapcore" 11 | "os" 12 | ) 13 | 14 | // Information ... 15 | type Information interface { 16 | Group(b bool) 17 | Write(names ...Name) error 18 | Head(heads ...string) error 19 | Finish() error 20 | } 21 | 22 | type jsonInformation struct { 23 | head []string 24 | path string 25 | file *os.File 26 | } 27 | 28 | func (j *jsonInformation) Group(b bool) { 29 | panic("implement me") 30 | } 31 | 32 | type logInformation struct { 33 | path string 34 | sugar *zap.SugaredLogger 35 | head []string 36 | } 37 | 38 | func (l *logInformation) Group(b bool) { 39 | panic("implement me") 40 | } 41 | 42 | type csvInformation struct { 43 | head []string 44 | path string 45 | file *os.File 46 | } 47 | 48 | func (c *csvInformation) Group(b bool) { 49 | panic("implement me") 50 | } 51 | 52 | // Finish ... 53 | func (l *logInformation) Finish() error { 54 | return l.sugar.Sync() 55 | } 56 | 57 | func initOutputWithConfig(output config.FileOutput) Information { 58 | switch output.OutputMode { 59 | //case config.OutputModelJSON: 60 | // return jsonOutput(output.Path) 61 | case config.OutputModeCSV: 62 | return csvOutput(output.Path) 63 | } 64 | 65 | return logOutput(output.Path) 66 | } 67 | 68 | // Finish ... 69 | func (j *jsonInformation) Finish() error { 70 | return j.file.Close() 71 | } 72 | 73 | // Write ... 74 | func (j *jsonInformation) Write(names ...Name) error { 75 | w := bufio.NewWriter(j.file) 76 | for _, n := range names { 77 | out := headNameJSONOutput(j.head, n, nil) 78 | //output json 79 | _, _ = w.Write(out) 80 | _, _ = w.WriteString(",\n") 81 | } 82 | return w.Flush() 83 | 84 | } 85 | 86 | // Head ... 87 | func (j *jsonInformation) Head(heads ...string) error { 88 | j.head = heads 89 | return nil 90 | } 91 | 92 | func jsonOutput(path string) Information { 93 | file, e := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_SYNC|os.O_RDWR, 0755) 94 | if e != nil { 95 | panic(fmt.Errorf("json output failed:%w", e)) 96 | } 97 | return &jsonInformation{ 98 | path: path, 99 | file: file, 100 | } 101 | } 102 | 103 | // Write ... 104 | func (l *logInformation) Write(names ...Name) error { 105 | for _, n := range names { 106 | out := headNameOutput(l.head, n, func(s string) bool { 107 | return s == "姓名" 108 | }) 109 | l.sugar.Infow(n.String(), out...) 110 | } 111 | return nil 112 | } 113 | 114 | // Head ... 115 | func (l *logInformation) Head(heads ...string) error { 116 | l.head = heads 117 | return nil 118 | } 119 | func logOutput(path string) Information { 120 | cfg := zap.NewProductionConfig() 121 | 122 | cfg.EncoderConfig = zapcore.EncoderConfig{ 123 | MessageKey: "name", 124 | LevelKey: "", 125 | TimeKey: "", 126 | NameKey: "", 127 | CallerKey: "", 128 | StacktraceKey: "", 129 | LineEnding: "", 130 | EncodeLevel: nil, 131 | EncodeTime: nil, 132 | EncodeDuration: nil, 133 | EncodeCaller: nil, 134 | EncodeName: nil, 135 | } 136 | cfg.OutputPaths = []string{ 137 | path, 138 | } 139 | 140 | cfg.DisableCaller = true 141 | cfg.DisableStacktrace = true 142 | 143 | logger, e := cfg.Build( 144 | zap.AddCaller(), 145 | zap.AddCallerSkip(1), 146 | ) 147 | if e != nil { 148 | panic(e) 149 | } 150 | return &logInformation{ 151 | path: path, 152 | sugar: logger.Sugar(), 153 | } 154 | } 155 | 156 | func csvOutput(path string) Information { 157 | file, e := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_SYNC|os.O_RDWR, 0755) 158 | if e != nil { 159 | panic(fmt.Errorf("json output failed:%w", e)) 160 | } 161 | 162 | return &csvInformation{ 163 | path: path, 164 | file: file, 165 | } 166 | } 167 | 168 | // Write ... 169 | func (c *csvInformation) Write(names ...Name) error { 170 | w := csv.NewWriter(c.file) 171 | for _, n := range names { 172 | out := nameOutputString(c.head, n) 173 | _ = w.Write(out) 174 | } 175 | w.Flush() 176 | return nil 177 | } 178 | 179 | // Finish ... 180 | func (c *csvInformation) Finish() error { 181 | return c.file.Close() 182 | } 183 | 184 | // Head ... 185 | func (c *csvInformation) Head(heads ...string) (e error) { 186 | c.head = heads 187 | w := csv.NewWriter(c.file) 188 | e = w.Write(heads) 189 | if e != nil { 190 | return e 191 | } 192 | w.Flush() 193 | return nil 194 | } 195 | 196 | func headNameOutput(heads []string, name Name, skip func(string) bool) (out []interface{}) { 197 | for _, h := range heads { 198 | if skip != nil && skip(h) { 199 | continue 200 | } 201 | switch h { 202 | case "姓名": 203 | out = append(out, h, name.String()) 204 | case "笔画": 205 | out = append(out, h, name.Strokes()) 206 | case "拼音": 207 | out = append(out, h, name.PinYin()) 208 | case "喜用神": 209 | out = append(out, h, name.XiYongShen()) 210 | case "八字", "生辰八字": 211 | out = append(out, h, name.BaZi()) 212 | } 213 | } 214 | return 215 | } 216 | 217 | func headNameJSONOutput(heads []string, name Name, skip func(string) bool) (b []byte) { 218 | out := make(map[string]string) 219 | for _, h := range heads { 220 | if skip != nil && skip(h) { 221 | continue 222 | } 223 | switch h { 224 | case "姓名": 225 | out[h] = name.String() 226 | case "笔画": 227 | out[h] = name.Strokes() 228 | case "拼音": 229 | out[h] = name.PinYin() 230 | case "喜用神": 231 | out[h] = name.XiYongShen() 232 | } 233 | } 234 | by, e := json.Marshal(out) 235 | if e != nil { 236 | return nil 237 | } 238 | return by 239 | } 240 | 241 | func headNameOutputString(heads []string, name Name, skip func(string) bool) (out []string) { 242 | for _, h := range heads { 243 | if skip != nil && skip(h) { 244 | continue 245 | } 246 | switch h { 247 | case "姓名": 248 | out = append(out, h, name.String()) 249 | case "笔画": 250 | out = append(out, h, name.Strokes()) 251 | case "拼音": 252 | out = append(out, h, name.PinYin()) 253 | case "喜用神": 254 | out = append(out, h, name.XiYongShen()) 255 | } 256 | } 257 | return 258 | } 259 | func nameOutputString(heads []string, name Name) (out []string) { 260 | for _, h := range heads { 261 | switch h { 262 | case "姓名": 263 | out = append(out, name.String()) 264 | case "笔画": 265 | out = append(out, name.Strokes()) 266 | case "拼音": 267 | out = append(out, name.PinYin()) 268 | case "喜用神": 269 | out = append(out, name.XiYongShen()) 270 | } 271 | } 272 | return 273 | } 274 | -------------------------------------------------------------------------------- /bazi.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/godcong/chronos" 5 | "strings" 6 | ) 7 | 8 | var diIndex = map[string]int{ 9 | "子": 0, "丑": 1, "寅": 2, "卯": 3, "辰": 4, "巳": 5, "午": 6, "未": 7, "申": 8, "酉": 9, "戌": 10, "亥": 11, 10 | } 11 | 12 | var tianIndex = map[string]int{ 13 | "甲": 0, "乙": 1, "丙": 2, "丁": 3, "戊": 4, "己": 5, "庚": 6, "辛": 7, "壬": 8, "癸": 9, 14 | } 15 | 16 | //天干强度表 17 | var tiangan = [][]int{ 18 | {1200, 1200, 1000, 1000, 1000, 1000, 1000, 1000, 1200, 1200}, 19 | {1060, 1060, 1000, 1000, 1100, 1100, 1140, 1140, 1100, 1100}, 20 | {1140, 1140, 1200, 1200, 1060, 1060, 1000, 1000, 1000, 1000}, 21 | {1200, 1200, 1200, 1200, 1000, 1000, 1000, 1000, 1000, 1000}, 22 | {1100, 1100, 1060, 1060, 1100, 1100, 1100, 1100, 1040, 1040}, 23 | {1000, 1000, 1140, 1140, 1140, 1140, 1060, 1060, 1060, 1060}, 24 | {1000, 1000, 1200, 1200, 1200, 1200, 1000, 1000, 1000, 1000}, 25 | {1040, 1040, 1100, 1100, 1160, 1160, 1100, 1100, 1000, 1000}, 26 | {1060, 1060, 1000, 1000, 1000, 1000, 1140, 1140, 1200, 1200}, 27 | {1000, 1000, 1000, 1000, 1000, 1000, 1200, 1200, 1200, 1200}, 28 | {1000, 1000, 1040, 1040, 1140, 1140, 1160, 1160, 1060, 1060}, 29 | {1200, 1200, 1000, 1000, 1000, 1000, 1000, 1000, 1140, 1140}, 30 | } 31 | 32 | //地支强度表 33 | var dizhi = []map[string][]int{ 34 | { 35 | "癸": {1200, 1100, 1000, 1000, 1040, 1060, 1000, 1000, 1200, 1200, 1060, 1140}, 36 | }, { 37 | "癸": {360, 330, 300, 300, 312, 318, 300, 300, 360, 360, 318, 342}, 38 | "辛": {200, 228, 200, 200, 230, 212, 200, 220, 228, 248, 232, 200}, 39 | "己": {500, 550, 530, 500, 550, 570, 600, 580, 500, 500, 570, 500}, 40 | }, { 41 | "丙": {300, 300, 360, 360, 318, 342, 360, 330, 300, 300, 342, 318}, 42 | "甲": {840, 742, 798, 840, 770, 700, 700, 728, 742, 700, 700, 840}, 43 | }, { 44 | "乙": {1200, 1060, 1140, 1200, 1100, 1000, 1000, 1040, 1060, 1000, 1000, 1200}, 45 | }, { 46 | "乙": {360, 318, 342, 360, 330, 300, 300, 312, 318, 300, 300, 360}, 47 | "癸": {240, 220, 200, 200, 208, 200, 200, 200, 240, 240, 212, 228}, 48 | "戊": {500, 550, 530, 500, 550, 600, 600, 580, 500, 500, 570, 500}, 49 | }, { 50 | "庚": {300, 342, 300, 300, 330, 300, 300, 330, 342, 360, 348, 300}, 51 | "丙": {700, 700, 840, 840, 742, 840, 840, 798, 700, 700, 728, 742}, 52 | }, { 53 | "丁": {1000, 1000, 1200, 1200, 1060, 1140, 1200, 1100, 1000, 1000, 1040, 1060}, 54 | }, { 55 | "丁": {300, 300, 360, 360, 318, 342, 360, 330, 300, 300, 312, 318}, 56 | "乙": {240, 212, 228, 240, 220, 200, 200, 208, 212, 200, 200, 240}, 57 | "己": {500, 550, 530, 500, 550, 570, 600, 580, 500, 500, 570, 500}, 58 | }, { 59 | "壬": {360, 330, 300, 300, 312, 318, 300, 300, 360, 360, 318, 342}, 60 | "庚": {700, 798, 700, 700, 770, 742, 700, 770, 798, 840, 812, 700}, 61 | }, { 62 | "辛": {1000, 1140, 1000, 1000, 1100, 1060, 1000, 1100, 1140, 1200, 1160, 1000}, 63 | }, { 64 | "辛": {300, 342, 300, 300, 330, 318, 300, 330, 342, 360, 348, 300}, 65 | "丁": {200, 200, 240, 240, 212, 228, 240, 220, 200, 200, 208, 212}, 66 | "戊": {500, 550, 530, 500, 550, 570, 600, 580, 500, 500, 570, 500}, 67 | }, { 68 | "甲": {360, 318, 342, 360, 330, 300, 300, 312, 318, 300, 300, 360}, 69 | "壬": {840, 770, 700, 700, 728, 742, 700, 700, 840, 840, 724, 798}, 70 | }, 71 | } 72 | 73 | var wuXingTianGan = map[string]string{ 74 | "甲": "木", 75 | "乙": "木", 76 | "丙": "火", 77 | "丁": "火", 78 | "戊": "土", 79 | "己": "土", 80 | "庚": "金", 81 | "辛": "金", 82 | "壬": "水", 83 | "癸": "水", 84 | } 85 | 86 | var wuXingDiZhi = map[string]string{ 87 | "子": "水", 88 | "丑": "土", 89 | "寅": "木", 90 | "卯": "木", 91 | "辰": "土", 92 | "巳": "火", 93 | "午": "火", 94 | "未": "土", 95 | "申": "金", 96 | "酉": "金", 97 | "戌": "土", 98 | "亥": "水", 99 | } 100 | 101 | //WuXingTianGan 五行天干 102 | func WuXingTianGan(s string) string { 103 | return wuXingTianGan[s] 104 | } 105 | 106 | //WuXingDiZhi 五行地支 107 | func WuXingDiZhi(s string) string { 108 | return wuXingDiZhi[s] 109 | } 110 | 111 | // BaZi ... 112 | type BaZi struct { 113 | baZi []string 114 | wuXing []string 115 | xiyong *XiYong 116 | } 117 | 118 | //NewBazi 创建八字 119 | func NewBazi(calendar chronos.Calendar) *BaZi { 120 | ec := calendar.Lunar().EightCharacter() 121 | return &BaZi{ 122 | baZi: ec, 123 | wuXing: baziToWuXing(ec), 124 | } 125 | } 126 | 127 | // String ... 128 | func (z *BaZi) String() string { 129 | return strings.Join(z.baZi, "") 130 | } 131 | 132 | //RiZhu 日主 133 | func (z *BaZi) RiZhu() string { 134 | return z.baZi[4] 135 | } 136 | 137 | func (z *BaZi) calcXiYong() { 138 | z.xiyong = &XiYong{} 139 | //TODO:need fix 140 | z.point().calcSimilar().calcHeterogeneous() //.yongShen().xiShen() 141 | } 142 | 143 | //XiYong 喜用神 144 | func (z *BaZi) XiYong() *XiYong { 145 | if z.xiyong == nil { 146 | z.calcXiYong() 147 | } 148 | return z.xiyong 149 | } 150 | 151 | //XiYongShen 平衡用神 152 | func (z *BaZi) XiYongShen() string { 153 | return z.XiYong().Shen() 154 | } 155 | 156 | //func (z *BaZi) yongShen() *BaZi { 157 | // z.xiyong.YongShen = z.xiyong.Similar[0] 158 | // return z 159 | //} 160 | //func (z *BaZi) xiShen() *BaZi { 161 | // rt := sheng 162 | // if z.QiangRuo() { 163 | // rt = ke 164 | // } 165 | // for i := range rt { 166 | // if rt[i] == z.xiyong.YongShen { 167 | // if i == len(rt) { 168 | // i = -1 169 | // } 170 | // z.xiyong.XiShen = rt[i-1] 171 | // break 172 | // } 173 | // } 174 | // return z 175 | //} 176 | func (z *BaZi) point() *BaZi { 177 | di := diIndex[z.baZi[3]] 178 | for idx, v := range z.baZi { 179 | if idx%2 == 0 { 180 | z.xiyong.AddFen(WuXingTianGan(v), tiangan[di][tianIndex[v]]) 181 | } else { 182 | dz := dizhi[diIndex[v]] 183 | for k := range dz { 184 | z.xiyong.AddFen(WuXingTianGan(k), dz[k][di]) 185 | } 186 | } 187 | } 188 | return z 189 | } 190 | 191 | func baziToWuXing(bazi []string) []string { 192 | var wx []string 193 | for idx, v := range bazi { 194 | if idx%2 == 0 { 195 | wx = append(wx, WuXingTianGan(v)) 196 | } else { 197 | wx = append(wx, WuXingDiZhi(v)) 198 | } 199 | } 200 | return wx 201 | } 202 | 203 | //计算同类 204 | func (z *BaZi) calcSimilar() *BaZi { 205 | for i := range sheng { 206 | if wuXingTianGan[z.RiZhu()] == sheng[i] { 207 | z.xiyong.Similar = append(z.xiyong.Similar, sheng[i]) 208 | z.xiyong.SimilarPoint = z.xiyong.GetFen(sheng[i]) 209 | if i == 0 { 210 | i = len(sheng) - 1 211 | z.xiyong.Similar = append(z.xiyong.Similar, sheng[i]) 212 | z.xiyong.SimilarPoint += z.xiyong.GetFen(sheng[i]) 213 | } else { 214 | z.xiyong.Similar = append(z.xiyong.Similar, sheng[i-1]) 215 | z.xiyong.SimilarPoint += z.xiyong.GetFen(sheng[i-1]) 216 | } 217 | break 218 | } 219 | } 220 | return z 221 | } 222 | 223 | //计算异类 224 | func (z *BaZi) calcHeterogeneous() *BaZi { 225 | for i := range sheng { 226 | for ti := range z.xiyong.Similar { 227 | if z.xiyong.Similar[ti] == sheng[i] { 228 | goto EndSimilar 229 | } 230 | } 231 | z.xiyong.Heterogeneous = append(z.xiyong.Heterogeneous, sheng[i]) 232 | z.xiyong.HeterogeneousPoint += z.xiyong.GetFen(sheng[i]) 233 | EndSimilar: 234 | continue 235 | 236 | } 237 | return z 238 | } 239 | -------------------------------------------------------------------------------- /wuge.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "github.com/goextension/log" 5 | "github.com/google/uuid" 6 | "github.com/xormsharp/xorm" 7 | ) 8 | 9 | // WuGe ... 10 | type WuGe struct { 11 | tianGe int 12 | renGe int 13 | diGe int 14 | waiGe int 15 | zongGe int 16 | } 17 | 18 | // ZongGe ... 19 | func (ge *WuGe) ZongGe() int { 20 | return ge.zongGe 21 | } 22 | 23 | // WaiGe ... 24 | func (ge *WuGe) WaiGe() int { 25 | return ge.waiGe 26 | } 27 | 28 | // DiGe ... 29 | func (ge *WuGe) DiGe() int { 30 | return ge.diGe 31 | } 32 | 33 | // RenGe ... 34 | func (ge *WuGe) RenGe() int { 35 | return ge.renGe 36 | } 37 | 38 | // TianGe ... 39 | func (ge *WuGe) TianGe() int { 40 | return ge.tianGe 41 | } 42 | 43 | //CalcWuGe 计算五格 44 | func CalcWuGe(l1, l2, f1, f2 int) *WuGe { 45 | return &WuGe{ 46 | tianGe: tianGe(l1, l2, f1, f2), 47 | renGe: renGe(l1, l2, f1, f2), 48 | diGe: diGe(l1, l2, f1, f2), 49 | waiGe: waiGe(l1, l2, f1, f2), 50 | zongGe: zongGe(l1, l2, f1, f2), 51 | } 52 | } 53 | 54 | //tianGe input the ScienceStrokes with last name 55 | //天格(复姓)姓的笔画相加 56 | //天格(单姓)姓的笔画上加一 57 | func tianGe(l1, l2, _, _ int) int { 58 | if l2 == 0 { 59 | return l1 + 1 60 | } 61 | return l1 + l2 62 | } 63 | 64 | //renGe input the ScienceStrokes with name 65 | //人格(复姓)姓氏的第二字的笔画加名的第一字 66 | //人格(复姓单名)姓的第二字加名 67 | //人格(单姓单名)姓加名 68 | // 人格(单姓复名)姓加名的第一字 69 | func renGe(l1, l2, f1, _ int) int { 70 | //人格(复姓)姓氏的第二字的笔画加名的第一字 71 | //人格(复姓单名)姓的第二字加名 72 | if l2 != 0 { 73 | return l2 + f1 74 | } 75 | return l1 + f1 76 | } 77 | 78 | //diGe input the ScienceStrokes with name 79 | //地格(复姓复名,单姓复名)名字相加 80 | //地格(复姓单名,单姓单名)名字+1 81 | func diGe(_, _, f1, f2 int) int { 82 | if f2 == 0 { 83 | return f1 + 1 84 | } 85 | return f1 + f2 86 | } 87 | 88 | //waiGe input the ScienceStrokes with name 89 | //外格(复姓单名)姓的第一字加笔画数一 90 | //外格(复姓复名)姓的第一字和名的最后一定相加的笔画数 91 | //外格(单姓复名)一加名的最后一个字 92 | //外格(单姓单名)一加一 93 | func waiGe(l1, l2, _, f2 int) (n int) { 94 | //单姓单名 95 | if l2 == 0 && f2 == 0 { 96 | n = 1 + 1 97 | } 98 | //单姓复名 99 | if l2 == 0 && f2 != 0 { 100 | n = 1 + f2 101 | } 102 | //复姓单名 103 | if l2 != 0 && f2 == 0 { 104 | n = l1 + 1 105 | } 106 | //复姓复名 107 | if l2 != 0 && f2 != 0 { 108 | n = l1 + f2 109 | } 110 | return n 111 | } 112 | 113 | //zongGe input the ScienceStrokes with name 114 | //总格,姓加名的笔画总数  数理五行分类 115 | func zongGe(l1, l2, f1, f2 int) int { 116 | //归1 117 | zg := (l1 + l2 + f1 + f2) - 1 118 | if zg < 0 { 119 | zg = zg + 81 120 | } 121 | return zg%81 + 1 122 | } 123 | 124 | func checkDaYan(idx int) bool { 125 | switch daYanList[idx-1].Lucky { 126 | case "吉", "半吉": 127 | return true 128 | } 129 | return false 130 | } 131 | 132 | //Check 格检查 133 | func (ge *WuGe) Check() bool { 134 | //ignore:tianGe 135 | for _, v := range []int{ge.diGe, ge.renGe, ge.waiGe, ge.zongGe} { 136 | if !checkDaYan(v) { 137 | return false 138 | } 139 | } 140 | return true 141 | } 142 | 143 | //WuGeLucky ... 144 | type WuGeLucky struct { 145 | ID string `xorm:"id pk"` 146 | LastStroke1 int `xorm:"last_stroke_1"` 147 | LastStroke2 int `xorm:"last_stroke_2"` 148 | FirstStroke1 int `xorm:"first_stroke_1"` 149 | FirstStroke2 int `xorm:"first_stroke_2"` 150 | TianGe int `xorm:"tian_ge"` 151 | TianDaYan string `xorm:"tian_da_yan"` 152 | RenGe int `xorm:"ren_ge"` 153 | RenDaYan string `xorm:"ren_da_yan"` 154 | DiGe int `xorm:"di_ge"` 155 | DiDaYan string `xorm:"di_da_yan"` 156 | WaiGe int `xorm:"wai_ge"` 157 | WaiDaYan string `xorm:"wai_da_yan"` 158 | ZongGe int `xorm:"zong_ge"` 159 | ZongDaYan string `xorm:"zong_da_yan"` 160 | ZongLucky bool `xorm:"zong_lucky"` 161 | ZongSex bool `xorm:"zong_sex"` 162 | ZongMax bool `xorm:"zong_max"` 163 | } 164 | 165 | // BeforeInsert ... 166 | func (w *WuGeLucky) BeforeInsert() { 167 | w.ID = uuid.Must(uuid.NewUUID()).String() 168 | } 169 | 170 | func countWuGeLucky(engine *xorm.Engine) (n int64, e error) { 171 | return engine.Table(&WuGeLucky{}).Count() 172 | } 173 | 174 | func insertOrUpdateWuGeLucky(engine *xorm.Engine, lucky *WuGeLucky) (n int64, e error) { 175 | session := engine.Where("last_stroke_1 = ?", lucky.LastStroke1). 176 | Where("last_stroke_2 = ?", lucky.LastStroke2). 177 | Where("first_stroke_1 = ?", lucky.FirstStroke1). 178 | Where("first_stroke_2 = ?", lucky.FirstStroke2) 179 | 180 | n, e = session.Clone().Count(&WuGeLucky{}) 181 | if e != nil { 182 | return n, e 183 | } 184 | log.Infow("lucky", lucky) 185 | if n == 0 { 186 | n, e = engine.InsertOne(lucky) 187 | return 188 | } 189 | return session.Clone().Update(lucky) 190 | } 191 | 192 | // WuGeMax ... 193 | const WuGeMax = 32 194 | 195 | func initWuGe(lucky chan<- *WuGeLucky) { 196 | defer func() { 197 | close(lucky) 198 | }() 199 | var wuge *WuGe 200 | for l1 := 1; l1 <= WuGeMax; l1++ { 201 | for l2 := 0; l2 <= WuGeMax; l2++ { 202 | for f1 := 1; f1 <= WuGeMax; f1++ { 203 | for f2 := 1; f2 <= WuGeMax; f2++ { 204 | wuge = CalcWuGe(l1, l2, f1, f2) 205 | lucky <- &WuGeLucky{ 206 | ID: "", 207 | LastStroke1: l1, 208 | LastStroke2: l2, 209 | FirstStroke1: f1, 210 | FirstStroke2: f2, 211 | TianGe: wuge.tianGe, 212 | TianDaYan: GetDaYan(wuge.tianGe).Lucky, 213 | RenGe: wuge.renGe, 214 | RenDaYan: GetDaYan(wuge.renGe).Lucky, 215 | DiGe: wuge.diGe, 216 | DiDaYan: GetDaYan(wuge.diGe).Lucky, 217 | WaiGe: wuge.waiGe, 218 | WaiDaYan: GetDaYan(wuge.waiGe).Lucky, 219 | ZongGe: wuge.zongGe, 220 | ZongDaYan: GetDaYan(wuge.zongGe).Lucky, 221 | ZongLucky: wuge.Check(), 222 | ZongSex: isSex(wuge.zongGe, wuge.waiGe, wuge.renGe, wuge.diGe), 223 | ZongMax: GetDaYan(wuge.zongGe).IsMax(), 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | 231 | func getStroke(character *Character) int { 232 | if character.ScienceStroke != 0 { 233 | return character.ScienceStroke 234 | } else if character.KangXiStroke != 0 { 235 | return character.KangXiStroke 236 | } else if character.Stroke != 0 { 237 | return character.Stroke 238 | } else if character.SimpleTotalStroke != 0 { 239 | return character.SimpleTotalStroke 240 | } else if character.TraditionalTotalStroke != 0 { 241 | return character.TraditionalTotalStroke 242 | } 243 | return 0 244 | } 245 | 246 | func isSex(dys ...int) bool { 247 | for _, dy := range dys { 248 | if GetDaYan(dy).Sex { 249 | return true 250 | } 251 | } 252 | return false 253 | } 254 | 255 | func filterWuGe(eng *xorm.Engine, last []*Character, wg chan<- *WuGeLucky) error { 256 | defer func() { 257 | close(wg) 258 | }() 259 | l1 := getStroke(last[0]) 260 | l2 := 0 261 | if len(last) == 2 { 262 | l2 = getStroke(last[1]) 263 | } 264 | s := eng.Where("last_stroke_1 =?", l1). 265 | And("last_stroke_2 =?", l2). 266 | And("zong_lucky = ?", 1) 267 | rows, e := s.Rows(&WuGeLucky{}) 268 | if e != nil { 269 | return e 270 | } 271 | for rows.Next() { 272 | var tmp WuGeLucky 273 | e := rows.Scan(&tmp) 274 | if e != nil { 275 | return e 276 | } 277 | wg <- &tmp 278 | } 279 | 280 | return nil 281 | } 282 | -------------------------------------------------------------------------------- /dayan.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | _ "github.com/godcong/fate/statik" 5 | ) 6 | 7 | var daYanList [81]DaYan 8 | 9 | func init() { 10 | daYanList = [81]DaYan{ 11 | {Number: 1, Lucky: "吉", SkyNine: "太极之数", Comment: "太极之数,万物开泰,生发无穷,利禄亨通。"}, 12 | {Number: 2, Lucky: "凶", SkyNine: "两仪之数", Comment: "两仪之数,混沌未开,进退保守,志望难达。"}, 13 | {Number: 3, Lucky: "吉", SkyNine: "三才之数", Comment: "三才之数,天地人和,大事大业,繁荣昌隆。"}, 14 | {Number: 4, Lucky: "凶", SkyNine: "四象之数", Comment: "四象之数,待于生发,万事慎重,不具营谋。"}, 15 | {Number: 5, Lucky: "吉", SkyNine: "五行之数", Comment: "五行俱权,循环相生,圆通畅达,福祉无穷。"}, 16 | {Number: 6, Lucky: "吉", SkyNine: "六爻之数", Comment: "六爻之数,发展变化,天赋美德,吉祥安泰。"}, 17 | {Number: 7, Lucky: "吉", SkyNine: "七政之数", Comment: "七政之数,精悍严谨,天赋之力,吉星照耀。"}, 18 | {Number: 8, Lucky: "半吉", SkyNine: "八卦之数", Comment: "八卦之数,乾坎艮震,巽离坤兑,无穷无尽。"}, 19 | {Number: 9, Lucky: "凶", SkyNine: "大成之数", Comment: "大成之数,蕴涵凶险,或成或败,难以把握。"}, 20 | {Number: 10, Lucky: "凶", SkyNine: "终结之数", Comment: "终结之数,雪暗飘零,偶或有成,回顾茫然。"}, 21 | {Number: 11, Lucky: "吉", SkyNine: "旱苗逢雨", Comment: "万物更新,调顺发达,恢弘泽世,繁荣富贵。"}, 22 | {Number: 12, Lucky: "凶", SkyNine: "掘井无泉", Comment: "无理之数,发展薄弱,虽生不足,难酬志向。"}, 23 | {Number: 13, Lucky: "吉", SkyNine: "春日牡丹", Comment: "才艺多能,智谋奇略,忍柔当事,鸣奏大功。"}, 24 | {Number: 14, Lucky: "凶", SkyNine: "破兆", Comment: "家庭缘薄,孤独遭难,谋事不达,悲惨不测。"}, 25 | {Number: 15, Lucky: "吉", SkyNine: "福寿", Comment: "福寿圆满,富贵荣誉,涵养雅量,德高望重。"}, 26 | {Number: 16, Lucky: "吉", SkyNine: "厚重", Comment: "厚重载德,安富尊荣,财官双美,功成名就。"}, 27 | {Number: 17, Lucky: "半吉", SkyNine: "刚强", Comment: "权威刚强,突破万难,如能容忍,必获成功。"}, 28 | {Number: 18, Lucky: "半吉", SkyNine: "铁镜重磨", Comment: "权威显达,博得名利,且养柔德,功成名就。"}, 29 | {Number: 19, Lucky: "凶", SkyNine: "多难", Comment: "风云蔽日,辛苦重来,虽有智谋,万事挫折。"}, 30 | {Number: 20, Lucky: "凶", SkyNine: "屋下藏金", Comment: "非业破运,灾难重重,进退维谷,万事难成。"}, 31 | {Number: 21, Lucky: "吉", Sex: true, SkyNine: "明月中天", Comment: "光风霁月,万物确立,官运亨通,大搏名利。女性不宜此数。"}, 32 | {Number: 22, Lucky: "凶", SkyNine: "秋草逢霜", Comment: "秋草逢霜,困难疾弱,虽出豪杰,人生波折。"}, 33 | {Number: 23, Lucky: "吉", Sex: true, SkyNine: "壮丽", Comment: "旭日东升,壮丽壮观,权威旺盛,功名荣达。女性不宜此数。"}, 34 | {Number: 24, Lucky: "吉", SkyNine: "掘藏得金", Comment: "家门余庆,金钱丰盈,白手成家,财源广进。"}, 35 | {Number: 25, Lucky: "半吉", SkyNine: "荣俊", Comment: "资性英敏,才能奇特,克服傲慢,尚可成功。"}, 36 | {Number: 26, Lucky: "凶", SkyNine: "变怪", Comment: "变怪之谜,英雄豪杰,波澜重叠,而奏大功。"}, 37 | {Number: 27, Lucky: "凶", SkyNine: "增长", Comment: "欲望无止,自我强烈,多受毁谤,尚可成功。"}, 38 | {Number: 28, Lucky: "凶", Sex: true, SkyNine: "阔水浮萍", Comment: "遭难之数,豪杰气概,四海漂泊,终世浮躁。女性不宜此数。"}, 39 | {Number: 29, Lucky: "吉", SkyNine: "智谋", Comment: "智谋优秀,财力归集,名闻海内,成就大业。"}, 40 | {Number: 30, Lucky: "半吉", SkyNine: "非运", Comment: "沉浮不定,凶吉难变,若明若暗,大成大败。"}, 41 | {Number: 31, Lucky: "吉", SkyNine: "春日花开", Comment: "智勇得志,博得名利,统领众人,繁荣富贵。"}, 42 | {Number: 32, Lucky: "吉", SkyNine: "宝马金鞍", Comment: "侥幸多望,贵人得助,财帛如裕,繁荣至上。"}, 43 | {Number: 33, Lucky: "吉", Sex: true, SkyNine: "旭日升天", Comment: "旭日升天,鸾凤相会,名闻天下,隆昌至极。女性不宜此数。"}, 44 | {Number: 34, Lucky: "凶", SkyNine: "破家", Comment: "破家之身,见识短小,辛苦遭逢,灾祸至极。"}, 45 | {Number: 35, Lucky: "吉", SkyNine: "高楼望月", Comment: "温和平静,智达通畅,文昌技艺,奏功洋洋。"}, 46 | {Number: 36, Lucky: "半吉", SkyNine: "波澜重叠", Comment: "波澜重叠,沉浮万状,侠肝义胆,舍己成仁。"}, 47 | {Number: 37, Lucky: "吉", SkyNine: "猛虎出林", Comment: "权威显达,热诚忠信,宜着雅量,终身荣富。"}, 48 | {Number: 38, Lucky: "半吉", SkyNine: "磨铁成针", Comment: "意志薄弱,刻意经营,才识不凡,技艺有成。"}, 49 | {Number: 39, Lucky: "半吉", SkyNine: "富贵荣华", Comment: "富贵荣华,财帛丰盈,暗藏险象,德泽四方。"}, 50 | {Number: 40, Lucky: "凶", SkyNine: "退安", Comment: "智谋胆力,冒险投机,沉浮不定,退保平安。"}, 51 | {Number: 41, Lucky: "吉", Max: true, SkyNine: "有德", Comment: "纯阳独秀,德高望重,和顺畅达,博得名利。此数为最大好运数。"}, 52 | {Number: 42, Lucky: "凶", SkyNine: "寒蝉在柳", Comment: "博识多能,精通世情,如能专心,尚可成功。"}, 53 | {Number: 43, Lucky: "凶", SkyNine: "散财破产", Comment: "散财破产,诸事不遂,虽有智谋,财来财去。"}, 54 | {Number: 44, Lucky: "凶", SkyNine: "烦闷", Comment: "破家亡身,暗藏惨淡,事不如意,乱世怪杰。"}, 55 | {Number: 45, Lucky: "吉", SkyNine: "顺风", Comment: "新生泰和,顺风扬帆,智谋经纬,富贵繁荣。"}, 56 | {Number: 46, Lucky: "凶", SkyNine: "浪里淘金", Comment: "载宝沉舟,浪里淘金,大难尝尽,大功有成。"}, 57 | {Number: 47, Lucky: "吉", SkyNine: "点石成金", Comment: "花开之象,万事如意,祯祥吉庆,天赋幸福。"}, 58 | {Number: 48, Lucky: "吉", SkyNine: "古松立鹤", Comment: "智谋兼备,德量荣达,威望成师,洋洋大观。"}, 59 | {Number: 49, Lucky: "半吉", SkyNine: "转变", Comment: "吉临则吉,凶来则凶,转凶为吉,配好三才。"}, 60 | {Number: 50, Lucky: "半吉", SkyNine: "小舟入海", Comment: "一成一败,吉凶参半,先得庇荫,后遭凄惨。"}, 61 | {Number: 51, Lucky: "半吉", SkyNine: "沉浮", Comment: "盛衰交加,波澜重叠,如能慎始,必获成功。"}, 62 | {Number: 52, Lucky: "吉", SkyNine: "达眼", Comment: "卓识达眼,先见之明,智谋超群,名利双收。"}, 63 | {Number: 53, Lucky: "凶", SkyNine: "曲卷难星", Comment: "外祥内患,外祸内安,先富后贫,先贫后富。"}, 64 | {Number: 54, Lucky: "凶", SkyNine: "石上栽花", Comment: "石上栽花,难得有活,忧闷烦来,辛惨不绝。"}, 65 | {Number: 55, Lucky: "半吉", SkyNine: "善恶", Comment: "善善得恶,恶恶得善,吉到极限,反生凶险。"}, 66 | {Number: 56, Lucky: "凶", SkyNine: "浪里行舟", Comment: "历尽艰辛,四周障碍,万事龃龌,做事难成。"}, 67 | {Number: 57, Lucky: "吉", SkyNine: "日照春松", Comment: "寒雪青松,夜莺吟春,必遭一过,繁荣白事。"}, 68 | {Number: 58, Lucky: "半吉", SkyNine: "晚行遇月", Comment: "沉浮多端,先苦后甜,宽宏扬名,富贵繁荣。"}, 69 | {Number: 59, Lucky: "凶", SkyNine: "寒蝉悲风", Comment: "寒蝉悲风,意志衰退,缺乏忍耐,苦难不休。"}, 70 | {Number: 60, Lucky: "凶", SkyNine: "无谋", Comment: "无谋之人,漂泊不定,晦暝暗黑,动摇不安。"}, 71 | {Number: 61, Lucky: "吉", SkyNine: "牡丹芙蓉", Comment: "牡丹芙蓉,花开富贵,名利双收,定享天赋。"}, 72 | {Number: 62, Lucky: "凶", SkyNine: "衰败", Comment: "衰败之象,内外不和,志望难达,灾祸频来。"}, 73 | {Number: 63, Lucky: "吉", SkyNine: "舟归平海", Comment: "富贵荣华,身心安泰,雨露惠泽,万事亨通。"}, 74 | {Number: 64, Lucky: "凶", SkyNine: "非命", Comment: "骨肉分离,孤独悲愁,难得心安,做事不成。"}, 75 | {Number: 65, Lucky: "吉", SkyNine: "巨流归海", Comment: "天长地久,家运隆昌,福寿绵长,事事成就。"}, 76 | {Number: 66, Lucky: "凶", SkyNine: "岩头步马", Comment: "进退维谷,艰难不堪,等待时机,一跃而起。"}, 77 | {Number: 67, Lucky: "吉", SkyNine: "顺风通达", Comment: "天赋幸运,四通八达,家道繁昌,富贵东来。"}, 78 | {Number: 68, Lucky: "吉", SkyNine: "顺风吹帆", Comment: "智虑周密,集众信达,发明能智,拓展昂进。"}, 79 | {Number: 69, Lucky: "凶", SkyNine: "非业", Comment: "非业非力,精神迫滞,灾害交至,遍偿痛苦。"}, 80 | {Number: 70, Lucky: "凶", SkyNine: "残菊逢霜", Comment: "残菊逢霜,寂寞无碍,惨淡忧愁,晚景凄凉。"}, 81 | {Number: 71, Lucky: "半吉", SkyNine: "石上金花", Comment: "石上金花,内心劳苦,贯彻始终,定可昌隆。"}, 82 | {Number: 72, Lucky: "半吉", SkyNine: "劳苦", Comment: "荣苦相伴,阴云覆月,外表吉祥,内实凶祸。"}, 83 | {Number: 73, Lucky: "半吉", SkyNine: "无勇", Comment: "盛衰交加,徒有高志,天王福祉,终世平安。"}, 84 | {Number: 74, Lucky: "凶", SkyNine: "残菊经霜", Comment: "残菊经霜,秋叶寂寞,无能无智,辛苦繁多。"}, 85 | {Number: 75, Lucky: "凶", SkyNine: "退守", Comment: "退守保吉,发迹甚迟,虽有吉象,无谋难成。"}, 86 | {Number: 76, Lucky: "凶", SkyNine: "离散", Comment: "倾覆离散,骨肉分离,内外不和,虽劳无功。"}, 87 | {Number: 77, Lucky: "半吉", SkyNine: "半吉", Comment: "家庭有悦,半吉半凶,能获援护,陷落不幸。"}, 88 | {Number: 78, Lucky: "凶", SkyNine: "晚苦", Comment: "祸福参半,先天智能,中年发达,晚景困苦。"}, 89 | {Number: 79, Lucky: "凶", SkyNine: "云头望月", Comment: "云头望月,身疲力尽,穷迫不伸,精神不定。"}, 90 | {Number: 80, Lucky: "凶", SkyNine: "遁吉", Comment: "辛苦不绝,早入隐遁,安心立命,化凶转吉。"}, 91 | {Number: 81, Lucky: "吉", SkyNine: "万物回春", Comment: "最吉之数,还本归元,吉祥重叠,富贵尊荣。"}, 92 | } 93 | } 94 | 95 | // DaYan ... 96 | type DaYan struct { 97 | Number int 98 | Lucky string 99 | Max bool 100 | Sex bool //male(false),female(true) 101 | SkyNine string 102 | Comment string 103 | } 104 | 105 | //IsSex 女性不宜此数 106 | func (dy DaYan) IsSex() bool { 107 | return dy.Sex 108 | } 109 | 110 | //IsMax 是否最大好运数 111 | func (dy DaYan) IsMax() bool { 112 | return dy.Max 113 | } 114 | 115 | //GetDaYan 获取大衍之数 116 | func GetDaYan(idx int) DaYan { 117 | if idx <= 0 { 118 | panic("wrong idx") 119 | } 120 | i := (idx - 1) % 81 121 | return daYanList[i] 122 | } 123 | -------------------------------------------------------------------------------- /regular/regular.go: -------------------------------------------------------------------------------- 1 | package regular 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/godcong/fate" 9 | "github.com/xormsharp/xorm" 10 | ) 11 | 12 | var regularList = map[int]string{ 13 | 1: `一、乙`, 14 | 2: `二、十、丁、厂、七、卜、人、入、八、九、几、儿、了、力、乃、刀、又`, 15 | 3: `三、于、干、亏、士、工、土、才、寸、下、大、丈、与、万、上、小 16 | 口、巾、山、千、乞、川、亿、个、勺、久、凡、及、夕、丸、么、广 17 | 亡、门、义、之、尸、弓、己、已、子、卫、也、女、飞、刃、习、叉 18 | 马、乡`, 19 | 4: `丰、王、井、开、夫、天、无、元、专、云、扎、艺、木、五、支、厅 20 | 不、太、犬、区、历、尤、友、匹、车、巨、牙、屯、比、互、切、瓦 21 | 止、少、日、中、冈、贝、内、水、见、午、牛、手、毛、气、升、长 22 | 仁、什、片、仆、化、仇、币、仍、仅、斤、爪、反、介、父、从、今 23 | 凶、分、乏、公、仓、月、氏、勿、欠、风、丹、匀、乌、凤、勾、文 24 | 六、方、火、为、斗、忆、订、计、户、认、心、尺、引、丑、巴、孔 25 | 队、办、以、允、予、劝、双、书、幻`, 26 | 5: `玉、刊、示、末、未、击、打、巧、正、扑、扒、功、扔、去、甘、世 27 | 古、节、本、术、可、丙、左、厉、右、石、布、龙、平、灭、轧、东 28 | 卡、北、占、业、旧、帅、归、且、旦、目、叶、甲、申、叮、电、号 29 | 田、由、史、只、央、兄、叼、叫、另、叨、叹、四、生、失、禾、丘 30 | 付、仗、代、仙、们、仪、白、仔、他、斥、瓜、乎、丛、令、用、甩 31 | 印、乐、句、匆、册、犯、外、处、冬、鸟、务、包、饥、主、市、立 32 | 闪、兰、半、汁、汇、头、汉、宁、穴、它、讨、写、让、礼、训、必 33 | 议、讯、记、永、司、尼、民、出、辽、奶、奴、加、召、皮、边、发 34 | 孕、圣、对、台、矛、纠、母、幼、丝`, 35 | 6: `式、刑、动、扛、寺、吉、扣、考、托、老、执、巩、圾、扩、扫、地 36 | 扬、场、耳、共、芒、亚、芝、朽、朴、机、权、过、臣、再、协、西 37 | 压、厌、在、有、百、存、而、页、匠、夸、夺、灰、达、列、死、成 38 | 夹、轨、邪、划、迈、毕、至、此、贞、师、尘、尖、劣、光、当、早 39 | 吐、吓、虫、曲、团、同、吊、吃、因、吸、吗、屿、帆、岁、回、岂 40 | 刚、则、肉、网、年、朱、先、丢、舌、竹、迁、乔、伟、传、乒、乓 41 | 休、伍、伏、优、伐、延、件、任、伤、价、份、华、仰、仿、伙、伪 42 | 自、血、向、似、后、行、舟、全、会、杀、合、兆、企、众、爷、伞 43 | 创、肌、朵、杂、危、旬、旨、负、各、名、多、争、色、壮、冲、冰 44 | 庄、庆、亦、刘、齐、交、次、衣、产、决、充、妄、闭、问、闯、羊 45 | 并、关、米、灯、州、汗、污、江、池、汤、忙、兴、宇、守、宅、字 46 | 安、讲、军、许、论、农、讽、设、访、寻、那、迅、尽、导、异、孙 47 | 阵、阳、收、阶、阴、防、奸、如、妇、好、她、妈、戏、羽、观、欢 48 | 买、红、纤、级、约、纪、驰、巡`, 49 | 7: `寿、弄、麦、形、进、戒、吞、远、违、运、扶、抚、坛、技、坏、扰 50 | 拒、找、批、扯、址、走、抄、坝、贡、攻、赤、折、抓、扮、抢、孝 51 | 均、抛、投、坟、抗、坑、坊、抖、护、壳、志、扭、块、声、把、报 52 | 却、劫、芽、花、芹、芬、苍、芳、严、芦、劳、克、苏、杆、杠、杜 53 | 材、村、杏、极、李、杨、求、更、束、豆、两、丽、医、辰、励、否 54 | 还、歼、来、连、步、坚、旱、盯、呈、时、吴、助、县、里、呆、园 55 | 旷、围、呀、吨、足、邮、男、困、吵、串、员、听、吩、吹、呜、吧 56 | 吼、别、岗、帐、财、针、钉、告、我、乱、利、秃、秀、私、每、兵 57 | 估、体、何、但、伸、作、伯、伶、佣、低、你、住、位、伴、身、皂 58 | 佛、近、彻、役、返、余、希、坐、谷、妥、含、邻、岔、肝、肚、肠 59 | 龟、免、狂、犹、角、删、条、卵、岛、迎、饭、饮、系、言、冻、状 60 | 亩、况、床、库、疗、应、冷、这、序、辛、弃、冶、忘、闲、间、闷 61 | 判、灶、灿、弟、汪、沙、汽、沃、泛、沟、没、沈、沉、怀、忧、快 62 | 完、宋、宏、牢、究、穷、灾、良、证、启、评、补、初、社、识、诉 63 | 诊、词、译、君、灵、即、层、尿、尾、迟、局、改、张、忌、际、陆 64 | 阿、陈、阻、附、妙、妖、妨、努、忍、劲、鸡、驱、纯、纱、纳、纲 65 | 驳、纵、纷、纸、纹、纺、驴、纽`, 66 | 8: `奉、玩、环、武、青、责、现、表、规、抹、拢、拔、拣、担、坦、押 67 | 抽、拐、拖、拍、者、顶、拆、拥、抵、拘、势、抱、垃、拉、拦、拌 68 | 幸、招、坡、披、拨、择、抬、其、取、苦、若、茂、苹、苗、英、范 69 | 直、茄、茎、茅、林、枝、杯、柜、析、板、松、枪、构、杰、述、枕 70 | 丧、或、画、卧、事、刺、枣、雨、卖、矿、码、厕、奔、奇、奋、态 71 | 欧、垄、妻、轰、顷、转、斩、轮、软、到、非、叔、肯、齿、些、虎 72 | 虏、肾、贤、尚、旺、具、果、味、昆、国、昌、畅、明、易、昂、典 73 | 固、忠、咐、呼、鸣、咏、呢、岸、岩、帖、罗、帜、岭、凯、败、贩 74 | 购、图、钓、制、知、垂、牧、物、乖、刮、秆、和、季、委、佳、侍 75 | 供、使、例、版、侄、侦、侧、凭、侨、佩、货、依、的、迫、质、欣 76 | 征、往、爬、彼、径、所、舍、金、命、斧、爸、采、受、乳、贪、念 77 | 贫、肤、肺、肢、肿、胀、朋、股、肥、服、胁、周、昏、鱼、兔、狐 78 | 忽、狗、备、饰、饱、饲、变、京、享、店、夜、庙、府、底、剂、郊 79 | 废、净、盲、放、刻、育、闸、闹、郑、券、卷、单、炒、炊、炕、炎 80 | 炉、沫、浅、法、泄、河、沾、泪、油、泊、沿、泡、注、泻、泳、泥 81 | 沸、波、泼、泽、治、怖、性、怕、怜、怪、学、宝、宗、定、宜、审 82 | 宙、官、空、帘、实、试、郎、诗、肩、房、诚、衬、衫、视、话、诞 83 | 询、该、详、建、肃、录、隶、居、届、刷、屈、弦、承、孟、孤、陕 84 | 降、限、妹、姑、姐、姓、始、驾、参、艰、线、练、组、细、驶、织 85 | 终、驻、驼、绍、经、贯`, 86 | 9: `奏、春、帮、珍、玻、毒、型、挂、封、持、项、垮、挎、城、挠、政 87 | 赴、赵、挡、挺、括、拴、拾、挑、指、垫、挣、挤、拼、挖、按、挥 88 | 挪、某、甚、革、荐、巷、带、草、茧、茶、荒、茫、荡、荣、故、胡 89 | 南、药、标、枯、柄、栋、相、查、柏、柳、柱、柿、栏、树、要、咸 90 | 威、歪、研、砖、厘、厚、砌、砍、面、耐、耍、牵、残、殃、轻、鸦 91 | 皆、背、战、点、临、览、竖、省、削、尝、是、盼、眨、哄、显、哑 92 | 冒、映、星、昨、畏、趴、胃、贵、界、虹、虾、蚁、思、蚂、虽、品 93 | 咽、骂、哗、咱、响、哈、咬、咳、哪、炭、峡、罚、贱、贴、骨、钞 94 | 钟、钢、钥、钩、卸、缸、拜、看、矩、怎、牲、选、适、秒、香、种 95 | 秋、科、重、复、竿、段、便、俩、贷、顺、修、保、促、侮、俭、俗 96 | 俘、信、皇、泉、鬼、侵、追、俊、盾、待、律、很、须、叙、剑、逃 97 | 食、盆、胆、胜、胞、胖、脉、勉、狭、狮、独、狡、狱、狠、贸、怨 98 | 急、饶、蚀、饺、饼、弯、将、奖、哀、亭、亮、度、迹、庭、疮、疯 99 | 疫、疤、姿、亲、音、帝、施、闻、阀、阁、差、养、美、姜、叛、送 100 | 类、迷、前、首、逆、总、炼、炸、炮、烂、剃、洁、洪、洒、浇、浊 101 | 洞、测、洗、活、派、洽、染、济、洋、洲、浑、浓、津、恒、恢、恰 102 | 恼、恨、举、觉、宣、室、宫、宪、突、穿、窃、客、冠、语、扁、袄 103 | 祖、神、祝、误、诱、说、诵、垦、退、既、屋、昼、费、陡、眉、孩 104 | 除、险、院、娃、姥、姨、姻、娇、怒、架、贺、盈、勇、怠、柔、垒 105 | 绑、绒、结、绕、骄、绘、给、络、骆、绝、绞、统`, 106 | 10: `耕、耗、艳、泰、珠、班、素、蚕、顽、盏、匪、捞、栽、捕、振、载 107 | 赶、起、盐、捎、捏、埋、捉、捆、捐、损、都、哲、逝、捡、换、挽 108 | 热、恐、壶、挨、耻、耽、恭、莲、莫、荷、获、晋、恶、真、框、桂 109 | 档、桐、株、桥、桃、格、校、核、样、根、索、哥、速、逗、栗、配 110 | 翅、辱、唇、夏、础、破、原、套、逐、烈、殊、顾、轿、较、顿、毙 111 | 致、柴、桌、虑、监、紧、党、晒、眠、晓、鸭、晃、晌、晕、蚊、哨 112 | 哭、恩、唤、啊、唉、罢、峰、圆、贼、贿、钱、钳、钻、铁、铃、铅 113 | 缺、氧、特、牺、造、乘、敌、秤、租、积、秧、秩、称、秘、透、笔 114 | 笑、笋、债、借、值、倚、倾、倒、倘、俱、倡、候、俯、倍、倦、健 115 | 臭、射、躬、息、徒、徐、舰、舱、般、航、途、拿、爹、爱、颂、翁 116 | 脆、脂、胸、胳、脏、胶、脑、狸、狼、逢、留、皱、饿、恋、桨、浆 117 | 衰、高、席、准、座、脊、症、病、疾、疼、疲、效、离、唐、资、凉 118 | 站、剖、竞、部、旁、旅、畜、阅、羞、瓶、拳、粉、料、益、兼、烤 119 | 烘、烦、烧、烛、烟、递、涛、浙、涝、酒、涉、消、浩、海、涂、浴 120 | 浮、流、润、浪、浸、涨、烫、涌、悟、悄、悔、悦、害、宽、家、宵 121 | 宴、宾、窄、容、宰、案、请、朗、诸、读、扇、袜、袖、袍、被、祥 122 | 课、谁、调、冤、谅、谈、谊、剥、恳、展、剧、屑、弱、陵、陶、陷 123 | 陪、娱、娘、通、能、难、预、桑、绢、绣、验、继`, 124 | 11: `球、理、捧、堵、描、域、掩、捷、排、掉、堆、推、掀、授、教、掏 125 | 掠、培、接、控、探、据、掘、职、基、著、勒、黄、萌、萝、菌、菜 126 | 萄、菊、萍、菠、营、械、梦、梢、梅、检、梳、梯、桶、救、副、票 127 | 戚、爽、聋、袭、盛、雪、辅、辆、虚、雀、堂、常、匙、晨、睁、眯 128 | 眼、悬、野、啦、晚、啄、距、跃、略、蛇、累、唱、患、唯、崖、崭 129 | 崇、圈、铜、铲、银、甜、梨、犁、移、笨、笼、笛、符、第、敏、做 130 | 袋、悠、偿、偶、偷、您、售、停、偏、假、得、衔、盘、船、斜、盒 131 | 鸽、悉、欲、彩、领、脚、脖、脸、脱、象、够、猜、猪、猎、猫、猛 132 | 馅、馆、凑、减、毫、麻、痒、痕、廊、康、庸、鹿、盗、章、竟、商 133 | 族、旋、望、率、着、盖、粘、粗、粒、断、剪、兽、清、添、淋、淹 134 | 渠、渐、混、渔、淘、液、淡、深、婆、梁、渗、情、惜、惭、悼、惧 135 | 惕、惊、惨、惯、寇、寄、宿、窑、密、谋、谎、祸、谜、逮、敢、屠 136 | 弹、随、蛋、隆、隐、婚、婶、颈、绩、绪、续、骑、绳、维、绵、绸 137 | 绿`, 138 | 12: `琴、斑、替、款、堪、搭、塔、越、趁、趋、超、提、堤、博、揭、喜 139 | 插、揪、搜、煮、援、裁、搁、搂、搅、握、揉、斯、期、欺、联、散 140 | 惹、葬、葛、董、葡、敬、葱、落、朝、辜、葵、棒、棋、植、森、椅 141 | 椒、棵、棍、棉、棚、棕、惠、惑、逼、厨、厦、硬、确、雁、殖、裂 142 | 雄、暂、雅、辈、悲、紫、辉、敞、赏、掌、晴、暑、最、量、喷、晶 143 | 喇、遇、喊、景、践、跌、跑、遗、蛙、蛛、蜓、喝、喂、喘、喉、幅 144 | 帽、赌、赔、黑、铸、铺、链、销、锁、锄、锅、锈、锋、锐、短、智 145 | 毯、鹅、剩、稍、程、稀、税、筐、等、筑、策、筛、筒、答、筋、筝 146 | 傲、傅、牌、堡、集、焦、傍、储、奥、街、惩、御、循、艇、舒、番 147 | 释、禽、腊、脾、腔、鲁、猾、猴、然、馋、装、蛮、就、痛、童、阔 148 | 善、羡、普、粪、尊、道、曾、焰、港、湖、渣、湿、温、渴、滑、湾 149 | 渡、游、滋、溉、愤、慌、惰、愧、愉、慨、割、寒、富、窜、窝、窗 150 | 遍、裕、裤、裙、谢、谣、谦、属、屡、强、粥、疏、隔、隙、絮、嫂 151 | 登、缎、缓、编、骗、缘`, 152 | 13: `瑞、魂、肆、摄、摸、填、搏、塌、鼓、摆、携、搬、摇、搞、塘、摊 153 | 蒜、勤、鹊、蓝、墓、幕、蓬、蓄、蒙、蒸、献、禁、楚、想、槐、榆 154 | 楼、概、赖、酬、感、碍、碑、碎、碰、碗、碌、雷、零、雾、雹、输 155 | 督、龄、鉴、睛、睡、睬、鄙、愚、暖、盟、歇、暗、照、跨、跳、跪 156 | 路、跟、遣、蛾、蜂、嗓、置、罪、罩、错、锡、锣、锤、锦、键、锯 157 | 矮、辞、稠、愁、筹、签、简、毁、舅、鼠、催、傻、像、躲、微、愈 158 | 遥、腰、腥、腹、腾、腿、触、解、酱、痰、廉、新、韵、意、粮、数 159 | 煎、塑、慈、煤、煌、满、漠、源、滤、滥、滔、溪、溜、滚、滨、粱 160 | 滩、慎、誉、塞、谨、福、群、殿、辟、障、嫌、嫁、叠、缝、缠`, 161 | 14: `静、碧、璃、墙、撇、嘉、摧、截、誓、境、摘、摔、聚、蔽、慕、暮 162 | 蔑、模、榴、榜、榨、歌、遭、酷、酿、酸、磁、愿、需、弊、裳、颗 163 | 嗽、蜻、蜡、蝇、蜘、赚、锹、锻、舞、稳、算、箩、管、僚、鼻、魄 164 | 貌、膜、膊、膀、鲜、疑、馒、裹、敲、豪、膏、遮、腐、瘦、辣、竭 165 | 端、旗、精、歉、熄、熔、漆、漂、漫、滴、演、漏、慢、寨、赛、察 166 | 蜜、谱、嫩、翠、熊、凳、骡、缩`, 167 | 15: `慧、撕、撒、趣、趟、撑、播、撞、撤、增、聪、鞋、蕉、蔬、横、槽 168 | 樱、橡、飘、醋、醉、震、霉、瞒、题、暴、瞎、影、踢、踏、踩、踪 169 | 蝶、蝴、嘱、墨、镇、靠、稻、黎、稿、稼、箱、箭、篇、僵、躺、僻 170 | 德、艘、膝、膛、熟、摩、颜、毅、糊、遵、潜、潮、懂、额、慰、劈`, 171 | 16: `操、燕、薯、薪、薄、颠、橘、整、融、醒、餐、嘴、蹄、器、赠、默 172 | 镜、赞、篮、邀、衡、膨、雕、磨、凝、辨、辩、糖、糕、燃、澡、激 173 | 懒、壁、避、缴`, 174 | 17: `戴、擦、鞠、藏、霜、霞、瞧、蹈、螺、穗、繁、辫、赢、糟、糠、燥 175 | 臂、翼、骤`, 176 | 18: `鞭、覆、蹦、镰、翻、鹰`, 177 | 19: `警、攀、蹲、颤、瓣、爆、疆`, 178 | 20: `壤、耀、躁、嚼、嚷、籍、魔、灌`, 179 | 21: `蠢、霸、露`, 180 | 22: `囊`, 181 | 23: `罐`, 182 | } 183 | 184 | type regular struct { 185 | db fate.Database 186 | total int 187 | fixed int 188 | unfixed int 189 | } 190 | 191 | func (r *regular) Run() { 192 | e := setAllRegular(r.db, false) 193 | if e != nil { 194 | return 195 | } 196 | for _, strVal := range regularList { 197 | list := strings.Split(strVal, "、") 198 | if len(list) == 0 { 199 | continue 200 | } 201 | for _, ch := range list { 202 | r.total++ 203 | fmt.Printf("character %s is fixing\n", ch) 204 | if fixRegular(r.db, ch) { 205 | r.fixed++ 206 | } else { 207 | r.unfixed++ 208 | } 209 | } 210 | } 211 | fmt.Printf("fix regular finished(total:%d,fixed:%d,unfixed%d)\n", r.total, r.fixed, r.unfixed) 212 | } 213 | 214 | type Regular interface { 215 | Run() 216 | } 217 | 218 | func New(database fate.Database) Regular { 219 | return ®ular{ 220 | db: database, 221 | } 222 | } 223 | 224 | func setAllRegular(db fate.Database, regular bool) (e error) { 225 | engine, b := db.Database().(*xorm.Engine) 226 | if !b { 227 | return errors.New("wrong type") 228 | } 229 | if !regular { 230 | _, e = engine.Exec("UPDATE `character` set regular = 0") 231 | } else { 232 | _, e = engine.Exec("UPDATE `character` set regular = 1") 233 | } 234 | if e != nil { 235 | return e 236 | } 237 | return nil 238 | } 239 | 240 | func fixRegular(db fate.Database, ch string) bool { 241 | char, err := db.GetCharacter(fate.Char(ch)) 242 | if err != nil { 243 | return false 244 | } 245 | char.Regular = true 246 | engine, b := db.Database().(*xorm.Engine) 247 | if !b { 248 | return false 249 | } 250 | update, e := engine.Where("hash = ?", char.Hash).Update(char) 251 | if e != nil { 252 | return false 253 | } 254 | if update == 0 { 255 | return false 256 | } 257 | return false 258 | } 259 | -------------------------------------------------------------------------------- /fate.go: -------------------------------------------------------------------------------- 1 | package fate 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "github.com/godcong/fate/config" 8 | "github.com/goextension/log" 9 | "github.com/xormsharp/xorm" 10 | "strings" 11 | "time" 12 | 13 | "github.com/godcong/chronos" 14 | "github.com/godcong/yi" 15 | ) 16 | 17 | // HandleOutputFunc ... 18 | type HandleOutputFunc func(name Name) 19 | 20 | // Sex ... 21 | type Sex bool 22 | 23 | // SexBoy ... 24 | const ( 25 | SexBoy Sex = false 26 | SexGirl Sex = true 27 | ) 28 | 29 | // HelpContent ... 30 | const HelpContent = "正在使用Fate生成姓名列表,如遇到问题请访问项目地址:https://github.com/godcong/fate获取帮助!" 31 | 32 | // Fate ... 33 | type Fate interface { 34 | MakeName(ctx context.Context) (e error) 35 | XiYong() *XiYong 36 | RunInit() (e error) 37 | RegisterHandle(outputFunc HandleOutputFunc) 38 | } 39 | 40 | type fateImpl struct { 41 | config *config.Config 42 | db Database 43 | out Information 44 | born chronos.Calendar 45 | last []string 46 | lastChar []*Character 47 | names []*Name 48 | nameType int 49 | sex Sex 50 | debug bool 51 | baZi *BaZi 52 | zodiac *Zodiac 53 | handle HandleOutputFunc 54 | } 55 | 56 | // RunInit ... 57 | func (f *fateImpl) RunInit() (e error) { 58 | if f.config.RunInit { 59 | if err := f.db.Sync(WuGeLucky{}); err != nil { 60 | return err 61 | } 62 | 63 | lucky := make(chan *WuGeLucky) 64 | go initWuGe(lucky) 65 | for la := range lucky { 66 | _, e = f.db.InsertOrUpdateWuGeLucky(la) 67 | if e != nil { 68 | return Wrap(e, "insert failed") 69 | } 70 | } 71 | } 72 | return nil 73 | } 74 | 75 | // Options ... 76 | type Options func(f *fateImpl) 77 | 78 | // ConfigOption ... 79 | func ConfigOption(cfg *config.Config) Options { 80 | return func(f *fateImpl) { 81 | f.config = cfg 82 | } 83 | } 84 | 85 | // SexOption ... 86 | func SexOption(sex Sex) Options { 87 | return func(f *fateImpl) { 88 | f.sex = sex 89 | } 90 | } 91 | 92 | // Debug ... 93 | func Debug() Options { 94 | return func(f *fateImpl) { 95 | f.debug = true 96 | } 97 | } 98 | 99 | //NewFate 所有的入口,新建一个fate对象 100 | func NewFate(lastName string, born time.Time, options ...Options) Fate { 101 | f := &fateImpl{ 102 | last: strings.Split(lastName, ""), 103 | born: chronos.New(born), 104 | } 105 | f.lastChar = make([]*Character, len(f.last)) 106 | if len(f.last) > 2 { 107 | panic("last name was bigger than 2 characters") 108 | } 109 | 110 | for _, op := range options { 111 | op(f) 112 | } 113 | 114 | f.init() 115 | 116 | return f 117 | } 118 | 119 | // RegisterHandle ... 120 | func (f *fateImpl) RegisterHandle(outputFunc HandleOutputFunc) { 121 | f.handle = outputFunc 122 | } 123 | 124 | func (f *fateImpl) getLastCharacter() error { 125 | size := len(f.last) 126 | if size == 0 { 127 | return errors.New("last name was not inputted") 128 | } else if size > 2 { 129 | return fmt.Errorf("%d characters last name was not supported", size) 130 | } else { 131 | //ok 132 | } 133 | 134 | for i, c := range f.last { 135 | character, e := f.db.GetCharacter(Char(c)) 136 | if e != nil { 137 | return e 138 | } 139 | f.lastChar[i] = character 140 | } 141 | return nil 142 | } 143 | 144 | // MakeName ... 145 | func (f *fateImpl) MakeName(ctx context.Context) (e error) { 146 | log.Info(HelpContent) 147 | e = f.out.Head(f.config.FileOutput.Heads...) 148 | if e != nil { 149 | return Wrap(e, "write head failed") 150 | } 151 | e = f.RunInit() 152 | if e != nil { 153 | return Wrap(e, "init failed") 154 | } 155 | n, e := f.db.CountWuGeLucky() 156 | if e != nil || n == 0 { 157 | return Wrap(e, "count total error") 158 | } 159 | 160 | e = f.getLastCharacter() 161 | if e != nil { 162 | return Wrap(e, "get char failed") 163 | } 164 | name := make(chan *Name) 165 | go func() { 166 | e := f.getWugeName(name) 167 | if e != nil { 168 | log.Error(e) 169 | } 170 | }() 171 | 172 | var tmpChar []*Character 173 | //supplyFilter := false 174 | for n := range name { 175 | select { 176 | case <-ctx.Done(): 177 | log.Info("end") 178 | return 179 | default: 180 | } 181 | 182 | tmpChar = n.FirstName 183 | tmpChar = append(tmpChar, n.LastName...) 184 | //filter bazi 185 | if f.config.SupplyFilter && !filterXiYong(f.XiYong().Shen(), tmpChar...) { 186 | //log.Infow("supply", "name", n.String()) 187 | continue 188 | } 189 | //filter zodiac 190 | if f.config.ZodiacFilter && !filterZodiac(f.born, n.FirstName...) { 191 | //log.Infow("zodiac", "name", n.String()) 192 | continue 193 | } 194 | //filter bagua 195 | if f.config.BaguaFilter && !filterYao(n.BaGua(), "凶") { 196 | //log.Infow("bagua", "name", n.String()) 197 | continue 198 | } 199 | ben := n.BaGua().Get(yi.BenGua) 200 | bian := n.BaGua().Get(yi.BianGua) 201 | if f.debug { 202 | log.Infow("bazi", "born", f.born.LunarDate(), "time", f.born.Lunar().EightCharacter()) 203 | log.Infow("xiyong", "wuxing", n.WuXing(), "god", f.XiYong().Shen(), "pinheng", f.XiYong()) 204 | log.Infow("ben", "ming", ben.GuaMing, "chu", ben.ChuYaoJiXiong, "er", ben.ErYaoJiXiong, "san", ben.SanYaoJiXiong, "si", ben.SiYaoJiXiong, "wu", ben.WuYaoJiXiong, "liu", ben.ShangYaoJiXiong) 205 | log.Infow("bian", "ming", bian.GuaMing, "chu", bian.ChuYaoJiXiong, "er", bian.ErYaoJiXiong, "san", bian.SanYaoJiXiong, "si", bian.SiYaoJiXiong, "wu", bian.WuYaoJiXiong, "liu", bian.ShangYaoJiXiong) 206 | } 207 | 208 | if err := f.out.Write(*n); err != nil { 209 | return err 210 | } 211 | if f.debug { 212 | log.Infow(n.String(), "笔画", n.Strokes(), "拼音", n.PinYin(), "八字", f.born.Lunar().EightCharacter(), "喜用神", f.XiYong().Shen(), "本卦", ben.GuaMing, "变卦", bian.GuaMing) 213 | } 214 | } 215 | return nil 216 | } 217 | 218 | // XiYong ... 219 | func (f *fateImpl) XiYong() *XiYong { 220 | if f.baZi == nil { 221 | f.baZi = NewBazi(f.born) 222 | } 223 | return f.baZi.XiYong() 224 | } 225 | 226 | func (f *fateImpl) init() { 227 | if f.config == nil { 228 | f.config = config.DefaultConfig() 229 | } 230 | 231 | if f.config.FileOutput.Heads == nil { 232 | f.config.FileOutput.Heads = config.DefaultHeads 233 | } 234 | 235 | f.db = initDatabaseWithConfig(f.config.Database) 236 | f.out = initOutputWithConfig(f.config.FileOutput) 237 | } 238 | 239 | //SetBornData 设定生日 240 | func (f *fateImpl) SetBornData(t time.Time) { 241 | f.born = chronos.New(t) 242 | } 243 | 244 | func (f *fateImpl) getWugeName(name chan<- *Name) (e error) { 245 | defer func() { 246 | close(name) 247 | }() 248 | lucky := make(chan *WuGeLucky) 249 | go func() { 250 | e = f.db.FilterWuGe(f.lastChar, lucky) 251 | if e != nil { 252 | log.Error(e) 253 | return 254 | } 255 | }() 256 | var f1s []*Character 257 | var f2s []*Character 258 | for l := range lucky { 259 | if f.config.FilterMode == config.FilterModeCustom { 260 | //TODO 261 | } 262 | 263 | if bool(f.sex) && filterSex(l) { 264 | continue 265 | } 266 | 267 | if f.config.HardFilter && hardFilter(l) { 268 | sc := NewSanCai(l.TianGe, l.RenGe, l.DiGe) 269 | if !Check(f.db.Database().(*xorm.Engine), sc, 5) { 270 | continue 271 | } 272 | } 273 | 274 | if f.config.StrokeMin > l.FirstStroke1 || f.config.StrokeMin > l.FirstStroke2 || f.config.StrokeMax < l.FirstStroke1 || f.config.StrokeMax < l.FirstStroke2 { 275 | continue 276 | } 277 | 278 | if f.debug { 279 | log.Infow("lucky", "l1", l.LastStroke1, "l2", l.LastStroke2, "f1", l.FirstStroke1, "f2", l.FirstStroke2) 280 | } 281 | if f.config.Regular { 282 | f1s, e = f.db.GetCharacters(Stoker(l.FirstStroke1, Regular())) 283 | } else { 284 | f1s, e = f.db.GetCharacters(Stoker(l.FirstStroke1)) 285 | } 286 | 287 | if e != nil { 288 | return Wrap(e, "first stroke1 error") 289 | } 290 | 291 | if f.config.Regular { 292 | f2s, e = f.db.GetCharacters(Stoker(l.FirstStroke2, Regular())) 293 | } else { 294 | f2s, e = f.db.GetCharacters(Stoker(l.FirstStroke2)) 295 | } 296 | 297 | if e != nil { 298 | return Wrap(e, "first stoke2 error") 299 | } 300 | 301 | for _, f1 := range f1s { 302 | if len(f1.PinYin) == 0 { 303 | continue 304 | } 305 | for _, f2 := range f2s { 306 | if len(f2.PinYin) == 0 { 307 | continue 308 | } 309 | n := createName(f, f1, f2) 310 | n.baZi = NewBazi(f.born) 311 | name <- n 312 | } 313 | } 314 | } 315 | return nil 316 | } 317 | 318 | func filterSex(lucky *WuGeLucky) bool { 319 | return lucky.ZongSex == true 320 | } 321 | 322 | func isLucky(s string) bool { 323 | if strings.Compare(s, "吉") == 0 || strings.Compare(s, "半吉") == 0 { 324 | return true 325 | } 326 | return false 327 | } 328 | 329 | func hardFilter(lucky *WuGeLucky) bool { 330 | if !isLucky(GetDaYan(lucky.DiGe).Lucky) || 331 | !isLucky(GetDaYan(lucky.RenGe).Lucky) || 332 | !isLucky(GetDaYan(lucky.WaiGe).Lucky) || 333 | !isLucky(GetDaYan(lucky.ZongGe).Lucky) { 334 | return true 335 | } 336 | return false 337 | } 338 | -------------------------------------------------------------------------------- /statik/statik.go: -------------------------------------------------------------------------------- 1 | // Code generated by statik. DO NOT EDIT. 2 | 3 | // Package statik contains static assets. 4 | package statik 5 | 6 | import ( 7 | "github.com/rakyll/statik/fs" 8 | ) 9 | 10 | func init() { 11 | data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\xe5DeO\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x00 \x00dayan.dataUT\x05\x00\x01/5\xc1]\x00g\x0e\x98\xf1x\x9c\x9cZ[\x8f\xe2X\x92\xfe/\xf9\xdc\x0f\xd3u\xed\xee\xd7}\xdd\x9d\x97}\\\xed\xc3\xec\xaaVZ\xcd\xf6\xac4;-\xedh\xb5\x12\x86\x04c\x8c\xb1\xc9\xca\xc4`C\x92db.I&\x97\x84\x04c\xc0\xfe1\xed8\x97\xa7\xfa\x0b\xa3s\x0eMb\x9b\xe9\xac\xb6TBe\x07*\xbe\x8a\x88\xf3\xc5\x17\x11\xe7_\xfe\xef\xec\xf7?\xfd\xf8o\x9f\xfe|\xf6\xc3\xb7\xdf\x9c\xfd\xe3O\xff\xfe\xc7\xbf\x9e\xfdp\x06\x86r\xf6\xcd\xd9?\xfd\xe1\x7f\xcf~\xf8\x8f?\xfc\xd7\xff|\xfa\xe6\xec\x9f?\x1d\xfd\xfd\x8f\x7f\xfd\xfd\x7f\xfe\xe9\x13\xfb^\xf7\x1e]K\xe1ZEW\xd3\xb3o\xce\xfe\xe1\xbf\x7f\xfc\xf1\xd3\x9f\xfe\x123|\xd9\x96CW\xc6\xca\x10\xb6\x194g\x8f\xf8\xb2\x0dz\x15\x997x\xb8\xfa\xb2-Cq\x88{\xe7\xa17\xa0\x19\xeb\xe7L\xf6\xec\xff\xbfy\x01\xf5\xe6\x08\x94\xbc\xfc*P\xa1\xdb\x0d7\xf7'@\x1d\x1b\xbel\xcbh\xb5BOe\xd4\xbc\x87m\xe6\xcb\xb6L\x02\x9bf2a\xd0\x82q\x91\x81\nL\xd4\xb4\xa9\xe5\x13\xdf\x8f\x83z\xfb\xdb=\x15\xba\nR\xb4\x93\xa0^\x0c\xecg\xbbChNC\xcf\x83\x8b2\x7f\xec\x87\x9e\xca>]\x8b9n-\x11\xed\x0e\xd5\xcb\xd4*\xc4A\xbd\xfb\xed\x9e\x02\xdb&\xb3\xce\xa9\xf0\x1d\x19\x18\n?\x1fz\x15\x115\x11\xcd\xd0SQ\xbeBe\x8d?j\x90_\x11\xc3!S5\x0e\xea}\nOy\x97\xa4S>\xe5)a\x08f\xa8\x95\xe3\xa0\xeeqe\x82m\x17_\xb6\xd9c\xb3@3\x16\xbe\xca\x13\xdfg\x9e\xea\xe9\xd8QD\x8a\xc5A}H\x91\xe8\xf9G\\\xdc\x9c\xf2\xd4\x91\x81\xa1\xd0\xab0\xbb\x02\xbd\x0e\xe5\x9a\x88&yV\xb1_\x01\x9f'\xba\xa1`\xc7\x81\xb1\x82\xe6\xd38\xa8\x8fir*\x87.\x83\x939\xf5b`\xbex\xf2QV\x0b]\x87L\x07\x07P\xe1Z\x85\x92-@\xa1z\x1b\xe7\xfb$\x93\x89\x83\xfa\xee\x08\x94V\xfazg\x8d@\xeb\x9dt\xd6\x8b\x81%\xce\xda\x87V\x85(c\xda\x94\x19\x90\xd5\x0e\xf76\xd0\xeaB\x9ee\x99\x88\x1d2o`\xba\x8b\xe3\xfa>E\xaew\xfb\xa8h\x9c\xa4\xaa\x17\x03\xa3\x81\xab\x05Z>\x83\xbc\xa4\x8d!CQ\xac\xa1\xa2\x81\x8a5\xb2p\xbel\xcb\xd4\xf2\xc3\x8d\x83J%\xa4w\xe2\xa0\xbe\xfd\xddoG\x857E\xbc\xf9|\x02\xd5\xb1\x81\xfd\xae}\x8f,\x93\xde\xd5\xa9\xbdd\xae\x92\x96\x0cXSAE\x83=\xda\xd7\xb4\xe3\x93\xf2\x08\x9f/\x13\xa8R\xd0:2gD5i\xe6\x96\xda\x83Xb1\x1eG\xf6\x02\xd5\xb8\xaf\xa69\xda\xf1@\xaf\x8a3\x87\xa4[\xd8\xd6\xd1|\x17\xba\xb5\x03Y\xc1\xa4L\x16\xcf T)x\x1dU\xea\xa1w\x85\xcc\x1b4W\"\xa8X\xa6\x18\x85\xd8\x19$\xb5s\xd8\xce\x18\xc8\xc6\x0e_\xb6CW#\xcb\xb9\x88 \xcd?@`\x82QM\xa0JA\xec\xa8\xee \xd3\xc1J't\xd7QT\x8aF\x14\x0f\xba\x16\xc9\xed\x98s\x1a\x1e\x99\xaa\xe0\xc8\xf8\xca\xe1\xe5EC\xedK\xd8}\x0e=\x95\xa1r\xef\xc0\xd1\xa1\xdb\x87R;\x81*\x05\xb3\xe3\x9b\x05\xe4\x0b\xd1<\x1f/\xc1{\xc4\xdb:\xa9\x9d3\x00\x8f]\xac>P\xe9\x91Z>\x0f\xa5\x1az*\xf3\x92\x08e\xf6 \xe5\x06\xa1\xab\xa1\xe7\x04\xa7\x7f\x9b\x82\xd4qO\x87I\x10\xcdp\xfe\n\x9a\x05\xb4\xe90<\xa6c\xcd\xa2\x05[/\x9aB\xad\x1c\x0c$a`\x07\xea^\xc27\x8b\xd0\x95E\xc8\xa0\x97%\xb9\x1d\x8c\xd7\x10h<\xa3\xf2\xa4\xb2b\xa8N\xa4P:\"\xa7\x9f%z\xd5\xa4\xb2\x86\xef\x06'\x80\xa1\xba/\xb2\x054\x0b|\x93y\xa38\xe4\x82\xe0\x12\xf2\x1b\x96\xde\xc2\x93\xbf\xe6\xabTLnQ\xcb\x8f\xe0\xa1w\x95\xd0\xab\x92\xcb\x1d2\xd9\xe1\"\xbeM\xd4\x1e\x955\xd4r\x04\x030\xaa\xe4\x07\xf0E\xbe\x94G\xa8TO\xc8\xcd\x14\x1c\x0e35tUb\xeaT\xaeFQ\xb5\xaeC\xd7\xc27\x0b\x120\x96\xc6\x92\xcf\xc8G\xd6\x84l\x12z\x13o\x16d\xba:\xa0\xa2\x96\x8f\x8aF\x02\xd5\xeb\x1c\xfe\x97?\xff\x14\xa3\xa5\nj\x16C\xf7\x11\xba\xc3X\x0dV\xe8]\x856%\xd4,\x1e\x949\xee\x8c\xf1H\xe5Y_'\x81!\xa4\xb8\x90\x9f\xc8\xd0E`\x7f\xced\xc1\x99\xa3L\x9f\xe9\xbdq\x13=v\xd1UB\xc5\xbcI\xc1\xeb\xb8\xaf\x12Ma\xd5\xa6\xd9\x8c2\xc4\x91\x81W\xb9)\xb5|\\\xf3\x0f\xbc\x0e\xb2Gf\xf7\xa8\xc5\xc5\x84\xe7\xe1\xcb6\x9a\xdf\x9e\x8a\xea\xeb\xbc\x1e\xf7\x1f\xdc\x8dCw\x17+3\x8f\xc8tB\xb7 \x1a\x97+\xfc\x1bp7&\xfd,#,q$L\x0f\xdb\xb6Hz04Fg\xbc}\xf8\n\xcf\xbdKQ{*ub\xea\xe0\x9b\xf1\xcc\x83\xf1\x92\x9a\x83p\xd7\x00\xaf\xc0\xaa\x8b\\\xa5\x17\xb3\xd0\x9db\x9b\xc5\x1c7vHQ\xd9\x99\x1c/\x05\xb5!\xcf\x80u@\x02;\x81\xea}*\xe2 \xda]\x18\x94\"\x90\xc8\xf39\xca\xf4\x89:CW\x8c\xd0Yu\xcc\xedX9T\xd6\xcc]y\x1555\xc8>\xa1\xfc-{\x9cZ\xa0ONs\xd9\x9b\x0f)\x8e\xa8^G\x99\xfb\xa8\x8b\xf8\xabp\xad\x92)K.\xa2\xce\xa8}~\xc8&\x96G>c>\xd0o\x985S\xfe\xbb\xe5\xf9\xcd\xc7\x14xn\xaf\xe9U\xb4\x1c\xa2\x87'\xd4\xb4\x99\xbayd\x1e \xf2=*Va\xeb\xe1\x1c\xefF\xbb\x16\xe8&\x9aHd\xda}\xcd?\xdf\xbd\x8a'\x9e\xec\xb4~\x89\xa6\x0b\xf4<&F\xb4&\ny\xf0\xa2\x8d\xb9{\xd0\xf4\x12\xf5\xb2\xfc@\xda\xe8y\x85\xb6Y4/\xb1\xb4\xda\x14C\xb7\xc6\xfe\x15O\xfa\xba\x94\xff>E\xcas\x16\x8fz\x8e\xbf\n\xb7u\xdc\xcf\xec+u\xc9\x86\xdd\x05\xb5\x0b\xbc\xbd\xd1\xa8\xb9A\xcf+(\xe4\xb9\x9e7`:\x13\x0du\xa2\xad\xff]\xba*\xd9\xba&\x81\x11\x85\xf4\xa4\xa0\xe71\xff\xbfs\x1a\x95\x97`(\xd4\xf2A\xaf\xf3\\sP\xbd\xc2>-sO\xb2E\x03\xba}\xb2p\x12\x90\xd2\xa8w\xaeHIi\x06\xdbL\xdcQ\xa0\xca\xacR\x07f\xb2j\xe3M\x9b\xde\x16\xc2\xad\x19z\xde+\xea\xfd\xed\x9b\x14\x8ak\xdc\xa2\xc3\x07\xc6D\xd7\xd1\x1c\x0b}\x07\xd6.t-\xd4\xb4y\xf8\x9eC\xcfc\xc0J\xc3}4]\x9bI\x9d\xbb\xab\x03*\"\xcfC\xb7\x94@\xf5\xdbY^P:hr\xbcJ\x1e\x1b\xb8<\xf7A\xeeb\xdb\x0d\xb7\xd6!\xa7\xa0;\x0c].\xde\xad\x02\xaa\x97\x89d\xb7\x83q\x0b=)\xa4\xd8f0\x8e\xbe'\x94\x16\x13a\xd3\x16Lw\xe2\x91\x15\x9f\x93\xa4\xf5.\x0d\xc7g\xd7\xb8=gT\x1aG\xc5\xb5\x18+\xd4\x9c\x93D\xab\x7f\x08\x16v&\xd8q\xc0PD\xb3&\xc6\xf3\xb0vqOO\xa0\xfa.\x85\xf0\xd2\xbb\xa8\xe5\xe3\x91J\xd7\xdd\x13\xbc\x05\xf9-t\xe5=Q\xc8\xba\xe8X\xd9\xe3@b\xc5\xbdh\x80\xcbi\x95\x97h&R\xfb\xd9\x04\xaat\x04Ov\x0f\xa0\xd7\xa3T`(\xa1\xbb\x80b\x03\x0cE\xe8f\xd4r\xd8\xa3\xcc\x1b\xd5\xdd\x03\xc8\xcb\xd0\xf5\x84\x95\xe65pvb\x7f\x96\xd8;\xa5\x93\xf20\xd5I\xb1\x0dy\x07=\xafb\x83\xef\x0c\xd3\x02nF\xac\x01X\xb0\xe4%\xe8Y\xd0J\xbc{-2\x16\xf5d\xa2\x8d\xb8\xb5B\xa5G\x90\xcfQn\x90\x00\xf6m:Q\xc3\xabH\x94\x10l\x9bt\xa6\xa1\xd7\x85\xd2M\xb2c\x15\xb4\x89\xf2\x15\xe8\xab\xaf\x0c\x07\xdf\xa7P\xf3\xc4\xf7qs\x1b\xa3\xf1\xcfdR\x10\x06\xe1\x13\xd2\xe7\x1b\xe0z\xe5@\x08d\x99\xc7~W(h(\x0eA/\xa3\xcb\xc4\xc6\xe2}\x1a\x1a\xb7\x9f@[Q\xcbG\xf5vl\xbbSc\x87\xab\x90G\xd9;~\xb8j\xd8q\xa1\x90\x87\xb1\xb2\x0f\xdc\x84\xc5\x8b,F{\xcc\x8b\x11\x18\x95\x13\xf2\xea}\x1a\x1ao\xb3>\x05\xdd\xecHi\x16\x8d\xdd\x91A\xec$\xc07\x19\x11-6'\x9d2)\xc6\xc2W)\xc0tG\x94)\xf1m1q\x80\xea\x80ZM|\xab\xbd\xccL\xfd\x1c\xf5\xf9\xb2\\\xb2\xfe\xee\x08\xf5}\n>G\xa6\x83\xf3}\xd6N\xb7\xfc\x98\x02\xbd\xa0\xf6=m]\xa0\x16\xa7\xcan\x93T<0\xda\xa8.V;y*=2\xae\x08\xe4C\xcb\x8a\x1b\xbb\xd0K\xae\xc7\xd3iv\xd4\xb0H\xa7L%9\xd1{q\x9a\x80\xae\x85G\x93}>\xab=0*\xf8\x92\x0fP\xc7;\x18\xeb\xacF\x1b\xda+E\xf9}\x9a\xb9<\x17x(\xfb\x14\x97\n\xc7\x06\x96Z\xa2\xb1\xe8Li\x86 T\xbc\xf5\xc2\xb5\x0e\x81F2\x06\x1f\x8e\xf4\xa8\xe5\x87\xae\x16n\x13\xfb\xb9\x0f)\x04;2o\x12\x03#\xfe*\\\xabb\xd2!\x06X\x07\x85\x8e\x1a=d\xb5\x90e\xd2\x0d\xd7\x0c\xa5\x01\xaa\xca\xdc\x9a\x10\xec\x1fRLg\xc4\xa6\x90\x94\x1a\xe4s\xb4\x8d860?p\xcd b\x14#L\x1eJ+\xf4FB*$P\xa5\x10\xe7\xa43%\x0b'*Z\xf8\xab\x83ha\x9c\xd9\xad1?\x88\x8b)G\xd7c\x0e\xd3\x05z[E\xad\xc4\x0c\xebC\x8a\xad*\xab\xc2\xbb\x0bX\xcf\xe3\x858\xde\xfcy#\x08r\xe2F\x05_\x93\x0fh\xf3 \xe5n\xd0|w\xe0\x87\xd3\x17\x8b>\xa4\xe0s\xda\xba\x86jt)@\xef\x07$\xab@\xb1\x80{\x9b\xc3V\x15e\x9f\xd0\xb9t v\x81\xf0@P\xa1\xab\x9d \xa8\x0f)d9\xac\x06\xe8Y\x82\xddE\xc2K\xdd!\xbd\n\xa09\x0d\xd7\xbc\x87\x1a/I`\x881\x95\xb8\x1b\x03\x93\x00o\x9e\xe9U\xb0\xef\x1d\xd9x~LyQ\xe6\x97\xaf\xc6\xef6\xb1\x06*\xdb\xe3SM\xf6\x0d\xf6)\xe6\x06\xb9\x1dk~\xf5\x05*\xb1\xde\x936V\xc4\xd81\x84\xebdn\xbf\xbe<=\xa9\xc6cg\x0d;.+\xb2\xc7\xf3\x81\xee\x90QzN\xc8\x92GX/^\xae\xcd ^\xb2\xa7\xa7\xd82\x05{\x87^\x95\xd5\xdf\xe4f\xe6\xd8 \xb4\x13\xae=A\xc9\x16\xd30<\\\x91`\xc4\x85\xb7{`x\xa1\x8a\x13\xd7B\xd3\x0c\xce%)\x1e5qvDc\xcbSw\x08y\x87Z\x06\x95\xa4\xfd\x05\xac \x87G*T\xf9\xb0\xae\\\x03yIv\x0f`$\x8e\xffw)t\xf8\xfeJ\xba}\x8d\xeaQ\xdd\x8b\x9a\x190\x94\x97\x9dwPG\xcd\x07&F\xf3\xb9\xc3\x15\xde\x971\x0b\xd7\x03\xe2\x96\x18G\xf5\xaf\x7f\x03\x00\x00\xff\xff\x01\x00\x00\xff\xff\xecC\xf9\x0c\x01\x00\x00\xff\xffPK\x07\x08eCc q\x0e\x00\x00g\x0e\x00\x00PK\x03\x04\x14\x00\x08\x00\x08\x00\xb7\x80fO\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00 \x00gua.dataUT\x05\x00\x01Z\xef\xc2]\x00\x8f!p\xdex\x9c\xac}Ko\xea\xda\xb6\xe6_)\xa5\xbdK\xaa\xfb\x96N\xb7TuK%U\xeb4\xee\xd9\xcd\xdd(\x9d\xb3:\xfbJ%\xad\xd6\xd5\x950\xc4\xb1\xcd\xc3@Bp\x08\x90\x84\xf0\nIxx\xc1\x02c\xb0\xf91\xcbcz\xba\xb5\xfeBi\xcei\x8cyz\x82wo-\xc2\xc4\xaf\xcf\xe3\xf1\x8do\x8c\xf9\x1fW\xce\xdcv\xe6\xf6\xd5\x9f\xfe\xe3\xea\xcf\x7f\xfb\xed\xf7\xbf\xfe\xeb\xd7\xdf\xae\xfeD?4Lh\xf5\xae~a\x1f\xff\xf9o_\xaf\xfe\xf4\xdf~\xb9\xfa\xcb\x97\xdf\xf6\xbf\xf1\x97/\xbf\xad\xff\xfe\xbf\xbf\xfc\xe5\xcb\xbf\xff\xfe\xd7\xab?]AA\xb9\xfa\xe5\xea_\xbf\xfe\xf6\x97/\xbf\xd1\x0f\xc8Q\xe8\x07\xff\xe7\xcb\xfa\xff\xc1/\xfc\xeb\xd7\xdf~\xfdB\x16\x89)\xc7|\xfb\xb9\xcc\x82\xdc\xc3\x93'\xff/_\x7f'\x7fju\xe1Nq\xe66\x88\xa9\x9f\xcb\xaccH\xae\xd2\xc3\xdf\xaf\xa1\x9b!\xff\x9d\xa7\xdc\xc53\xb4z?\x12I\xc7,\xe2F\xd6\xab\xbe\xa1\xb2E~\xeaNp\x95\x1e\xfa.\x80\xf5\xfa#\x91\x84V\x17=\xa8\xd0\xcd\xb8\x0b\x99\xfcU\xec;V\x0eiS$\x17~.\xb3H\x9b:\xf3\x07\x10\xfb\x9e]q\x16m\xb0\x1b\xfeo\xcemO\xb8\x83\xfc\x03d\xcbdU\xe1\x1a\xf5\x9b(\xd1\x85\"9\x84\xb3\xaaCA&gx\x9be'\xc3\xce\xffG\"\xe9u\xca \x99`N]\xa5\xc7N\x1b\xaa\x16\xdc\x1a0\x10\xd8\x9d\xfb\xfd\xaf\xbf~\xfd\xbf\xf4\xfaz\xb8\x91\x05\xa1M\x7f\xbe\n\xfd\x82\xb3hc\xe9\x1d\x96\xa6c\xe4\x900\xbc\xfa\xe5\xea\x7f~\xfd_\xbf\xfd;\xb9u\xb3\xc4\xd5/W\xff\xfdo_\x7f\xa5\xffEV\xcd\xb3+\x90Y\xb9%r\xef\xbc\x871\xd4\xde\x1c#\xe3\xcc\x9f\x83\xaf\x85\x1e\xcc||\xf5\xcb\xd5\xff\xf8\x7fl-\xee\ndm\xed\xcd-\x8d\xc8\x91\xed\x19*[\xa82`k\xe9\xb7v\x9f\xe9\x9f\x7f\xfb\x9d\xadu\x172\xd2\xda\x0c@dm>\x07\xad\x9c'\xdc\xb1\xb5\xeck\xbb\xc7\xfd\xf3\x17\xff\x9c\xe52\x9e\xa5\xa0\xf6\x86\x8c\xf4\xcfe\x16\xaf\xaaH{\x81[\xd5_\xfb\xe5\xc0\xd2\x7f\xf3/\xd7k>\xb1S\x86\x16\xb9\xa5\xd0\xea:\xa6\xe9%^\xd8\xd2\x7f\xfbz\xe8\x94 \x86\xd9j\xc7|\xf5\xec\n\xaa)(Y\xfa\xb9\xcc\xbaU\xd91r\x90\x1f:s\xd1?\xb6\xff\xdd\xdd\xc3\xff\xea\xff\xa7\xd5\x03{\xe6\xaf1L\xafSf\xcb\xc8\x9f7K\xfe\xeb\xd5\x7f\xferE\xc1Z<\xfb\xd5\x02\xb1\xe8\x18&\x1a[\xa1W\xeb\xef\xc2\xaf\xd6\xf6{\x05z{\xeb\xbd\x82V\x0f\x8d\xad\xe0S\xfa^\x85_\xa4m\xd8\x85P\x15\x86\x94;y\x01\xbd\xed\xcc3`'\xc8]\xca|\xe2F\x16]\xafx \x05s\xcb1M\xbd\x0c\x9c\xc4\x1e\x8e\x0c\xa4$\x1c\x93\xd8~ff\x16\xf1\xd5M5\x84\x99\x7f<\x81\x99nk\x173^S\x0d>\xbd\xd0\xa5\x8e\x17\x8e\xa9zR\x11=\x8b\xe4]~.y\xc2\x9d\xab|\xe7\xc2LVD5\xc5\xd3\x974\xbaT\xa8\xb9K\xc3\xc0\xe6\x02\x8c8%\xbe\xfb\xb3\xe1\x18$\xe0!\xff\xae\xbd\x07\xc7\x8d\x80\x8d\xf6\xe2\xe9\xcb\xc0\x93\xe2U\x0d\x8d\x8a\x87aC\xd7\xada\xe3\xcc\xeb\x8eY\x82\xc2\x87\xfb\xf1\xc2B\x00fj~.\xab\xe4:*o$\xb0e\xd1\xdbJ#\xa6D\xceA\xd1:\x0c*v5!Pu[\xe4\x92\xba\xb7\xf4\x87\xd3no\x06\x85\xfaQD\xd1\xd3\x8a@\x94\xdbY\x9c\x8d(\xb7\xb3p\x0c\xd3\x15>B\x88\xfa\xfbSV(\xeb\x98\xe6.\xa8\\\xe1#\xfc\x87\xcbp\x05\x92\xe9io\xecwh\x14.\xe3\x91\x10D\xd2\x11\xb8\xa2\xabH 4\xd0\xa8O\xa9\x07\xe1\xfb.\xa8\x18.\xd6\xa0r\x96y$\xab\x8e\xa9b\x95:\xa6\xfb,\x0b\x9f\xe83Q\xe0\x9b@\xdd\xe8\x84\xfc\xe6@\xd9\x98\x9a\x93`\xa3\x89\xd7\x14^\x15\x06rXj 2\xcfK<\xb8oi\xe5\nTG8A\x93\x0d\xb9\xc2\x13w\xb1K\x9cg@\x94\x03\xc7\xe7V'~\xa8\xd8\xea\x82!\xbbU\xc3\x13$\x02\xf0\xb7\x84[5\xd8ay\xa0\xb8\xbe}^*\xcd\xb0\x8cj\xef`k\xb1\xec\x1bV\x06g\xa3\x11+\x03\xf2\x0d]\x0f\xa1\xf1\x9f\x8f\xa3\xd1\x13\x84=\x9f\xa8\xeb\xc1\xa7\x97\xe1\xd0\x13\x04\x18\xd9\xe4F\xab\xeb\xc8\xc4N8\xd6\xbd+\xd8G\xa0H\x9f\xfe\x1a\x8aH\xe9\xba\xa57oq\xed*4 \xaf\x9a\xc44\xf0\xe4\x0b\xe3\x85'\x08\xc1qQMq\xcb6J}\xb0\x07\xec\xde\xd7\xb0\xd4\x84\x8e\xbd\x89\x97\xf2C\xea\xd52\\\xd1\x17\xcd\xc4\xa1my\x82@\xcej\x94g\xbe\x9b\x07x\x0f\x8a'\x08\x9b4h\xd1&\xaes}MQ\xae\x13'\xdb\x9e \xed\x85\x9c\xb1\xdc\xa3\xd4\xc4\x0bR\x12n\xb9\x18+\xe6\xf7j\xd2\xd9\xe8\xf2j\x12\xf1\x9e\xd5Y\x08]\xffp\x1c]$\xca\xe8\\\xef9\xd0\xea,\xfc\x87\x0b\xe3.\xfa\x0bAZ\n\xb6\x16\xdc\xd0\xc8\xa8\x1e'\xee\xb1:\xa3\x08y\x87a\x96\x87\xe0 \x86\xcb4\xc1\xd6\x18&\xbdd\xd11\xcd\x00\xcf\xa7\xad\x19\xe4\x87x\xf2\xb4\x89\xb8\xaa&\xaa)\xce<\xc3\x81\x9c\xe0*qn\x18`\x16\x0f\xef\xf9\x8c\xd2fu#KR\xf7\xde\xcc\x99g6'}\x81Q\x02\xb1\xb8O\x11\x86Y\x8a\x0dl\xfe\xee\x1c\x8ap\x1b6[\x80Ac\x8b\x18\xa5\xd6g\xcc<\x11\xa7j\xc4Y0\xb4\x1c\xf5\x89\xdb\x86\xa8\xa6 Y\x85\xcc\n -\x861\xc7\xe8s\xbaE\xdf\\\xb4>\xa1\xf5I\xee\xfdB\xdeb\xb5N\x03f;N\x0b\x87\xf7?\x97UO[\xe0\xb7\x04\xc9\x14V\x0d\xe2\xa8\x84w\x92\x05?\x1c\xe1\xcb\xb6\x831\xa3O~x\x8dD\x12\x8c\xd5\xdeAT\xf8\xe1\x94\x9f\x05!\xa0\xbb\x90\xc3\xc9\xf6\x85A\x17\x88\xc5}f,\x1aQ\x91\xcc\xd8>\xe9lXhLY`\xb1H\xdc\xfd\x9aXE\xb5\x0c\xe43x\xf0\xcd\x99\xbfl[\xaa\xd0!.\x0f\xc9n\xb3\xf4\x9d\xf1\xb3&?\xe4^[\xee\xd3\x96\n\xfa\x8f\xe1\xb5\xce\xaaq\xd4\x0fn\x1b+To\xfb\x0b\xf7X/\x8e\xd0\xab\x0e\xd5*Y[\xae1\x1f\xba\xe1\x96N\xfa\xb8\xfe# \x1e\x95vtn\xb8\xcbh9F\x1a\xc4>,\xefA,\xfaFy\x0d\xc9\x0bm\xd4>\x9d\xc5\x81\xa8\xf3\xe8\xac]\x1b\x85F\x13\xa8\x8ebAEl\x93;8\xb7\xf0\x88\xf8&\x98[\xe1\xf7\xfa\xb4\xa5\x82\xea\xc81U4\xb9\xf5\x9a\xcf\xeb\x17{\xf3\xe0NGM(7pL\xd5-\xdbX\xab\xd1x\xfba\x1d\xc0W\xfdS\x12\xa70\xf0\xd9 \xdc\x15\xc8\x7f;\x0b\xf6_\xb7\xdd\xe6J\x1e\xebm\xb0\x0b`\x17\x02\x86\x84\xd5$~$\x92\xb8b\xf9\xe0\xb4r\x0co\x8e\xc1c\xca }\x07ry'\xd4\xa6\xe5\x99\x14\xd8\x05TS\xf0pr \xc8\x97{n\xe9\xcdm\xf7\xdd6\xf5\x03y\xcd\xed\xe49yWz\x8bq\xb1\x8a\xb5g\x1f\xa5k\x1e\x19\xd2o(Y\n\n P\x08\xe59\x97\x02x\x97\x0d\xe3\x01\xf0Yl\xd8\x9e\x93\xad\x8dp!\x15\xcb\xc9\xceS\x94\xd8O\xe1B\xca\xcf\xd4\x88\xbd\xd2\xb9\xd2\xcf\xe5=\x14\x94]\xcf\x94\x7f\xe01w`'B\x0b\xd30\xb3\xb8\x9cl\xab\xbbu\xc4\x1d#y\xca\xd6\xe1B\x8a\xe0\x94\x02\xd6\x87\x1f\xaf\x0f\xc5\xdfsp\xfb\x86\xa6\xf7h\xb2F\xd1@q\x8ct<\x07\xba\xc7\x83q\xa0\xe5<\x1el\x17-^S\x85V\x17\xaf\xa48\x80\xc1\x9aB\xde\xc6\x8a\x85\xb3>\x0fvF\xb52!@\xeb\x03\xdacf\x8b\xf0Jr\x16m\xb7j\x04\xd6#\xc2E\xbedP\xa3\xb1q\x91\xac\x88G\xabK\xd8\x16\xb9l\xdaK\xc6{\xbc\xd9xg#G\x7fP\x0d\xce\xff$\x9b\x8a\x9e\x86\xa8\xfe\xe6\x96\x9eqZ\x0f\xf8PVx$F1!@G\x82\xda3\xb4>\x18\xc9NK\x8cEN\x8c\xad$4Uv\xaem\x13z^\x86\xb1}f,\x1acg2c\xbb\x18s\x85\x0f\xaf\xde\x8b\xe5Rg\xbd0\x93\x10~\xca\x8ear\xd9\xa5\x99\x8e\xb4\xb6W\xef9\xf3\xcc:~S\xe0A\xe1\xc1\x98W\xef\xd1@]\x81\x91\xce\xe88\xc7\xba'\x19\xd8s3\x1a]\xa59\xa5A\x0f\xc4~\x11\xb5\xc5\xaec\x9a\xb8\xa2B\xfe\x81\xd9`T\x96\xdc\xe4\x98\x97\xa5'A1\xd6\xe7\xe1\xd5\xb8\xf4\xe8\xbb9Jyx\xf5\x9eW\x7f%9p\xc3$\xdeu\xa1\x06\xd5\x8e\x0b\x9d\xdd>\xcd\x15\x0d\xadH\x9ak/\xfe\x07]w\x8c4q\xd2,\x0b\xb85\xc2Y\x00\xae\x8d\xde\x97\x1a\x88\xcb\xa3Nv\x9b\x03q\xc7\x0b\xc7\x90\x99\x0f\x83\x95\x86\xe5\x1c'\xcc\xbcGZ\xb2\xa7\x1c\x1d\x88Sg\xae\x804\xf51VSH^\\{\xf3\x84;\xf2\xb4\x1fTH?\xf3\xe7\xa7\x0fJ\xb8|\xe9\x18}>\xc3\x882\x0f\xe4b\xa8\x0f`\x95\xa6\x18\xce\xb4\xae\x1e\xe0\xd0B\xd9\xe7\x06]\xff\xf4Gqh\xa3 \xb4z^-\x11\x8b\xd5\xaf%\x82\xfa\x06I\xfd\xd2C\xef\xd1f\x89\x0e\x01\x18\xcd\xac\x90p\xcb\xf8i\x16T\x13\x0b\xd0\xd2\xc10x\xcc\x1d\xfb}\xf4\xadB\xfdl\x8e\x86\x82\xfd\x83*\x0e\x12\xe9Q\xd5\x0d\x97\x17f?;&\x16\xc9\x15\xec\xc0\xfc\x920KzGr\x11K\x13\x18J\xb4t\xf5\x89D\x95$\xb9\x13\xae\xac\x96\xfd2n$\x02g\x08\x85O\x1e\xd5\x9aH\xd2\xf4p9\xe0,\x01\x86\x91\xf3\x12\xcf$2\x18\xbc\xb2\x93&!\x85/B\xaa\xee\xa5\xd3\xef$\xcf t!\x97\x18\xc3\xbaz\x80\xa0\x8b\x84\xeb\x99\xd2\xb5]\xb8\xa2\xb1\x85\xd3\xc9\x98\x94/H&\x92g`\xf6\xc9\xa3\x7fn{\x89Gh<\xf1@\x91\xad\xf5\xb47\xb6\x16Z:\xd2\xa6\xe8I\xe0\xaa\x87\x1a9\x9cN\x92\xe7Cy\x82\x9d\"lD\x8di\xa0\xb0\xb5L\xfa\x8a\x94\x95c\xa472\xcaS \x85[z\xf0\x0f\xcb\xaa\xa3\xbaH3ZN\xfb\x863\x1d\x9cN\x12H\xd2\x94\x01\xc4\xa9'\xdc\xc5\xb5r\x07X\xb8h\xd8\xc4`\xe1\xc2kc\x90\x18/\x14\xf1m\xa8\xab\xec\xd1{\xc2\x1d\xf3>\xd1\xf5\x02\x9d\xc4\xc8`k\xfe\x9b'\x99\xc1\x03\x88\xa0\xe0\xeaT`Io\xd9\xa6X\x10\xf8\xb5\xd3\x99\xc2\x9b\xe5\x89\xb7\xee(\x83'T\xb6+?\xa2\xe7\x92W\x11y|\"\xb9a9\xb7*o\x18\x97u\xb0\x16\x15w\xf9\x9c-\xbd;\xe4\xa8\xd2\xd4/\xf6\xc7\x03\xcc\x1e\xeb\xc5\x01\x98\x18\xac\xd7h\x02\xb5\x11\x1a\x96b\x15\"\x87%\xf2\xec\xe4:\x88}\x9f0\x1f\xa4\x02\xdft:\xb2bk\xb1\xf4\x0e7\xa2\xcf\xafJ\xef\x81\xb5\x8e`0\xd8q\xb3\xef,\x8cw\x8c\x1c\x89\xf3\x97-g\xaerp_e\xb2\xdcT\xf1\xa4\xe5{ *D\xe4!.\x1el\xff\xc8{q\x14\xf1\xa8r\xceK\xdc@\xbe\xec5L\xf6\xf6\x80\x92s;\x16\xfb+\xab\x9a\x92\xab\x1c2:9\xedX+\xfe\x18\x8c\x1e\x16i/^\xa7\xbc)\x82/\xe4x\x90\xdb\xa7\xce\xa2!\x17\x87:\x1bM\xbc\xa6\xea\x98\xf7\xb1l\x94y\x8f\xc6m\x12\x08\xf8l\xbf\xcf\xa5#\xadK\xfe\xa4\xbd\xb8\x1d\x8bu0\x90\x90\x9b\xc3p9\xe6=\x1e\xcd`t\xed}\xcb\xb0[\xcb\x19\xe1\x93\xc3\x19\x1f\xc1\x99\xe0F\x16 \x0b\xffd\xf4\xa4\xabf\xd0\x83\xba\xc3\xb3\x9f\xf6\x80\x8ey\xef\x96R\x1bVv5p\xcc{\x1eS6\xbcEc\xc5\x99g6\x05\x10\xde\x80\xea\x80\xa0Z.\\\xae\xac\x80\xbaz\x80+\x8b\x04U,\xael4q\x85\x0f\xa4\xbd\xa2\xefj,SV\x1d\x93d\xda\x1a0\xd9U\xb8`\x1d\x15/\xa5\x90\xd6f\x8e\x8f\x85\xb3G\xab\xe4\xdb\x8e\x8f8\x8d\xf9\x84\xaa\xac(\xf0R\x1f<.\x8fu\x9b \xf9\x96\xd9\xdb--\xcc)\x908F\xcdK.P=\xb1\xa1\x03;I\xdc^y\xc9\x05\xb5,~\x8a \x83'\xc8k N\xddN\x9e\x95s\x08&\xeamN3\xb5j\x90\xf0\xa9S\xf6\xc5O!f\xf7r3u\x80\"\x8bD\xd4\x99J\xb0=\xcf\xa8\xebx\x1e\x8b\xde\x07;\x81\xe7\x12\xaa\xb7\xf1;\x0dI\x075XS\xeb\xa7\xe1\xe4\xaa\x19,5\xf1\\\xc2si\x13\x0e\x8d\x8e\x88\xa2wt\x17\xeb\x83B\x9e\x96gnD(\xd76b\x9b\xd3\xe1wp\xc2+\xaa\xab\xa7Y\x14\x0c\x9ex\xca\x91\xad.YZ\xcb0\xea\x8b\xbd\x044 \xe72A\xeb\x03\xbb\x8d\xfb\x0dKx#\x06\xa95\xee\n\x8c\xd9\x0d\xbc5\x9e|\x8fe\xa3\x0e\x10\\\x91\x88\x8aEp\x8d&^u\x06\xfa0V\xc1\xa8b\xb9\xd5\x07\xd4\xb8\x0b\x84\xeb\x81\x98\xd8Y\xb4\xc9-12x\xa23+\x0e\xb6\x16H\x94#H~\xb1\xef\x98Y\xe2<\x1e\xed\xdd\nxN\x80\xf9\xc4\x99\xa7\xa0\xaf\xf9\x8dmk6#\x82\x80\xcd\x8d\xbd\xf9\ni/\xb8\xf2\xe4S\x16\xe6\xf7 \x12\xf2\x89v\xe2\x9d3TY\x94\x80B}-\xd1\xe2\x88\xf9\xf5d\xa0e:\xaa\xfc\xd9V\xef\xebCb\xdao\x88ACe\xeb,\xd9\xcf\xb8\x89\x1b 4}\x86N\x92K\xba\xcfa\xd0Z\x87\x18\xb0M \xbf\x81\xdf\xbf\\\xce\x80\xa1\xf1h;=\xac\x8dhC\\,\x91\x06k\xf7\x00[\xd8j\xf78\xca\xe7o\xeby\xb2\"\xce\xdd\xfab\xc5\xd1\xa3c\xaaL\x8f\xc5\xe0\x11\xa6\xca#\"\x7f\xed\x05\xec\x04\xe5o\xa9\x89\xa3m,\x9b\x8c\xef\xa4\x89sW=w\xd5#k\x87T\x12\xf8xCbtj\xe2\xc8Kd\xe4\x90|KN\xa6\xff\xc8\xa2(X\xa5\x82^\xbf\xd3\xbeu\xd1v\xdb\xca\xa6\xab\xc8\xe8\x9372\xd4)\x18i\x03\x9fUh\xe5\x1cS\xf5\x1es\xbez\xa0h\x05\xea\x81\x0bav\x88\xb9\x8a\x82\xd9\x99\xcc\x95cLva\x86\xc6V\xf0\xe9\xc55#\xc7\x98\x84\xbb\x8a\x02[\x17\x0d3\xba\x96\x05.[\xaa\xe1\xda\xbb\xd70\x83\xe6\x8a\x88\x86\xde\xd2\x03\xfb\x91\x9d\x96I\xc8\x8da\xd5\xf5\xad\xd6\xadJ\"\xff\xc0\x12\x9c4YX\x1a;\xc6$,\xb7\xe0\xd3Z\xb0\xbeLJw\xd6X\x86A\x13\xc6\x0c\x1eqv\x1e\xa1\xfb\x8ecL6\xc4X\xc8\xb7^\xec=[\x87\xa8\xadH\\\x9dGm\x81!\xef\xe1j4 >\xbd\x10W\x86\x0c\x12e\xaa\xed\x8c\x9f\x9f\xdb\x19Nv\x8b\xdc6C&6\x81\xdeH\xa4\xac\x88\xe5\x19\xbc\xb0\xbe\x0cW\xcd8\x86\xe2\x95\x1a~\x7fb\"\xe1\x18\x92\x97\xecp x\x0c\x19\xc9e,\xdf\xc0\xc8\xf030n\xfa\x0bf\x1d\xf4\xd98Vq8\xcd\xc3\xdf\xaf\xa0_\x00C\x04c\xd3\x0f\xb2)h,\x9f\xa9\x8b\xf6O\x8a2\x15\xb9\xa3\x9a\xc6\xbd\xba$\x85-\xeb\xb5\xdbH\xfe\xe9%\x91\xdff\xcd\x03\xeb6}X\x89\xce\\\x0fn\xd6e,}\xeb\x10{\x16\x8d\xc9\xf3:(\xeb;\xddp\xa1\xe5\x97cRo{\xb5\x1a\xd4\x1f\xe1fDg\x16L\xa0\x9b\x01\xa9\xeesF\xbd!\x96&\x8c\x90&\xef\xbf4f\xdf<+\xae\x83\xf4\x1bm\xf0\x9f\x90\xe7P\x9e\x07\xce\xce\x99\xbf\x84-$q\xa3\xc2]\x10\x18E\x80\x96\xb6\xb41m\xbf\xff\x84\xb5)\xe4\x8b~o\x9b\\v\x16*y)hc\xb2\xfb\xbc\xe5\xdf#\x06\"d>\xa1\x9a\xde@\x9a\xd6\xa4\x82\xba\xffiH/\xaeqs\x1cxaT\x96\x822\x1a\x87\xa9\xf4\xec\n\x92\x1fhk\xa2\xfaGU\x01Z\x87\x18\xb6HX\x9e\xd9\xa4\x99\x93vM\xa5\xd7T\x83O/\x95\xe3\n\x90\x93\x98J\xd0\x17\x16\x16d\xde\x1e\x93y\xdd\x07\x1e\x8d\xa3\x88\x19 I(O\xd6 \xe1\xca\xa3\x97,\x1e\xe8\xf29\x1d\xd7\xa9\x19\xb7\xf4\xe6\x98o\x8e\xa9\xc2\xb7\x02\xe8\xba_\x944y\xd4h,\xd0\x80\x9c\xe4=L\x83\xe4\x89\xbbA n\xda\xe4N\xad 44\x95Y|\x19\xcb\x9a\x1d\xe2\xd0\xa2`s&\x87\x86\x1eTh\xcdv\x91\xe3\n\x1f\xe1?\\\x08\x1e\xa6+2U?\xbc\xa7\x8d\xba^\xf3\xf9<\xab\x15\xc8~\x16\xed\xa0\xc31\xc2(\xe547\xd3#kW\x9a?~\x86>K.\xf6\x83\x89\xbdg\x1d,\xce\x89\xa5Ug4\xf8\xcfs\x98\x1dwpO.w\x9ea\xb6\x90\xa4\xa4Tj\x87\x84!\xa7\xbb\x94\xebneA\xc7p\x10C\xec\x8a]\xa8V\xa1\x1ad\xcb\xaa\x7fr\xb5\x91\x1f\xb5\x04\x0d\x9f\x97\x19\xa5C|Z\x14\xba\xce\x97\x9c\xe1Qg/\x03\xd5\xf5\xe0\xd3\x08hAm\xe4\xeb\xf8\xe9\xcb\x8cG\x9d-\xc1Z\xf3\x16Z\x8fn5\x0d\xc3\x06\xb9c\xdd\x91\xab\xf4`>Fe\xeb\x18y2\xea\xe0Q\x87\xfd\x00\xb9\x8b\xb9\"\x1b+\xe4*].y\x86\xd1$\xbf\x10\x9a\xe5\x02\xabT\x00\xad\x08X\xa6\xc7\xe1C;\x86\x84FET\xcb\x1d\x81%[\xbci<\xdf\xa40\xb7u<\xea\xf8\x95\xb2U\xfdh\xdb\xef6\xf5A\x95)\x8e\xfd\xddY\xd2\xeb\xb6\x05\x92\xe6\xae\x0f\x1e\x85Lv\xd9;}\x06$\x84\xcb\x0f\xdd\xd2\x1bndY\xf0\x08\xb6\xe0%\x8b\x0c\xb1\x97\x1b\xbdC\xa4\\\x14,\xcf$\xe5\xa0\x95\xdb\xf3\x95\xd5Y\xf0\xe9\xe5\xedu\xab\x1a1;\x94\x91 \x91\xf4j\x80\xcd\x0f._\xb9,\x92\xbc?((\x92(<\xe3,\x8eh-v\xb4=\xaf\xeb\xb5\xaa\xb2_\xb3\x88\xa84\xd1X\xdf\xcd|n\xcey\xa1\x1e\xd5Zlwe\xdew\xa0\x95#\xfe\x99\xf6{\xf8\\\x87\xf4\x8e\x13)N\xb9\xc5j\xe6\x9f7\x93[\xe4sP\xa8n\x8e}\x89M\x9bY\x07(\xb5P\x18\xb5\x01\xcf?\xfeA\xa22\xda\x02\xd0\x83Q\xde\xbd\xaf\xc5\xf2\x95\xad\x1c\x96\xde}\x1d\x01\x13\xfb\x1d\xad\x9eo\x97 \x94\xef\xd0\xf2ub\x9bQ4\xdc\x05th}@g\x01\xf9\x9c[\x1d\xf8&%e\x91,m\xd0\xe2\xe2`\xa9\x10\x11\xa5\xeeA2\xf7\xe3\xc3\xd3\xf8aK\xb3U\x9fQ5r\x04\x86\xeb\x80)\x92\xd0\xd0^\xbd\xea\x1b\xd2^\xa1u\xcd\xe6\xb4\xb9\xdd!\xb6\xb6\x98e\xb0\x05\x06\xad\xdd\xf2\xd8%vif\x1d\xa0\xd1\"\xa1\x15G\x00\xe65U\xca\xa1\xf5\xa1\xff\x18\x0bZr\xdd\x99\xd7qeC\xa3\x85\xbb\x8a\"h4qJn\xe4mv\xad\xfa\xdc\xe2B#\x18Z\xb9\xec-\xef\x90\\v\xad\xd7s\x1b0\xbd\xde'd\xe7L_\xed.\xea\xae\xbe8*\xcc8 \xaa\xf3\xe6\xf3\xb8\xab\x91\xf7<\x0e\xc7`\x7f\x04\xcf?\xb3\x0e\x10e\xd1\xc8\x89\xa1\x01#\xc8\x19M\xd0\xb4\x19\x136$\x08\x0fG\xe0\x13\xc4\xce\x98*_\xf1\xaa\xb6\xe1&.4/\xfb\xcc\x15\x07H.\xd7}\x11\xcfU\x1b\xe1n,})\x03\x89\xfb\xd1\xc6\xddd0\x0f$\xf0\xe1\xa7\xa9T\xf7\x9d\xac\x82\xf6\xd8\xe7\x8e\xb6\xfb\xbbN\xa3\x05w\x93H.\xba\xa5g\xbc\xaaz\x89D\xc0yrN\xdb$\xc7\xad\xd2\xc6\"\x91\xa2e\xf4\x18\x0c\x8f:\xdd\xf3\xb8>,y\xe4\xdddPY\x8d\x0cu\xbaI\x82Q\xba\xce\xb7\xbf\xf3\x98h\xd9'\x94\xa2\xd1\x12C\xb2\x15^{y\xe5z\xfd\xb0`\xa51o\xcc\xba\x91\xfd\x11\x94\xeb\xcc\x99\xdc\xa1o\x0b\xae\xe0\xc7\x9c\xe1L{S\xd6\xa0\xb3)xc\xe6\x19\xeb,\xab\xfb\xe7\xc3WtvK#\xac\xce\x1cC\x81;\xc1'\xb5\x8eu^l\xd9\x196\x01,\xac\x18`0\x8d9\xfb\xcb\xd3\xbeQ\xe9\xe9\x94#\xce\xe1\xa0\x9bf\\UBv\xda\xa0\xa5@K\x05\x86\xc8\xcf\x8f;\x12 \x9f\x1e\x16\xf0\xb0\xf09\x9b\xc14\x10\xc4D\xd4t\x86Y\x18L\x03\xea\xd5k\x98$\xc8_;\xa7H\xa7&H\xc1\x9dp\xcc\x96[5\\Y\xe7\x04\xdb\x9b\x00\x9d\x90\x88>\x9f\xa3I\xec\xa6\xd8xQ\xb9pf\x1d\xa0\x9b\"A\x15G\xbeE\x1c\x9c\xae#\xa3\x10\xcb\xc1\xd1\x9e\xafc\xc9\xf5i\x07\xe7\xb5\x07^\xf3\x197T\xdcP\xfd\x0cg\xf2\xe2\xb5\xb9\xf32\xca\xd1\xb0\xc4\xdc\xed,\\\xbb\xc5\x9c#\xb1\x99\x04W\xf7$YK~\xf3qE\xcb\x14\xe1\xf9\x0e`7XG\x8f\xd70\xdd\xaa\xe1\xac\xea\\ \x9d\\\x06[#\xf1[c\xb6\xff\"\x9c\xe6?\x172V)PR\xb5` + \x00\x95\x04\xbf\xfe\x81Dr\x16\xa3\x95\x1c\xc3t\x16\xef[\xa3]\xf3\xc3SZ\x08\x1e\x10\x1e \x97\"A\x18G\xf1\xe55U\xaf:s\xab\xe9xU\x98\xd4\xf6\\\x88\x0c\xb9\x19\xeacP\xd7\x88\x88\xc9\xe5\xb2[M\xfb\xbd\xdb\xd2;\xb4\xca\x81\x8e3B\xffPM\x13 ISV\xbf\xdb\x9d\xd9u\x9aH/\xa6A\xfct\x16\xaa\xaf\xfb\xaa\xa6\xcf\xa2\x05R/\xb0\xa2\xf332+O\x1b\xb0~\xf1\x1f\x89$J\xbd \xb9\xc8\xc6\x06\x9fY\xa0\xc1\xeaGp\x17@\xc8c\xfb\xc9\x97h\xcbe\x90\x16\x07\xef\xce%\xde\x93\xb8\xc1=\x0e*\xec\x1b7\x18\xfb\xfb?\x88\x83\"\xae\xb3\xd5c3\xb0\xe3qPt\x8a6\xa5\x0b|\x01\xbc\xd9\n\xd2\x9a\xc8)\xbe\xd8\xea8\x8b6\xb6,\xca\xc4\x0f\xfd9\xe7\x13.\xa4\x81\xf8\xb9\xa9\xdc\xb5z>9\xcf\x04\x02A^u\x1ao\xd9w\x10\xa7`\xf5\xb7Z/\x1fTl\xf7Pe\xc4\xa3\xb1Q\xdb\xb4=\xb6\xe5S\x07\xab\x06\xb1|\xf9\"\x03\x18q\xe6\xdb~\x11=\xdc\xe1\x04=TK\xe24n\xf4\xfe\xb2Q\xd7k\xb0\xf5\xdcv\x0c\x99\xbd\xdbY\xec\xb3R\xd1`\x8b\xc3J\xb9\xc2\x07\x1a[n=\xd6@0\xdc\x15\x900\x0d\x94\xbc\xd8~\xe6\xd4\xd8{\x82\xe4\x18\x94\x9e\x99\xcd\xf6\x93\xbe\xa8\x9cQ\xc0\xf2\x0d\xaa\x8e\xf7\xa7\xc9\x91\xa7(\xd7QMa\x9b`x\x82\xc49\xfd\x9e\xc0\xa5\xff\xc85Gz\x0fl\x03\x0d*\x9f8\xc9\x86\xea%\xc2\xa3\xaa\"\xcb1\x82\xe4U\xdf\x02$\xbav\x8bdSf\xe3\xf2\x8c\x92\x00i\x8f\xa4\xe2\x00R\x0c\x92\x8a\x00i4A\xb5\xf7\xb8\xfd\x1a\xb4\xd5\x00Fv\xc0~\xbb\xcf\xed\xa0M5\xa2\xe5\x87J\x14\xb6\xb6f`z\xcdub\x16\xc1p\xd2\x93\x0fh\xe6\xb3\x18\xce\x9d!\x12\xfc\x13\xc8Y\xed3\xa0.\xc4)\xaa\x94\x83ZA\xa4\xb8\xa5=\xf0\xc4[\xb4j\xb0\xf6\xb1\xe0~mr\x92K\xc1\xb3K^\xf1\x80\xe7r\xf2\x8a\xb8\xbc\xda\x08U2\xb1\x90S\xc9@'\x89\x8a]f\xf1\xfdM=\xe8\xa3\xff\x91H\xe2\xe6\xfd\x96\xa0.\xaf\x05\xaa\xd1\x08W\x98\xd7H\x8c\xb4\xc8\xb0\xce\x99\x9d\xce\xf6\xd3\x88r\x96\x1a\x88\x82\x1f\xa4\xac4\xc7H\x1f\x1f\x16\xbd=,b\xf9\xe1-_\xd8v\x1a\xd1\x83\xbcv\xba6t\x12Gm\x06|\x9e\xb4E{\x9c\xf9bB<\xf7\xb2\xc0\xf4:\x9ep\x17wt!\x81\xd3\x1e\xbb\xc5\x01\xa7\x18\xec\x96+|\x90@}\x19\xcb\x10yK\xd5{}\xc1S\xdb\x9f \x93,\x07\xe9\x18H\xeb\x0d\x0e\xb6\xdbV\"\x9c\xddR\xa59\xfc\x13\xd3\xbf!%\xc1bo\x1a\xb4\x16\x9d\x85\xc4f;G7\x07\xedp_K\x15'\xc6^\xbd\x17d\x8e\xce\x9ck\xeb\x0d\xdc\xb9\x01\xf1\xd3ki\xfe,\xa6N\x92\x8er\x8a\x04\x18\xb91\x8bk\x9c\x18\x07&\x96\xbc\xf7\xeb\x8e\xa2H\x80\xa9\x8aw\x17\xeaL\xa4\xad\xdd\xa7\xecUA\xf9/\xd1\x08\xdbg\xb8\xa2\x11\x16\x87\xe1\n\xaf\x8d%\x12-U\x9cy\x06\xdd\x7f\x9e\x1d9-\xaei\xb4\x98\nS\xa5G#\xa7\xdd^\x8b6zH\x91$\x8c\x8d\xbc\xdc\xe9\xe6;M\x98\xbe\x93\xa8\x99\xb8\xa9z\x9b\xd9Y&\xe9\x83\xc1\x9c\xc76\x89\xfd0mJ\x1e\x9c\x9a!y%W\x9c\xc4\xf4\x80\xe4\xe5\xb3\x85@\x7f|Ja\xcc\x05\x9d}\x1e+\x1a:qx,\xe2\xebt\x1dib,_\xa7\x89n\xa1\xe0\x16\n\x01\xdb\xcd9\x87\x1el\xcd\xfdh;\x8b\x1b\xc6\xcd\x9fei\xc8A\xaf\x1f\xc9\xb3\xff\\\x8f\xe0Z\xb4\x9de\x8b\xe5\xf2T,,:\x86\xcaHm\xdf\x0e\x19\xc7\xd4\xc1;\x1bq\x884S\xbc\xf6\x9d\xb3\xad1f\x94\x98[J_\x05\x848\xacR\xe4\x0b\xab\x0f\x0e\xb4\xb9\x0b\x99\xbcS\xefk\xbd\xba\x91\xf6\x12\x03>+\xc5.fc\xa5\xe8\xc5\xb8\xd7\xfe\xd08\xc7\xe8\xbaJ\xd51U\xf4p\xc7n\"c\xca\xb6\x9b\xf6\xbc\xc1\xdb\x14\xda\xe3u;g.\x10XE\xb8\xa4\xea\x08\xdfV\x02\xe5\x82\x9b\xf9\xa4\xda#\x9e\xf1\x0c\xeeG{\xbd\xf4@\x91;\x123\xdbUE\x027#\xb39\xe9\x0b\x12}\x8a\x99]\xde\x88\x073\x97\xf3F\xc41\xd5F\xa0\xc4\xda\x0c\x16\x946\x98i\x12)N\xc7~uK\xe8\x1f\x9f\xd8\xbd\x8d\x99`\xad\xfd\xe6\xf3\x04\xa1a\xff\x11\x8eIi\xb3\xd9O~T\xd1\xd2\xd9C\xe0rL\xc1q\x19\xe1,KxU\xdc\xec\x82sr\xbf\x94E\x1b\x06\x1f\xb4\x12\xf3\xb2\x9f\x01\xf0MS\x06[\xc3\xf2\x0d\xb9\xe0Q\x11) &\xd4\xdd\xf4\x80\x92\x93+\x84wSqKo\xf1p\xb5G q\xe0*\x8e\xf0\xe4[\xacb\x9a\x9c\xc3V\x87\x8eB\xb9\x0d\xb6\nt\xe6\\\xba'<\xf9\x06\xe2\xd4k\xb0\x9dL\xe86\xbc\xe2\x84K\xae;2\xf0\xe4iC\xcc\x04\x19m\xe5\xd8F\x9a[\xfdL~\x9cLg\x0bm\x94\x80\xd9w\x18J\xd0{\x84\xf7\x03\xa4&G8\xb4\x15?\xaf\xc3\xa8H~\xb1b\xe1\xc9\xb7\xad\xbd3N\xc7B<@\xda\xe7\x88\xa2\x81\x14\x87#\n\xaf\xbd\x1cH$\xee\x9f\x06\x046\xb4\xf4\xe3\xc36v'\xc5\xa2\xcc\x90\x00\xe91\xef\xcf\xd8H$\x821\xc0\xa7\x9d\x1a;\xa8Wa\xddx:.\x8f`\x95\xe2\xb2<\xecl\xe9\x8e\xc1\xa8\xff\x8a\x87\x066y\x06\x0f\xfb\xebl1z\xea\xf0\xde\x10\xa0\xfb\x0eM\xa67]Z\xa0>\x9e\x1a\xbe\xc8\x136\xefs8\xd1P\x89\xc3\xe1\x10WU\x9dy\xaf\xb1dqL\x08\x8dj\xdf\xbd\xd7\xc2\xcf\xd0\x06\xd8\xc7+\x1b\xdbQ\x10\x95[\x06\x85S\xdc \xc1\x8c\xab/\xb8\xa2 :\x8c*\x18\x1b\xc1\xf2]Vl\x89\xc4\x8c\xf7\xfa\xe2\xbd\x16B\xdb\x95\xa4Q\xd9\xe2\xa3t@\x17\xc3\x06/\xd8\xf7!\xe8K\x89\xb43%\xdd{-\x80\xea\xcf^\xff\x03\xb6\xac'(\xd8#v\xc2\xd0\xd8\x80\xe7\x1f\xfe\xa8v\xb7\xea\x8c\x11;\xd0\x1c\xc4\nu\x9a\x03\xc7T\x99\xa9\xa1=F\x8f\x81\xfe\xfa\xbc\x8a=}\x81\xb9r.\x1ai\x92\x0c\xa69\xa0\x9aB\x12\x96\xbaV\x89\xcb\xd4h=\xb8\x19;F\xce\xb5\x0d\x9fX\xb0\x13<\xa2o\xa3\xeb\xda\xe9\x80\xf6\xdd\xa1\x1e\xa3w\x84\xcb\xe1\x94\xc5\x04\xf3\xfe\xbf\x05\xbfS\x0e\x0f;\xfeLxe\x04r\xc5G\xd4\xce$\xa2\x0b<\x97W\x93\xf6\x99\x9fhD\xc5\xear\xab\xce\xd0\xd8\x02\xeb\x16:\xf3X\x88\xa2\xbf@L\xf2[\xd3O\xe4\x85[\xbf\x92?\xab\xe2\x94\x05z\xdb\x8fU\xaa\x06\x895y\x82j\xb9\x07s+\xdc\x9a\xc0\x14\xe5\xbc\xd3\xef\xd6\xa7\xc4\xe2\xab`\xb3\xb4\xe8\xea\xc6\xf5\x0d\xaa=\x07\x03\x0c\x88\x9d\xb0E\x9c\xc8rj\x8b\x8c\xba3\xaf\xb0\x83\x07\x03>\xc9K\xf6\xd6$\xd7\xf1\x9a\xc4\xca\xd0\x0f\xb8\xc4\xa9c\x85zG\xe9\xf4\xc0\xe0 \xd1\x11x\x1aD\xca\xab\xb2\n\xb5\xb2\xc2\x95G\xb7\x7f\\\xce\x16\xc9T\x13\xf8\xed\x91H\x1c\xf0\x8b\xd3*W\x9d\xa1\xd1\x04wc\xb6\xca=\xa2\xe7\x12\x8d~\xc5\xb3\xa7\xc6n\x1b\xb4\xb3\xea\xb2x\xf2\xec\x18%g\xfe\xb0\xd3>E\x0c\xc3zW\x07$\xab\x1c\x03\xf8\xb7\xcd]\xb7\x89\x13Y\xb6W\x8f\x0f\xdacm\x07\xdb \x1d\xb5\xa9\xa8\xa6\xe0ns\xd3\x0c\x96H\xf0J\xbf?\x89u\x1e]{\x8fK\x1f\x8c\xdd\xe6\xc6\xaf_\xe6\x1f\xf7\xf9%\x1e8\xc5h\xaa\xab\xce\xa06\xc2z\xbc2?m\xaa\xf3\x8c&\xd6?\x82r-\xe7|2\xe2\xa4\xe8``\x12V\x1d\xd9\\#J\xf4\xadc\xfd#\xd8\xc7\xf1\xacz\x99[\"k\xfd\xd0\xc6\xd6\xfc}\x96\xc2\xe5\x88\xe8\"\x08\x9e<\xf9t\xf8\xba\xb8\xf7#\x91$\xb6\xdc\xc8\xa1\xfe\"\x18\xd2\x1f\xc8\x1d#\xb7\xac\xbci\x93sZWf\xa3;z\xb9\xbc\xe4\x1e\xbf\xc4\x81\xab\x18\xfc\x12\x89\xd8\x9b*\x12ncU\xd3\xbe?R\x9f\xb8\x1e\xb8\xd0\xcd =\x89f\xc7\xb6?:\x10w\x05rE\x9c\xb2\x9c\xb9\xc8\xb9\xb1\x03yr\xc2-\xf1@T\xb7\xbf\xab\xff\x88\xd8\x89W\xf4\xeaO\xccQ\xd1\xf1\xc9\x04Wl\x82l\xa49\xeaH\x8ei\x86^\x02\xd51\x128\x91e \x1b\xc1f\xeb\x03\xfa\x05\x90\xa7\xce\xdc\xff\x02t\xa4\xe0=\x8b\xc2\x15\xca\x0e\xc9U\x85'\xa6\x87\xe7\xf5]\xe6\xfe\xf6 \xa8h\\\xc5j\xbc\xab\xce\\\xe1\xc31b\xcd\xae\xc3\x15\x0bi\x9f\x01\x83\x82W\x12\xd2>\x8fWi\xb7\xdc\x9f\xbf\x93U\xbe\x883\xed}\xd5}\xb4^\xd2\x18\x818E\xdf6\x1b\x1b\xd2 \xd1k\x95\\\xfa\x81\xa0.?\xc6I\xfd0\xbb\x1c1\x1c\x85\xfc8.%\xf6'\x80\"\x8d\x8eI\xec\n\xa8\xac\xedlS\xfc#\x91\xf4\x04\x89\x1c\xb75s\x8cE\xd0\xbf\xc4\x19\xbc\xc5(\x04\xd3\xd3\x05\x9dU\xf4z^EtW%vB\xee{\x9b\xdc&\x99\xb6t=\x90W\x916w\x98\xacr\x88\xb5|,\xd0\xee\x93]\xd1\xa0\x8d\xd5\xd8W\x9d\x81\xae\xc3(\x1fs\xe7U\xaf\xf9\xe4\x19\xcf\x04o\xe1-BC\xaa\xc6HW\x0b\xf94\xb9\xe5\x85*\xbd\x91M\xf6\x0bx%qY\xc5\x85\x8a\xe42\x92\xef\xfd\x1a\xac4\xdd\x12T\x9e.\x02.5\xbc\x92