diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-10-16 21:30:13 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2017-10-16 21:57:04 +0800 |
commit | 0bb194c956ac41eed5445c962b33f56d904b7759 (patch) | |
tree | d293daca749cd9208bcfdabb3966edc2af6d49dc /cmd/faucet | |
parent | e9295163aa25479e817efee4aac23eaeb7554bba (diff) | |
download | dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar.gz dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar.bz2 dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar.lz dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar.xz dexon-0bb194c956ac41eed5445c962b33f56d904b7759.tar.zst dexon-0bb194c956ac41eed5445c962b33f56d904b7759.zip |
cmd/faucet: support twitter, google+ and facebook auth too
Diffstat (limited to 'cmd/faucet')
-rw-r--r-- | cmd/faucet/faucet.go | 255 | ||||
-rw-r--r-- | cmd/faucet/faucet.html | 25 | ||||
-rw-r--r-- | cmd/faucet/website.go | 2 |
3 files changed, 215 insertions, 67 deletions
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 8cd62441e..6b2987315 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -21,8 +21,10 @@ package main import ( "bytes" + "compress/zlib" "context" "encoding/json" + "errors" "flag" "fmt" "html/template" @@ -33,6 +35,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "strconv" "strings" "sync" @@ -181,10 +184,10 @@ func main() { // request represents an accepted funding request. type request struct { - Username string `json:"username"` // GitHub user for displaying an avatar - Account common.Address `json:"account"` // Ethereum address being funded - Time time.Time `json:"time"` // Timestamp when te request was accepted - Tx *types.Transaction `json:"tx"` // Transaction funding the account + Avatar string `json:"avatar"` // Avatar URL to make the UI nicer + Account common.Address `json:"account"` // Ethereum address being funded + Time time.Time `json:"time"` // Timestamp when te request was accepted + Tx *types.Transaction `json:"tx"` // Transaction funding the account } // faucet represents a crypto faucet backed by an Ethereum light client. @@ -344,15 +347,16 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { if err := websocket.JSON.Receive(conn, &msg); err != nil { return } - if !strings.HasPrefix(msg.URL, "https://gist.github.com/") { - websocket.JSON.Send(conn, map[string]string{"error": "URL doesn't link to GitHub Gists"}) + if !strings.HasPrefix(msg.URL, "https://gist.github.com/") && !strings.HasPrefix(msg.URL, "https://twitter.com/") && + !strings.HasPrefix(msg.URL, "https://plus.google.com/") && !strings.HasPrefix(msg.URL, "https://www.facebook.com/") { + websocket.JSON.Send(conn, map[string]string{"error": "URL doesn't link to supported services"}) continue } if msg.Tier >= uint(*tiersFlag) { websocket.JSON.Send(conn, map[string]string{"error": "Invalid funding tier requested"}) continue } - log.Info("Faucet funds requested", "gist", msg.URL, "tier", msg.Tier) + log.Info("Faucet funds requested", "url", msg.URL, "tier", msg.Tier) // If captcha verifications are enabled, make sure we're not dealing with a robot if *captchaToken != "" { @@ -381,65 +385,37 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { continue } } - // Retrieve the gist from the GitHub Gist APIs - parts := strings.Split(msg.URL, "/") - req, _ := http.NewRequest("GET", "https://api.github.com/gists/"+parts[len(parts)-1], nil) - if *githubUser != "" { - req.SetBasicAuth(*githubUser, *githubToken) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - websocket.JSON.Send(conn, map[string]string{"error": err.Error()}) - continue - } - var gist struct { - Owner struct { - Login string `json:"login"` - } `json:"owner"` - Files map[string]struct { - Content string `json:"content"` - } `json:"files"` + // Retrieve the Ethereum address to fund, the requesting user and a profile picture + var ( + username string + avatar string + address common.Address + ) + switch { + case strings.HasPrefix(msg.URL, "https://gist.github.com/"): + username, avatar, address, err = authGitHub(msg.URL) + case strings.HasPrefix(msg.URL, "https://twitter.com/"): + username, avatar, address, err = authTwitter(msg.URL) + case strings.HasPrefix(msg.URL, "https://plus.google.com/"): + username, avatar, address, err = authGooglePlus(msg.URL) + case strings.HasPrefix(msg.URL, "https://www.facebook.com/"): + username, avatar, address, err = authFacebook(msg.URL) + default: + err = errors.New("Something funky happened, please open an issue at https://github.com/ethereum/go-ethereum/issues") } - err = json.NewDecoder(res.Body).Decode(&gist) - res.Body.Close() if err != nil { websocket.JSON.Send(conn, map[string]string{"error": err.Error()}) continue } - if gist.Owner.Login == "" { - websocket.JSON.Send(conn, map[string]string{"error": "Anonymous Gists not allowed"}) - continue - } - // Iterate over all the files and look for Ethereum addresses - var address common.Address - for _, file := range gist.Files { - content := strings.TrimSpace(file.Content) - if len(content) == 2+common.AddressLength*2 { - address = common.HexToAddress(content) - } - } - if address == (common.Address{}) { - websocket.JSON.Send(conn, map[string]string{"error": "No Ethereum address found to fund"}) - continue - } - // Validate the user's existence since the API is unhelpful here - if res, err = http.Head("https://github.com/" + gist.Owner.Login); err != nil { - websocket.JSON.Send(conn, map[string]string{"error": err.Error()}) - continue - } - res.Body.Close() + log.Info("Faucet request valid", "url", msg.URL, "tier", msg.Tier, "user", username, "address", address) - if res.StatusCode != 200 { - websocket.JSON.Send(conn, map[string]string{"error": "Invalid user... boom!"}) - continue - } // Ensure the user didn't request funds too recently f.lock.Lock() var ( fund bool timeout time.Time ) - if timeout = f.timeouts[gist.Owner.Login]; time.Now().After(timeout) { + if timeout = f.timeouts[username]; time.Now().After(timeout) { // User wasn't funded recently, create the funding transaction amount := new(big.Int).Mul(big.NewInt(int64(*payoutFlag)), ether) amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) @@ -459,12 +435,12 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { continue } f.reqs = append(f.reqs, &request{ - Username: gist.Owner.Login, - Account: address, - Time: time.Now(), - Tx: signed, + Avatar: avatar, + Account: address, + Time: time.Now(), + Tx: signed, }) - f.timeouts[gist.Owner.Login] = time.Now().Add(time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute) + f.timeouts[username] = time.Now().Add(time.Duration(*minutesFlag*int(math.Pow(3, float64(msg.Tier)))) * time.Minute) fund = true } f.lock.Unlock() @@ -474,7 +450,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { websocket.JSON.Send(conn, map[string]string{"error": fmt.Sprintf("%s left until next allowance", common.PrettyDuration(timeout.Sub(time.Now())))}) continue } - websocket.JSON.Send(conn, map[string]string{"success": fmt.Sprintf("Funding request accepted for %s into %s", gist.Owner.Login, address.Hex())}) + websocket.JSON.Send(conn, map[string]string{"success": fmt.Sprintf("Funding request accepted for %s into %s", username, address.Hex())}) select { case f.update <- struct{}{}: default: @@ -542,3 +518,162 @@ func (f *faucet) loop() { } } } + +// authGitHub tries to authenticate a faucet request using GitHub gists, returning +// the username, avatar URL and Ethereum address to fund on success. +func authGitHub(url string) (string, string, common.Address, error) { + // Retrieve the gist from the GitHub Gist APIs + parts := strings.Split(url, "/") + req, _ := http.NewRequest("GET", "https://api.github.com/gists/"+parts[len(parts)-1], nil) + if *githubUser != "" { + req.SetBasicAuth(*githubUser, *githubToken) + } + res, err := http.DefaultClient.Do(req) + if err != nil { + return "", "", common.Address{}, err + } + var gist struct { + Owner struct { + Login string `json:"login"` + } `json:"owner"` + Files map[string]struct { + Content string `json:"content"` + } `json:"files"` + } + err = json.NewDecoder(res.Body).Decode(&gist) + res.Body.Close() + if err != nil { + return "", "", common.Address{}, err + } + if gist.Owner.Login == "" { + return "", "", common.Address{}, errors.New("Anonymous Gists not allowed") + } + // Iterate over all the files and look for Ethereum addresses + var address common.Address + for _, file := range gist.Files { + content := strings.TrimSpace(file.Content) + if len(content) == 2+common.AddressLength*2 { + address = common.HexToAddress(content) + } + } + if address == (common.Address{}) { + return "", "", common.Address{}, errors.New("No Ethereum address found to fund") + } + // Validate the user's existence since the API is unhelpful here + if res, err = http.Head("https://github.com/" + gist.Owner.Login); err != nil { + return "", "", common.Address{}, err + } + res.Body.Close() + + if res.StatusCode != 200 { + return "", "", common.Address{}, errors.New("Invalid user... boom!") + } + // Everything passed validation, return the gathered infos + return gist.Owner.Login + "@github", fmt.Sprintf("https://github.com/%s.png?size=64", gist.Owner.Login), address, nil +} + +// authTwitter tries to authenticate a faucet request using Twitter posts, returning +// the username, avatar URL and Ethereum address to fund on success. +func authTwitter(url string) (string, string, common.Address, error) { + // Ensure the user specified a meaningful URL, no fancy nonsense + parts := strings.Split(url, "/") + if len(parts) < 4 || parts[len(parts)-2] != "status" { + return "", "", common.Address{}, errors.New("Invalid Twitter status URL") + } + username := parts[len(parts)-3] + + // Twitter's API isn't really friendly with direct links. Still, we don't + // want to do ask read permissions from users, so just load the public posts and + // scrape it for the Ethereum address and profile URL. + res, err := http.Get(url) + if err != nil { + return "", "", common.Address{}, err + } + defer res.Body.Close() + + reader, err := zlib.NewReader(res.Body) + if err != nil { + return "", "", common.Address{}, err + } + body, err := ioutil.ReadAll(reader) + if err != nil { + return "", "", common.Address{}, err + } + address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) + if address == (common.Address{}) { + return "", "", common.Address{}, errors.New("No Ethereum address found to fund") + } + var avatar string + if parts = regexp.MustCompile("src=\"([^\"]+twimg.com/profile_images[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 { + avatar = parts[1] + } + return username + "@twitter", avatar, address, nil +} + +// authGooglePlus tries to authenticate a faucet request using GooglePlus posts, +// returning the username, avatar URL and Ethereum address to fund on success. +func authGooglePlus(url string) (string, string, common.Address, error) { + // Ensure the user specified a meaningful URL, no fancy nonsense + parts := strings.Split(url, "/") + if len(parts) < 4 || parts[len(parts)-2] != "posts" { + return "", "", common.Address{}, errors.New("Invalid Google+ post URL") + } + username := parts[len(parts)-3] + + // Google's API isn't really friendly with direct links. Still, we don't + // want to do ask read permissions from users, so just load the public posts and + // scrape it for the Ethereum address and profile URL. + res, err := http.Get(url) + if err != nil { + return "", "", common.Address{}, err + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return "", "", common.Address{}, err + } + address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) + if address == (common.Address{}) { + return "", "", common.Address{}, errors.New("No Ethereum address found to fund") + } + var avatar string + if parts = regexp.MustCompile("src=\"([^\"]+googleusercontent.com[^\"]+photo.jpg)\"").FindStringSubmatch(string(body)); len(parts) == 2 { + avatar = parts[1] + } + return username + "@google+", avatar, address, nil +} + +// authFacebook tries to authenticate a faucet request using Facebook posts, +// returning the username, avatar URL and Ethereum address to fund on success. +func authFacebook(url string) (string, string, common.Address, error) { + // Ensure the user specified a meaningful URL, no fancy nonsense + parts := strings.Split(url, "/") + if len(parts) < 4 || parts[len(parts)-2] != "posts" { + return "", "", common.Address{}, errors.New("Invalid Facebook post URL") + } + username := parts[len(parts)-3] + + // Facebook's Graph API isn't really friendly with direct links. Still, we don't + // want to do ask read permissions from users, so just load the public posts and + // scrape it for the Ethereum address and profile URL. + res, err := http.Get(url) + if err != nil { + return "", "", common.Address{}, err + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return "", "", common.Address{}, err + } + address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) + if address == (common.Address{}) { + return "", "", common.Address{}, errors.New("No Ethereum address found to fund") + } + var avatar string + if parts = regexp.MustCompile("src=\"([^\"]+fbcdn.net[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 { + avatar = parts[1] + } + return username + "@facebook", avatar, address, nil +} diff --git a/cmd/faucet/faucet.html b/cmd/faucet/faucet.html index 56dd37623..3b928d636 100644 --- a/cmd/faucet/faucet.html +++ b/cmd/faucet/faucet.html @@ -5,7 +5,7 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>{{.Network}}: GitHub Faucet</title> + <title>{{.Network}}: Authenticated Faucet</title> <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" /> @@ -43,13 +43,13 @@ <div class="container"> <div class="row" style="margin-bottom: 16px;"> <div class="col-lg-12"> - <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{.Network}} GitHub Authenticated Faucet <i class="fa fa-github-alt" aria-hidden="true"></i></h1> + <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{.Network}} Authenticated Faucet</h1> </div> </div> <div class="row"> <div class="col-lg-8 col-lg-offset-2"> <div class="input-group"> - <input id="gist" type="text" class="form-control" placeholder="GitHub Gist URL containing your Ethereum address..."> + <input id="gist" type="text" class="form-control" placeholder="Social network URL containing your Ethereum address..."> <span class="input-group-btn"> <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Give me Ether <i class="fa fa-caret-down" aria-hidden="true"></i></button> <ul class="dropdown-menu dropdown-menu-right">{{range $idx, $amount := .Amounts}} @@ -80,8 +80,21 @@ <div class="row" style="margin-top: 32px;"> <div class="col-lg-12"> <h3>How does this work?</h3> - <p>This Ether faucet is running on the {{.Network}} network. To prevent malicious actors from exhausting all available funds or accumulating enough Ether to mount long running spam attacks, requests are tied to GitHub accounts. Anyone having a GitHub account may request funds within the permitted limits.</p> - <p>To request funds, simply create a <a href="https://gist.github.com/" target="_about:blank">GitHub Gist</a> with your Ethereum address pasted into the contents (the file name doesn't matter), copy paste the gists URL into the above input box and fire away! You can track the current pending requests below the input field to see how much you have to wait until your turn comes.</p> + <p>This Ether faucet is running on the {{.Network}} network. To prevent malicious actors from exhausting all available funds or accumulating enough Ether to mount long running spam attacks, requests are tied to certain common 3rd party accounts. Anyone having a GitHub, Twitter, Google+ or Facebook account may request funds within the permitted limits.</p> + <dl class="dl-horizontal"> + <dt style="width: auto; margin-left: 40px;"><i class="fa fa-github-alt" aria-hidden="true" style="font-size: 36px;"></i></dt> + <dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via GitHub, create a <a href="https://gist.github.com/" target="_about:blank">gist</a> with your Ethereum address embedded into the content (the file name doesn't matter).<br/>Copy-paste the gists URL into the above input box and fire away!</dd> + + <dt style="width: auto; margin-left: 40px;"><i class="fa fa-twitter" aria-hidden="true" style="font-size: 36px;"></i></dt> + <dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Twitter, make a <a href="https://twitter.com/intent/tweet?text=Requesting%20faucet%20funds%20into%200x0000000000000000000000000000000000000000%20on%20the%20%23{{.Network}}%20%23Ethereum%20test%20network." target="_about:blank">tweet</a> with your Ethereum address pasted into the contents (surrounding text doesn't matter).<br/>Copy-paste the <a href="https://support.twitter.com/articles/80586" target="_about:blank">tweets URL</a> into the above input box and fire away!</dd> + + <dt style="width: auto; margin-left: 40px;"><i class="fa fa-google-plus-official" aria-hidden="true" style="font-size: 36px;"></i></dt> + <dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Google Plus, publish a new <strong>public</strong> post with your Ethereum address embedded into the content (surrounding text doesn't matter).<br/>Copy-paste the posts URL into the above input box and fire away!</dd> + + <dt style="width: auto; margin-left: 40px;"><i class="fa fa-facebook" aria-hidden="true" style="font-size: 36px;"></i></dt> + <dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Facebook, publish a new <strong>public</strong> post with your Ethereum address embedded into the content (surrounding text doesn't matter).<br/>Copy-paste the <a href="https://www.facebook.com/help/community/question/?id=282662498552845" target="_about:blank">posts URL</a> into the above input box and fire away!</dd> + </dl> + <p>You can track the current pending requests below the input field to see how much you have to wait until your turn comes.</p> {{if .Recaptcha}}<em>The faucet is running invisible reCaptcha protection against bots.</em>{{end}} </div> </div> @@ -135,7 +148,7 @@ if (msg.requests !== undefined && msg.requests !== null) { var content = ""; for (var i=0; i<msg.requests.length; i++) { - content += "<tr><td><div style=\"background: url('https://github.com/" + msg.requests[i].username + ".png?size=64'); background-size: cover; width:32px; height: 32px; border-radius: 4px;\"></div></td><td><pre>" + msg.requests[i].account + "</pre></td><td style=\"width: 100%; text-align: center; vertical-align: middle;\">" + moment.duration(moment(msg.requests[i].time).unix()-moment().unix(), 'seconds').humanize(true) + "</td></tr>"; + content += "<tr><td><div style=\"background: url('" + msg.requests[i].avatar + "'); background-size: cover; width:32px; height: 32px; border-radius: 4px;\"></div></td><td><pre>" + msg.requests[i].account + "</pre></td><td style=\"width: 100%; text-align: center; vertical-align: middle;\">" + moment.duration(moment(msg.requests[i].time).unix()-moment().unix(), 'seconds').humanize(true) + "</td></tr>"; } $("#requests").html("<tbody>" + content + "</tbody>"); } diff --git a/cmd/faucet/website.go b/cmd/faucet/website.go index 3151ab584..5a80cb0a7 100644 --- a/cmd/faucet/website.go +++ b/cmd/faucet/website.go @@ -68,7 +68,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _faucetHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x59\x6d\x6f\xdc\x36\x12\xfe\xec\xfc\x8a\xa9\x2e\xad\x77\x61\x4b\xb2\xe3\x20\x2d\xd6\xd2\x16\x41\x9a\x4b\x7b\x38\xb4\x45\x9b\xe2\xae\x68\x8b\x03\x25\xcd\x4a\x8c\x29\x52\x25\x87\xbb\xde\x1a\xfb\xdf\x0f\x24\x25\xad\x76\x6d\xa7\xb9\x4b\xf3\x61\x23\x92\x33\xcf\xbc\x51\xf3\x22\x67\x9f\x7c\xf5\xdd\xab\xb7\x3f\x7f\xff\x1a\x1a\x6a\xc5\xf2\x49\xe6\xfe\x03\xc1\x64\x9d\x47\x28\xa3\xe5\x93\x93\xac\x41\x56\x2d\x9f\x9c\x9c\x64\x2d\x12\x83\xb2\x61\xda\x20\xe5\x91\xa5\x55\xfc\x45\xb4\x3f\x68\x88\xba\x18\x7f\xb7\x7c\x9d\x47\xff\x8e\x7f\x7a\x19\xbf\x52\x6d\xc7\x88\x17\x02\x23\x28\x95\x24\x94\x94\x47\xdf\xbc\xce\xb1\xaa\x71\xc2\x27\x59\x8b\x79\xb4\xe6\xb8\xe9\x94\xa6\x09\xe9\x86\x57\xd4\xe4\x15\xae\x79\x89\xb1\x5f\x9c\x03\x97\x9c\x38\x13\xb1\x29\x99\xc0\xfc\x32\x5a\x3e\x71\x38\xc4\x49\xe0\xf2\xee\x2e\xf9\x16\x69\xa3\xf4\xcd\x6e\xb7\x80\x37\x9c\xbe\xb6\x05\xfc\x9d\xd9\x12\x29\x4b\x03\x89\xa7\x16\x5c\xde\x40\xa3\x71\x95\x47\x4e\x67\xb3\x48\xd3\xb2\x92\xef\x4c\x52\x0a\x65\xab\x95\x60\x1a\x93\x52\xb5\x29\x7b\xc7\x6e\x53\xc1\x0b\x93\xd2\x86\x13\xa1\x8e\x0b\xa5\xc8\x90\x66\x5d\x7a\x95\x5c\x25\x9f\xa7\xa5\x31\xe9\xb8\x97\xb4\x5c\x26\xa5\x31\x11\x68\x14\x79\x64\x68\x2b\xd0\x34\x88\x14\x41\xba\xfc\xff\xe4\xae\x94\xa4\x98\x6d\xd0\xa8\x16\xd3\xe7\xc9\xe7\xc9\x85\x17\x39\xdd\x7e\xbf\x54\x27\xd6\x94\x9a\x77\x04\x46\x97\x1f\x2c\xf7\xdd\xef\x16\xf5\x36\xbd\x4a\x2e\x93\xcb\x7e\xe1\xe5\xbc\x33\xd1\x32\x4b\x03\xe0\xf2\xa3\xb0\x63\xa9\x68\x9b\x3e\x4b\x9e\x27\x97\x69\xc7\xca\x1b\x56\x63\x35\x48\x72\x47\xc9\xb0\xf9\x97\xc9\x7d\x2c\x86\xef\x8e\x43\xf8\x57\x08\x6b\x55\x8b\x92\x92\x77\x26\x7d\x96\x5c\x7e\x91\x5c\x0c\x1b\xf7\xf1\xbd\x00\x17\x34\x27\xea\x24\x59\xa3\x26\x5e\x32\x11\x97\x28\x09\x35\xdc\xb9\xdd\x93\x96\xcb\xb8\x41\x5e\x37\xb4\x80\xcb\x8b\x8b\x4f\xaf\x1f\xda\x5d\x37\x61\xbb\xe2\xa6\x13\x6c\xbb\x80\x95\xc0\xdb\xb0\xc5\x04\xaf\x65\xcc\x09\x5b\xb3\x80\x80\xec\x0f\x76\x5e\x66\xa7\x55\xad\xd1\x98\x5e\x58\xa7\x0c\x27\xae\xe4\xc2\xdd\x28\x46\x7c\x8d\x0f\xd1\x9a\x8e\xc9\x7b\x0c\xac\x30\x4a\x58\xc2\x23\x45\x0a\xa1\xca\x9b\xb0\xe7\x5f\xe3\xa9\x11\xa5\x12\x4a\x2f\x60\xd3\xf0\x9e\x0d\xbc\x20\xe8\x34\xf6\xf0\xd0\xb1\xaa\xe2\xb2\x5e\xc0\x8b\xae\xb7\x07\x5a\xa6\x6b\x2e\x17\x70\xb1\x67\xc9\xd2\xc1\x8d\x59\x1a\x32\xd6\x93\x93\xac\x50\xd5\xd6\xc7\xb0\xe2\x6b\x28\x05\x33\x26\x8f\x8e\x5c\xec\x33\xd1\x01\x81\x4b\x40\x8c\xcb\xe1\xe8\xe0\x4c\xab\x4d\x04\x5e\x50\x1e\x05\x25\xe2\x42\x11\xa9\x76\x01\x97\x4e\xbd\x9e\xe5\x08\x4f\xc4\xa2\x8e\x2f\x9f\x0d\x87\x27\x59\x73\x39\x80\x10\xde\x52\xec\xe3\x33\x46\x26\x5a\x66\x7c\xe0\x5d\x31\x58\xb1\xb8\x60\xd4\x44\xc0\x34\x67\x71\xc3\xab\x0a\x65\x1e\x91\xb6\xe8\xee\x11\x5f\xc2\x34\xef\x0d\x69\xef\xa5\xa5\x06\xa5\xb3\x93\xb0\xea\x93\x20\x1c\xc3\xd6\x9c\x1a\x5b\xc4\x4c\xd0\xa3\xe0\x59\xda\x5c\x0e\x26\xa5\x15\x5f\xf7\x1e\x99\x3c\x1e\x39\xe7\x71\xfb\xbf\x80\xfe\x41\xad\x56\x06\x29\x9e\xb8\x63\x42\xcc\x65\x67\x29\xae\xb5\xb2\xdd\x78\x7e\x92\xf9\x5d\xe0\x55\x1e\xd5\xdc\x50\x04\xb4\xed\x7a\xdf\x45\xa3\x49\x4a\xb7\xb1\x0b\x9d\x56\x22\x82\x4e\xb0\x12\x1b\x25\x2a\xd4\x79\xd4\xfb\xe4\x0d\x37\x04\x3f\xfd\xf0\x4f\xe8\x03\xcc\x65\x0d\x5b\x65\x35\xbc\xa6\x06\x35\xda\x16\x58\x55\xb9\xcb\x9d\x24\xc9\x44\xb6\xbf\xe9\xf7\xb5\x8b\x0b\x92\x7b\xaa\x93\xac\xb0\x44\x6a\x24\x2c\x48\x42\x41\x32\xae\x70\xc5\xac\x20\xa8\xb4\xea\x2a\xb5\x91\x31\xa9\xba\x76\x05\x31\x58\x10\x98\x22\xa8\x18\xb1\xfe\x28\x8f\x06\xda\x21\x28\xcc\x74\xaa\xb3\x5d\x1f\x96\xb0\x89\xb7\x1d\x93\x15\x56\x2e\x94\xc2\x60\xb4\x7c\xc3\xd7\x08\x2d\x06\x5b\x4e\x8e\x23\x5d\x32\x8d\x14\x4f\x41\x1f\x88\x74\x50\x26\x98\x04\xfd\xbf\xcc\x8a\x01\x69\x34\xa1\x45\x69\xe1\x60\x15\x6b\x97\x85\xa2\xe5\xdd\x9d\x66\xb2\x46\x78\xca\xab\xdb\x73\x78\xca\x5a\x65\x25\xc1\x22\x87\xe4\xa5\x7f\x34\xbb\xdd\x01\x3a\x40\x26\xf8\x32\x63\xef\x7b\x19\x40\xc9\x52\xf0\xf2\x26\x8f\x88\xa3\xce\xef\xee\x1c\xf8\x6e\x77\x0d\x77\x77\x7c\x05\x4f\x93\x1f\xb0\x64\x1d\x95\x0d\xdb\xed\x6a\x3d\x3c\x27\x78\x8b\xa5\x25\x9c\xcd\xef\xee\x50\x18\xdc\xed\x8c\x2d\x5a\x4e\xb3\x81\xdd\xed\xcb\x6a\xb7\x73\x3a\xf7\x7a\xee\x76\x90\x3a\x50\x59\xe1\x2d\x3c\x4d\xbe\x47\xcd\x55\x65\x20\xd0\x67\x29\x5b\x66\xa9\xe0\xcb\x9e\xef\xd0\x49\xa9\x15\xfb\xfb\x92\xba\x0b\x33\x5e\x6d\xff\xa6\x78\x55\xa7\x9a\x3e\x70\xf1\xeb\x78\xd4\xbe\xbf\x0f\x86\x13\xde\xe0\x36\x8f\xee\xee\xa6\xbc\xfd\x69\xc9\x84\x28\x98\xf3\x4b\x30\x6d\x64\xfa\x03\xdd\x3d\x5d\x73\xe3\x3b\xaf\xe5\xa0\xc1\x5e\xed\x0f\x7c\x93\x8f\xd2\x1c\xa9\x6e\x01\x57\xcf\x26\x39\xee\xa1\x97\xfc\xc5\xd1\x4b\x7e\xf5\x20\x71\xc7\x24\x0a\xf0\xbf\xb1\x69\x99\x18\x9e\xfb\xb7\x65\xf2\xf2\x1d\x33\xc5\x2e\xa3\x8f\xaa\x8d\x95\xe1\xe2\x1a\xd4\x1a\xf5\x4a\xa8\xcd\x02\x98\x25\x75\x0d\x2d\xbb\x1d\xab\xe3\xd5\xc5\xc5\x54\x6f\xd7\x31\xb2\x42\xa0\x4f\x28\x1a\x7f\xb7\x68\xc8\x8c\x89\x24\x1c\xf9\x5f\x97\x4f\x2a\x94\x06\xab\x23\x6f\x38\x89\xce\xb5\x9e\x6a\x12\xfa\xd1\x99\x0f\xea\xbe\x52\x6a\x2c\x38\x53\x35\x7a\xe8\x49\x6d\x8c\x96\x19\xe9\x3d\xdd\x49\x46\xd5\xff\x54\x30\xb4\x6b\x08\x1f\xab\x17\x21\xa3\x39\xdb\x3b\x44\x1d\xba\x11\x77\x65\xc1\x2f\xb3\x94\xaa\x8f\x90\xec\x2e\x61\xc1\x0c\x7e\x88\x78\xdf\x17\xec\xc5\xfb\xe5\xc7\xca\x6f\x90\x69\x2a\x90\x3d\x5e\xd2\x26\x0a\xac\xac\xac\x26\xf6\xfb\xdc\xf9\xb1\x0a\x58\xc9\xd7\xa8\x0d\xa7\xed\x87\x6a\x80\xd5\x5e\x85\xb0\x3e\x54\x21\x4b\x49\xbf\xff\xae\x4d\x17\x7f\xd1\xcb\xfd\x67\x0d\xcc\xd5\xf2\x6b\xb5\x81\x4a\xa1\x01\x6a\xb8\x01\xd7\x7e\x7c\x99\xa5\xcd\xd5\x48\xd2\x2d\xdf\xba\x03\xef\x54\x58\x85\x0e\x84\x1b\xd0\x56\xfa\xca\xab\x24\x50\x83\x87\xcd\x8b\x0c\x4f\x09\xbc\x55\xae\x01\x5c\xa3\x24\x68\x99\xe0\x25\x57\xd6\x00\x2b\x49\x69\x03\x2b\xad\x5a\xc0\xdb\x86\x59\x43\x0e\xc8\xa5\x0f\xb6\x66\x5c\xf8\x77\xc9\x87\x14\x94\x06\x56\x96\xb6\xb5\xae\x81\x95\x35\xa0\x54\xb6\x6e\x7a\x5d\x48\x41\x28\x4c\x42\xc9\x7a\xd4\xc7\x74\xac\x05\x46\xc4\xca\x1b\x73\x0e\x43\x56\x00\xa6\x11\x88\x63\xe5\xb8\xfa\x3e\x82\x95\xa5\x2f\x66\x09\xbc\x94\x5b\x25\x11\x1a\xb6\xf6\x8a\x1c\x11\x40\xcb\xb6\x03\x50\xaf\xd7\x86\x53\xc3\x83\xe1\x1d\xea\xd6\x4d\x24\x15\x08\xde\x72\x32\x49\x96\x76\x53\xdf\xa9\x43\xd6\x73\x30\xbc\xed\xc4\x16\x4a\x8d\x8c\x10\x18\x64\xec\x68\x98\x74\xad\x51\x12\x7a\x3a\x3f\x8e\x44\x40\x4c\xd7\x6e\x54\xff\x0f\x2b\x94\xa5\x45\x21\x98\xbc\x71\xad\xc2\xd8\x0e\xb9\xb2\xe6\x95\x7a\xb8\x11\x82\x8e\x19\xa7\x21\x97\xa4\xbc\xd2\xfd\x6c\x6e\x60\xe6\x56\x2b\x2e\xd0\x8f\xef\xfe\x1e\xc8\x53\x67\xb1\x9b\xb1\xe6\xe7\x50\xaa\x6e\x1b\xb8\x3d\x9f\x53\xcd\xf8\xde\x6b\x84\x62\x85\x5a\x23\x84\xc6\xae\x50\xb7\xc0\x64\x05\x2b\xae\x11\xd8\x86\x6d\x3f\x81\x9f\x95\x85\x92\x49\x20\xcd\xca\x9b\x20\xdb\x6a\xed\x2e\x44\x87\xd2\x25\xfd\x7d\x88\x0a\x14\x6a\xe3\x49\x02\xda\x8a\xa3\xf0\xf1\x32\x88\xd0\xa8\x0d\xb4\xb6\xf4\x06\xba\x40\xa1\x3b\xd8\x30\x4e\x60\x25\x71\x11\xec\x26\xab\x25\x94\xaa\xc5\x83\x28\xdc\xab\xda\x19\xb6\xcb\xb7\xce\xee\x7b\x97\x79\xac\xb7\xa0\xf1\x55\x20\x87\x4e\x2b\xc2\xd2\x0d\x46\xc0\x6a\xc6\xa5\x71\x76\xfa\x38\x63\xfb\x01\xf5\x78\x7c\xea\x1f\xf6\x93\xa8\x3f\x4e\x53\x78\x23\x54\xc1\x04\xac\x5d\x96\x29\x84\x7b\x11\x15\xb8\x96\xf7\xc0\x5b\x86\x18\x59\x03\x6a\xe5\x77\x83\xe6\x8e\x7f\xcd\xb4\xbb\xed\xd8\x76\x04\x79\x3f\x47\xb9\x3d\x83\x7a\xdd\x4f\x87\x6e\xe9\x7a\xae\x70\xde\x0b\xfd\x0a\x57\x5c\x86\xa0\xae\xac\x0c\xe6\x51\xc3\x08\x42\x17\x62\x80\xf9\x60\x83\xd5\x02\xfa\x48\x07\xc8\x51\x80\xa7\x83\x7c\x64\x9f\xdd\xf3\x73\xff\xd0\xfb\x68\xde\xcf\x81\x01\x26\x31\x28\xab\xd9\x3f\x7e\xfc\xee\xdb\xc4\x90\xe6\xb2\xe6\xab\xed\xec\xce\x6a\xb1\x80\xa7\xb3\xe8\x6f\x7e\x3c\x98\xff\x72\xf1\x5b\xb2\x66\xc2\xe2\xb9\x37\x60\xe1\x7f\xef\x89\x39\x87\xfe\x71\x01\x87\x12\x77\xf3\xf9\xf5\xc3\x2d\xdb\xa4\xc3\xd4\x68\x90\x66\x8e\x70\x8c\xe4\xee\xfa\xd0\x49\x0c\x5a\xa4\x46\xf9\xbb\xa8\xb1\x54\x52\x62\x49\x60\x3b\x25\x7b\x9f\x80\x50\xc6\x0c\x8e\xd9\x53\x4c\x7c\x33\x18\xcf\x57\x30\x1b\xc2\xf5\x29\x3c\x83\x3c\x87\x8b\xe1\xac\xf7\x0c\xe4\x20\x71\x03\xff\xc2\xe2\x47\x55\xde\x20\xcd\xa2\x8d\x71\x69\x21\x82\x33\x10\xaa\x64\x0e\x2f\x69\x94\x21\x38\x83\x28\x65\x1d\x8f\xe6\x61\x9a\xde\x81\x6b\x91\xff\x1c\xec\x83\xb0\xc2\xf7\x86\xa0\xe9\xd9\x59\xb8\x36\x43\xe8\x94\x6c\xd1\x18\x56\xe3\xd4\x42\x9f\xe5\x47\x53\x9c\x23\x5a\x53\x43\x0e\x3e\xc4\x1d\xd3\x06\x03\x49\xe2\x3a\x8b\x5e\x8a\x77\x87\x27\xcb\x73\x90\x56\x88\x91\xff\x44\xa3\x7b\x99\x7b\xb2\xdd\x93\x03\xf2\x24\x24\xe1\x4f\xf2\x1c\x5c\x99\x75\x31\xaa\xf6\x9c\xee\xfa\x84\x86\x60\x9e\xb8\x4a\xbf\xe7\x98\x8f\x70\xf7\xd0\xb0\xfa\x33\x38\xac\x8e\xf1\xb0\x7a\x04\xd0\xf7\x5f\xef\xc3\x0b\xfd\xda\x04\xce\x6f\x3c\x82\x26\x6d\x5b\xa0\x7e\x1f\x5c\xe8\xbf\x7a\x38\xef\xea\x6f\x24\x4d\x78\xcf\xe1\xf2\xc5\xfc\x11\x74\xd4\x5a\x3d\x0a\x2e\x15\x6d\x67\x77\x82\x6d\x5d\xd5\x81\x53\x52\xdd\x2b\xdf\x2e\x9d\x9e\x83\x93\xb5\x80\x11\xe1\xdc\x0f\xc2\x0b\x38\xf5\xab\xd3\xdd\x23\xd2\x8c\x2d\x4b\x57\x8f\x3e\x46\x5e\x8f\x31\x4a\xec\xd7\x8f\xca\x1c\xeb\xcb\x81\x50\xf8\xec\x33\xb8\x77\x7a\x78\x05\xdd\x1d\xee\x0b\x25\xe4\x10\x45\x3d\xfc\xc9\x4a\x69\x98\xb9\x43\x9e\x5f\x5c\x03\xcf\xa6\x30\x89\x40\x59\x53\x73\x0d\xfc\xec\x6c\x8f\x74\x32\xc0\x9c\xe5\x10\xb9\x89\x20\xa3\x6a\xe9\x3b\xb3\xd0\xbe\xfd\x1a\xb9\x09\xb0\xd6\xca\xca\x6a\xe1\x52\xee\xec\x74\xdf\x0c\x4c\xfa\x80\xb3\x03\x95\x7f\xe1\xbf\x25\xd6\xa0\xf6\x95\xfb\x0c\xa2\xa4\x93\xf5\x97\x7e\x6e\x7c\xf1\xfc\x74\x7e\x0d\x7b\x4c\x3f\x4d\x2e\xa0\x74\xb3\xd5\x35\x84\xf9\xc4\x77\x89\x30\x4e\x56\x7e\x55\x28\x5d\xa1\x8e\x35\xab\xb8\x35\x0b\x78\xde\xdd\x5e\xff\x3a\x4c\x9e\xbe\x97\xf5\x7a\x77\x1a\x97\x0f\xe9\x32\xb4\x4b\x67\x10\x65\xa9\x23\x1a\x58\x46\x2b\xa7\x5f\x0d\xe1\x81\x2e\x1c\xc6\x6f\x7a\xfd\x7e\xcb\xab\x4a\xa0\x53\xc2\x0b\x0c\x1f\x5f\x2b\xab\x7d\xe2\x9a\x85\xf5\xec\x58\x0f\xe2\x2d\xce\x13\x2b\xf9\xed\x6c\x1e\xf7\x34\xc3\xfa\x1c\x4e\x8d\xcb\xcf\x95\x39\x9d\x27\x8d\x6d\x99\xe4\x7f\xe0\xcc\xb5\xf4\xf3\xa0\xb7\xd3\xd8\xf5\xe9\x63\xb4\x77\x93\x17\x6d\x9c\x31\xe7\x49\x43\xad\x98\x45\x19\xf9\x2f\x93\x4e\xb9\x31\xc4\x1e\x25\x6c\x1f\xde\xc8\xdd\x61\x0e\x2d\x85\x32\x78\x54\x23\xc0\x20\xbd\xe5\x2d\x2a\x4b\xb3\xb1\x8e\x9c\xbb\xb9\xf7\x62\x7e\x0d\xbb\xfd\x07\xdc\x34\x85\xd7\xc6\x4d\x12\xdc\x34\xc0\x60\x83\x85\xf1\xf9\x1d\x7a\x1e\x5f\xce\x43\xd9\x7e\xf9\xfd\x37\x93\xd2\x3d\xa2\xce\xbc\x72\xe3\x07\xec\x87\xea\xe4\x83\x5f\xcc\x37\x9b\x4d\x52\x2b\x55\x8b\xf0\xad\x7c\x2c\xa4\xae\x7a\x24\xef\xdc\xb8\x6a\xb6\xb2\x84\x0a\x57\xa8\x97\x13\xf8\xbe\xba\x66\x69\xf8\x96\x9b\xa5\xe1\xef\x54\xff\x0d\x00\x00\xff\xff\x71\x50\x77\xf3\xb8\x1a\x00\x00") +var _faucetHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x3a\x7f\x73\xe3\xb6\xb1\x7f\xfb\x3e\xc5\x86\xef\x5c\x4b\x63\x93\x94\xe5\xcb\xd5\x4f\x26\x95\xb9\xb9\xa6\x69\xde\xbc\x69\x6f\x92\xeb\xbc\xd7\x69\x3b\x6f\x40\x72\x45\xe2\x0c\x02\x0c\xb0\x94\xac\x78\xf4\xdd\xdf\x00\x20\x29\x4a\xb6\xef\x9c\xbb\x4c\x9b\xfb\xc3\x21\x80\xfd\xbd\x8b\xdd\xc5\x2a\xc9\x57\x7f\xf8\xcb\xdb\xf7\x7f\x7b\xf7\x2d\x54\x54\x8b\xe5\x8b\xc4\xfe\x07\x04\x93\x65\x1a\xa0\x0c\x96\x2f\x4e\x92\x0a\x59\xb1\x7c\x71\x72\x92\xd4\x48\x0c\xf2\x8a\x69\x83\x94\x06\x2d\xad\xc2\xeb\x60\x7f\x50\x11\x35\x21\xfe\xd4\xf2\x75\x1a\xfc\x6f\xf8\xd7\x37\xe1\x5b\x55\x37\x8c\x78\x26\x30\x80\x5c\x49\x42\x49\x69\xf0\xfd\xb7\x29\x16\x25\x8e\xf0\x24\xab\x31\x0d\xd6\x1c\x37\x8d\xd2\x34\x02\xdd\xf0\x82\xaa\xb4\xc0\x35\xcf\x31\x74\x8b\x0b\xe0\x92\x13\x67\x22\x34\x39\x13\x98\x5e\x06\xcb\x17\x96\x0e\x71\x12\xb8\xbc\xbf\x8f\xfe\x8c\xb4\x51\xfa\x76\xb7\x5b\xc0\x9b\x96\x2a\x94\xc4\x73\x46\x58\xc0\x1f\x59\x9b\x23\x25\xb1\x87\x74\x48\x82\xcb\x5b\xa8\x34\xae\xd2\xc0\x8a\x6e\x16\x71\x9c\x17\xf2\x83\x89\x72\xa1\xda\x62\x25\x98\xc6\x28\x57\x75\xcc\x3e\xb0\xbb\x58\xf0\xcc\xc4\xb4\xe1\x44\xa8\xc3\x4c\x29\x32\xa4\x59\x13\x5f\x45\x57\xd1\xef\xe3\xdc\x98\x78\xd8\x8b\x6a\x2e\xa3\xdc\x98\x00\x34\x8a\x34\x30\xb4\x15\x68\x2a\x44\x0a\x20\x5e\x7e\x1e\xdf\x95\x92\x14\xb2\x0d\x1a\x55\x63\xfc\x2a\xfa\x7d\x34\x73\x2c\xc7\xdb\x1f\xe7\x6a\xd9\x9a\x5c\xf3\x86\xc0\xe8\xfc\xd9\x7c\x3f\xfc\xd4\xa2\xde\xc6\x57\xd1\x65\x74\xd9\x2d\x1c\x9f\x0f\x26\x58\x26\xb1\x27\xb8\xfc\x22\xda\xa1\x54\xb4\x8d\xe7\xd1\xab\xe8\x32\x6e\x58\x7e\xcb\x4a\x2c\x7a\x4e\xf6\x28\xea\x37\x7f\x35\xbe\x4f\xf9\xf0\xc3\xb1\x0b\x7f\x0d\x66\xb5\xaa\x51\x52\xf4\xc1\xc4\xf3\xe8\xf2\x3a\x9a\xf5\x1b\x0f\xe9\x3b\x06\xd6\x69\x96\xd5\x49\xb4\x46\x6d\x23\x57\x84\x39\x4a\x42\x0d\xf7\x76\xf7\xa4\xe6\x32\xac\x90\x97\x15\x2d\xe0\x72\x36\x3b\xbd\x79\x6c\x77\x5d\xf9\xed\x82\x9b\x46\xb0\xed\x02\x56\x02\xef\xfc\x16\x13\xbc\x94\x21\x27\xac\xcd\x02\x3c\x65\x77\xb0\x73\x3c\x1b\xad\x4a\x8d\xc6\x74\xcc\x1a\x65\x38\x71\x25\x17\x36\xa2\x18\xf1\x35\x3e\x06\x6b\x1a\x26\x1f\x20\xb0\xcc\x28\xd1\x12\x1e\x09\x92\x09\x95\xdf\xfa\x3d\x77\x9b\xc7\x4a\xe4\x4a\x28\xbd\x80\x4d\xc5\x3b\x34\x70\x8c\xa0\xd1\xd8\x91\x87\x86\x15\x05\x97\xe5\x02\x5e\x37\x9d\x3e\x50\x33\x5d\x72\xb9\x80\xd9\x1e\x25\x89\x7b\x33\x26\xb1\x4f\x5c\x2f\x4e\x92\x4c\x15\x5b\xe7\xc3\x82\xaf\x21\x17\xcc\x98\x34\x38\x32\xb1\x4b\x48\x07\x00\x36\x0f\x31\x2e\xfb\xa3\x83\x33\xad\x36\x01\x38\x46\x69\xe0\x85\x08\x33\x45\xa4\xea\x05\x5c\x5a\xf1\x3a\x94\x23\x7a\x22\x14\x65\x78\x39\xef\x0f\x4f\x92\xea\xb2\x27\x42\x78\x47\xa1\xf3\xcf\xe0\x99\x60\x99\xf0\x1e\x77\xc5\x60\xc5\xc2\x8c\x51\x15\x00\xd3\x9c\x85\x15\x2f\x0a\x94\x69\x40\xba\x45\x1b\x47\x7c\x09\xe3\xf4\xf7\x44\xf6\xab\x2e\x7b\xb9\xe2\x82\xaf\x3b\xb5\x46\x9f\x47\x1a\x3e\xad\xc4\x35\x74\x1f\x6a\xb5\x32\x48\xe1\x48\xa7\x11\x30\x97\x4d\x4b\x61\xa9\x55\xdb\x0c\xe7\x27\x89\xdb\x05\x5e\xa4\x41\xc9\x0d\x05\x40\xdb\xa6\x33\x40\x30\xa8\xab\x74\x1d\x5a\xfb\x6b\x25\x02\x68\x04\xcb\xb1\x52\xa2\x40\x9d\x06\x3f\xaa\x9c\x33\x01\xd2\x6b\x0a\x7f\xfd\xe1\xbf\xa1\x73\x14\x97\x25\x6c\x55\xab\xe1\x5b\xaa\x50\x63\x5b\x03\x2b\x0a\x1b\xa4\x51\x14\x8d\xd8\xbb\x88\x7d\x28\x60\x98\x91\xdc\x43\x9d\x24\x59\x4b\xa4\x06\xc0\x8c\x24\x64\x24\xc3\x02\x57\xac\x15\x04\x85\x56\x4d\xa1\x36\x32\x24\x55\x96\xb6\xbe\x79\x25\x3c\x52\x00\x05\x23\xd6\x1d\xa5\x41\x0f\xdb\x7b\x8e\x99\x46\x35\x6d\xd3\xf9\xce\x6f\xe2\x5d\xc3\x64\x81\x85\xf5\xb4\x30\x18\x2c\xbf\xe3\x6b\x84\x1a\xbd\x2e\x27\xc7\x81\x90\x33\x8d\x14\x8e\x89\x3e\x08\x87\x24\xf6\xc2\x78\x95\xa0\xfb\x97\xb4\xa2\xa7\x34\xa8\x50\xa3\x6c\xe1\x60\x15\x6a\x9b\x4d\x82\xe5\xfd\xbd\x66\xb2\x44\x78\xc9\x8b\xbb\x0b\x78\xc9\x6a\xd5\x4a\x82\x45\x0a\xd1\x1b\xf7\x69\x76\xbb\x03\xea\x00\x89\xe0\xcb\x84\x7d\x2c\xa8\x41\xc9\x5c\xf0\xfc\x36\x0d\x88\xa3\x4e\xef\xef\x2d\xf1\xdd\xee\x06\xee\xef\xf9\x0a\x5e\x46\x3f\x60\xce\x1a\xca\x2b\xb6\xdb\x95\xba\xff\x8e\xf0\x0e\xf3\x96\x70\x32\xbd\xbf\x47\x61\x70\xb7\x33\x6d\x56\x73\x9a\xf4\xe8\x76\x5f\x16\xbb\x9d\x95\xb9\x93\x73\xb7\x83\xd8\x12\x95\x05\xde\xc1\xcb\xe8\x1d\x6a\xae\x0a\x03\x1e\x3e\x89\xd9\x32\x89\x05\x5f\x76\x78\x87\x46\x8a\x5b\xb1\x8f\x97\xd8\x06\xcc\x10\xdd\xee\xb2\x38\x51\xc7\x92\x3e\x12\xfb\x65\x38\x48\xdf\xc5\x83\xe1\x84\xb7\xb8\x4d\x83\xfb\xfb\x31\x6e\x77\x9a\x33\x21\x32\x66\xed\xe2\x55\x1b\x90\x7e\x46\x1b\xa7\x6b\x6e\x5c\x23\xb5\xec\x25\xd8\x8b\xfd\xcc\xcb\x7c\x94\xae\x48\x35\x0b\xb8\x9a\x8f\x72\xd5\x63\xf7\xfc\xf5\xd1\x3d\xbf\x7a\x14\xb8\x61\x12\x05\xb8\xbf\xa1\xa9\x99\xe8\xbf\xbb\xdb\x32\xba\x7c\xc7\x48\xa1\xcd\xcc\x83\x68\x43\x86\x9f\xdd\x80\x5a\xa3\x5e\x09\xb5\x59\x00\x6b\x49\xdd\x40\xcd\xee\x86\x2a\x77\x35\x9b\x8d\xe5\xb6\x0d\x20\xcb\x04\xba\x9c\xa2\xf1\xa7\x16\x0d\x99\x21\x97\xf8\x23\xf7\xd7\xa6\x94\x02\xa5\xc1\xe2\xc8\x1a\x96\xa3\x35\xad\x83\x1a\xb9\x7e\x30\xe6\xa3\xb2\xaf\x94\x1a\x0a\xc7\x58\x8c\x8e\xf4\xa8\xc6\x05\xcb\x84\xf4\x1e\xee\x24\xa1\xe2\x17\x25\x7e\x6d\x1b\xbb\xa7\xf2\xbe\xcf\x68\x56\xf7\x06\x51\xfb\xae\xc2\x86\x2c\xb8\x65\x12\x53\xf1\x05\x9c\x6d\x10\x66\xcc\xe0\x73\xd8\xbb\xfa\xbe\x67\xef\x96\x5f\xca\xbf\x42\xa6\x29\x43\x46\xcf\x11\x60\xd5\xca\x62\xa4\xbf\xcb\x9d\x5f\x2a\x40\x2b\xf9\x1a\xb5\xe1\xb4\x7d\xae\x04\x58\xec\x45\xf0\xeb\x43\x11\x92\x98\xf4\xc7\x63\x6d\xbc\xf8\x95\x2e\xf7\xa7\x1a\x91\xab\xe5\x9f\xd4\x06\x0a\x85\x06\xa8\xe2\x06\x6c\x71\xfd\x26\x89\xab\xab\x01\xa4\x59\xbe\xb7\x07\xce\xa8\xb0\x72\x0d\x05\x70\x03\xba\x95\xae\xf2\x2a\x09\x54\xe1\x61\x13\xd2\x15\xe9\x08\xde\x2b\xdb\xc8\xad\x51\x12\xd4\x4c\xf0\x9c\xab\xd6\x00\xcb\x49\x69\x03\x2b\xad\x6a\xc0\xbb\x8a\xb5\x86\x2c\x21\x9b\x3e\xd8\x9a\x71\xe1\xee\x92\x73\x29\x28\x0d\x2c\xcf\xdb\xba\xb5\x8d\xa8\x2c\x01\xa5\x6a\xcb\xaa\x93\x85\x14\xf8\xc2\x24\x94\x2c\x07\x79\x4c\xc3\x6a\x60\x44\x2c\xbf\x35\x17\xd0\x67\x05\x60\x1a\x81\x38\x16\x16\x2b\x47\x6d\xfb\x06\xc8\x55\x5d\x2b\x09\x57\xba\x80\x86\x69\xda\x5a\x5e\xae\xbc\x45\xf0\x46\x6e\x95\x44\xa8\xd8\xda\x89\x06\xdf\x71\xfa\x53\x9b\x5d\xc0\x7b\xff\x8a\xb8\x80\xef\x94\x2a\x05\x9e\x5b\x09\xff\xc8\x72\xcc\x94\xba\xed\xd1\xa1\x66\xdb\x9e\x71\xa7\xc7\x86\x53\xc5\xbd\xa1\x1a\xd4\xb5\xa5\x51\x80\xe0\x35\x27\x13\x25\x71\xb3\xcf\xad\xfb\x2a\x2d\xc2\x4a\x69\xfe\xb3\x6d\x71\xc4\xe0\x2f\x80\xa4\xa0\xa3\x3c\xd3\xa7\x49\x17\x00\x02\x57\xb4\x80\x57\x3e\x4d\x1e\x87\x74\xc9\xa9\x6a\xb3\x90\x89\x47\x2f\x55\x4f\xd6\xbd\x2e\x6d\xf9\x59\xc0\x95\x6f\x69\x7d\x5b\x51\xd0\x28\x25\x16\x47\x81\xe7\xf9\x5e\x5f\x37\x77\x83\x28\x43\x5f\x3c\x1b\x88\xd8\x78\x38\x34\xcc\x9a\xef\x6d\x9b\x6b\x64\x84\xc0\x20\x61\x47\xcf\x64\xdb\x2f\x46\x5e\x7a\xf7\xd0\x0a\x80\x98\x2e\x91\xd2\xe0\xff\x58\xa6\x5a\x5a\x64\x82\xc9\xdb\x60\x69\xe1\x6c\x85\x77\xf6\x7e\xbc\x27\x04\xac\x33\x2c\x0a\x2c\x80\x4b\x52\xce\x23\xdd\xdc\x01\x26\x76\xb1\xe2\x02\xdd\x64\xc2\xdd\x09\x79\x66\xbd\x69\x3d\x3e\x8d\x92\x4c\xc7\xcb\xb7\xaa\xd9\x86\x0d\x33\x84\x0e\xd5\x32\x34\xae\x17\x1d\xa8\xb1\x4c\xad\x11\x7c\xaf\x9b\xa9\x3b\x60\xb2\x80\x15\xd7\x08\x6c\xc3\xb6\x5f\x25\x71\xe1\x5e\x26\xbd\x1d\x3f\xdf\x99\xdd\x7b\xf6\x37\xe5\xc9\xe1\x76\xd4\xec\xf6\x51\x47\x76\x42\x3b\x27\x72\x67\xf5\x98\x36\x88\xf4\x8d\x4d\xc9\xe9\x0f\x9e\x20\x97\xe5\xe9\x7c\xe6\x33\x8d\xfd\xb0\xe4\x4f\xe7\x33\x6b\xe1\xd3\xf9\x6c\x76\x37\x7b\xe6\xbf\xd3\xf9\x4c\xc9\xd3\xf9\x8c\x2a\x3c\x9d\xcf\x4e\xe7\x57\xe3\x1c\xe5\x77\xfa\xe8\xb0\x50\x68\x2c\xb7\x3e\x75\x3d\x15\x62\x4e\xdc\x4f\xc5\x98\x0b\x90\x87\x11\x66\x60\x62\x5a\xad\x55\x2b\x6d\xb7\x03\x56\xe7\x67\x45\xd9\x03\x33\x9a\xb6\x69\x94\xa6\x68\x6c\x4e\x66\x5f\xb5\x02\x4d\x7c\x3d\xfb\xfa\xfa\xf5\x47\xc5\x77\x11\xeb\x74\xf8\x97\x47\x6d\xe9\xd2\x66\xd8\x88\xd6\xd8\xd6\x92\xdb\x37\xdd\x6f\x2a\x84\x7d\x5e\x87\x77\xa2\x35\x17\xd0\xb4\x99\xe0\xa6\x02\x06\x12\x37\x90\x18\xd2\x4a\x96\x4b\xb7\x9b\x27\x71\xb7\x84\x46\x19\xfa\xcc\x8c\xf3\x59\xe1\x60\xf9\xfd\x9b\x92\xce\xaa\x2b\x75\xbf\x29\x97\xf5\xf5\xf7\x17\xf9\x4b\xc9\x7f\xa5\xcb\x1e\xdc\xe0\xcd\x66\x13\xf5\xc6\x74\xd7\xb7\x42\xd1\xc4\xb6\x21\x69\x25\xa7\x6d\xec\x13\xa1\x92\xf1\x37\xbc\x48\xe7\xd7\xf3\xd7\xaf\xe7\xaf\xfe\xf3\xfa\xeb\xaf\xe7\xd7\xaf\xbe\x7e\xea\x6e\x0f\x71\xf1\xcb\xaf\xf6\xd0\x7e\x8a\x51\xdb\xf7\x37\xd5\x42\xce\x24\x90\x66\xf9\xad\x37\x42\xab\xb5\x35\x42\x83\x5e\xff\xa1\xbb\xca\x50\xa8\x8d\x03\xf1\x7c\x56\x1c\x85\x6b\xb5\x0c\x22\x54\x6a\x03\x75\x9b\x3b\x5b\xdb\x8e\x0a\xed\xc1\x86\x71\x82\x56\x12\x17\xde\x05\xd4\x6a\xd7\x90\xe1\x41\x43\xf4\xe0\xc1\x9d\x60\xbd\x7c\x6f\xcb\xf4\x83\x3e\x74\x78\x2a\x83\xc6\xb7\x1e\x1c\x1a\xad\x08\x73\x6b\x47\x60\x25\xe3\xd2\x58\x0b\xb8\x96\x0b\xeb\x67\x3c\xa5\x87\xaf\xee\x63\x3f\x0c\x76\xc7\x71\x0c\xdf\x09\x95\x31\x01\x6b\x7b\x1b\x32\x61\x7b\x68\x05\x95\xb2\xaa\x8f\xac\x65\x88\x51\x6b\x40\xad\xdc\xae\x97\xdc\xe2\xaf\x99\xb6\x8d\x2a\xd6\x0d\x41\xda\x8d\x32\xed\x9e\x41\xbd\xee\x06\xb4\x76\x49\x1c\xb5\x3f\xef\x98\xfe\x01\x57\x5c\xfa\xb8\x5a\xb5\xd2\xab\x47\x15\x23\xf0\x03\x04\x03\xcc\xf5\x25\xd0\x6a\x01\x5d\x0c\x78\x92\x03\x03\x07\x07\xe9\x80\x3e\x79\x60\xe7\xee\xa3\xb3\xd1\xb4\x1b\xc5\x7a\x32\x91\x41\x59\x4c\xfe\xeb\xc7\xbf\xfc\x39\x32\xa4\xb9\x2c\xf9\x6a\x3b\xb9\x6f\xb5\x58\xc0\xcb\x49\xf0\x1f\x6e\xb8\x37\xfd\xfb\xec\x9f\xd1\x9a\x89\x16\x2f\x9c\x02\x0b\xf7\xf7\x01\x9b\x0b\xe8\x3e\x17\x70\xc8\x71\x37\x9d\xde\x3c\x3e\x6d\x19\x0d\x87\x34\x1a\xa4\x89\x05\x1c\x3c\xb9\xbb\x39\x34\x12\x83\x1a\xa9\x52\x2e\x16\x35\xe6\x4a\x4a\xcc\x09\xda\x46\xc9\xce\x26\x20\x94\x31\xbd\x61\xf6\x10\x23\xdb\xf4\xca\xf3\x15\x4c\x7a\x77\x9d\xc2\x1c\xd2\x14\x66\xfd\x59\x67\x19\x48\x5d\xe2\xf9\x1f\xcc\x7e\x54\xf9\x2d\xd2\x24\xd8\x18\x7b\xdb\x03\x38\x07\xa1\x72\x66\xe9\x45\x95\x4d\x3f\xe7\x10\xc4\xac\xe1\xc1\xd4\x0f\xb4\x77\x80\xc2\xe0\xa7\x89\x3d\x8b\x96\x1f\xf9\x7b\x49\xcf\xcf\x7d\xd8\xf4\xae\x53\xb2\x46\x63\x58\x89\x63\x0d\xdd\x03\x6d\x50\xc5\x1a\xa2\x36\x25\xa4\xe0\x5c\xdc\x30\x6d\xd0\x83\x44\x05\x23\xd6\x71\x71\xe6\x70\x60\x69\x0a\xb2\x15\x62\xc0\x3f\xd1\x68\x2f\x73\x07\xb6\x7b\x71\x00\x1e\xf9\xb4\xfd\x55\x9a\x82\x7d\x21\x5b\x1f\x15\x7b\x4c\x1b\x3e\xfe\x2d\x3f\x8d\x6c\x6e\xdd\x63\x4c\x07\x72\x0f\xa8\x61\xf1\x29\x72\x58\x1c\xd3\xc3\xe2\x09\x82\x6e\x74\xf2\x31\x7a\x7e\xd4\x32\x22\xe7\x36\x9e\xa0\x26\xdb\x3a\x43\xfd\x31\x72\x7e\x74\xd2\x91\x73\xa6\xfe\x5e\xd2\x08\xf7\x02\x2e\x5f\x4f\x9f\xa0\x8e\x5a\xab\x27\x89\x4b\x45\xdb\xc9\xbd\x60\x5b\x5b\x20\xe0\x8c\x54\xf3\xd6\x4d\x3a\xce\x2e\x5c\xd5\x5a\xc0\x40\xe1\xc2\xcd\xb0\x17\x70\xe6\x56\x67\xbb\x27\xb8\x99\x36\xcf\x6d\x69\xfc\x12\x7e\x1d\x8d\x81\x63\xb7\x7e\x92\xe7\x50\x5f\x0e\x98\xc2\xef\x7e\x07\x0f\x4e\x0f\x43\xd0\xc6\x70\x5f\xb1\x53\x08\x82\x8e\xfc\xc9\x4a\x69\x98\xd8\x43\x9e\xce\x6e\x80\x27\x63\x32\x91\x40\x59\x52\x75\x03\xfc\xfc\x7c\x4f\xe9\xa4\x27\x73\x9e\x42\x90\x90\x5e\x26\x54\x2c\xdd\x50\xc5\x37\x30\xff\x08\x32\x96\xdf\x96\xae\x25\x58\xd8\x94\x3b\x39\xb3\x37\x74\x4c\xf8\xef\xfc\x9f\x11\x5b\x33\x62\xda\x5e\xd5\xb3\xe9\x0d\xec\x51\xba\x46\x29\x57\x36\xe3\x83\xef\xc7\xdc\xfc\x06\x86\x99\xa7\x5b\x65\x4a\x17\xa8\x43\xcd\x0a\xde\x9a\x05\xbc\x6a\xee\x6e\xfe\xd1\xcf\x84\xdd\x94\xc9\x89\xd5\x68\x5c\x3e\xca\xbd\x1b\x4c\x9c\x43\x90\xc4\x16\xa8\x47\x19\x94\x18\xff\x2e\x07\x8f\xcc\xc7\x60\xf8\xd5\xac\xdb\xaf\x79\x51\x08\xb4\x42\x38\x86\xfe\xe7\xcd\xa2\xd5\x2e\x2f\x4d\xfc\x7a\x72\x2c\x07\xf1\x1a\xa7\x51\x2b\xf9\xdd\x64\x1a\x76\x30\xfd\xfa\x02\xce\x8c\x4d\xbf\x85\x39\x9b\x46\x55\x5b\x33\xc9\x7f\xc6\x89\xed\x2c\xa7\x5e\x6e\x2b\x71\x4c\x7a\x39\x38\x73\x37\xba\x47\xc3\xf4\x77\x1a\x55\x54\x8b\x49\x90\x90\xfb\xed\xcf\x0a\x37\x78\xd0\x51\xf1\xdb\x87\x01\xb7\x3b\x4c\x91\xb9\x50\x06\x8f\x4a\x00\x18\xa4\xf7\xbc\x46\xd5\xd2\x64\x28\x13\x17\x70\x35\x9b\xcd\xa6\x37\xb0\xdb\xff\x44\x1a\xc7\xf0\xad\x21\xd6\x37\xa2\x1b\xcc\x8c\x4b\xdf\xd0\xe1\xb8\x6a\xed\xab\xf2\x9b\x77\xdf\x8f\x2a\xf3\x40\x75\xe2\x84\x1b\x7e\x22\x7e\xac\x0c\x3e\xfa\x9b\xb4\xed\x29\xfd\xfb\xca\x75\x94\x43\x9d\xb4\xc5\x21\xfa\x60\x02\x60\x66\x2b\x73\x28\x70\x85\x7a\x39\x22\xdf\x15\xcf\x24\xf6\xbf\x96\x26\xb1\xff\x1f\x42\xfe\x3f\x00\x00\xff\xff\x1f\xb2\x73\x97\x21\x22\x00\x00") func faucetHtmlBytes() ([]byte, error) { return bindataRead( |