diff options
| author | Christine Dodrill <me@christine.website> | 2018-07-25 14:50:13 -0700 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2018-07-25 14:50:13 -0700 |
| commit | 73344db07bd55329f87a4176802443edb7c464ae (patch) | |
| tree | 05032079968010b4d9168752a097607160c3de02 | |
| parent | f52b09be25fb0ec0d654fbf027120e1702ac404f (diff) | |
| parent | 9243dc2b7583119d8306cef006aaaae299547209 (diff) | |
| download | x-73344db07bd55329f87a4176802443edb7c464ae.tar.xz x-73344db07bd55329f87a4176802443edb7c464ae.zip | |
Merge branch 'master' of github.com:Xe/tools
50 files changed, 4113 insertions, 1 deletions
diff --git a/cmd/ghettoscale/main.go b/cmd/ghettoscale/main.go new file mode 100644 index 0000000..8ad78c6 --- /dev/null +++ b/cmd/ghettoscale/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "flag" + "net/url" + "os" + "time" + + "github.com/Xe/ln" + _ "github.com/joho/godotenv/autoload" +) + +var ( + every = flag.Duration("every", 10*time.Minute, "how often this binary is being run") + do = flag.Int("do", 1, "do this number of scale checks, staggered by -every") +) + +func main() { + flag.Parse() + ctx := context.Background() + ctx = ln.WithF(ctx, ln.F{"at": "main"}) + + pool, err := NewRedisPoolFromURL(os.Getenv("REDIS_URL")) + if err != nil { + ln.FatalErr(ctx, err) + } + _ = pool + + for _, a := range flag.Args() { + ln.Log(ctx, ln.F{"url": a}) + u, err := url.Parse(a) + if err != nil { + ln.FatalErr(ctx, err) + } + + err = Check(ctx, u) + if err != nil { + ln.FatalErr(ctx, err) + } + } +} diff --git a/cmd/ghettoscale/redis.go b/cmd/ghettoscale/redis.go new file mode 100644 index 0000000..94375c0 --- /dev/null +++ b/cmd/ghettoscale/redis.go @@ -0,0 +1,27 @@ +package main + +import ( + "time" + + "github.com/garyburd/redigo/redis" +) + +// NewRedisPoolFromURL returns a new *redigo/redis.Pool configured for th1e supplied url +// The url can include a password in the standard form and if so is used to AUTH against +// the redis server. +func NewRedisPoolFromURL(url string) (*redis.Pool, error) { + return &redis.Pool{ + MaxIdle: 3, + IdleTimeout: 240 * time.Second, + Dial: func() (redis.Conn, error) { + return redis.DialURL(url) + }, + TestOnBorrow: func(c redis.Conn, t time.Time) error { + if time.Since(t) < time.Minute { + return nil + } + _, err := c.Do("PING") + return err + }, + }, nil +} diff --git a/cmd/ghettoscale/scale.go b/cmd/ghettoscale/scale.go new file mode 100644 index 0000000..fa503f8 --- /dev/null +++ b/cmd/ghettoscale/scale.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "net/url" +) + +// State is the state of the ghetto autoscaler. +type State int + +/* +States that this can be in + + digraph G { + ok [label="OK"] + scaling_up [label="Scaling Up"] + scaling_down [label="Scaling Down"] + max_scale [label="Max Scale"] + + init -> ok [label="test passes"] + init -> scaling_up [label="test fails"] + ok -> scaling_up [label="test fails"] + scaling_up -> scaling_up [label="test fails"] + scaling_up -> max_scale [label="test fails"] + scaling_up -> ok [label="test passes"] + scaling_down -> ok [label="minimum\nscale"] + ok -> scaling_down [label="test has\npassed\nn times"] + scaling_down -> scaling_down [label="test passes"] + max_scale -> scaling_down [label="test passes"] + max_scale -> ok [label="test passes"] + } + +This is the overall state machine for the autoscaler. +*/ +const ( + Init State = iota + OK + ScalingUp + MaxScale + ScalingDown +) + +func Check(ctx context.Context, u *url.URL) error { + switch u.Scheme { + case "heroku": + return CheckHeroku(ctx, u) + } + + return fmt.Errorf("no such scheme for %s", u.Scheme) +} + +func CheckHeroku(ctx context.Context, u *url.URL) error { + // q := u.Query() + var err error + + // heroku://printerfacts/web?kind=lang&metric=g:go.routines_max&min=1&max=3&stagger=1&mode=threshold&threshold=500 + // appID := u.Host + // processType := u.Path[1:] + // kind := q.Get("kind") + // metric := q.Get("metric") + // min := q.Get("min") + // max := q.Get("max") + // stagger := q.Get("stagger") + // mode := q.Get("mode") + + // get redis connection + // check if app:process type is currently staggered in redis + // if so decrement stagger counter in redis and exit + // fetch metrics data from metrics-api + // fetch current number of dynos for this app id and process type + // fetch state of the + + return err +} diff --git a/discord/cadeybot/.gitignore b/discord/cadeybot/.gitignore new file mode 100644 index 0000000..a029fb7 --- /dev/null +++ b/discord/cadeybot/.gitignore @@ -0,0 +1,3 @@ +.env +cadeybot +*.gob diff --git a/discord/cadeybot/corpusmake.sh b/discord/cadeybot/corpusmake.sh new file mode 100755 index 0000000..884f3d0 --- /dev/null +++ b/discord/cadeybot/corpusmake.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e +set -x + +for dir in $(find -type d) +do + [ "$dir" != . ] && ./importer ./"$dir"/messages.csv >> brain.txt +done diff --git a/discord/cadeybot/importer/main.go b/discord/cadeybot/importer/main.go new file mode 100644 index 0000000..bb38417 --- /dev/null +++ b/discord/cadeybot/importer/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/csv" + "flag" + "fmt" + "log" + "os" +) + +func main() { + flag.Parse() + + if flag.NArg() != 1 { + log.Fatal("usage: importer <messages.csv>") + } + + fname := flag.Arg(0) + if fname == "" { + log.Fatal("usage: importer <messages.csv>") + } + + fin, err := os.Open(fname) + if err != nil { + log.Fatal(err) + } + + csvReader := csv.NewReader(fin) + _, err = csvReader.Read() // ignore the first row, it's the index + if err != nil { + log.Fatal(err) + } + + all, err := csvReader.ReadAll() + if err != nil { + log.Fatal(err) + } + + for _, row := range all { + fmt.Println(row[2]) + } +} diff --git a/discord/cadeybot/main.go b/discord/cadeybot/main.go new file mode 100644 index 0000000..6b18fd8 --- /dev/null +++ b/discord/cadeybot/main.go @@ -0,0 +1,102 @@ +package main + +import ( + "bufio" + "flag" + "log" + "math/rand" + "os" + "os/signal" + "syscall" + "time" + + "github.com/bwmarrin/discordgo" + "github.com/facebookgo/flagenv" + _ "github.com/joho/godotenv" +) + +var ( + token = flag.String("token", "", "discord token") + brainInput = flag.String("brain", "", "brain file") +) + +func main() { + flagenv.Parse() + flag.Parse() + + chain := NewChain(3) + + if *brainInput != "" { + log.Printf("Opening %s...", *brainInput) + + fin, err := os.Open(*brainInput) + if err != nil { + panic(err) + } + + s := bufio.NewScanner(fin) + for s.Scan() { + t := s.Text() + + _, err := chain.Write(t) + if err != nil { + panic(err) + } + } + + err = chain.Save("cadey.gob") + if err != nil { + panic(err) + } + } else { + err := chain.Load("cadey.gob") + if err != nil { + panic(err) + } + } + + rand.Seed(time.Now().Unix()) + + mc := func(s *discordgo.Session, m *discordgo.MessageCreate) { + // Ignore all messages created by the bot itself + // This isn't required in this specific example but it's a good practice. + if m.Author.ID == s.State.User.ID { + return + } + + mentionsMe := false + for _, us := range m.Mentions { + if us.ID == s.State.User.ID { + mentionsMe = true + break + } + } + + if !mentionsMe { + return + } + + s.ChannelMessageSend(m.ChannelID, chain.Generate(15)) + } + + if *token == "" { + log.Fatal("set -token or TOKEN") + } + + dg, err := discordgo.New("Bot " + *token) + if err != nil { + log.Fatal(err) + } + + dg.AddHandler(mc) + + err = dg.Open() + if err != nil { + log.Fatal(err) + } + defer dg.Close() + + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + <-sc +} diff --git a/discord/cadeybot/markov.go b/discord/cadeybot/markov.go new file mode 100644 index 0000000..f31c133 --- /dev/null +++ b/discord/cadeybot/markov.go @@ -0,0 +1,137 @@ +package main + +// This Markov chain code is taken from the "Generating arbitrary text" +// codewalk: http://golang.org/doc/codewalk/markov/ +// +// Minor modifications have been made to make it easier to integrate +// with a webserver and to save/load state + +import ( + "encoding/gob" + "fmt" + "math/rand" + "os" + "strings" + "sync" +) + +// Prefix is a Markov chain prefix of one or more words. +type Prefix []string + +// String returns the Prefix as a string (for use as a map key). +func (p Prefix) String() string { + return strings.Join(p, " ") +} + +// Shift removes the first word from the Prefix and appends the given word. +func (p Prefix) Shift(word string) { + copy(p, p[1:]) + p[len(p)-1] = word +} + +// Chain contains a map ("chain") of prefixes to a list of suffixes. +// A prefix is a string of prefixLen words joined with spaces. +// A suffix is a single word. A prefix can have multiple suffixes. +type Chain struct { + Chain map[string][]string + prefixLen int + mu sync.Mutex +} + +// NewChain returns a new Chain with prefixes of prefixLen words. +func NewChain(prefixLen int) *Chain { + return &Chain{ + Chain: make(map[string][]string), + prefixLen: prefixLen, + } +} + +// Write parses the bytes into prefixes and suffixes that are stored in Chain. +func (c *Chain) Write(in string) (int, error) { + sr := strings.NewReader(in) + p := make(Prefix, c.prefixLen) + for { + var s string + if _, err := fmt.Fscan(sr, &s); err != nil { + break + } + key := p.String() + c.mu.Lock() + c.Chain[key] = append(c.Chain[key], s) + c.mu.Unlock() + p.Shift(s) + } + return len(in), nil +} + +// Generate returns a string of at most n words generated from Chain. +func (c *Chain) Generate(n int) string { + c.mu.Lock() + defer c.mu.Unlock() + p := make(Prefix, c.prefixLen) + var words []string + for i := 0; i < n; i++ { + choices := c.Chain[p.String()] + if len(choices) == 0 { + break + } + next := choices[rand.Intn(len(choices))] + words = append(words, next) + p.Shift(next) + } + return strings.Join(words, " ") +} + +// Save the chain to a file +func (c *Chain) Save(fileName string) error { + // Open the file for writing + fo, err := os.Create(fileName) + if err != nil { + return err + } + // close fo on exit and check for its returned error + defer func() { + if err := fo.Close(); err != nil { + panic(err) + } + }() + + // Create an encoder and dump to it + c.mu.Lock() + defer c.mu.Unlock() + + enc := gob.NewEncoder(fo) + err = enc.Encode(c) + if err != nil { + return err + } + + return nil +} + +// Load the chain from a file +func (c *Chain) Load(fileName string) error { + // Open the file for reading + fi, err := os.Open(fileName) + if err != nil { + return err + } + // close fi on exit and check for its returned error + defer func() { + if err := fi.Close(); err != nil { + panic(err) + } + }() + + // Create a decoder and read from it + c.mu.Lock() + defer c.mu.Unlock() + + dec := gob.NewDecoder(fi) + err = dec.Decode(c) + if err != nil { + return err + } + + return nil +} diff --git a/discord/pdevbitcoinbot/.gitignore b/discord/pdevbitcoinbot/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/discord/pdevbitcoinbot/.gitignore @@ -0,0 +1 @@ +.env
\ No newline at end of file diff --git a/discord/pdevbitcoinbot/Gopkg.lock b/discord/pdevbitcoinbot/Gopkg.lock new file mode 100644 index 0000000..c30a77f --- /dev/null +++ b/discord/pdevbitcoinbot/Gopkg.lock @@ -0,0 +1,30 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/caarlos0/env" + packages = ["."] + revision = "7cd7992b3bc86f920394f8de92c13900da1a46b7" + version = "v3.2.0" + +[[projects]] + branch = "master" + name = "github.com/codahale/hdrhistogram" + packages = ["."] + revision = "3a0bb77429bd3a61596f5e8a3172445844342120" + +[[projects]] + name = "github.com/joho/godotenv" + packages = [ + ".", + "autoload" + ] + revision = "a79fa1e548e2c689c241d10173efd51e5d689d5b" + version = "v1.2.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "ce13f8ee2ca2392356358cef4fbb7bf0e8361b29789607b061ba3b024d9cf493" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/discord/pdevbitcoinbot/Gopkg.toml b/discord/pdevbitcoinbot/Gopkg.toml new file mode 100644 index 0000000..1fecccd --- /dev/null +++ b/discord/pdevbitcoinbot/Gopkg.toml @@ -0,0 +1,33 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + name = "github.com/caarlos0/env" + version = "3.2.0" + +[[constraint]] + branch = "master" + name = "github.com/codahale/hdrhistogram" + +[[constraint]] + name = "github.com/joho/godotenv" + version = "1.2.0" diff --git a/discord/pdevbitcoinbot/data.json b/discord/pdevbitcoinbot/data.json new file mode 100644 index 0000000..1ea89a5 --- /dev/null +++ b/discord/pdevbitcoinbot/data.json @@ -0,0 +1 @@ +{"Snapshot":{"LowestTrackableValue":-400,"HighestTrackableValue":3000000000,"SignificantFigures":5,"Counts":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
