Этот коммит содержится в:
Christopher Speller
2017-09-29 12:46:30 -07:00
коммит произвёл GitHub
родитель 8b9dbb8613
Коммит b84736e9b6
422 изменённых файлов: 39231 добавлений и 28592 удалений

Просмотреть файл

@@ -80,7 +80,7 @@ endif
# Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target # Prepares the enterprise build if exists. The IGNORE stuff is a hack to get the Makefile to execute the commands outside a target
ifeq ($(BUILD_ENTERPRISE_READY),true) ifeq ($(BUILD_ENTERPRISE_READY),true)
IGNORE:=$(shell echo Enterprise build selected, preparing) IGNORE:=$(shell echo Enterprise build selected, preparing)
IGNORE:=$(shell mkdir -p imports/) IGNORE:=$(shell rm -f imports/imports.go)
IGNORE:=$(shell cp $(BUILD_ENTERPRISE_DIR)/imports/imports.go imports/) IGNORE:=$(shell cp $(BUILD_ENTERPRISE_DIR)/imports/imports.go imports/)
IGNORE:=$(shell rm -f enterprise) IGNORE:=$(shell rm -f enterprise)
IGNORE:=$(shell ln -s $(BUILD_ENTERPRISE_DIR) enterprise) IGNORE:=$(shell ln -s $(BUILD_ENTERPRISE_DIR) enterprise)
@@ -465,7 +465,7 @@ clean: stop-docker
rm -f ecover.out rm -f ecover.out
rm -f *.out rm -f *.out
rm -f *.test rm -f *.test
rm -f imports.go rm -f imports/imports.go
nuke: clean clean-docker nuke: clean clean-docker
@echo BOOM @echo BOOM

Просмотреть файл

@@ -1,106 +0,0 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"testing"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
)
func TestParseChannelArg(t *testing.T) {
if team, channel := parseChannelArg("channel"); team != "" {
t.Fatal("got incorrect team", team)
} else if channel != "channel" {
t.Fatal("got incorrect channel", channel)
}
if team, channel := parseChannelArg("team:channel"); team != "team" {
t.Fatal("got incorrect team", team)
} else if channel != "channel" {
t.Fatal("got incorrect channel", channel)
}
}
func TestGetChannelFromChannelArg(t *testing.T) {
th := app.Setup().InitBasic()
team := th.BasicTeam
channel := th.BasicChannel
if found := getChannelFromChannelArg(""); found != nil {
t.Fatal("shoudn't have gotten a channel", found)
}
if found := getChannelFromChannelArg(channel.Id); found == nil || found.Id != channel.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelFromChannelArg(model.NewId()); found != nil {
t.Fatal("shouldn't have gotten a channel that doesn't exist", found)
}
if found := getChannelFromChannelArg(channel.Name); found != nil {
t.Fatal("shouldn't have gotten a channel by name without team", found)
}
if found := getChannelFromChannelArg(team.Id + ":" + channel.Name); found == nil || found.Id != channel.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelFromChannelArg(team.Name + ":" + channel.Name); found == nil || found.Id != channel.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelFromChannelArg(team.Name + ":" + channel.Id); found == nil || found.Id != channel.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelFromChannelArg("notateam" + ":" + channel.Name); found != nil {
t.Fatal("shouldn't have gotten a channel by name on incorrect team", found)
}
if found := getChannelFromChannelArg(team.Name + ":" + "notachannel"); found != nil {
t.Fatal("shouldn't have gotten a channel that doesn't exist", found)
}
}
func TestGetChannelsFromChannelArg(t *testing.T) {
th := app.Setup().InitBasic()
team := th.BasicTeam
channel := th.BasicChannel
channel2 := th.CreateChannel(team)
if found := getChannelsFromChannelArgs([]string{}); len(found) != 0 {
t.Fatal("shoudn't have gotten any channels", found)
}
if found := getChannelsFromChannelArgs([]string{channel.Id}); len(found) == 1 && found[0].Id != channel.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelsFromChannelArgs([]string{team.Name + ":" + channel2.Name}); len(found) == 1 && found[0].Id != channel2.Id {
t.Fatal("got incorrect channel", found)
}
if found := getChannelsFromChannelArgs([]string{team.Name + ":" + channel.Name, team.Name + ":" + channel2.Name}); len(found) != 2 {
t.Fatal("got incorrect number of channels", found)
} else if !(found[0].Id == channel.Id && found[1].Id == channel2.Id) && !(found[1].Id == channel.Id && found[0].Id == channel2.Id) {
t.Fatal("got incorrect channels", found[0], found[1])
}
if found := getChannelsFromChannelArgs([]string{channel.Id, channel2.Id}); len(found) != 2 {
t.Fatal("got incorrect number of channels", found)
} else if !(found[0].Id == channel.Id && found[1].Id == channel2.Id) && !(found[1].Id == channel.Id && found[0].Id == channel2.Id) {
t.Fatal("got incorrect channels", found[0], found[1])
}
if found := getChannelsFromChannelArgs([]string{channel.Id, team.Name + ":" + channel2.Name}); len(found) != 2 {
t.Fatal("got incorrect number of channels", found)
} else if !(found[0].Id == channel.Id && found[1].Id == channel2.Id) && !(found[1].Id == channel.Id && found[0].Id == channel2.Id) {
t.Fatal("got incorrect channels", found[0], found[1])
}
}

Просмотреть файл

@@ -1,58 +0,0 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"testing"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
)
func TestGetTeamFromTeamArg(t *testing.T) {
th := app.Setup().InitBasic()
team := th.BasicTeam
if found := getTeamFromTeamArg(""); found != nil {
t.Fatal("shoudn't have gotten a team", found)
}
if found := getTeamFromTeamArg(model.NewId()); found != nil {
t.Fatal("shoudn't have gotten a team", found)
}
if found := getTeamFromTeamArg(team.Id); found == nil || found.Id != team.Id {
t.Fatal("got incorrect team", found)
}
if found := getTeamFromTeamArg(team.Name); found == nil || found.Id != team.Id {
t.Fatal("got incorrect team", found)
}
}
func TestGetTeamsFromTeamArg(t *testing.T) {
th := app.Setup().InitBasic()
team := th.BasicTeam
team2 := th.CreateTeam()
if found := getTeamsFromTeamArgs([]string{}); len(found) != 0 {
t.Fatal("shoudn't have gotten any teams", found)
}
if found := getTeamsFromTeamArgs([]string{team.Id}); len(found) == 1 && found[0].Id != team.Id {
t.Fatal("got incorrect team", found)
}
if found := getTeamsFromTeamArgs([]string{team2.Name}); len(found) == 1 && found[0].Id != team2.Id {
t.Fatal("got incorrect team", found)
}
if found := getTeamsFromTeamArgs([]string{team.Name, team2.Id}); len(found) != 2 {
t.Fatal("got incorrect number of teams", found)
} else if !(found[0].Id == team.Id && found[1].Id == team2.Id) && !(found[1].Id == team.Id && found[0].Id == team2.Id) {
t.Fatal("got incorrect teams", found[0], found[1])
}
}

Просмотреть файл

@@ -1,212 +0,0 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"testing"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
)
func TestChangeUserActiveStatus(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
if err := changeUserActiveStatus(nil, "user", false); err == nil {
t.Fatal("should've returned error when user doesn't exist")
}
if err := changeUserActiveStatus(user, user.Username, false); err != nil {
t.Fatal(err)
} else if user, _ = app.GetUser(user.Id); user.DeleteAt == 0 {
t.Fatal("should've deactivated user")
}
if err := changeUserActiveStatus(user, user.Username, true); err != nil {
t.Fatal(err)
} else if user, _ := app.GetUser(user.Id); user.DeleteAt != 0 {
t.Fatal("should've activated user")
}
}
func TestChangeUsersActiveStatus(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
user2 := th.CreateUser()
changeUsersActiveStatus([]string{user.Username, user2.Id}, false)
if user, _ = app.GetUser(user.Id); user.DeleteAt == 0 {
t.Fatal("should've deactivated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt == 0 {
t.Fatal("should've deactivated user")
}
changeUsersActiveStatus([]string{user.Username, user2.Id}, true)
if user, _ = app.GetUser(user.Id); user.DeleteAt != 0 {
t.Fatal("should've activated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt != 0 {
t.Fatal("should've activated user")
}
}
func TestUserActivateDeactivateCmdF(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
user2 := th.CreateUser()
userDeactivateCmdF(userDeactivateCmd, []string{user.Username, user2.Id})
if user, _ = app.GetUser(user.Id); user.DeleteAt == 0 {
t.Fatal("should've deactivated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt == 0 {
t.Fatal("should've deactivated user")
}
userActivateCmdF(userActivateCmd, []string{user.Username, user2.Id})
if user, _ = app.GetUser(user.Id); user.DeleteAt != 0 {
t.Fatal("should've activated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt != 0 {
t.Fatal("should've activated user")
}
}
func TestUserActivateDeactivateCmd(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
user2 := th.CreateUser()
if err := runCommand("user deactivate " + user.Username + " " + user2.Id); err != nil {
t.Fatal(err)
} else if user, _ = app.GetUser(user.Id); user.DeleteAt == 0 {
t.Fatal("should've deactivated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt == 0 {
t.Fatal("should've deactivated user")
}
if err := runCommand("user activate " + user.Id + " " + user2.Username); err != nil {
t.Fatal(err)
} else if user, _ = app.GetUser(user.Id); user.DeleteAt != 0 {
t.Fatal("should've activated user")
} else if user2, _ = app.GetUser(user2.Id); user2.DeleteAt != 0 {
t.Fatal("should've activated user")
}
}
func TestUserCreateCmd(t *testing.T) {
th := app.Setup().InitBasic()
if err := runCommand("user create"); err == nil {
t.Fatal("should've failed without any arguments")
}
username := th.MakeUsername()
email := th.MakeEmail()
if err := runCommand("user create --username " + username + " --email " + email + " --password " + model.NewId()); err != nil {
t.Fatal(err)
} else if user, err := app.GetUserByUsername(username); err != nil {
t.Fatal(err.Message)
} else if user.Username != username {
t.Fatal("should've set correct username")
} else if user.Email != email {
t.Fatal("should've set correct email")
}
username = th.MakeUsername()
nickname := model.NewId()
firstName := model.NewId()
lastName := model.NewId()
locale := "fr"
if err := runCommand("user create --username " + username + " --email " + th.MakeEmail() + " --password " + model.NewId() +
" --nickname " + nickname + " --firstname " + firstName + " --lastname " + lastName + " --locale " + locale); err != nil {
t.Fatal(err)
} else if user, err := app.GetUserByUsername(username); err != nil {
t.Fatal(err)
} else if user.Nickname != nickname {
t.Fatal("should've set correct nickname")
} else if user.FirstName != firstName {
t.Fatal("should've set correct first name")
} else if user.LastName != lastName {
t.Fatal("should've set correct last name")
} else if user.Locale != locale {
t.Fatal("should've set correct locale", user.Locale)
} else if user.Roles != "system_user" {
t.Fatal("should've set correct roles for user")
}
username = th.MakeUsername()
if err := runCommand("user create --username " + username + " --email " + th.MakeEmail() + " --password " + model.NewId() + " --system_admin"); err != nil {
t.Fatal(err)
} else if user, err := app.GetUserByUsername(username); err != nil {
t.Fatal(err)
} else if user.Roles != "system_user system_admin" {
t.Fatal("should've set correct roles for system admin")
}
if err := runCommand("user create --email " + th.MakeEmail() + " --password " + model.NewId()); err == nil {
t.Fatal("should've failed without username")
}
if err := runCommand("user create --username " + th.MakeUsername() + " --email " + th.MakeEmail()); err == nil {
t.Fatal("should've failed without password")
}
if err := runCommand("user create --username " + th.MakeUsername() + " --password " + model.NewId()); err == nil {
t.Fatal("should've failed without email")
}
}
func TestInviteUser(t *testing.T) {
th := app.Setup().InitBasic()
team := th.CreateTeam()
if err := inviteUser(th.MakeEmail(), nil, "faketeam"); err == nil {
t.Fatal("should've failed with nonexistent team")
}
if err := inviteUser(th.MakeEmail(), team, team.Name); err != nil {
t.Fatal(err)
}
// Nothing else to test here since this just fires off an email
}
func TestUserInviteCmd(t *testing.T) {
th := app.Setup().InitBasic()
team := th.BasicTeam
team2 := th.CreateTeam()
if err := runCommand("user invite"); err == nil {
t.Fatal("should've failed without any arguments")
}
if err := runCommand("user invite " + th.MakeEmail()); err == nil {
t.Fatal("should've failed with 1 argument")
}
if err := runCommand("user invite " + th.MakeEmail() + " " + team.Id); err != nil {
t.Fatal(err)
}
if err := runCommand("user invite " + th.MakeEmail() + " " + team.Name); err != nil {
t.Fatal(err)
}
if err := runCommand("user invite " + th.MakeEmail() + " " + team.Id + " " + team2.Name); err != nil {
t.Fatal(err)
}
if err := runCommand("user invite " + th.MakeEmail() + " " + team.Id + " " + team2.Name + " " + "faketeam"); err != nil {
t.Fatal(err)
}
}

Просмотреть файл

@@ -1,58 +0,0 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"testing"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
)
func TestGetUserFromUserArg(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
if found := getUserFromUserArg(""); found != nil {
t.Fatal("shoudn't have gotten a user", found)
}
if found := getUserFromUserArg(model.NewId()); found != nil {
t.Fatal("shoudn't have gotten a user", found)
}
if found := getUserFromUserArg(user.Id); found == nil || found.Id != user.Id {
t.Fatal("got incorrect user", found)
}
if found := getUserFromUserArg(user.Username); found == nil || found.Id != user.Id {
t.Fatal("got incorrect user", found)
}
}
func TestGetUsersFromUserArg(t *testing.T) {
th := app.Setup().InitBasic()
user := th.BasicUser
user2 := th.CreateUser()
if found := getUsersFromUserArgs([]string{}); len(found) != 0 {
t.Fatal("shoudn't have gotten any users", found)
}
if found := getUsersFromUserArgs([]string{user.Id}); len(found) == 1 && found[0].Id != user.Id {
t.Fatal("got incorrect user", found)
}
if found := getUsersFromUserArgs([]string{user2.Username}); len(found) == 1 && found[0].Id != user2.Id {
t.Fatal("got incorrect user", found)
}
if found := getUsersFromUserArgs([]string{user.Username, user2.Id}); len(found) != 2 {
t.Fatal("got incorrect number of users", found)
} else if !(found[0].Id == user.Id && found[1].Id == user2.Id) && !(found[1].Id == user.Id && found[0].Id == user2.Id) {
t.Fatal("got incorrect users", found[0], found[1])
}
}

67
glide.lock сгенерированный
Просмотреть файл

@@ -1,17 +1,17 @@
hash: c8c28a291e4ef606837d38252852246fa634c9eebac12ceaae37103caed16883 hash: a63bdc06107e9917f943ab3af7d55d64702bc745e3a5dd0affa2c012a8d8e07f
updated: 2017-08-17T09:43:52.281308245-07:00 updated: 2017-09-29T08:20:31.615625246-07:00
imports: imports:
- name: github.com/alecthomas/log4go - name: github.com/alecthomas/log4go
version: 3fbce08846379ec7f4f6bc7fce6dd01ce28fae4c version: 3fbce08846379ec7f4f6bc7fce6dd01ce28fae4c
repo: https://github.com/mattermost/log4go.git repo: https://github.com/mattermost/log4go.git
- name: github.com/armon/go-metrics - name: github.com/armon/go-metrics
version: 023a4bbe4bb9bfb23ee7e1afc8d0abad217641f3 version: 0a12dc6f6b9da6da644031a1b9b5a85478c5ee27
- name: github.com/beorn7/perks - name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages: subpackages:
- quantile - quantile
- name: github.com/cpanato/html2text - name: github.com/cpanato/html2text
version: d788b7d6dc58bea298b318059332a25442583880 version: d47a5532a7bc36ad7b2b8ec3eebe24e975154f94
- name: github.com/davecgh/go-spew - name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages: subpackages:
@@ -21,7 +21,7 @@ imports:
- name: github.com/dimchansky/utfbom - name: github.com/dimchansky/utfbom
version: 6c6132ff69f0f6c088739067407b5d32c52e1d0f version: 6c6132ff69f0f6c088739067407b5d32c52e1d0f
- name: github.com/disintegration/imaging - name: github.com/disintegration/imaging
version: a5858022df0e1734a59f973fffe3f87b51c087ed version: c3956f26e8f5f2370428d573648fedc717fbe51e
- name: github.com/dyatlov/go-opengraph - name: github.com/dyatlov/go-opengraph
version: 41a3523719dfbe7e8f853fbd4061867543db5270 version: 41a3523719dfbe7e8f853fbd4061867543db5270
subpackages: subpackages:
@@ -33,7 +33,7 @@ imports:
- name: github.com/go-ldap/ldap - name: github.com/go-ldap/ldap
version: 8168ee085ee43257585e50c6441aadf54ecb2c9f version: 8168ee085ee43257585e50c6441aadf54ecb2c9f
- name: github.com/go-redis/redis - name: github.com/go-redis/redis
version: 19c1c2272e00c1aaa903cf574c746cd449f9cd3c version: 8e6b51ec3a92ec095dcbd2439c7a3eec6b6cb586
subpackages: subpackages:
- internal - internal
- internal/consistenthash - internal/consistenthash
@@ -48,7 +48,7 @@ imports:
- raster - raster
- truetype - truetype
- name: github.com/golang/protobuf - name: github.com/golang/protobuf
version: ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e version: 130e6b02ab059e7b717a096f397c5b60111cae74
subpackages: subpackages:
- proto - proto
- name: github.com/gorilla/context - name: github.com/gorilla/context
@@ -56,7 +56,7 @@ imports:
- name: github.com/gorilla/handlers - name: github.com/gorilla/handlers
version: a4043c62cc2329bacda331d33fc908ab11ef0ec3 version: a4043c62cc2329bacda331d33fc908ab11ef0ec3
- name: github.com/gorilla/mux - name: github.com/gorilla/mux
version: bcd8bc72b08df0f70df986b97f95590779502d31 version: 24fca303ac6da784b9e8269f724ddeb0b2eea5e7
- name: github.com/gorilla/websocket - name: github.com/gorilla/websocket
version: ea4d1f681babbce9545c9c5f3d5194a789c89f5b version: ea4d1f681babbce9545c9c5f3d5194a789c89f5b
- name: github.com/hashicorp/errwrap - name: github.com/hashicorp/errwrap
@@ -76,7 +76,7 @@ imports:
subpackages: subpackages:
- simplelru - simplelru
- name: github.com/hashicorp/hcl - name: github.com/hashicorp/hcl
version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca version: 68e816d1c783414e79bc65b3994d9ab6b0a722ab
subpackages: subpackages:
- hcl/ast - hcl/ast
- hcl/parser - hcl/parser
@@ -87,21 +87,21 @@ imports:
- json/scanner - json/scanner
- json/token - json/token
- name: github.com/hashicorp/memberlist - name: github.com/hashicorp/memberlist
version: d6c1fb0b99c33d0a8e22acea9da9709b369b5d39 version: 687988a0b5daaf7ed5051e5e374aef27f8254822
- name: github.com/inconshreveable/mousetrap - name: github.com/inconshreveable/mousetrap
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
- name: github.com/jehiah/go-strftime - name: github.com/jehiah/go-strftime
version: 834e15c05a45371503440cc195bbd05c9a0968d9 version: 834e15c05a45371503440cc195bbd05c9a0968d9
- name: github.com/lib/pq - name: github.com/lib/pq
version: e42267488fe361b9dc034be7a6bffef5b195bceb version: b77235e3890a962fe8a6f8c4c7198679ca7814e7
subpackages: subpackages:
- oid - oid
- name: github.com/magiconair/properties - name: github.com/magiconair/properties
version: be5ece7dd465ab0765a9682137865547526d1dfb version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a
- name: github.com/mattermost/gorp - name: github.com/mattermost/gorp
version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a
- name: github.com/mattermost/html2text - name: github.com/mattermost/html2text
version: d788b7d6dc58bea298b318059332a25442583880 version: d47a5532a7bc36ad7b2b8ec3eebe24e975154f94
- name: github.com/mattermost/rsc - name: github.com/mattermost/rsc
version: bbaefb05eaa0389ea712340066837c8ce4d287f9 version: bbaefb05eaa0389ea712340066837c8ce4d287f9
subpackages: subpackages:
@@ -113,11 +113,13 @@ imports:
subpackages: subpackages:
- pbutil - pbutil
- name: github.com/miekg/dns - name: github.com/miekg/dns
version: 0598bd43cf51d0375c5bcd3a42e807cc19b3b7d9 version: aade52d68e0bf400ae55afd3adadffce3b027043
subpackages:
- internal/socket
- name: github.com/minio/go-homedir - name: github.com/minio/go-homedir
version: 21304a94172ae3a09dee2cd86a12fb6f842138c7 version: 21304a94172ae3a09dee2cd86a12fb6f842138c7
- name: github.com/minio/minio-go - name: github.com/minio/minio-go
version: 1a09415eed6025360c2c3142f92d3bcf339f873d version: 4e0f567303d4cc90ceb055a451959fb9fc391fb9
subpackages: subpackages:
- pkg/credentials - pkg/credentials
- pkg/encrypt - pkg/encrypt
@@ -128,22 +130,22 @@ imports:
- name: github.com/mitchellh/mapstructure - name: github.com/mitchellh/mapstructure
version: d0303fe809921458f417bcf828397a65db30a7e4 version: d0303fe809921458f417bcf828397a65db30a7e4
- name: github.com/mssola/user_agent - name: github.com/mssola/user_agent
version: 85b2f5798558a46fc23443c596e781712f4b7792 version: a2f39d5a9b15ecc1fa1005b6aae73cd83da240ef
- name: github.com/nicksnyder/go-i18n - name: github.com/nicksnyder/go-i18n
version: 3e70a1a463008cea6726380c908b1a6a8bdf7b24 version: ca33e78c8a430e2df435b02f63a3944fa8e9ea11
subpackages: subpackages:
- i18n - i18n
- i18n/bundle - i18n/bundle
- i18n/language - i18n/language
- i18n/translation - i18n/translation
- name: github.com/NYTimes/gziphandler - name: github.com/NYTimes/gziphandler
version: 967539e5e271a2bc9b3dcb1285078a1b1df105ae version: 97ae7fbaf81620fe97840685304a78a306a39c64
- name: github.com/pborman/uuid - name: github.com/pborman/uuid
version: e790cca94e6cc75c7064b1332e63811d4aae1a53 version: e790cca94e6cc75c7064b1332e63811d4aae1a53
- name: github.com/pelletier/go-toml - name: github.com/pelletier/go-toml
version: 4692b8f9babfc93db58cc592ba2689d8736781de version: 16398bac157da96aa88f98a2df640c7f32af1da2
- name: github.com/pkg/errors - name: github.com/pkg/errors
version: c605e284fe17294bda444b34710735b29d1a9d90 version: 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb
- name: github.com/pmezard/go-difflib - name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages: subpackages:
@@ -157,7 +159,7 @@ imports:
subpackages: subpackages:
- go - go
- name: github.com/prometheus/common - name: github.com/prometheus/common
version: 61f87aac8082fa8c3c5655c7608d7478d46ac2ad version: 2f17f4a9d485bf34b4bfaccc273805040e4f86c8
subpackages: subpackages:
- expfmt - expfmt
- name: github.com/prometheus/procfs - name: github.com/prometheus/procfs
@@ -176,15 +178,15 @@ imports:
- name: github.com/segmentio/backo-go - name: github.com/segmentio/backo-go
version: 204274ad699c0983a70203a566887f17a717fef4 version: 204274ad699c0983a70203a566887f17a717fef4
- name: github.com/spf13/afero - name: github.com/spf13/afero
version: 9be650865eab0c12963d8753212f4f9c66cdcf12 version: ee1bd8ee15a1306d1f9201acc41ef39cd9f99a1b
subpackages: subpackages:
- mem - mem
- name: github.com/spf13/cast - name: github.com/spf13/cast
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4 version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
- name: github.com/spf13/cobra - name: github.com/spf13/cobra
version: cb731b898346822cc0c225c28550a8a29d93c732 version: b78744579491c1ceeaaa3b40205e56b0591b93a3
- name: github.com/spf13/jwalterweatherman - name: github.com/spf13/jwalterweatherman
version: 0efa5202c04663c757d84f90f5219c1250baf94f version: 12bd96e66386c1960ab0f74ced1362f66f552f7b
- name: github.com/spf13/pflag - name: github.com/spf13/pflag
version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 version: e57e3eeb33f795204c1ca35f56c44f83227c6e66
- name: github.com/spf13/viper - name: github.com/spf13/viper
@@ -197,22 +199,23 @@ imports:
- assert - assert
- mock - mock
- require - require
- suite
- name: github.com/tylerb/graceful - name: github.com/tylerb/graceful
version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
- name: github.com/xenolf/lego - name: github.com/xenolf/lego
version: 92ed20909982bc411971291622e8d379e1627a0b version: 5a2fd5039fbba3c06b640be91a2c436bc23f74e8
subpackages: subpackages:
- acme - acme
- name: github.com/xtgo/uuid - name: github.com/xtgo/uuid
version: a0b114877d4caeffbd7f87e3757c17fce570fea7 version: a0b114877d4caeffbd7f87e3757c17fce570fea7
- name: golang.org/x/crypto - name: golang.org/x/crypto
version: b176d7def5d71bdd214203491f89843ed217f420 version: 76eec36fa14229c4b25bb894c2d0e591527af429
subpackages: subpackages:
- bcrypt - bcrypt
- blowfish - blowfish
- ocsp - ocsp
- name: golang.org/x/image - name: golang.org/x/image
version: 426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d version: 334384d9e19178a0488c9360d94d183c1ef0f711
subpackages: subpackages:
- bmp - bmp
- font - font
@@ -220,23 +223,23 @@ imports:
- tiff - tiff
- tiff/lzw - tiff/lzw
- name: golang.org/x/net - name: golang.org/x/net
version: 1c05540f6879653db88113bc4a2b70aec4bd491f version: 0a9397675ba34b2845f758fe3cd68828369c6517
subpackages: subpackages:
- context - context
- html - html
- html/atom - html/atom
- publicsuffix - publicsuffix
- name: golang.org/x/sys - name: golang.org/x/sys
version: 9f7170bcd8e9f4d3691c06401119c46a769a1e03 version: 314a259e304ff91bd6985da2a7149bbf91237993
subpackages: subpackages:
- unix - unix
- name: golang.org/x/text - name: golang.org/x/text
version: e56139fd9c5bc7244c76116c68e500765bb6db6b version: 1cbadb444a806fd9430d14ad08967ed91da4fa0a
subpackages: subpackages:
- transform - transform
- unicode/norm - unicode/norm
- name: golang.org/x/time - name: golang.org/x/time
version: 8be79e1e0910c292df4e79c241bb7e8f7e725959 version: 6dc17368e09b0e8634d71cac8168d853e869a0c7
subpackages: subpackages:
- rate - rate
- name: gopkg.in/alexcesaro/quotedprintable.v3 - name: gopkg.in/alexcesaro/quotedprintable.v3
@@ -246,7 +249,7 @@ imports:
- name: gopkg.in/gomail.v2 - name: gopkg.in/gomail.v2
version: 41f3572897373c5538c50a2402db15db079fa4fd version: 41f3572897373c5538c50a2402db15db079fa4fd
- name: gopkg.in/olivere/elastic.v5 - name: gopkg.in/olivere/elastic.v5
version: edbef41beaacc2ee95e61af8faff04e67c01e268 version: 2a08d39723b7f4df92b96e2dff891a60952714d6
subpackages: subpackages:
- config - config
- uritemplates - uritemplates

Просмотреть файл

@@ -1,11 +1,11 @@
package: github.com/mattermost/platform package: github.com/mattermost/mattermost-server
import: import:
- package: github.com/NYTimes/gziphandler - package: github.com/NYTimes/gziphandler
- package: github.com/alecthomas/log4go - package: github.com/alecthomas/log4go
repo: https://github.com/mattermost/log4go.git repo: https://github.com/mattermost/log4go.git
- package: github.com/dgryski/dgoogauth - package: github.com/dgryski/dgoogauth
- package: github.com/disintegration/imaging - package: github.com/disintegration/imaging
version: v1.2.1 version: v1.2.2
- package: github.com/dyatlov/go-opengraph - package: github.com/dyatlov/go-opengraph
subpackages: subpackages:
- opengraph - opengraph
@@ -19,7 +19,7 @@ import:
- package: github.com/gorilla/handlers - package: github.com/gorilla/handlers
version: v1.2.1 version: v1.2.1
- package: github.com/gorilla/mux - package: github.com/gorilla/mux
version: v1.4.0 version: v1.5.0
- package: github.com/gorilla/websocket - package: github.com/gorilla/websocket
version: v1.2.0 version: v1.2.0
- package: github.com/lib/pq - package: github.com/lib/pq
@@ -27,11 +27,10 @@ import:
subpackages: subpackages:
- qr - qr
- package: github.com/minio/minio-go - package: github.com/minio/minio-go
version: v3.0.1 version: v3.0.3
- package: github.com/mssola/user_agent - package: github.com/mssola/user_agent
version: v0.4.1
- package: github.com/nicksnyder/go-i18n - package: github.com/nicksnyder/go-i18n
version: v1.8.1 version: v1.9.0
subpackages: subpackages:
- i18n - i18n
- package: github.com/pborman/uuid - package: github.com/pborman/uuid
@@ -82,11 +81,11 @@ import:
- package: github.com/prometheus/procfs - package: github.com/prometheus/procfs
- package: github.com/cpanato/html2text - package: github.com/cpanato/html2text
- package: gopkg.in/olivere/elastic.v5 - package: gopkg.in/olivere/elastic.v5
version: v5.0.45 version: v5.0.48
- package: github.com/mattermost/gorp - package: github.com/mattermost/gorp
version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a
- package: github.com/go-redis/redis - package: github.com/go-redis/redis
version: v6.5.7 version: v6.7.1
- package: github.com/stretchr/testify - package: github.com/stretchr/testify
version: v1.1.4 version: v1.1.4
subpackages: subpackages:

201
vendor/github.com/NYTimes/gziphandler/LICENSE сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016-2017 The New York Times Company
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

13
vendor/github.com/NYTimes/gziphandler/LICENSE.md сгенерированный поставляемый
Просмотреть файл

@@ -1,13 +0,0 @@
Copyright (c) 2015 The New York Times Company
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this library except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

4
vendor/github.com/NYTimes/gziphandler/gzip.go сгенерированный поставляемый
Просмотреть файл

@@ -105,7 +105,7 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
// If the global writes are bigger than the minSize and we're about to write // If the global writes are bigger than the minSize and we're about to write
// a response containing a content type we want to handle, enable // a response containing a content type we want to handle, enable
// compression. // compression.
if len(w.buf) >= w.minSize && handleContentType(w.contentTypes, w) { if len(w.buf) >= w.minSize && handleContentType(w.contentTypes, w) && w.Header().Get(contentEncoding) == "" {
err := w.startGzip() err := w.startGzip()
if err != nil { if err != nil {
return 0, err return 0, err
@@ -134,7 +134,7 @@ func (w *GzipResponseWriter) startGzip() error {
// Initialize the GZIP response. // Initialize the GZIP response.
w.init() w.init()
// Flush the buffer into the gzip reponse. // Flush the buffer into the gzip response.
n, err := w.gw.Write(w.buf) n, err := w.gw.Write(w.buf)
// This should never happen (per io.Writer docs), but if the write didn't // This should never happen (per io.Writer docs), but if the write didn't

19
vendor/github.com/NYTimes/gziphandler/gzip_test.go сгенерированный поставляемый
Просмотреть файл

@@ -81,6 +81,17 @@ func TestGzipHandler(t *testing.T) {
assert.Equal(t, http.DetectContentType([]byte(testBody)), res3.Header().Get("Content-Type")) assert.Equal(t, http.DetectContentType([]byte(testBody)), res3.Header().Get("Content-Type"))
} }
func TestGzipHandlerAlreadyCompressed(t *testing.T) {
handler := newTestHandler(testBody)
req, _ := http.NewRequest("GET", "/gzipped", nil)
req.Header.Set("Accept-Encoding", "gzip")
res := httptest.NewRecorder()
handler.ServeHTTP(res, req)
assert.Equal(t, testBody, res.Body.String())
}
func TestNewGzipLevelHandler(t *testing.T) { func TestNewGzipLevelHandler(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@@ -435,6 +446,12 @@ func runBenchmark(b *testing.B, req *http.Request, handler http.Handler) {
func newTestHandler(body string) http.Handler { func newTestHandler(body string) http.Handler {
return GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, body) switch r.URL.Path {
case "/gzipped":
w.Header().Set("Content-Encoding", "gzip")
io.WriteString(w, body)
default:
io.WriteString(w, body)
}
})) }))
} }

6
vendor/github.com/armon/go-metrics/prometheus/prometheus.go сгенерированный поставляемый
Просмотреть файл

@@ -66,7 +66,7 @@ func (p *PrometheusSink) SetGaugeWithLabels(parts []string, val float32, labels
ConstLabels: prometheusLabels(labels), ConstLabels: prometheusLabels(labels),
}) })
prometheus.MustRegister(g) prometheus.MustRegister(g)
p.gauges[key] = g p.gauges[hash] = g
} }
g.Set(float64(val)) g.Set(float64(val))
} }
@@ -88,7 +88,7 @@ func (p *PrometheusSink) AddSampleWithLabels(parts []string, val float32, labels
ConstLabels: prometheusLabels(labels), ConstLabels: prometheusLabels(labels),
}) })
prometheus.MustRegister(g) prometheus.MustRegister(g)
p.summaries[key] = g p.summaries[hash] = g
} }
g.Observe(float64(val)) g.Observe(float64(val))
} }
@@ -115,7 +115,7 @@ func (p *PrometheusSink) IncrCounterWithLabels(parts []string, val float32, labe
ConstLabels: prometheusLabels(labels), ConstLabels: prometheusLabels(labels),
}) })
prometheus.MustRegister(g) prometheus.MustRegister(g)
p.counters[key] = g p.counters[hash] = g
} }
g.Add(float64(val)) g.Add(float64(val))
} }

1
vendor/github.com/cpanato/html2text/LICENSE сгенерированный поставляемый
Просмотреть файл

@@ -1,6 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Jay Taylor Copyright (c) 2015 Jay Taylor
Modified work: Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

5
vendor/github.com/disintegration/imaging/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -4,12 +4,9 @@ sudo: false
go: go:
- 1.2 - 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7 - 1.7
- 1.8 - 1.8
- 1.9
before_install: before_install:
- go get golang.org/x/tools/cmd/cover - go get golang.org/x/tools/cmd/cover

429
vendor/github.com/disintegration/imaging/helpers.go сгенерированный поставляемый
Просмотреть файл

@@ -168,213 +168,266 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
// Clone returns a copy of the given image. // Clone returns a copy of the given image.
func Clone(img image.Image) *image.NRGBA { func Clone(img image.Image) *image.NRGBA {
srcBounds := img.Bounds() dstBounds := img.Bounds().Sub(img.Bounds().Min)
srcMinX := srcBounds.Min.X
srcMinY := srcBounds.Min.Y
dstBounds := srcBounds.Sub(srcBounds.Min)
dstW := dstBounds.Dx()
dstH := dstBounds.Dy()
dst := image.NewNRGBA(dstBounds) dst := image.NewNRGBA(dstBounds)
switch src := img.(type) { switch src := img.(type) {
case *image.NRGBA: case *image.NRGBA:
rowSize := srcBounds.Dx() * 4 copyNRGBA(dst, src)
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
}
})
case *image.NRGBA64: case *image.NRGBA64:
parallel(dstH, func(partStart, partEnd int) { copyNRGBA64(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
dst.Pix[di+3] = src.Pix[si+6]
di += 4
si += 8
}
}
})
case *image.RGBA: case *image.RGBA:
parallel(dstH, func(partStart, partEnd int) { copyRGBA(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+3]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+1]
dst.Pix[di+2] = src.Pix[si+2]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 4
}
}
})
case *image.RGBA64: case *image.RGBA64:
parallel(dstH, func(partStart, partEnd int) { copyRGBA64(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+6]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 8
}
}
})
case *image.Gray: case *image.Gray:
parallel(dstH, func(partStart, partEnd int) { copyGray(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si += 1
}
}
})
case *image.Gray16: case *image.Gray16:
parallel(dstH, func(partStart, partEnd int) { copyGray16(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si += 2
}
}
})
case *image.YCbCr: case *image.YCbCr:
parallel(dstH, func(partStart, partEnd int) { copyYCbCr(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
srcX := srcMinX + dstX
srcY := srcMinY + dstY
siy := src.YOffset(srcX, srcY)
sic := src.COffset(srcX, srcY)
r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
dst.Pix[di+0] = r
dst.Pix[di+1] = g
dst.Pix[di+2] = b
dst.Pix[di+3] = 0xff
di += 4
}
}
})
case *image.Paletted: case *image.Paletted:
plen := len(src.Palette) copyPaletted(dst, src)
pnew := make([]color.NRGBA, plen)
for i := 0; i < plen; i++ {
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
}
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := pnew[src.Pix[si]]
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
si += 1
}
}
})
default: default:
parallel(dstH, func(partStart, partEnd int) { copyImage(dst, src)
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := color.NRGBAModel.Convert(img.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
}
}
})
} }
return dst return dst
} }
func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
rowSize := dstW * 4
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
}
})
}
func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
dst.Pix[di+3] = src.Pix[si+6]
di += 4
si += 8
}
}
})
}
func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+3]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+1]
dst.Pix[di+2] = src.Pix[si+2]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 4
}
}
})
}
func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
a := src.Pix[si+6]
dst.Pix[di+3] = a
switch a {
case 0:
dst.Pix[di+0] = 0
dst.Pix[di+1] = 0
dst.Pix[di+2] = 0
case 0xff:
dst.Pix[di+0] = src.Pix[si+0]
dst.Pix[di+1] = src.Pix[si+2]
dst.Pix[di+2] = src.Pix[si+4]
default:
var tmp uint16
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
dst.Pix[di+0] = uint8(tmp)
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
dst.Pix[di+1] = uint8(tmp)
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
dst.Pix[di+2] = uint8(tmp)
}
di += 4
si += 8
}
}
})
}
func copyGray(dst *image.NRGBA, src *image.Gray) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si++
}
}
})
}
func copyGray16(dst *image.NRGBA, src *image.Gray16) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := src.Pix[si]
dst.Pix[di+0] = c
dst.Pix[di+1] = c
dst.Pix[di+2] = c
dst.Pix[di+3] = 0xff
di += 4
si += 2
}
}
})
}
func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
srcX := srcMinX + dstX
srcY := srcMinY + dstY
siy := src.YOffset(srcX, srcY)
sic := src.COffset(srcX, srcY)
r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
dst.Pix[di+0] = r
dst.Pix[di+1] = g
dst.Pix[di+2] = b
dst.Pix[di+3] = 0xff
di += 4
}
}
})
}
func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
srcMinX := src.Rect.Min.X
srcMinY := src.Rect.Min.Y
dstW := dst.Rect.Dx()
dstH := dst.Rect.Dy()
plen := len(src.Palette)
pnew := make([]color.NRGBA, plen)
for i := 0; i < plen; i++ {
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
}
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
si := src.PixOffset(srcMinX, srcMinY+dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := pnew[src.Pix[si]]
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
si++
}
}
})
}
func copyImage(dst *image.NRGBA, src image.Image) {
srcMinX := src.Bounds().Min.X
srcMinY := src.Bounds().Min.Y
dstW := dst.Bounds().Dx()
dstH := dst.Bounds().Dy()
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
di := dst.PixOffset(0, dstY)
for dstX := 0; dstX < dstW; dstX++ {
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
dst.Pix[di+0] = c.R
dst.Pix[di+1] = c.G
dst.Pix[di+2] = c.B
dst.Pix[di+3] = c.A
di += 4
}
}
})
}
// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0). // toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
func toNRGBA(img image.Image) *image.NRGBA { func toNRGBA(img image.Image) *image.NRGBA {
srcBounds := img.Bounds() if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
if srcBounds.Min.X == 0 && srcBounds.Min.Y == 0 { return img
if src0, ok := img.(*image.NRGBA); ok {
return src0
}
} }
return Clone(img) return Clone(img)
} }

1
vendor/github.com/go-redis/redis/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -8,6 +8,7 @@ go:
- 1.4.x - 1.4.x
- 1.7.x - 1.7.x
- 1.8.x - 1.8.x
- 1.9.x
- tip - tip
matrix: matrix:

3
vendor/github.com/go-redis/redis/README.md сгенерированный поставляемый
Просмотреть файл

@@ -6,6 +6,7 @@
Supports: Supports:
- Redis 3 commands except QUIT, MONITOR, SLOWLOG and SYNC. - Redis 3 commands except QUIT, MONITOR, SLOWLOG and SYNC.
- Automatic connection pooling with [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support.
- [Pub/Sub](https://godoc.org/github.com/go-redis/redis#PubSub). - [Pub/Sub](https://godoc.org/github.com/go-redis/redis#PubSub).
- [Transactions](https://godoc.org/github.com/go-redis/redis#Multi). - [Transactions](https://godoc.org/github.com/go-redis/redis#Multi).
- [Pipeline](https://godoc.org/github.com/go-redis/redis#example-Client-Pipeline) and [TxPipeline](https://godoc.org/github.com/go-redis/redis#example-Client-TxPipeline). - [Pipeline](https://godoc.org/github.com/go-redis/redis#example-Client-Pipeline) and [TxPipeline](https://godoc.org/github.com/go-redis/redis#example-Client-TxPipeline).
@@ -16,7 +17,7 @@ Supports:
- [Ring](https://godoc.org/github.com/go-redis/redis#NewRing). - [Ring](https://godoc.org/github.com/go-redis/redis#NewRing).
- [Instrumentation](https://godoc.org/github.com/go-redis/redis#ex-package--Instrumentation). - [Instrumentation](https://godoc.org/github.com/go-redis/redis#ex-package--Instrumentation).
- [Cache friendly](https://github.com/go-redis/cache). - [Cache friendly](https://github.com/go-redis/cache).
- [Rate limiting](https://github.com/go-redis/rate). - [Rate limiting](https://github.com/go-redis/redis_rate).
- [Distributed Locks](https://github.com/bsm/redis-lock). - [Distributed Locks](https://github.com/bsm/redis-lock).
API docs: https://godoc.org/github.com/go-redis/redis. API docs: https://godoc.org/github.com/go-redis/redis.

368
vendor/github.com/go-redis/redis/cluster.go сгенерированный поставляемый
Просмотреть файл

@@ -14,8 +14,8 @@ import (
"github.com/go-redis/redis/internal/proto" "github.com/go-redis/redis/internal/proto"
) )
var errClusterNoNodes = internal.RedisError("redis: cluster has no nodes") var errClusterNoNodes = fmt.Errorf("redis: cluster has no nodes")
var errNilClusterState = internal.RedisError("redis: cannot load cluster slots") var errNilClusterState = fmt.Errorf("redis: cannot load cluster slots")
// ClusterOptions are used to configure a cluster client and should be // ClusterOptions are used to configure a cluster client and should be
// passed to NewClusterClient. // passed to NewClusterClient.
@@ -64,6 +64,19 @@ func (opt *ClusterOptions) init() {
opt.ReadOnly = true opt.ReadOnly = true
} }
switch opt.ReadTimeout {
case -1:
opt.ReadTimeout = 0
case 0:
opt.ReadTimeout = 3 * time.Second
}
switch opt.WriteTimeout {
case -1:
opt.WriteTimeout = 0
case 0:
opt.WriteTimeout = opt.ReadTimeout
}
switch opt.MinRetryBackoff { switch opt.MinRetryBackoff {
case -1: case -1:
opt.MinRetryBackoff = 0 opt.MinRetryBackoff = 0
@@ -192,6 +205,21 @@ func (c *clusterNodes) Close() error {
return firstErr return firstErr
} }
func (c *clusterNodes) Addrs() ([]string, error) {
c.mu.RLock()
closed := c.closed
addrs := c.addrs
c.mu.RUnlock()
if closed {
return nil, pool.ErrClosed
}
if len(addrs) == 0 {
return nil, errClusterNoNodes
}
return addrs, nil
}
func (c *clusterNodes) NextGeneration() uint32 { func (c *clusterNodes) NextGeneration() uint32 {
c.generation++ c.generation++
return c.generation return c.generation
@@ -272,16 +300,9 @@ func (c *clusterNodes) GetOrCreate(addr string) (*clusterNode, error) {
} }
func (c *clusterNodes) Random() (*clusterNode, error) { func (c *clusterNodes) Random() (*clusterNode, error) {
c.mu.RLock() addrs, err := c.Addrs()
closed := c.closed if err != nil {
addrs := c.addrs return nil, err
c.mu.RUnlock()
if closed {
return nil, pool.ErrClosed
}
if len(addrs) == 0 {
return nil, errClusterNoNodes
} }
var nodeErr error var nodeErr error
@@ -468,13 +489,23 @@ func (c *ClusterClient) Options() *ClusterOptions {
return c.opt return c.opt
} }
func (c *ClusterClient) state() *clusterState { func (c *ClusterClient) retryBackoff(attempt int) time.Duration {
return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
}
func (c *ClusterClient) state() (*clusterState, error) {
v := c._state.Load() v := c._state.Load()
if v != nil { if v != nil {
return v.(*clusterState) return v.(*clusterState), nil
} }
_, err := c.nodes.Addrs()
if err != nil {
return nil, err
}
c.lazyReloadState() c.lazyReloadState()
return nil return nil, errNilClusterState
} }
func (c *ClusterClient) cmdInfo(name string) *CommandInfo { func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
@@ -495,17 +526,22 @@ func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
if err != nil { if err != nil {
return nil return nil
} }
return c.cmdsInfo[name] info := c.cmdsInfo[name]
if info == nil {
internal.Logf("info for cmd=%s not found", name)
}
return info
}
func (c *ClusterClient) cmdSlot(cmd Cmder) int {
cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
return hashtag.Slot(firstKey)
} }
func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) { func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) {
if state == nil {
node, err := c.nodes.Random()
return 0, node, err
}
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.arg(cmdFirstKeyPos(cmd, cmdInfo)) firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
slot := hashtag.Slot(firstKey) slot := hashtag.Slot(firstKey)
if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly { if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly {
@@ -523,19 +559,51 @@ func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *cl
} }
func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error { func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error {
state := c.state() if len(keys) == 0 {
return fmt.Errorf("redis: keys don't hash to the same slot")
var node *clusterNode
var err error
if state != nil && len(keys) > 0 {
node, err = state.slotMasterNode(hashtag.Slot(keys[0]))
} else {
node, err = c.nodes.Random()
} }
state, err := c.state()
if err != nil { if err != nil {
return err return err
} }
return node.Client.Watch(fn, keys...)
slot := hashtag.Slot(keys[0])
for _, key := range keys[1:] {
if hashtag.Slot(key) != slot {
return fmt.Errorf("redis: Watch requires all keys to be in the same slot")
}
}
node, err := state.slotMasterNode(slot)
if err != nil {
return err
}
for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
if attempt > 0 {
time.Sleep(c.retryBackoff(attempt))
}
err = node.Client.Watch(fn, keys...)
if err == nil {
break
}
moved, ask, addr := internal.IsMovedError(err)
if moved || ask {
c.lazyReloadState()
node, err = c.nodes.GetOrCreate(addr)
if err != nil {
return err
}
continue
}
return err
}
return err
} }
// Close closes the cluster client, releasing any open resources. // Close closes the cluster client, releasing any open resources.
@@ -547,7 +615,13 @@ func (c *ClusterClient) Close() error {
} }
func (c *ClusterClient) Process(cmd Cmder) error { func (c *ClusterClient) Process(cmd Cmder) error {
slot, node, err := c.cmdSlotAndNode(c.state(), cmd) state, err := c.state()
if err != nil {
cmd.setErr(err)
return err
}
_, node, err := c.cmdSlotAndNode(state, cmd)
if err != nil { if err != nil {
cmd.setErr(err) cmd.setErr(err)
return err return err
@@ -556,7 +630,7 @@ func (c *ClusterClient) Process(cmd Cmder) error {
var ask bool var ask bool
for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
if attempt > 0 { if attempt > 0 {
time.Sleep(node.Client.retryBackoff(attempt)) time.Sleep(c.retryBackoff(attempt))
} }
if ask { if ask {
@@ -572,7 +646,7 @@ func (c *ClusterClient) Process(cmd Cmder) error {
// If there is no error - we are done. // If there is no error - we are done.
if err == nil { if err == nil {
return nil break
} }
// If slave is loading - read from master. // If slave is loading - read from master.
@@ -582,12 +656,11 @@ func (c *ClusterClient) Process(cmd Cmder) error {
continue continue
} }
// On network errors try random node. if internal.IsRetryableError(err, true) {
if internal.IsRetryableError(err) || internal.IsClusterDownError(err) { var nodeErr error
node, err = c.nodes.Random() node, nodeErr = c.nodes.Random()
if err != nil { if nodeErr != nil {
cmd.setErr(err) break
return err
} }
continue continue
} }
@@ -596,20 +669,13 @@ func (c *ClusterClient) Process(cmd Cmder) error {
var addr string var addr string
moved, ask, addr = internal.IsMovedError(err) moved, ask, addr = internal.IsMovedError(err)
if moved || ask { if moved || ask {
state := c.state() c.lazyReloadState()
if state != nil && slot >= 0 {
master, _ := state.slotMasterNode(slot)
if moved && (master == nil || master.Client.getAddr() != addr) {
c.lazyReloadState()
}
}
node, err = c.nodes.GetOrCreate(addr) var nodeErr error
if err != nil { node, nodeErr = c.nodes.GetOrCreate(addr)
cmd.setErr(err) if nodeErr != nil {
return err break
} }
continue continue
} }
@@ -622,9 +688,9 @@ func (c *ClusterClient) Process(cmd Cmder) error {
// ForEachMaster concurrently calls the fn on each master node in the cluster. // ForEachMaster concurrently calls the fn on each master node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
state := c.state() state, err := c.state()
if state == nil { if err != nil {
return errNilClusterState return err
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -655,9 +721,9 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
// ForEachSlave concurrently calls the fn on each slave node in the cluster. // ForEachSlave concurrently calls the fn on each slave node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error { func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
state := c.state() state, err := c.state()
if state == nil { if err != nil {
return errNilClusterState return err
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -688,9 +754,9 @@ func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
// ForEachNode concurrently calls the fn on each known node in the cluster. // ForEachNode concurrently calls the fn on each known node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error {
state := c.state() state, err := c.state()
if state == nil { if err != nil {
return errNilClusterState return err
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -728,27 +794,31 @@ func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error {
func (c *ClusterClient) PoolStats() *PoolStats { func (c *ClusterClient) PoolStats() *PoolStats {
var acc PoolStats var acc PoolStats
state := c.state() state, _ := c.state()
if state == nil { if state == nil {
return &acc return &acc
} }
for _, node := range state.masters { for _, node := range state.masters {
s := node.Client.connPool.Stats() s := node.Client.connPool.Stats()
acc.Requests += s.Requests
acc.Hits += s.Hits acc.Hits += s.Hits
acc.Misses += s.Misses
acc.Timeouts += s.Timeouts acc.Timeouts += s.Timeouts
acc.TotalConns += s.TotalConns acc.TotalConns += s.TotalConns
acc.FreeConns += s.FreeConns acc.FreeConns += s.FreeConns
acc.StaleConns += s.StaleConns
} }
for _, node := range state.slaves { for _, node := range state.slaves {
s := node.Client.connPool.Stats() s := node.Client.connPool.Stats()
acc.Requests += s.Requests
acc.Hits += s.Hits acc.Hits += s.Hits
acc.Misses += s.Misses
acc.Timeouts += s.Timeouts acc.Timeouts += s.Timeouts
acc.TotalConns += s.TotalConns acc.TotalConns += s.TotalConns
acc.FreeConns += s.FreeConns acc.FreeConns += s.FreeConns
acc.StaleConns += s.StaleConns
} }
return &acc return &acc
@@ -762,10 +832,8 @@ func (c *ClusterClient) lazyReloadState() {
go func() { go func() {
defer atomic.StoreUint32(&c.reloading, 0) defer atomic.StoreUint32(&c.reloading, 0)
var state *clusterState
for { for {
var err error state, err := c.reloadState()
state, err = c.reloadState()
if err == pool.ErrClosed { if err == pool.ErrClosed {
return return
} }
@@ -776,11 +844,10 @@ func (c *ClusterClient) lazyReloadState() {
} }
c._state.Store(state) c._state.Store(state)
time.Sleep(5 * time.Second)
c.nodes.GC(state.generation)
break break
} }
time.Sleep(3 * time.Second)
c.nodes.GC(state.generation)
}() }()
} }
@@ -810,21 +877,12 @@ func (c *ClusterClient) reaper(idleCheckFrequency time.Duration) {
break break
} }
var n int
for _, node := range nodes { for _, node := range nodes {
nn, err := node.Client.connPool.(*pool.ConnPool).ReapStaleConns() _, err := node.Client.connPool.(*pool.ConnPool).ReapStaleConns()
if err != nil { if err != nil {
internal.Logf("ReapStaleConns failed: %s", err) internal.Logf("ReapStaleConns failed: %s", err)
} else {
n += nn
} }
} }
s := c.PoolStats()
internal.Logf(
"reaper: removed %d stale conns (TotalConns=%d FreeConns=%d Requests=%d Hits=%d Timeouts=%d)",
n, s.TotalConns, s.FreeConns, s.Requests, s.Hits, s.Timeouts,
)
} }
} }
@@ -837,16 +895,21 @@ func (c *ClusterClient) Pipeline() Pipeliner {
} }
func (c *ClusterClient) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *ClusterClient) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipeline().pipelined(fn) return c.Pipeline().Pipelined(fn)
} }
func (c *ClusterClient) pipelineExec(cmds []Cmder) error { func (c *ClusterClient) pipelineExec(cmds []Cmder) error {
cmdsMap, err := c.mapCmdsByNode(cmds) cmdsMap, err := c.mapCmdsByNode(cmds)
if err != nil { if err != nil {
setCmdsErr(cmds, err)
return err return err
} }
for i := 0; i <= c.opt.MaxRedirects; i++ { for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
if attempt > 0 {
time.Sleep(c.retryBackoff(attempt))
}
failedCmds := make(map[*clusterNode][]Cmder) failedCmds := make(map[*clusterNode][]Cmder)
for node, cmds := range cmdsMap { for node, cmds := range cmdsMap {
@@ -856,8 +919,12 @@ func (c *ClusterClient) pipelineExec(cmds []Cmder) error {
continue continue
} }
err = c.pipelineProcessCmds(cn, cmds, failedCmds) err = c.pipelineProcessCmds(node, cn, cmds, failedCmds)
node.Client.releaseConn(cn, err) if err == nil || internal.IsRedisError(err) {
_ = node.Client.connPool.Put(cn)
} else {
_ = node.Client.connPool.Remove(cn)
}
} }
if len(failedCmds) == 0 { if len(failedCmds) == 0 {
@@ -866,21 +933,20 @@ func (c *ClusterClient) pipelineExec(cmds []Cmder) error {
cmdsMap = failedCmds cmdsMap = failedCmds
} }
var firstErr error return firstCmdsErr(cmds)
for _, cmd := range cmds {
if err := cmd.Err(); err != nil {
firstErr = err
break
}
}
return firstErr
} }
func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, error) { func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, error) {
state := c.state() state, err := c.state()
if err != nil {
setCmdsErr(cmds, err)
return nil, err
}
cmdsMap := make(map[*clusterNode][]Cmder) cmdsMap := make(map[*clusterNode][]Cmder)
for _, cmd := range cmds { for _, cmd := range cmds {
_, node, err := c.cmdSlotAndNode(state, cmd) slot := c.cmdSlot(cmd)
node, err := state.slotMasterNode(slot)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -890,11 +956,12 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, e
} }
func (c *ClusterClient) pipelineProcessCmds( func (c *ClusterClient) pipelineProcessCmds(
cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder, node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
) error { ) error {
cn.SetWriteTimeout(c.opt.WriteTimeout) cn.SetWriteTimeout(c.opt.WriteTimeout)
if err := writeCmd(cn, cmds...); err != nil { if err := writeCmd(cn, cmds...); err != nil {
setCmdsErr(cmds, err) setCmdsErr(cmds, err)
failedCmds[node] = cmds
return err return err
} }
@@ -907,46 +974,53 @@ func (c *ClusterClient) pipelineProcessCmds(
func (c *ClusterClient) pipelineReadCmds( func (c *ClusterClient) pipelineReadCmds(
cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
) error { ) error {
var firstErr error
for _, cmd := range cmds { for _, cmd := range cmds {
err := cmd.readReply(cn) err := cmd.readReply(cn)
if err == nil { if err == nil {
continue continue
} }
if firstErr == nil { if c.checkMovedErr(cmd, err, failedCmds) {
firstErr = err continue
} }
err = c.checkMovedErr(cmd, failedCmds) if internal.IsRedisError(err) {
if err != nil && firstErr == nil { continue
firstErr = err
} }
return err
} }
return firstErr return nil
} }
func (c *ClusterClient) checkMovedErr(cmd Cmder, failedCmds map[*clusterNode][]Cmder) error { func (c *ClusterClient) checkMovedErr(
moved, ask, addr := internal.IsMovedError(cmd.Err()) cmd Cmder, err error, failedCmds map[*clusterNode][]Cmder,
) bool {
moved, ask, addr := internal.IsMovedError(err)
if moved { if moved {
c.lazyReloadState() c.lazyReloadState()
node, err := c.nodes.GetOrCreate(addr) node, err := c.nodes.GetOrCreate(addr)
if err != nil { if err != nil {
return err return false
} }
failedCmds[node] = append(failedCmds[node], cmd) failedCmds[node] = append(failedCmds[node], cmd)
return true
} }
if ask { if ask {
node, err := c.nodes.GetOrCreate(addr) node, err := c.nodes.GetOrCreate(addr)
if err != nil { if err != nil {
return err return false
} }
failedCmds[node] = append(failedCmds[node], NewCmd("ASKING"), cmd) failedCmds[node] = append(failedCmds[node], NewCmd("ASKING"), cmd)
return true
} }
return nil
return false
} }
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
@@ -959,29 +1033,29 @@ func (c *ClusterClient) TxPipeline() Pipeliner {
} }
func (c *ClusterClient) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *ClusterClient) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.TxPipeline().pipelined(fn) return c.TxPipeline().Pipelined(fn)
} }
func (c *ClusterClient) txPipelineExec(cmds []Cmder) error { func (c *ClusterClient) txPipelineExec(cmds []Cmder) error {
cmdsMap, err := c.mapCmdsBySlot(cmds) state, err := c.state()
if err != nil { if err != nil {
return err return err
} }
state := c.state() cmdsMap := c.mapCmdsBySlot(cmds)
if state == nil {
return errNilClusterState
}
for slot, cmds := range cmdsMap { for slot, cmds := range cmdsMap {
node, err := state.slotMasterNode(slot) node, err := state.slotMasterNode(slot)
if err != nil { if err != nil {
setCmdsErr(cmds, err) setCmdsErr(cmds, err)
continue continue
} }
cmdsMap := map[*clusterNode][]Cmder{node: cmds} cmdsMap := map[*clusterNode][]Cmder{node: cmds}
for i := 0; i <= c.opt.MaxRedirects; i++ {
for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
if attempt > 0 {
time.Sleep(c.retryBackoff(attempt))
}
failedCmds := make(map[*clusterNode][]Cmder) failedCmds := make(map[*clusterNode][]Cmder)
for node, cmds := range cmdsMap { for node, cmds := range cmdsMap {
@@ -992,7 +1066,11 @@ func (c *ClusterClient) txPipelineExec(cmds []Cmder) error {
} }
err = c.txPipelineProcessCmds(node, cn, cmds, failedCmds) err = c.txPipelineProcessCmds(node, cn, cmds, failedCmds)
node.Client.releaseConn(cn, err) if err == nil || internal.IsRedisError(err) {
_ = node.Client.connPool.Put(cn)
} else {
_ = node.Client.connPool.Remove(cn)
}
} }
if len(failedCmds) == 0 { if len(failedCmds) == 0 {
@@ -1002,27 +1080,16 @@ func (c *ClusterClient) txPipelineExec(cmds []Cmder) error {
} }
} }
var firstErr error return firstCmdsErr(cmds)
for _, cmd := range cmds {
if err := cmd.Err(); err != nil {
firstErr = err
break
}
}
return firstErr
} }
func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) (map[int][]Cmder, error) { func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
state := c.state()
cmdsMap := make(map[int][]Cmder) cmdsMap := make(map[int][]Cmder)
for _, cmd := range cmds { for _, cmd := range cmds {
slot, _, err := c.cmdSlotAndNode(state, cmd) slot := c.cmdSlot(cmd)
if err != nil {
return nil, err
}
cmdsMap[slot] = append(cmdsMap[slot], cmd) cmdsMap[slot] = append(cmdsMap[slot], cmd)
} }
return cmdsMap, nil return cmdsMap
} }
func (c *ClusterClient) txPipelineProcessCmds( func (c *ClusterClient) txPipelineProcessCmds(
@@ -1039,22 +1106,20 @@ func (c *ClusterClient) txPipelineProcessCmds(
cn.SetReadTimeout(c.opt.ReadTimeout) cn.SetReadTimeout(c.opt.ReadTimeout)
if err := c.txPipelineReadQueued(cn, cmds, failedCmds); err != nil { if err := c.txPipelineReadQueued(cn, cmds, failedCmds); err != nil {
setCmdsErr(cmds, err)
return err return err
} }
_, err := pipelineReadCmds(cn, cmds) return pipelineReadCmds(cn, cmds)
return err
} }
func (c *ClusterClient) txPipelineReadQueued( func (c *ClusterClient) txPipelineReadQueued(
cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
) error { ) error {
var firstErr error
// Parse queued replies. // Parse queued replies.
var statusCmd StatusCmd var statusCmd StatusCmd
if err := statusCmd.readReply(cn); err != nil && firstErr == nil { if err := statusCmd.readReply(cn); err != nil {
firstErr = err return err
} }
for _, cmd := range cmds { for _, cmd := range cmds {
@@ -1063,15 +1128,11 @@ func (c *ClusterClient) txPipelineReadQueued(
continue continue
} }
cmd.setErr(err) if c.checkMovedErr(cmd, err, failedCmds) || internal.IsRedisError(err) {
if firstErr == nil { continue
firstErr = err
} }
err = c.checkMovedErr(cmd, failedCmds) return err
if err != nil && firstErr == nil {
firstErr = err
}
} }
// Parse number of replies. // Parse number of replies.
@@ -1085,7 +1146,13 @@ func (c *ClusterClient) txPipelineReadQueued(
switch line[0] { switch line[0] {
case proto.ErrorReply: case proto.ErrorReply:
return proto.ParseErrorReply(line) err := proto.ParseErrorReply(line)
for _, cmd := range cmds {
if !c.checkMovedErr(cmd, err, failedCmds) {
break
}
}
return err
case proto.ArrayReply: case proto.ArrayReply:
// ok // ok
default: default:
@@ -1093,7 +1160,7 @@ func (c *ClusterClient) txPipelineReadQueued(
return err return err
} }
return firstErr return nil
} }
func (c *ClusterClient) pubSub(channels []string) *PubSub { func (c *ClusterClient) pubSub(channels []string) *PubSub {
@@ -1112,7 +1179,12 @@ func (c *ClusterClient) pubSub(channels []string) *PubSub {
slot = -1 slot = -1
} }
masterNode, err := c.state().slotMasterNode(slot) state, err := c.state()
if err != nil {
return nil, err
}
masterNode, err := state.slotMasterNode(slot)
if err != nil { if err != nil {
return nil, err return nil, err
} }

22
vendor/github.com/go-redis/redis/cluster_commands.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,22 @@
package redis
import "sync/atomic"
func (c *ClusterClient) DBSize() *IntCmd {
cmd := NewIntCmd("dbsize")
var size int64
err := c.ForEachMaster(func(master *Client) error {
n, err := master.DBSize().Result()
if err != nil {
return err
}
atomic.AddInt64(&size, n)
return nil
})
if err != nil {
cmd.setErr(err)
return cmd
}
cmd.val = size
return cmd
}

81
vendor/github.com/go-redis/redis/cluster_test.go сгенерированный поставляемый
Просмотреть файл

@@ -200,7 +200,7 @@ var _ = Describe("ClusterClient", func() {
Eventually(func() string { Eventually(func() string {
return client.Get("A").Val() return client.Get("A").Val()
}).Should(Equal("VALUE")) }, 30*time.Second).Should(Equal("VALUE"))
cnt, err := client.Del("A").Result() cnt, err := client.Del("A").Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -215,7 +215,7 @@ var _ = Describe("ClusterClient", func() {
Eventually(func() string { Eventually(func() string {
return client.Get("A").Val() return client.Get("A").Val()
}).Should(Equal("VALUE")) }, 30*time.Second).Should(Equal("VALUE"))
}) })
It("distributes keys", func() { It("distributes keys", func() {
@@ -227,7 +227,7 @@ var _ = Describe("ClusterClient", func() {
for _, master := range cluster.masters() { for _, master := range cluster.masters() {
Eventually(func() string { Eventually(func() string {
return master.Info("keyspace").Val() return master.Info("keyspace").Val()
}, 5*time.Second).Should(Or( }, 30*time.Second).Should(Or(
ContainSubstring("keys=31"), ContainSubstring("keys=31"),
ContainSubstring("keys=29"), ContainSubstring("keys=29"),
ContainSubstring("keys=40"), ContainSubstring("keys=40"),
@@ -251,7 +251,7 @@ var _ = Describe("ClusterClient", func() {
for _, master := range cluster.masters() { for _, master := range cluster.masters() {
Eventually(func() string { Eventually(func() string {
return master.Info("keyspace").Val() return master.Info("keyspace").Val()
}, 5*time.Second).Should(Or( }, 30*time.Second).Should(Or(
ContainSubstring("keys=31"), ContainSubstring("keys=31"),
ContainSubstring("keys=29"), ContainSubstring("keys=29"),
ContainSubstring("keys=40"), ContainSubstring("keys=40"),
@@ -320,10 +320,6 @@ var _ = Describe("ClusterClient", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(cmds).To(HaveLen(14)) Expect(cmds).To(HaveLen(14))
if opt.RouteByLatency {
return
}
for _, key := range keys { for _, key := range keys {
slot := hashtag.Slot(key) slot := hashtag.Slot(key)
client.SwapSlotNodes(slot) client.SwapSlotNodes(slot)
@@ -432,6 +428,9 @@ var _ = Describe("ClusterClient", func() {
}) })
AfterEach(func() { AfterEach(func() {
_ = client.ForEachMaster(func(master *redis.Client) error {
return master.FlushDB().Err()
})
Expect(client.Close()).NotTo(HaveOccurred()) Expect(client.Close()).NotTo(HaveOccurred())
}) })
@@ -476,11 +475,9 @@ var _ = Describe("ClusterClient", func() {
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
for _, client := range cluster.masters() { size, err := client.DBSize().Result()
size, err := client.DBSize().Result() Expect(err).NotTo(HaveOccurred())
Expect(err).NotTo(HaveOccurred()) Expect(size).To(Equal(int64(0)))
Expect(size).To(Equal(int64(0)))
}
}) })
It("should CLUSTER SLOTS", func() { It("should CLUSTER SLOTS", func() {
@@ -560,6 +557,9 @@ var _ = Describe("ClusterClient", func() {
}) })
AfterEach(func() { AfterEach(func() {
_ = client.ForEachMaster(func(master *redis.Client) error {
return master.FlushDB().Err()
})
Expect(client.Close()).NotTo(HaveOccurred()) Expect(client.Close()).NotTo(HaveOccurred())
}) })
@@ -575,10 +575,19 @@ var _ = Describe("ClusterClient", func() {
_ = client.ForEachMaster(func(master *redis.Client) error { _ = client.ForEachMaster(func(master *redis.Client) error {
return master.FlushDB().Err() return master.FlushDB().Err()
}) })
_ = client.ForEachSlave(func(slave *redis.Client) error {
Eventually(func() int64 {
return client.DBSize().Val()
}, 30*time.Second).Should(Equal(int64(0)))
return nil
})
}) })
AfterEach(func() { AfterEach(func() {
client.FlushDB() _ = client.ForEachMaster(func(master *redis.Client) error {
return master.FlushDB().Err()
})
Expect(client.Close()).NotTo(HaveOccurred()) Expect(client.Close()).NotTo(HaveOccurred())
}) })
@@ -597,7 +606,7 @@ var _ = Describe("ClusterClient without nodes", func() {
Expect(client.Close()).NotTo(HaveOccurred()) Expect(client.Close()).NotTo(HaveOccurred())
}) })
It("returns an error", func() { It("Ping returns an error", func() {
err := client.Ping().Err() err := client.Ping().Err()
Expect(err).To(MatchError("redis: cluster has no nodes")) Expect(err).To(MatchError("redis: cluster has no nodes"))
}) })
@@ -626,7 +635,7 @@ var _ = Describe("ClusterClient without valid nodes", func() {
It("returns an error", func() { It("returns an error", func() {
err := client.Ping().Err() err := client.Ping().Err()
Expect(err).To(MatchError("ERR This instance has cluster support disabled")) Expect(err).To(MatchError("redis: cannot load cluster slots"))
}) })
It("pipeline returns an error", func() { It("pipeline returns an error", func() {
@@ -634,7 +643,7 @@ var _ = Describe("ClusterClient without valid nodes", func() {
pipe.Ping() pipe.Ping()
return nil return nil
}) })
Expect(err).To(MatchError("ERR This instance has cluster support disabled")) Expect(err).To(MatchError("redis: cannot load cluster slots"))
}) })
}) })
@@ -664,7 +673,7 @@ var _ = Describe("ClusterClient timeout", func() {
It("Tx timeouts", func() { It("Tx timeouts", func() {
err := client.Watch(func(tx *redis.Tx) error { err := client.Watch(func(tx *redis.Tx) error {
return tx.Ping().Err() return tx.Ping().Err()
}) }, "foo")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.(net.Error).Timeout()).To(BeTrue()) Expect(err.(net.Error).Timeout()).To(BeTrue())
}) })
@@ -676,42 +685,20 @@ var _ = Describe("ClusterClient timeout", func() {
return nil return nil
}) })
return err return err
}) }, "foo")
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.(net.Error).Timeout()).To(BeTrue()) Expect(err.(net.Error).Timeout()).To(BeTrue())
}) })
} }
Context("read timeout", func() { const pause = time.Second
Context("read/write timeout", func() {
BeforeEach(func() { BeforeEach(func() {
opt := redisClusterOptions() opt := redisClusterOptions()
opt.ReadTimeout = time.Nanosecond opt.ReadTimeout = 100 * time.Millisecond
opt.WriteTimeout = -1 opt.WriteTimeout = 100 * time.Millisecond
client = cluster.clusterClient(opt) opt.MaxRedirects = 1
})
testTimeout()
})
Context("write timeout", func() {
BeforeEach(func() {
opt := redisClusterOptions()
opt.ReadTimeout = time.Nanosecond
opt.WriteTimeout = -1
client = cluster.clusterClient(opt)
})
testTimeout()
})
Context("ClientPause timeout", func() {
const pause = time.Second
BeforeEach(func() {
opt := redisClusterOptions()
opt.ReadTimeout = pause / 10
opt.WriteTimeout = pause / 10
opt.MaxRedirects = -1
client = cluster.clusterClient(opt) client = cluster.clusterClient(opt)
err := client.ForEachNode(func(client *redis.Client) error { err := client.ForEachNode(func(client *redis.Client) error {

86
vendor/github.com/go-redis/redis/command.go сгенерированный поставляемый
Просмотреть файл

@@ -12,28 +12,10 @@ import (
"github.com/go-redis/redis/internal/proto" "github.com/go-redis/redis/internal/proto"
) )
var (
_ Cmder = (*Cmd)(nil)
_ Cmder = (*SliceCmd)(nil)
_ Cmder = (*StatusCmd)(nil)
_ Cmder = (*IntCmd)(nil)
_ Cmder = (*DurationCmd)(nil)
_ Cmder = (*BoolCmd)(nil)
_ Cmder = (*StringCmd)(nil)
_ Cmder = (*FloatCmd)(nil)
_ Cmder = (*StringSliceCmd)(nil)
_ Cmder = (*BoolSliceCmd)(nil)
_ Cmder = (*StringStringMapCmd)(nil)
_ Cmder = (*StringIntMapCmd)(nil)
_ Cmder = (*ZSliceCmd)(nil)
_ Cmder = (*ScanCmd)(nil)
_ Cmder = (*ClusterSlotsCmd)(nil)
)
type Cmder interface { type Cmder interface {
args() []interface{}
arg(int) string
Name() string Name() string
Args() []interface{}
stringArg(int) string
readReply(*pool.Conn) error readReply(*pool.Conn) error
setErr(error) setErr(error)
@@ -46,14 +28,25 @@ type Cmder interface {
func setCmdsErr(cmds []Cmder, e error) { func setCmdsErr(cmds []Cmder, e error) {
for _, cmd := range cmds { for _, cmd := range cmds {
cmd.setErr(e) if cmd.Err() == nil {
cmd.setErr(e)
}
} }
} }
func firstCmdsErr(cmds []Cmder) error {
for _, cmd := range cmds {
if err := cmd.Err(); err != nil {
return err
}
}
return nil
}
func writeCmd(cn *pool.Conn, cmds ...Cmder) error { func writeCmd(cn *pool.Conn, cmds ...Cmder) error {
cn.Wb.Reset() cn.Wb.Reset()
for _, cmd := range cmds { for _, cmd := range cmds {
if err := cn.Wb.Append(cmd.args()); err != nil { if err := cn.Wb.Append(cmd.Args()); err != nil {
return err return err
} }
} }
@@ -64,7 +57,7 @@ func writeCmd(cn *pool.Conn, cmds ...Cmder) error {
func cmdString(cmd Cmder, val interface{}) string { func cmdString(cmd Cmder, val interface{}) string {
var ss []string var ss []string
for _, arg := range cmd.args() { for _, arg := range cmd.Args() {
ss = append(ss, fmt.Sprint(arg)) ss = append(ss, fmt.Sprint(arg))
} }
s := strings.Join(ss, " ") s := strings.Join(ss, " ")
@@ -86,7 +79,7 @@ func cmdString(cmd Cmder, val interface{}) string {
func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
switch cmd.Name() { switch cmd.Name() {
case "eval", "evalsha": case "eval", "evalsha":
if cmd.arg(2) != "0" { if cmd.stringArg(2) != "0" {
return 3 return 3
} else { } else {
return -1 return -1
@@ -95,7 +88,6 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
return 1 return 1
} }
if info == nil { if info == nil {
internal.Logf("info for cmd=%s not found", cmd.Name())
return -1 return -1
} }
return int(info.FirstKeyPos) return int(info.FirstKeyPos)
@@ -110,15 +102,17 @@ type baseCmd struct {
_readTimeout *time.Duration _readTimeout *time.Duration
} }
var _ Cmder = (*Cmd)(nil)
func (cmd *baseCmd) Err() error { func (cmd *baseCmd) Err() error {
return cmd.err return cmd.err
} }
func (cmd *baseCmd) args() []interface{} { func (cmd *baseCmd) Args() []interface{} {
return cmd._args return cmd._args
} }
func (cmd *baseCmd) arg(pos int) string { func (cmd *baseCmd) stringArg(pos int) string {
if pos < 0 || pos >= len(cmd._args) { if pos < 0 || pos >= len(cmd._args) {
return "" return ""
} }
@@ -129,7 +123,7 @@ func (cmd *baseCmd) arg(pos int) string {
func (cmd *baseCmd) Name() string { func (cmd *baseCmd) Name() string {
if len(cmd._args) > 0 { if len(cmd._args) > 0 {
// Cmd name must be lower cased. // Cmd name must be lower cased.
s := internal.ToLower(cmd.arg(0)) s := internal.ToLower(cmd.stringArg(0))
cmd._args[0] = s cmd._args[0] = s
return s return s
} }
@@ -194,6 +188,8 @@ type SliceCmd struct {
val []interface{} val []interface{}
} }
var _ Cmder = (*SliceCmd)(nil)
func NewSliceCmd(args ...interface{}) *SliceCmd { func NewSliceCmd(args ...interface{}) *SliceCmd {
return &SliceCmd{ return &SliceCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -230,6 +226,8 @@ type StatusCmd struct {
val string val string
} }
var _ Cmder = (*StatusCmd)(nil)
func NewStatusCmd(args ...interface{}) *StatusCmd { func NewStatusCmd(args ...interface{}) *StatusCmd {
return &StatusCmd{ return &StatusCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -261,6 +259,8 @@ type IntCmd struct {
val int64 val int64
} }
var _ Cmder = (*IntCmd)(nil)
func NewIntCmd(args ...interface{}) *IntCmd { func NewIntCmd(args ...interface{}) *IntCmd {
return &IntCmd{ return &IntCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -293,6 +293,8 @@ type DurationCmd struct {
precision time.Duration precision time.Duration
} }
var _ Cmder = (*DurationCmd)(nil)
func NewDurationCmd(precision time.Duration, args ...interface{}) *DurationCmd { func NewDurationCmd(precision time.Duration, args ...interface{}) *DurationCmd {
return &DurationCmd{ return &DurationCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -330,6 +332,8 @@ type TimeCmd struct {
val time.Time val time.Time
} }
var _ Cmder = (*TimeCmd)(nil)
func NewTimeCmd(args ...interface{}) *TimeCmd { func NewTimeCmd(args ...interface{}) *TimeCmd {
return &TimeCmd{ return &TimeCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -366,6 +370,8 @@ type BoolCmd struct {
val bool val bool
} }
var _ Cmder = (*BoolCmd)(nil)
func NewBoolCmd(args ...interface{}) *BoolCmd { func NewBoolCmd(args ...interface{}) *BoolCmd {
return &BoolCmd{ return &BoolCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -421,6 +427,8 @@ type StringCmd struct {
val []byte val []byte
} }
var _ Cmder = (*StringCmd)(nil)
func NewStringCmd(args ...interface{}) *StringCmd { func NewStringCmd(args ...interface{}) *StringCmd {
return &StringCmd{ return &StringCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -484,6 +492,8 @@ type FloatCmd struct {
val float64 val float64
} }
var _ Cmder = (*FloatCmd)(nil)
func NewFloatCmd(args ...interface{}) *FloatCmd { func NewFloatCmd(args ...interface{}) *FloatCmd {
return &FloatCmd{ return &FloatCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -515,6 +525,8 @@ type StringSliceCmd struct {
val []string val []string
} }
var _ Cmder = (*StringSliceCmd)(nil)
func NewStringSliceCmd(args ...interface{}) *StringSliceCmd { func NewStringSliceCmd(args ...interface{}) *StringSliceCmd {
return &StringSliceCmd{ return &StringSliceCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -555,6 +567,8 @@ type BoolSliceCmd struct {
val []bool val []bool
} }
var _ Cmder = (*BoolSliceCmd)(nil)
func NewBoolSliceCmd(args ...interface{}) *BoolSliceCmd { func NewBoolSliceCmd(args ...interface{}) *BoolSliceCmd {
return &BoolSliceCmd{ return &BoolSliceCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -591,6 +605,8 @@ type StringStringMapCmd struct {
val map[string]string val map[string]string
} }
var _ Cmder = (*StringStringMapCmd)(nil)
func NewStringStringMapCmd(args ...interface{}) *StringStringMapCmd { func NewStringStringMapCmd(args ...interface{}) *StringStringMapCmd {
return &StringStringMapCmd{ return &StringStringMapCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -627,6 +643,8 @@ type StringIntMapCmd struct {
val map[string]int64 val map[string]int64
} }
var _ Cmder = (*StringIntMapCmd)(nil)
func NewStringIntMapCmd(args ...interface{}) *StringIntMapCmd { func NewStringIntMapCmd(args ...interface{}) *StringIntMapCmd {
return &StringIntMapCmd{ return &StringIntMapCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -663,6 +681,8 @@ type ZSliceCmd struct {
val []Z val []Z
} }
var _ Cmder = (*ZSliceCmd)(nil)
func NewZSliceCmd(args ...interface{}) *ZSliceCmd { func NewZSliceCmd(args ...interface{}) *ZSliceCmd {
return &ZSliceCmd{ return &ZSliceCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -702,6 +722,8 @@ type ScanCmd struct {
process func(cmd Cmder) error process func(cmd Cmder) error
} }
var _ Cmder = (*ScanCmd)(nil)
func NewScanCmd(process func(cmd Cmder) error, args ...interface{}) *ScanCmd { func NewScanCmd(process func(cmd Cmder) error, args ...interface{}) *ScanCmd {
return &ScanCmd{ return &ScanCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -752,6 +774,8 @@ type ClusterSlotsCmd struct {
val []ClusterSlot val []ClusterSlot
} }
var _ Cmder = (*ClusterSlotsCmd)(nil)
func NewClusterSlotsCmd(args ...interface{}) *ClusterSlotsCmd { func NewClusterSlotsCmd(args ...interface{}) *ClusterSlotsCmd {
return &ClusterSlotsCmd{ return &ClusterSlotsCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -811,6 +835,8 @@ type GeoLocationCmd struct {
locations []GeoLocation locations []GeoLocation
} }
var _ Cmder = (*GeoLocationCmd)(nil)
func NewGeoLocationCmd(q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd { func NewGeoLocationCmd(q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
args = append(args, q.Radius) args = append(args, q.Radius)
if q.Unit != "" { if q.Unit != "" {
@@ -881,6 +907,8 @@ type GeoPosCmd struct {
positions []*GeoPos positions []*GeoPos
} }
var _ Cmder = (*GeoPosCmd)(nil)
func NewGeoPosCmd(args ...interface{}) *GeoPosCmd { func NewGeoPosCmd(args ...interface{}) *GeoPosCmd {
return &GeoPosCmd{ return &GeoPosCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},
@@ -927,6 +955,8 @@ type CommandsInfoCmd struct {
val map[string]*CommandInfo val map[string]*CommandInfo
} }
var _ Cmder = (*CommandsInfoCmd)(nil)
func NewCommandsInfoCmd(args ...interface{}) *CommandsInfoCmd { func NewCommandsInfoCmd(args ...interface{}) *CommandsInfoCmd {
return &CommandsInfoCmd{ return &CommandsInfoCmd{
baseCmd: baseCmd{_args: args}, baseCmd: baseCmd{_args: args},

5
vendor/github.com/go-redis/redis/commands.go сгенерированный поставляемый
Просмотреть файл

@@ -11,7 +11,7 @@ func readTimeout(timeout time.Duration) time.Duration {
if timeout == 0 { if timeout == 0 {
return 0 return 0
} }
return timeout + time.Second return timeout + 10*time.Second
} }
func usePrecise(dur time.Duration) bool { func usePrecise(dur time.Duration) bool {
@@ -42,6 +42,9 @@ type Cmdable interface {
Pipeline() Pipeliner Pipeline() Pipeliner
Pipelined(fn func(Pipeliner) error) ([]Cmder, error) Pipelined(fn func(Pipeliner) error) ([]Cmder, error)
TxPipelined(fn func(Pipeliner) error) ([]Cmder, error)
TxPipeline() Pipeliner
ClientGetName() *StringCmd ClientGetName() *StringCmd
Echo(message interface{}) *StringCmd Echo(message interface{}) *StringCmd
Ping() *StatusCmd Ping() *StatusCmd

55
vendor/github.com/go-redis/redis/commands_test.go сгенерированный поставляемый
Просмотреть файл

@@ -27,11 +27,21 @@ var _ = Describe("Commands", func() {
Describe("server", func() { Describe("server", func() {
It("should Auth", func() { It("should Auth", func() {
_, err := client.Pipelined(func(pipe redis.Pipeliner) error { cmds, err := client.Pipelined(func(pipe redis.Pipeliner) error {
pipe.Auth("password") pipe.Auth("password")
pipe.Auth("")
return nil return nil
}) })
Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set")) Expect(err).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(cmds[0].Err()).To(MatchError("ERR Client sent AUTH, but no password is set"))
Expect(cmds[1].Err()).To(MatchError("ERR Client sent AUTH, but no password is set"))
stats := client.PoolStats()
Expect(stats.Hits).To(Equal(uint32(1)))
Expect(stats.Misses).To(Equal(uint32(1)))
Expect(stats.Timeouts).To(Equal(uint32(0)))
Expect(stats.TotalConns).To(Equal(uint32(1)))
Expect(stats.FreeConns).To(Equal(uint32(1)))
}) })
It("should Echo", func() { It("should Echo", func() {
@@ -187,6 +197,29 @@ var _ = Describe("Commands", func() {
Expect(tm).To(BeTemporally("~", time.Now(), 3*time.Second)) Expect(tm).To(BeTemporally("~", time.Now(), 3*time.Second))
}) })
It("Should Command", func() {
cmds, err := client.Command().Result()
Expect(err).NotTo(HaveOccurred())
Expect(len(cmds)).To(BeNumerically("~", 180, 10))
cmd := cmds["mget"]
Expect(cmd.Name).To(Equal("mget"))
Expect(cmd.Arity).To(Equal(int8(-2)))
Expect(cmd.Flags).To(ContainElement("readonly"))
Expect(cmd.FirstKeyPos).To(Equal(int8(1)))
Expect(cmd.LastKeyPos).To(Equal(int8(-1)))
Expect(cmd.StepCount).To(Equal(int8(1)))
cmd = cmds["ping"]
Expect(cmd.Name).To(Equal("ping"))
Expect(cmd.Arity).To(Equal(int8(-1)))
Expect(cmd.Flags).To(ContainElement("stale"))
Expect(cmd.Flags).To(ContainElement("fast"))
Expect(cmd.FirstKeyPos).To(Equal(int8(0)))
Expect(cmd.LastKeyPos).To(Equal(int8(0)))
Expect(cmd.StepCount).To(Equal(int8(0)))
})
}) })
Describe("debugging", func() { Describe("debugging", func() {
@@ -1358,8 +1391,8 @@ var _ = Describe("Commands", func() {
Expect(client.Ping().Err()).NotTo(HaveOccurred()) Expect(client.Ping().Err()).NotTo(HaveOccurred())
stats := client.PoolStats() stats := client.PoolStats()
Expect(stats.Requests).To(Equal(uint32(3)))
Expect(stats.Hits).To(Equal(uint32(1))) Expect(stats.Hits).To(Equal(uint32(1)))
Expect(stats.Misses).To(Equal(uint32(2)))
Expect(stats.Timeouts).To(Equal(uint32(0))) Expect(stats.Timeouts).To(Equal(uint32(0)))
}) })
@@ -2887,24 +2920,6 @@ var _ = Describe("Commands", func() {
}) })
Describe("Command", func() {
It("returns map of commands", func() {
cmds, err := client.Command().Result()
Expect(err).NotTo(HaveOccurred())
Expect(len(cmds)).To(BeNumerically("~", 180, 10))
cmd := cmds["mget"]
Expect(cmd.Name).To(Equal("mget"))
Expect(cmd.Arity).To(Equal(int8(-2)))
Expect(cmd.Flags).To(ContainElement("readonly"))
Expect(cmd.FirstKeyPos).To(Equal(int8(1)))
Expect(cmd.LastKeyPos).To(Equal(int8(-1)))
Expect(cmd.StepCount).To(Equal(int8(1)))
})
})
Describe("Eval", func() { Describe("Eval", func() {
It("returns keys and values", func() { It("returns keys and values", func() {

14
vendor/github.com/go-redis/redis/export_test.go сгенерированный поставляемый
Просмотреть файл

@@ -20,8 +20,13 @@ func (c *PubSub) ReceiveMessageTimeout(timeout time.Duration) (*Message, error)
} }
func (c *ClusterClient) SlotAddrs(slot int) []string { func (c *ClusterClient) SlotAddrs(slot int) []string {
state, err := c.state()
if err != nil {
panic(err)
}
var addrs []string var addrs []string
for _, n := range c.state().slotNodes(slot) { for _, n := range state.slotNodes(slot) {
addrs = append(addrs, n.Client.getAddr()) addrs = append(addrs, n.Client.getAddr())
} }
return addrs return addrs
@@ -29,7 +34,12 @@ func (c *ClusterClient) SlotAddrs(slot int) []string {
// SwapSlot swaps a slot's master/slave address for testing MOVED redirects. // SwapSlot swaps a slot's master/slave address for testing MOVED redirects.
func (c *ClusterClient) SwapSlotNodes(slot int) { func (c *ClusterClient) SwapSlotNodes(slot int) {
nodes := c.state().slots[slot] state, err := c.state()
if err != nil {
panic(err)
}
nodes := state.slots[slot]
if len(nodes) == 2 { if len(nodes) == 2 {
nodes[0], nodes[1] = nodes[1], nodes[0] nodes[0], nodes[1] = nodes[1], nodes[0]
} }

27
vendor/github.com/go-redis/redis/internal/error.go сгенерированный поставляемый
Просмотреть файл

@@ -12,11 +12,24 @@ type RedisError string
func (e RedisError) Error() string { return string(e) } func (e RedisError) Error() string { return string(e) }
func IsRetryableError(err error) bool { func IsRetryableError(err error, retryNetError bool) bool {
return IsNetworkError(err) || err.Error() == "ERR max number of clients reached" if IsNetworkError(err) {
return retryNetError
}
s := err.Error()
if s == "ERR max number of clients reached" {
return true
}
if strings.HasPrefix(s, "LOADING ") {
return true
}
if strings.HasPrefix(s, "CLUSTERDOWN ") {
return true
}
return false
} }
func IsInternalError(err error) bool { func IsRedisError(err error) bool {
_, ok := err.(RedisError) _, ok := err.(RedisError)
return ok return ok
} }
@@ -33,7 +46,7 @@ func IsBadConn(err error, allowTimeout bool) bool {
if err == nil { if err == nil {
return false return false
} }
if IsInternalError(err) { if IsRedisError(err) {
return false return false
} }
if allowTimeout { if allowTimeout {
@@ -45,7 +58,7 @@ func IsBadConn(err error, allowTimeout bool) bool {
} }
func IsMovedError(err error) (moved bool, ask bool, addr string) { func IsMovedError(err error) (moved bool, ask bool, addr string) {
if !IsInternalError(err) { if !IsRedisError(err) {
return return
} }
@@ -69,7 +82,3 @@ func IsMovedError(err error) (moved bool, ask bool, addr string) {
func IsLoadingError(err error) bool { func IsLoadingError(err error) bool {
return strings.HasPrefix(err.Error(), "LOADING ") return strings.HasPrefix(err.Error(), "LOADING ")
} }
func IsClusterDownError(err error) bool {
return strings.HasPrefix(err.Error(), "CLUSTERDOWN ")
}

25
vendor/github.com/go-redis/redis/internal/pool/pool.go сгенерированный поставляемый
Просмотреть файл

@@ -23,12 +23,13 @@ var timers = sync.Pool{
// Stats contains pool state information and accumulated stats. // Stats contains pool state information and accumulated stats.
type Stats struct { type Stats struct {
Requests uint32 // number of times a connection was requested by the pool
Hits uint32 // number of times free connection was found in the pool Hits uint32 // number of times free connection was found in the pool
Misses uint32 // number of times free connection was NOT found in the pool
Timeouts uint32 // number of times a wait timeout occurred Timeouts uint32 // number of times a wait timeout occurred
TotalConns uint32 // the number of total connections in the pool TotalConns uint32 // number of total connections in the pool
FreeConns uint32 // the number of free connections in the pool FreeConns uint32 // number of free connections in the pool
StaleConns uint32 // number of stale connections removed from the pool
} }
type Pooler interface { type Pooler interface {
@@ -150,8 +151,6 @@ func (p *ConnPool) Get() (*Conn, bool, error) {
return nil, false, ErrClosed return nil, false, ErrClosed
} }
atomic.AddUint32(&p.stats.Requests, 1)
select { select {
case p.queue <- struct{}{}: case p.queue <- struct{}{}:
default: default:
@@ -189,6 +188,8 @@ func (p *ConnPool) Get() (*Conn, bool, error) {
return cn, false, nil return cn, false, nil
} }
atomic.AddUint32(&p.stats.Misses, 1)
newcn, err := p.NewConn() newcn, err := p.NewConn()
if err != nil { if err != nil {
<-p.queue <-p.queue
@@ -265,11 +266,13 @@ func (p *ConnPool) FreeLen() int {
func (p *ConnPool) Stats() *Stats { func (p *ConnPool) Stats() *Stats {
return &Stats{ return &Stats{
Requests: atomic.LoadUint32(&p.stats.Requests), Hits: atomic.LoadUint32(&p.stats.Hits),
Hits: atomic.LoadUint32(&p.stats.Hits), Misses: atomic.LoadUint32(&p.stats.Misses),
Timeouts: atomic.LoadUint32(&p.stats.Timeouts), Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
TotalConns: uint32(p.Len()), TotalConns: uint32(p.Len()),
FreeConns: uint32(p.FreeLen()), FreeConns: uint32(p.FreeLen()),
StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
} }
} }
@@ -362,10 +365,6 @@ func (p *ConnPool) reaper(frequency time.Duration) {
internal.Logf("ReapStaleConns failed: %s", err) internal.Logf("ReapStaleConns failed: %s", err)
continue continue
} }
s := p.Stats() atomic.AddUint32(&p.stats.StaleConns, uint32(n))
internal.Logf(
"reaper: removed %d stale conns (TotalConns=%d FreeConns=%d Requests=%d Hits=%d Timeouts=%d)",
n, s.TotalConns, s.FreeConns, s.Requests, s.Hits, s.Timeouts,
)
} }
} }

2
vendor/github.com/go-redis/redis/internal/proto/reader.go сгенерированный поставляемый
Просмотреть файл

@@ -63,7 +63,7 @@ func (p *Reader) ReadLine() ([]byte, error) {
return nil, bufio.ErrBufferFull return nil, bufio.ErrBufferFull
} }
if len(line) == 0 { if len(line) == 0 {
return nil, internal.RedisError("redis: reply is empty") return nil, fmt.Errorf("redis: reply is empty")
} }
if isNilReply(line) { if isNilReply(line) {
return nil, internal.Nil return nil, internal.Nil

2
vendor/github.com/go-redis/redis/internal/proto/scan.go сгенерированный поставляемый
Просмотреть файл

@@ -11,7 +11,7 @@ import (
func Scan(b []byte, v interface{}) error { func Scan(b []byte, v interface{}) error {
switch v := v.(type) { switch v := v.(type) {
case nil: case nil:
return internal.RedisError("redis: Scan(nil)") return fmt.Errorf("redis: Scan(nil)")
case *string: case *string:
*v = internal.BytesToString(b) *v = internal.BytesToString(b)
return nil return nil

4
vendor/github.com/go-redis/redis/main_test.go сгенерированный поставляемый
Просмотреть файл

@@ -50,10 +50,6 @@ var cluster = &clusterScenario{
clients: make(map[string]*redis.Client, 6), clients: make(map[string]*redis.Client, 6),
} }
func init() {
//redis.SetLogger(log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile))
}
var _ = BeforeSuite(func() { var _ = BeforeSuite(func() {
var err error var err error

10
vendor/github.com/go-redis/redis/options.go сгенерированный поставляемый
Просмотреть файл

@@ -198,13 +198,3 @@ func newConnPool(opt *Options) *pool.ConnPool {
IdleCheckFrequency: opt.IdleCheckFrequency, IdleCheckFrequency: opt.IdleCheckFrequency,
}) })
} }
// PoolStats contains pool state information and accumulated stats.
type PoolStats struct {
Requests uint32 // number of times a connection was requested by the pool
Hits uint32 // number of times free connection was found in the pool
Timeouts uint32 // number of times a wait timeout occurred
TotalConns uint32 // the number of total connections in the pool
FreeConns uint32 // the number of free connections in the pool
}

10
vendor/github.com/go-redis/redis/pipeline.go сгенерированный поставляемый
Просмотреть файл

@@ -13,9 +13,7 @@ type Pipeliner interface {
Process(cmd Cmder) error Process(cmd Cmder) error
Close() error Close() error
Discard() error Discard() error
discard() error
Exec() ([]Cmder, error) Exec() ([]Cmder, error)
pipelined(fn func(Pipeliner) error) ([]Cmder, error)
} }
var _ Pipeliner = (*Pipeline)(nil) var _ Pipeliner = (*Pipeline)(nil)
@@ -104,3 +102,11 @@ func (c *Pipeline) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
func (c *Pipeline) Pipeline() Pipeliner { func (c *Pipeline) Pipeline() Pipeliner {
return c return c
} }
func (c *Pipeline) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.pipelined(fn)
}
func (c *Pipeline) TxPipeline() Pipeliner {
return c
}

10
vendor/github.com/go-redis/redis/pool_test.go сгенерированный поставляемый
Просмотреть файл

@@ -95,8 +95,8 @@ var _ = Describe("pool", func() {
Expect(pool.FreeLen()).To(Equal(1)) Expect(pool.FreeLen()).To(Equal(1))
stats := pool.Stats() stats := pool.Stats()
Expect(stats.Requests).To(Equal(uint32(4)))
Expect(stats.Hits).To(Equal(uint32(2))) Expect(stats.Hits).To(Equal(uint32(2)))
Expect(stats.Misses).To(Equal(uint32(2)))
Expect(stats.Timeouts).To(Equal(uint32(0))) Expect(stats.Timeouts).To(Equal(uint32(0)))
}) })
@@ -112,30 +112,32 @@ var _ = Describe("pool", func() {
Expect(pool.FreeLen()).To(Equal(1)) Expect(pool.FreeLen()).To(Equal(1))
stats := pool.Stats() stats := pool.Stats()
Expect(stats.Requests).To(Equal(uint32(101)))
Expect(stats.Hits).To(Equal(uint32(100))) Expect(stats.Hits).To(Equal(uint32(100)))
Expect(stats.Misses).To(Equal(uint32(1)))
Expect(stats.Timeouts).To(Equal(uint32(0))) Expect(stats.Timeouts).To(Equal(uint32(0)))
}) })
It("removes idle connections", func() { It("removes idle connections", func() {
stats := client.PoolStats() stats := client.PoolStats()
Expect(stats).To(Equal(&redis.PoolStats{ Expect(stats).To(Equal(&redis.PoolStats{
Requests: 1,
Hits: 0, Hits: 0,
Misses: 1,
Timeouts: 0, Timeouts: 0,
TotalConns: 1, TotalConns: 1,
FreeConns: 1, FreeConns: 1,
StaleConns: 0,
})) }))
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
stats = client.PoolStats() stats = client.PoolStats()
Expect(stats).To(Equal(&redis.PoolStats{ Expect(stats).To(Equal(&redis.PoolStats{
Requests: 1,
Hits: 0, Hits: 0,
Misses: 1,
Timeouts: 0, Timeouts: 0,
TotalConns: 0, TotalConns: 0,
FreeConns: 0, FreeConns: 0,
StaleConns: 1,
})) }))
}) })
}) })

5
vendor/github.com/go-redis/redis/pubsub.go сгенерированный поставляемый
Просмотреть файл

@@ -95,7 +95,10 @@ func (c *PubSub) releaseConn(cn *pool.Conn, err error) {
} }
func (c *PubSub) _releaseConn(cn *pool.Conn, err error) { func (c *PubSub) _releaseConn(cn *pool.Conn, err error) {
if internal.IsBadConn(err, true) && c.cn == cn { if c.cn != cn {
return
}
if internal.IsBadConn(err, true) {
_ = c.closeTheCn() _ = c.closeTheCn()
} }
} }

6
vendor/github.com/go-redis/redis/pubsub_test.go сгенерированный поставляемый
Просмотреть файл

@@ -68,7 +68,7 @@ var _ = Describe("PubSub", func() {
} }
stats := client.PoolStats() stats := client.PoolStats()
Expect(stats.Requests - stats.Hits).To(Equal(uint32(2))) Expect(stats.Misses).To(Equal(uint32(2)))
}) })
It("should pub/sub channels", func() { It("should pub/sub channels", func() {
@@ -191,7 +191,7 @@ var _ = Describe("PubSub", func() {
} }
stats := client.PoolStats() stats := client.PoolStats()
Expect(stats.Requests - stats.Hits).To(Equal(uint32(2))) Expect(stats.Misses).To(Equal(uint32(2)))
}) })
It("should ping/pong", func() { It("should ping/pong", func() {
@@ -290,8 +290,8 @@ var _ = Describe("PubSub", func() {
Eventually(done).Should(Receive()) Eventually(done).Should(Receive())
stats := client.PoolStats() stats := client.PoolStats()
Expect(stats.Requests).To(Equal(uint32(2)))
Expect(stats.Hits).To(Equal(uint32(1))) Expect(stats.Hits).To(Equal(uint32(1)))
Expect(stats.Misses).To(Equal(uint32(1)))
}) })
It("returns an error when subscribe fails", func() { It("returns an error when subscribe fails", func() {

92
vendor/github.com/go-redis/redis/redis.go сгенерированный поставляемый
Просмотреть файл

@@ -3,6 +3,7 @@ package redis
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"time" "time"
"github.com/go-redis/redis/internal" "github.com/go-redis/redis/internal"
@@ -13,6 +14,10 @@ import (
// Redis nil reply, .e.g. when key does not exist. // Redis nil reply, .e.g. when key does not exist.
const Nil = internal.Nil const Nil = internal.Nil
func init() {
SetLogger(log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile))
}
func SetLogger(logger *log.Logger) { func SetLogger(logger *log.Logger) {
internal.Logger = logger internal.Logger = logger
} }
@@ -131,7 +136,7 @@ func (c *baseClient) defaultProcess(cmd Cmder) error {
cn, _, err := c.getConn() cn, _, err := c.getConn()
if err != nil { if err != nil {
cmd.setErr(err) cmd.setErr(err)
if internal.IsRetryableError(err) { if internal.IsRetryableError(err, true) {
continue continue
} }
return err return err
@@ -141,7 +146,7 @@ func (c *baseClient) defaultProcess(cmd Cmder) error {
if err := writeCmd(cn, cmd); err != nil { if err := writeCmd(cn, cmd); err != nil {
c.releaseConn(cn, err) c.releaseConn(cn, err)
cmd.setErr(err) cmd.setErr(err)
if internal.IsRetryableError(err) { if internal.IsRetryableError(err, true) {
continue continue
} }
return err return err
@@ -150,7 +155,7 @@ func (c *baseClient) defaultProcess(cmd Cmder) error {
cn.SetReadTimeout(c.cmdTimeout(cmd)) cn.SetReadTimeout(c.cmdTimeout(cmd))
err = cmd.readReply(cn) err = cmd.readReply(cn)
c.releaseConn(cn, err) c.releaseConn(cn, err)
if err != nil && internal.IsRetryableError(err) { if err != nil && internal.IsRetryableError(err, cmd.readTimeout() == nil) {
continue continue
} }
@@ -197,8 +202,11 @@ type pipelineProcessor func(*pool.Conn, []Cmder) (bool, error)
func (c *baseClient) pipelineExecer(p pipelineProcessor) pipelineExecer { func (c *baseClient) pipelineExecer(p pipelineProcessor) pipelineExecer {
return func(cmds []Cmder) error { return func(cmds []Cmder) error {
var firstErr error for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
for i := 0; i <= c.opt.MaxRetries; i++ { if attempt > 0 {
time.Sleep(c.retryBackoff(attempt))
}
cn, _, err := c.getConn() cn, _, err := c.getConn()
if err != nil { if err != nil {
setCmdsErr(cmds, err) setCmdsErr(cmds, err)
@@ -206,18 +214,18 @@ func (c *baseClient) pipelineExecer(p pipelineProcessor) pipelineExecer {
} }
canRetry, err := p(cn, cmds) canRetry, err := p(cn, cmds)
c.releaseConn(cn, err)
if err == nil { if err == nil || internal.IsRedisError(err) {
return nil _ = c.connPool.Put(cn)
break
} }
if firstErr == nil { _ = c.connPool.Remove(cn)
firstErr = err
} if !canRetry || !internal.IsRetryableError(err, true) {
if !canRetry || !internal.IsRetryableError(err) {
break break
} }
} }
return firstErr return firstCmdsErr(cmds)
} }
} }
@@ -230,23 +238,17 @@ func (c *baseClient) pipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, err
// Set read timeout for all commands. // Set read timeout for all commands.
cn.SetReadTimeout(c.opt.ReadTimeout) cn.SetReadTimeout(c.opt.ReadTimeout)
return pipelineReadCmds(cn, cmds) return true, pipelineReadCmds(cn, cmds)
} }
func pipelineReadCmds(cn *pool.Conn, cmds []Cmder) (retry bool, firstErr error) { func pipelineReadCmds(cn *pool.Conn, cmds []Cmder) error {
for i, cmd := range cmds { for _, cmd := range cmds {
err := cmd.readReply(cn) err := cmd.readReply(cn)
if err == nil { if err != nil && !internal.IsRedisError(err) {
continue return err
}
if i == 0 {
retry = true
}
if firstErr == nil {
firstErr = err
} }
} }
return return nil
} }
func (c *baseClient) txPipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) { func (c *baseClient) txPipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
@@ -260,11 +262,11 @@ func (c *baseClient) txPipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, e
cn.SetReadTimeout(c.opt.ReadTimeout) cn.SetReadTimeout(c.opt.ReadTimeout)
if err := c.txPipelineReadQueued(cn, cmds); err != nil { if err := c.txPipelineReadQueued(cn, cmds); err != nil {
setCmdsErr(cmds, err)
return false, err return false, err
} }
_, err := pipelineReadCmds(cn, cmds) return false, pipelineReadCmds(cn, cmds)
return false, err
} }
func txPipelineWriteMulti(cn *pool.Conn, cmds []Cmder) error { func txPipelineWriteMulti(cn *pool.Conn, cmds []Cmder) error {
@@ -276,21 +278,16 @@ func txPipelineWriteMulti(cn *pool.Conn, cmds []Cmder) error {
} }
func (c *baseClient) txPipelineReadQueued(cn *pool.Conn, cmds []Cmder) error { func (c *baseClient) txPipelineReadQueued(cn *pool.Conn, cmds []Cmder) error {
var firstErr error
// Parse queued replies. // Parse queued replies.
var statusCmd StatusCmd var statusCmd StatusCmd
if err := statusCmd.readReply(cn); err != nil && firstErr == nil { if err := statusCmd.readReply(cn); err != nil {
firstErr = err return err
} }
for _, cmd := range cmds { for _ = range cmds {
err := statusCmd.readReply(cn) err := statusCmd.readReply(cn)
if err != nil { if err != nil && !internal.IsRedisError(err) {
cmd.setErr(err) return err
if firstErr == nil {
firstErr = err
}
} }
} }
@@ -355,21 +352,16 @@ func (c *Client) Options() *Options {
return c.opt return c.opt
} }
type PoolStats pool.Stats
// PoolStats returns connection pool stats. // PoolStats returns connection pool stats.
func (c *Client) PoolStats() *PoolStats { func (c *Client) PoolStats() *PoolStats {
s := c.connPool.Stats() stats := c.connPool.Stats()
return &PoolStats{ return (*PoolStats)(stats)
Requests: s.Requests,
Hits: s.Hits,
Timeouts: s.Timeouts,
TotalConns: s.TotalConns,
FreeConns: s.FreeConns,
}
} }
func (c *Client) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Client) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipeline().pipelined(fn) return c.Pipeline().Pipelined(fn)
} }
func (c *Client) Pipeline() Pipeliner { func (c *Client) Pipeline() Pipeliner {
@@ -381,7 +373,7 @@ func (c *Client) Pipeline() Pipeliner {
} }
func (c *Client) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Client) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.TxPipeline().pipelined(fn) return c.TxPipeline().Pipelined(fn)
} }
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
@@ -433,7 +425,7 @@ type Conn struct {
} }
func (c *Conn) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Conn) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipeline().pipelined(fn) return c.Pipeline().Pipelined(fn)
} }
func (c *Conn) Pipeline() Pipeliner { func (c *Conn) Pipeline() Pipeliner {
@@ -445,7 +437,7 @@ func (c *Conn) Pipeline() Pipeliner {
} }
func (c *Conn) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Conn) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.TxPipeline().pipelined(fn) return c.TxPipeline().Pipelined(fn)
} }
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.

121
vendor/github.com/go-redis/redis/ring.go сгенерированный поставляемый
Просмотреть файл

@@ -34,7 +34,9 @@ type RingOptions struct {
DB int DB int
Password string Password string
MaxRetries int MaxRetries int
MinRetryBackoff time.Duration
MaxRetryBackoff time.Duration
DialTimeout time.Duration DialTimeout time.Duration
ReadTimeout time.Duration ReadTimeout time.Duration
@@ -50,6 +52,19 @@ func (opt *RingOptions) init() {
if opt.HeartbeatFrequency == 0 { if opt.HeartbeatFrequency == 0 {
opt.HeartbeatFrequency = 500 * time.Millisecond opt.HeartbeatFrequency = 500 * time.Millisecond
} }
switch opt.MinRetryBackoff {
case -1:
opt.MinRetryBackoff = 0
case 0:
opt.MinRetryBackoff = 8 * time.Millisecond
}
switch opt.MaxRetryBackoff {
case -1:
opt.MaxRetryBackoff = 0
case 0:
opt.MaxRetryBackoff = 512 * time.Millisecond
}
} }
func (opt *RingOptions) clientOptions() *Options { func (opt *RingOptions) clientOptions() *Options {
@@ -130,9 +145,10 @@ type Ring struct {
opt *RingOptions opt *RingOptions
nreplicas int nreplicas int
mu sync.RWMutex mu sync.RWMutex
hash *consistenthash.Map hash *consistenthash.Map
shards map[string]*ringShard shards map[string]*ringShard
shardsList []*ringShard
cmdsInfoOnce internal.Once cmdsInfoOnce internal.Once
cmdsInfo map[string]*CommandInfo cmdsInfo map[string]*CommandInfo
@@ -154,24 +170,41 @@ func NewRing(opt *RingOptions) *Ring {
for name, addr := range opt.Addrs { for name, addr := range opt.Addrs {
clopt := opt.clientOptions() clopt := opt.clientOptions()
clopt.Addr = addr clopt.Addr = addr
ring.addClient(name, NewClient(clopt)) ring.addShard(name, NewClient(clopt))
} }
go ring.heartbeat() go ring.heartbeat()
return ring return ring
} }
func (c *Ring) addShard(name string, cl *Client) {
shard := &ringShard{Client: cl}
c.mu.Lock()
c.hash.Add(name)
c.shards[name] = shard
c.shardsList = append(c.shardsList, shard)
c.mu.Unlock()
}
// Options returns read-only Options that were used to create the client. // Options returns read-only Options that were used to create the client.
func (c *Ring) Options() *RingOptions { func (c *Ring) Options() *RingOptions {
return c.opt return c.opt
} }
func (c *Ring) retryBackoff(attempt int) time.Duration {
return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
}
// PoolStats returns accumulated connection pool stats. // PoolStats returns accumulated connection pool stats.
func (c *Ring) PoolStats() *PoolStats { func (c *Ring) PoolStats() *PoolStats {
c.mu.RLock()
shards := c.shardsList
c.mu.RUnlock()
var acc PoolStats var acc PoolStats
for _, shard := range c.shards { for _, shard := range shards {
s := shard.Client.connPool.Stats() s := shard.Client.connPool.Stats()
acc.Requests += s.Requests
acc.Hits += s.Hits acc.Hits += s.Hits
acc.Misses += s.Misses
acc.Timeouts += s.Timeouts acc.Timeouts += s.Timeouts
acc.TotalConns += s.TotalConns acc.TotalConns += s.TotalConns
acc.FreeConns += s.FreeConns acc.FreeConns += s.FreeConns
@@ -210,9 +243,13 @@ func (c *Ring) PSubscribe(channels ...string) *PubSub {
// ForEachShard concurrently calls the fn on each live shard in the ring. // ForEachShard concurrently calls the fn on each live shard in the ring.
// It returns the first error if any. // It returns the first error if any.
func (c *Ring) ForEachShard(fn func(client *Client) error) error { func (c *Ring) ForEachShard(fn func(client *Client) error) error {
c.mu.RLock()
shards := c.shardsList
c.mu.RUnlock()
var wg sync.WaitGroup var wg sync.WaitGroup
errCh := make(chan error, 1) errCh := make(chan error, 1)
for _, shard := range c.shards { for _, shard := range shards {
if shard.IsDown() { if shard.IsDown() {
continue continue
} }
@@ -241,8 +278,12 @@ func (c *Ring) ForEachShard(fn func(client *Client) error) error {
func (c *Ring) cmdInfo(name string) *CommandInfo { func (c *Ring) cmdInfo(name string) *CommandInfo {
err := c.cmdsInfoOnce.Do(func() error { err := c.cmdsInfoOnce.Do(func() error {
c.mu.RLock()
shards := c.shardsList
c.mu.RUnlock()
var firstErr error var firstErr error
for _, shard := range c.shards { for _, shard := range shards {
cmdsInfo, err := shard.Client.Command().Result() cmdsInfo, err := shard.Client.Command().Result()
if err == nil { if err == nil {
c.cmdsInfo = cmdsInfo c.cmdsInfo = cmdsInfo
@@ -257,14 +298,11 @@ func (c *Ring) cmdInfo(name string) *CommandInfo {
if err != nil { if err != nil {
return nil return nil
} }
return c.cmdsInfo[name] info := c.cmdsInfo[name]
} if info == nil {
internal.Logf("info for cmd=%s not found", name)
func (c *Ring) addClient(name string, cl *Client) { }
c.mu.Lock() return info
c.hash.Add(name)
c.shards[name] = &ringShard{Client: cl}
c.mu.Unlock()
} }
func (c *Ring) shardByKey(key string) (*ringShard, error) { func (c *Ring) shardByKey(key string) (*ringShard, error) {
@@ -305,7 +343,7 @@ func (c *Ring) shardByName(name string) (*ringShard, error) {
func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) {
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
firstKey := cmd.arg(cmdFirstKeyPos(cmd, cmdInfo)) firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
return c.shardByKey(firstKey) return c.shardByKey(firstKey)
} }
@@ -346,7 +384,10 @@ func (c *Ring) heartbeat() {
break break
} }
for _, shard := range c.shards { shards := c.shardsList
c.mu.RUnlock()
for _, shard := range shards {
err := shard.Client.Ping().Err() err := shard.Client.Ping().Err()
if shard.Vote(err == nil || err == pool.ErrPoolTimeout) { if shard.Vote(err == nil || err == pool.ErrPoolTimeout) {
internal.Logf("ring shard state changed: %s", shard) internal.Logf("ring shard state changed: %s", shard)
@@ -354,8 +395,6 @@ func (c *Ring) heartbeat() {
} }
} }
c.mu.RUnlock()
if rebalance { if rebalance {
c.rebalance() c.rebalance()
} }
@@ -383,6 +422,7 @@ func (c *Ring) Close() error {
} }
c.hash = nil c.hash = nil
c.shards = nil c.shards = nil
c.shardsList = nil
return firstErr return firstErr
} }
@@ -396,51 +436,48 @@ func (c *Ring) Pipeline() Pipeliner {
} }
func (c *Ring) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Ring) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipeline().pipelined(fn) return c.Pipeline().Pipelined(fn)
} }
func (c *Ring) pipelineExec(cmds []Cmder) (firstErr error) { func (c *Ring) pipelineExec(cmds []Cmder) error {
cmdsMap := make(map[string][]Cmder) cmdsMap := make(map[string][]Cmder)
for _, cmd := range cmds { for _, cmd := range cmds {
cmdInfo := c.cmdInfo(cmd.Name()) cmdInfo := c.cmdInfo(cmd.Name())
name := cmd.arg(cmdFirstKeyPos(cmd, cmdInfo)) name := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
if name != "" { if name != "" {
name = c.hash.Get(hashtag.Key(name)) name = c.hash.Get(hashtag.Key(name))
} }
cmdsMap[name] = append(cmdsMap[name], cmd) cmdsMap[name] = append(cmdsMap[name], cmd)
} }
for i := 0; i <= c.opt.MaxRetries; i++ { for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
if attempt > 0 {
time.Sleep(c.retryBackoff(attempt))
}
var failedCmdsMap map[string][]Cmder var failedCmdsMap map[string][]Cmder
for name, cmds := range cmdsMap { for name, cmds := range cmdsMap {
shard, err := c.shardByName(name) shard, err := c.shardByName(name)
if err != nil { if err != nil {
setCmdsErr(cmds, err) setCmdsErr(cmds, err)
if firstErr == nil {
firstErr = err
}
continue continue
} }
cn, _, err := shard.Client.getConn() cn, _, err := shard.Client.getConn()
if err != nil { if err != nil {
setCmdsErr(cmds, err) setCmdsErr(cmds, err)
if firstErr == nil {
firstErr = err
}
continue continue
} }
canRetry, err := shard.Client.pipelineProcessCmds(cn, cmds) canRetry, err := shard.Client.pipelineProcessCmds(cn, cmds)
shard.Client.releaseConn(cn, err) if err == nil || internal.IsRedisError(err) {
if err == nil { _ = shard.Client.connPool.Put(cn)
continue continue
} }
if firstErr == nil { _ = shard.Client.connPool.Remove(cn)
firstErr = err
} if canRetry && internal.IsRetryableError(err, true) {
if canRetry && internal.IsRetryableError(err) {
if failedCmdsMap == nil { if failedCmdsMap == nil {
failedCmdsMap = make(map[string][]Cmder) failedCmdsMap = make(map[string][]Cmder)
} }
@@ -454,5 +491,13 @@ func (c *Ring) pipelineExec(cmds []Cmder) (firstErr error) {
cmdsMap = failedCmdsMap cmdsMap = failedCmdsMap
} }
return firstErr return firstCmdsErr(cmds)
}
func (c *Ring) TxPipeline() Pipeliner {
panic("not implemented")
}
func (c *Ring) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
panic("not implemented")
} }

6
vendor/github.com/go-redis/redis/sentinel.go сгенерированный поставляемый
Просмотреть файл

@@ -301,8 +301,10 @@ func (d *sentinelFailover) listen(sentinel *sentinelClient) {
msg, err := pubsub.ReceiveMessage() msg, err := pubsub.ReceiveMessage()
if err != nil { if err != nil {
internal.Logf("sentinel: ReceiveMessage failed: %s", err) if err != pool.ErrClosed {
pubsub.Close() internal.Logf("sentinel: ReceiveMessage failed: %s", err)
pubsub.Close()
}
d.resetSentinel() d.resetSentinel()
return return
} }

23
vendor/github.com/go-redis/redis/tx.go сгенерированный поставляемый
Просмотреть файл

@@ -36,11 +36,10 @@ func (c *Client) Watch(fn func(*Tx) error, keys ...string) error {
return err return err
} }
} }
firstErr := fn(tx)
if err := tx.Close(); err != nil && firstErr == nil { err := fn(tx)
firstErr = err _ = tx.Close()
} return err
return firstErr
} }
// close closes the transaction, releasing any open resources. // close closes the transaction, releasing any open resources.
@@ -53,7 +52,7 @@ func (c *Tx) Close() error {
// of a transaction. // of a transaction.
func (c *Tx) Watch(keys ...string) *StatusCmd { func (c *Tx) Watch(keys ...string) *StatusCmd {
args := make([]interface{}, 1+len(keys)) args := make([]interface{}, 1+len(keys))
args[0] = "WATCH" args[0] = "watch"
for i, key := range keys { for i, key := range keys {
args[1+i] = key args[1+i] = key
} }
@@ -65,7 +64,7 @@ func (c *Tx) Watch(keys ...string) *StatusCmd {
// Unwatch flushes all the previously watched keys for a transaction. // Unwatch flushes all the previously watched keys for a transaction.
func (c *Tx) Unwatch(keys ...string) *StatusCmd { func (c *Tx) Unwatch(keys ...string) *StatusCmd {
args := make([]interface{}, 1+len(keys)) args := make([]interface{}, 1+len(keys))
args[0] = "UNWATCH" args[0] = "unwatch"
for i, key := range keys { for i, key := range keys {
args[1+i] = key args[1+i] = key
} }
@@ -92,5 +91,13 @@ func (c *Tx) Pipeline() Pipeliner {
// TxFailedErr is returned. Otherwise Exec returns error of the first // TxFailedErr is returned. Otherwise Exec returns error of the first
// failed command or nil. // failed command or nil.
func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipeline().pipelined(fn) return c.Pipeline().Pipelined(fn)
}
func (c *Tx) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
return c.Pipelined(fn)
}
func (c *Tx) TxPipeline() Pipeliner {
return c.Pipeline()
} }

7
vendor/github.com/go-redis/redis/universal.go сгенерированный поставляемый
Просмотреть файл

@@ -90,8 +90,8 @@ func (o *UniversalOptions) simple() *Options {
} }
return &Options{ return &Options{
Addr: addr, Addr: addr,
DB: o.DB, DB: o.DB,
MaxRetries: o.MaxRetries, MaxRetries: o.MaxRetries,
Password: o.Password, Password: o.Password,
@@ -117,6 +117,9 @@ type UniversalClient interface {
Close() error Close() error
} }
var _ UniversalClient = (*Client)(nil)
var _ UniversalClient = (*ClusterClient)(nil)
// NewUniversalClient returns a new multi client. The type of client returned depends // NewUniversalClient returns a new multi client. The type of client returned depends
// on the following three conditions: // on the following three conditions:
// //

1
vendor/github.com/golang/protobuf/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -4,6 +4,7 @@ go:
- 1.6.x - 1.6.x
- 1.7.x - 1.7.x
- 1.8.x - 1.8.x
- 1.9.x
install: install:
- go get -v -d -t github.com/golang/protobuf/... - go get -v -d -t github.com/golang/protobuf/...

1
vendor/github.com/golang/protobuf/README.md сгенерированный поставляемый
Просмотреть файл

@@ -111,6 +111,7 @@ When the .proto file specifies `syntax="proto3"`, there are some differences:
Consider file test.proto, containing Consider file test.proto, containing
```proto ```proto
syntax = "proto2";
package example; package example;
enum FOO { X = 17; }; enum FOO { X = 17; };

66
vendor/github.com/golang/protobuf/jsonpb/jsonpb.go сгенерированный поставляемый
Просмотреть файл

@@ -73,6 +73,31 @@ type Marshaler struct {
// Whether to use the original (.proto) name for fields. // Whether to use the original (.proto) name for fields.
OrigName bool OrigName bool
// A custom URL resolver to use when marshaling Any messages to JSON.
// If unset, the default resolution strategy is to extract the
// fully-qualified type name from the type URL and pass that to
// proto.MessageType(string).
AnyResolver AnyResolver
}
// AnyResolver takes a type URL, present in an Any message, and resolves it into
// an instance of the associated message.
type AnyResolver interface {
Resolve(typeUrl string) (proto.Message, error)
}
func defaultResolveAny(typeUrl string) (proto.Message, error) {
// Only the part of typeUrl after the last slash is relevant.
mname := typeUrl
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
}
mt := proto.MessageType(mname)
if mt == nil {
return nil, fmt.Errorf("unknown message type %q", mname)
}
return reflect.New(mt.Elem()).Interface().(proto.Message), nil
} }
// JSONPBMarshaler is implemented by protobuf messages that customize the // JSONPBMarshaler is implemented by protobuf messages that customize the
@@ -344,16 +369,17 @@ func (m *Marshaler) marshalAny(out *errWriter, any proto.Message, indent string)
turl := v.Field(0).String() turl := v.Field(0).String()
val := v.Field(1).Bytes() val := v.Field(1).Bytes()
// Only the part of type_url after the last slash is relevant. var msg proto.Message
mname := turl var err error
if slash := strings.LastIndex(mname, "/"); slash >= 0 { if m.AnyResolver != nil {
mname = mname[slash+1:] msg, err = m.AnyResolver.Resolve(turl)
} else {
msg, err = defaultResolveAny(turl)
} }
mt := proto.MessageType(mname) if err != nil {
if mt == nil { return err
return fmt.Errorf("unknown message type %q", mname)
} }
msg := reflect.New(mt.Elem()).Interface().(proto.Message)
if err := proto.Unmarshal(val, msg); err != nil { if err := proto.Unmarshal(val, msg); err != nil {
return err return err
} }
@@ -590,6 +616,12 @@ type Unmarshaler struct {
// Whether to allow messages to contain unknown fields, as opposed to // Whether to allow messages to contain unknown fields, as opposed to
// failing to unmarshal. // failing to unmarshal.
AllowUnknownFields bool AllowUnknownFields bool
// A custom URL resolver to use when unmarshaling Any messages from JSON.
// If unset, the default resolution strategy is to extract the
// fully-qualified type name from the type URL and pass that to
// proto.MessageType(string).
AnyResolver AnyResolver
} }
// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream. // UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
@@ -641,7 +673,8 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
if targetType.Kind() == reflect.Ptr { if targetType.Kind() == reflect.Ptr {
// If input value is "null" and target is a pointer type, then the field should be treated as not set // If input value is "null" and target is a pointer type, then the field should be treated as not set
// UNLESS the target is structpb.Value, in which case it should be set to structpb.NullValue. // UNLESS the target is structpb.Value, in which case it should be set to structpb.NullValue.
if string(inputValue) == "null" && targetType != reflect.TypeOf(&stpb.Value{}) { _, isJSONPBUnmarshaler := target.Interface().(JSONPBUnmarshaler)
if string(inputValue) == "null" && targetType != reflect.TypeOf(&stpb.Value{}) && !isJSONPBUnmarshaler {
return nil return nil
} }
target.Set(reflect.New(targetType.Elem())) target.Set(reflect.New(targetType.Elem()))
@@ -679,16 +712,17 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
} }
target.Field(0).SetString(turl) target.Field(0).SetString(turl)
mname := turl var m proto.Message
if slash := strings.LastIndex(mname, "/"); slash >= 0 { var err error
mname = mname[slash+1:] if u.AnyResolver != nil {
m, err = u.AnyResolver.Resolve(turl)
} else {
m, err = defaultResolveAny(turl)
} }
mt := proto.MessageType(mname) if err != nil {
if mt == nil { return err
return fmt.Errorf("unknown message type %q", mname)
} }
m := reflect.New(mt.Elem()).Interface().(proto.Message)
if _, ok := m.(wkt); ok { if _, ok := m.(wkt); ok {
val, ok := jsonFields["value"] val, ok := jsonFields["value"]
if !ok { if !ok {

107
vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go сгенерированный поставляемый
Просмотреть файл

@@ -721,6 +721,65 @@ func TestUnmarshalingBadInput(t *testing.T) {
} }
} }
type funcResolver func(turl string) (proto.Message, error)
func (fn funcResolver) Resolve(turl string) (proto.Message, error) {
return fn(turl)
}
func TestAnyWithCustomResolver(t *testing.T) {
var resolvedTypeUrls []string
resolver := funcResolver(func(turl string) (proto.Message, error) {
resolvedTypeUrls = append(resolvedTypeUrls, turl)
return new(pb.Simple), nil
})
msg := &pb.Simple{
OBytes: []byte{1, 2, 3, 4},
OBool: proto.Bool(true),
OString: proto.String("foobar"),
OInt64: proto.Int64(1020304),
}
msgBytes, err := proto.Marshal(msg)
if err != nil {
t.Errorf("an unexpected error occurred when marshaling message: %v", err)
}
// make an Any with a type URL that won't resolve w/out custom resolver
any := &anypb.Any{
TypeUrl: "https://foobar.com/some.random.MessageKind",
Value: msgBytes,
}
m := Marshaler{AnyResolver: resolver}
js, err := m.MarshalToString(any)
if err != nil {
t.Errorf("an unexpected error occurred when marshaling any to JSON: %v", err)
}
if len(resolvedTypeUrls) != 1 {
t.Errorf("custom resolver was not invoked during marshaling")
} else if resolvedTypeUrls[0] != "https://foobar.com/some.random.MessageKind" {
t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[0], "https://foobar.com/some.random.MessageKind")
}
wanted := `{"@type":"https://foobar.com/some.random.MessageKind","oBool":true,"oInt64":"1020304","oString":"foobar","oBytes":"AQIDBA=="}`
if js != wanted {
t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", js, wanted)
}
u := Unmarshaler{AnyResolver: resolver}
roundTrip := &anypb.Any{}
err = u.Unmarshal(bytes.NewReader([]byte(js)), roundTrip)
if err != nil {
t.Errorf("an unexpected error occurred when unmarshaling any from JSON: %v", err)
}
if len(resolvedTypeUrls) != 2 {
t.Errorf("custom resolver was not invoked during marshaling")
} else if resolvedTypeUrls[1] != "https://foobar.com/some.random.MessageKind" {
t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[1], "https://foobar.com/some.random.MessageKind")
}
if !proto.Equal(any, roundTrip) {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", roundTrip, any)
}
}
func TestUnmarshalJSONPBUnmarshaler(t *testing.T) { func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }` rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
var msg dynamicMessage var msg dynamicMessage
@@ -732,6 +791,19 @@ func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
} }
} }
func TestUnmarshalNullWithJSONPBUnmarshaler(t *testing.T) {
rawJson := `{"stringField":null}`
var ptrFieldMsg ptrFieldMessage
if err := Unmarshal(strings.NewReader(rawJson), &ptrFieldMsg); err != nil {
t.Errorf("unmarshal error: %v", err)
}
want := ptrFieldMessage{StringField: &stringField{IsSet: true, StringValue: "null"}}
if !proto.Equal(&ptrFieldMsg, &want) {
t.Errorf("unmarshal result StringField: got %v, want %v", ptrFieldMsg, want)
}
}
func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) { func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) {
rawJson := `{ "@type": "blah.com/` + dynamicMessageName + `", "foo": "bar", "baz": [0, 1, 2, 3] }` rawJson := `{ "@type": "blah.com/` + dynamicMessageName + `", "foo": "bar", "baz": [0, 1, 2, 3] }`
var got anypb.Any var got anypb.Any
@@ -762,6 +834,41 @@ func init() {
proto.RegisterType((*dynamicMessage)(nil), dynamicMessageName) proto.RegisterType((*dynamicMessage)(nil), dynamicMessageName)
} }
type ptrFieldMessage struct {
StringField *stringField `protobuf:"bytes,1,opt,name=stringField"`
}
func (m *ptrFieldMessage) Reset() {
}
func (m *ptrFieldMessage) String() string {
return m.StringField.StringValue
}
func (m *ptrFieldMessage) ProtoMessage() {
}
type stringField struct {
IsSet bool `protobuf:"varint,1,opt,name=isSet"`
StringValue string `protobuf:"bytes,2,opt,name=stringValue"`
}
func (s *stringField) Reset() {
}
func (s *stringField) String() string {
return s.StringValue
}
func (s *stringField) ProtoMessage() {
}
func (s *stringField) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
s.IsSet = true
s.StringValue = string(js)
return nil
}
// dynamicMessage implements protobuf.Message but is not a normal generated message type. // dynamicMessage implements protobuf.Message but is not a normal generated message type.
// It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support. // It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support.
type dynamicMessage struct { type dynamicMessage struct {

425
vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go сгенерированный поставляемый
Просмотреть файл

@@ -11,6 +11,7 @@ It has these top-level messages:
FileDescriptorSet FileDescriptorSet
FileDescriptorProto FileDescriptorProto
DescriptorProto DescriptorProto
ExtensionRangeOptions
FieldDescriptorProto FieldDescriptorProto
OneofDescriptorProto OneofDescriptorProto
EnumDescriptorProto EnumDescriptorProto
@@ -137,7 +138,7 @@ func (x *FieldDescriptorProto_Type) UnmarshalJSON(data []byte) error {
*x = FieldDescriptorProto_Type(value) *x = FieldDescriptorProto_Type(value)
return nil return nil
} }
func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} } func (FieldDescriptorProto_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4, 0} }
type FieldDescriptorProto_Label int32 type FieldDescriptorProto_Label int32
@@ -176,7 +177,7 @@ func (x *FieldDescriptorProto_Label) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) { func (FieldDescriptorProto_Label) EnumDescriptor() ([]byte, []int) {
return fileDescriptor0, []int{3, 1} return fileDescriptor0, []int{4, 1}
} }
// Generated classes can be optimized for speed or code size. // Generated classes can be optimized for speed or code size.
@@ -216,7 +217,7 @@ func (x *FileOptions_OptimizeMode) UnmarshalJSON(data []byte) error {
*x = FileOptions_OptimizeMode(value) *x = FileOptions_OptimizeMode(value)
return nil return nil
} }
func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{9, 0} } func (FileOptions_OptimizeMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{10, 0} }
type FieldOptions_CType int32 type FieldOptions_CType int32
@@ -254,7 +255,7 @@ func (x *FieldOptions_CType) UnmarshalJSON(data []byte) error {
*x = FieldOptions_CType(value) *x = FieldOptions_CType(value)
return nil return nil
} }
func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 0} } func (FieldOptions_CType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{12, 0} }
type FieldOptions_JSType int32 type FieldOptions_JSType int32
@@ -294,7 +295,7 @@ func (x *FieldOptions_JSType) UnmarshalJSON(data []byte) error {
*x = FieldOptions_JSType(value) *x = FieldOptions_JSType(value)
return nil return nil
} }
func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{11, 1} } func (FieldOptions_JSType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{12, 1} }
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent, // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
// or neither? HTTP based RPC implementation may choose GET verb for safe // or neither? HTTP based RPC implementation may choose GET verb for safe
@@ -335,7 +336,7 @@ func (x *MethodOptions_IdempotencyLevel) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) { func (MethodOptions_IdempotencyLevel) EnumDescriptor() ([]byte, []int) {
return fileDescriptor0, []int{16, 0} return fileDescriptor0, []int{17, 0}
} }
// The protocol compiler can output a FileDescriptorSet containing the .proto // The protocol compiler can output a FileDescriptorSet containing the .proto
@@ -567,9 +568,10 @@ func (m *DescriptorProto) GetReservedName() []string {
} }
type DescriptorProto_ExtensionRange struct { type DescriptorProto_ExtensionRange struct {
Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"` Start *int32 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"` End *int32 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`
XXX_unrecognized []byte `json:"-"` Options *ExtensionRangeOptions `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"`
XXX_unrecognized []byte `json:"-"`
} }
func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} } func (m *DescriptorProto_ExtensionRange) Reset() { *m = DescriptorProto_ExtensionRange{} }
@@ -593,6 +595,13 @@ func (m *DescriptorProto_ExtensionRange) GetEnd() int32 {
return 0 return 0
} }
func (m *DescriptorProto_ExtensionRange) GetOptions() *ExtensionRangeOptions {
if m != nil {
return m.Options
}
return nil
}
// Range of reserved tag numbers. Reserved tag numbers may not be used by // Range of reserved tag numbers. Reserved tag numbers may not be used by
// fields or extension ranges in the same message. Reserved ranges may // fields or extension ranges in the same message. Reserved ranges may
// not overlap. // not overlap.
@@ -623,6 +632,33 @@ func (m *DescriptorProto_ReservedRange) GetEnd() int32 {
return 0 return 0
} }
type ExtensionRangeOptions struct {
// The parser stores options it doesn't recognize here. See above.
UninterpretedOption []*UninterpretedOption `protobuf:"bytes,999,rep,name=uninterpreted_option,json=uninterpretedOption" json:"uninterpreted_option,omitempty"`
proto.XXX_InternalExtensions `json:"-"`
XXX_unrecognized []byte `json:"-"`
}
func (m *ExtensionRangeOptions) Reset() { *m = ExtensionRangeOptions{} }
func (m *ExtensionRangeOptions) String() string { return proto.CompactTextString(m) }
func (*ExtensionRangeOptions) ProtoMessage() {}
func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
var extRange_ExtensionRangeOptions = []proto.ExtensionRange{
{1000, 536870911},
}
func (*ExtensionRangeOptions) ExtensionRangeArray() []proto.ExtensionRange {
return extRange_ExtensionRangeOptions
}
func (m *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption {
if m != nil {
return m.UninterpretedOption
}
return nil
}
// Describes a field within a message. // Describes a field within a message.
type FieldDescriptorProto struct { type FieldDescriptorProto struct {
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
@@ -661,7 +697,7 @@ type FieldDescriptorProto struct {
func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} } func (m *FieldDescriptorProto) Reset() { *m = FieldDescriptorProto{} }
func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *FieldDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*FieldDescriptorProto) ProtoMessage() {} func (*FieldDescriptorProto) ProtoMessage() {}
func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func (*FieldDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *FieldDescriptorProto) GetName() string { func (m *FieldDescriptorProto) GetName() string {
if m != nil && m.Name != nil { if m != nil && m.Name != nil {
@@ -743,7 +779,7 @@ type OneofDescriptorProto struct {
func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} } func (m *OneofDescriptorProto) Reset() { *m = OneofDescriptorProto{} }
func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *OneofDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*OneofDescriptorProto) ProtoMessage() {} func (*OneofDescriptorProto) ProtoMessage() {}
func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*OneofDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *OneofDescriptorProto) GetName() string { func (m *OneofDescriptorProto) GetName() string {
if m != nil && m.Name != nil { if m != nil && m.Name != nil {
@@ -770,7 +806,7 @@ type EnumDescriptorProto struct {
func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} } func (m *EnumDescriptorProto) Reset() { *m = EnumDescriptorProto{} }
func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *EnumDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*EnumDescriptorProto) ProtoMessage() {} func (*EnumDescriptorProto) ProtoMessage() {}
func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*EnumDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *EnumDescriptorProto) GetName() string { func (m *EnumDescriptorProto) GetName() string {
if m != nil && m.Name != nil { if m != nil && m.Name != nil {
@@ -804,7 +840,7 @@ type EnumValueDescriptorProto struct {
func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} } func (m *EnumValueDescriptorProto) Reset() { *m = EnumValueDescriptorProto{} }
func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *EnumValueDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*EnumValueDescriptorProto) ProtoMessage() {} func (*EnumValueDescriptorProto) ProtoMessage() {}
func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (*EnumValueDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *EnumValueDescriptorProto) GetName() string { func (m *EnumValueDescriptorProto) GetName() string {
if m != nil && m.Name != nil { if m != nil && m.Name != nil {
@@ -838,7 +874,7 @@ type ServiceDescriptorProto struct {
func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} } func (m *ServiceDescriptorProto) Reset() { *m = ServiceDescriptorProto{} }
func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *ServiceDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*ServiceDescriptorProto) ProtoMessage() {} func (*ServiceDescriptorProto) ProtoMessage() {}
func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } func (*ServiceDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *ServiceDescriptorProto) GetName() string { func (m *ServiceDescriptorProto) GetName() string {
if m != nil && m.Name != nil { if m != nil && m.Name != nil {
@@ -879,7 +915,7 @@ type MethodDescriptorProto struct {
func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} } func (m *MethodDescriptorProto) Reset() { *m = MethodDescriptorProto{} }
func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) } func (m *MethodDescriptorProto) String() string { return proto.CompactTextString(m) }
func (*MethodDescriptorProto) ProtoMessage() {} func (*MethodDescriptorProto) ProtoMessage() {}
func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (*MethodDescriptorProto) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
const Default_MethodDescriptorProto_ClientStreaming bool = false const Default_MethodDescriptorProto_ClientStreaming bool = false
const Default_MethodDescriptorProto_ServerStreaming bool = false const Default_MethodDescriptorProto_ServerStreaming bool = false
@@ -974,7 +1010,7 @@ type FileOptions struct {
CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"` CcGenericServices *bool `protobuf:"varint,16,opt,name=cc_generic_services,json=ccGenericServices,def=0" json:"cc_generic_services,omitempty"`
JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"` JavaGenericServices *bool `protobuf:"varint,17,opt,name=java_generic_services,json=javaGenericServices,def=0" json:"java_generic_services,omitempty"`
PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"` PyGenericServices *bool `protobuf:"varint,18,opt,name=py_generic_services,json=pyGenericServices,def=0" json:"py_generic_services,omitempty"`
PhpGenericServices *bool `protobuf:"varint,19,opt,name=php_generic_services,json=phpGenericServices,def=0" json:"php_generic_services,omitempty"` PhpGenericServices *bool `protobuf:"varint,42,opt,name=php_generic_services,json=phpGenericServices,def=0" json:"php_generic_services,omitempty"`
// Is this file deprecated? // Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations // Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very // for everything in the file, or it will be completely ignored; in the very
@@ -1009,7 +1045,7 @@ type FileOptions struct {
func (m *FileOptions) Reset() { *m = FileOptions{} } func (m *FileOptions) Reset() { *m = FileOptions{} }
func (m *FileOptions) String() string { return proto.CompactTextString(m) } func (m *FileOptions) String() string { return proto.CompactTextString(m) }
func (*FileOptions) ProtoMessage() {} func (*FileOptions) ProtoMessage() {}
func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (*FileOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
var extRange_FileOptions = []proto.ExtensionRange{ var extRange_FileOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1222,7 +1258,7 @@ type MessageOptions struct {
func (m *MessageOptions) Reset() { *m = MessageOptions{} } func (m *MessageOptions) Reset() { *m = MessageOptions{} }
func (m *MessageOptions) String() string { return proto.CompactTextString(m) } func (m *MessageOptions) String() string { return proto.CompactTextString(m) }
func (*MessageOptions) ProtoMessage() {} func (*MessageOptions) ProtoMessage() {}
func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } func (*MessageOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
var extRange_MessageOptions = []proto.ExtensionRange{ var extRange_MessageOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1285,13 +1321,15 @@ type FieldOptions struct {
Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"` Packed *bool `protobuf:"varint,2,opt,name=packed" json:"packed,omitempty"`
// The jstype option determines the JavaScript type used for values of the // The jstype option determines the JavaScript type used for values of the
// field. The option is permitted only for 64 bit integral and fixed types // field. The option is permitted only for 64 bit integral and fixed types
// (int64, uint64, sint64, fixed64, sfixed64). By default these types are // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
// represented as JavaScript strings. This avoids loss of precision that can // is represented as JavaScript string, which avoids loss of precision that
// happen when a large value is converted to a floating point JavaScript // can happen when a large value is converted to a floating point JavaScript.
// numbers. Specifying JS_NUMBER for the jstype causes the generated // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
// JavaScript code to use the JavaScript "number" type instead of strings. // use the JavaScript "number" type. The behavior of the default option
// This option is an enum to permit additional types to be added, // JS_NORMAL is implementation dependent.
// e.g. goog.math.Integer. //
// This option is an enum to permit additional types to be added, e.g.
// goog.math.Integer.
Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"` Jstype *FieldOptions_JSType `protobuf:"varint,6,opt,name=jstype,enum=google.protobuf.FieldOptions_JSType,def=0" json:"jstype,omitempty"`
// Should this field be parsed lazily? Lazy applies only to message-type // Should this field be parsed lazily? Lazy applies only to message-type
// fields. It means that when the outer message is initially parsed, the // fields. It means that when the outer message is initially parsed, the
@@ -1338,7 +1376,7 @@ type FieldOptions struct {
func (m *FieldOptions) Reset() { *m = FieldOptions{} } func (m *FieldOptions) Reset() { *m = FieldOptions{} }
func (m *FieldOptions) String() string { return proto.CompactTextString(m) } func (m *FieldOptions) String() string { return proto.CompactTextString(m) }
func (*FieldOptions) ProtoMessage() {} func (*FieldOptions) ProtoMessage() {}
func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } func (*FieldOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
var extRange_FieldOptions = []proto.ExtensionRange{ var extRange_FieldOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1413,7 +1451,7 @@ type OneofOptions struct {
func (m *OneofOptions) Reset() { *m = OneofOptions{} } func (m *OneofOptions) Reset() { *m = OneofOptions{} }
func (m *OneofOptions) String() string { return proto.CompactTextString(m) } func (m *OneofOptions) String() string { return proto.CompactTextString(m) }
func (*OneofOptions) ProtoMessage() {} func (*OneofOptions) ProtoMessage() {}
func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } func (*OneofOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
var extRange_OneofOptions = []proto.ExtensionRange{ var extRange_OneofOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1448,7 +1486,7 @@ type EnumOptions struct {
func (m *EnumOptions) Reset() { *m = EnumOptions{} } func (m *EnumOptions) Reset() { *m = EnumOptions{} }
func (m *EnumOptions) String() string { return proto.CompactTextString(m) } func (m *EnumOptions) String() string { return proto.CompactTextString(m) }
func (*EnumOptions) ProtoMessage() {} func (*EnumOptions) ProtoMessage() {}
func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } func (*EnumOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
var extRange_EnumOptions = []proto.ExtensionRange{ var extRange_EnumOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1496,7 +1534,7 @@ type EnumValueOptions struct {
func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} } func (m *EnumValueOptions) Reset() { *m = EnumValueOptions{} }
func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) } func (m *EnumValueOptions) String() string { return proto.CompactTextString(m) }
func (*EnumValueOptions) ProtoMessage() {} func (*EnumValueOptions) ProtoMessage() {}
func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } func (*EnumValueOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
var extRange_EnumValueOptions = []proto.ExtensionRange{ var extRange_EnumValueOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1537,7 +1575,7 @@ type ServiceOptions struct {
func (m *ServiceOptions) Reset() { *m = ServiceOptions{} } func (m *ServiceOptions) Reset() { *m = ServiceOptions{} }
func (m *ServiceOptions) String() string { return proto.CompactTextString(m) } func (m *ServiceOptions) String() string { return proto.CompactTextString(m) }
func (*ServiceOptions) ProtoMessage() {} func (*ServiceOptions) ProtoMessage() {}
func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } func (*ServiceOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
var extRange_ServiceOptions = []proto.ExtensionRange{ var extRange_ServiceOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1579,7 +1617,7 @@ type MethodOptions struct {
func (m *MethodOptions) Reset() { *m = MethodOptions{} } func (m *MethodOptions) Reset() { *m = MethodOptions{} }
func (m *MethodOptions) String() string { return proto.CompactTextString(m) } func (m *MethodOptions) String() string { return proto.CompactTextString(m) }
func (*MethodOptions) ProtoMessage() {} func (*MethodOptions) ProtoMessage() {}
func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } func (*MethodOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} }
var extRange_MethodOptions = []proto.ExtensionRange{ var extRange_MethodOptions = []proto.ExtensionRange{
{1000, 536870911}, {1000, 536870911},
@@ -1635,7 +1673,7 @@ type UninterpretedOption struct {
func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} } func (m *UninterpretedOption) Reset() { *m = UninterpretedOption{} }
func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) } func (m *UninterpretedOption) String() string { return proto.CompactTextString(m) }
func (*UninterpretedOption) ProtoMessage() {} func (*UninterpretedOption) ProtoMessage() {}
func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } func (*UninterpretedOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart { func (m *UninterpretedOption) GetName() []*UninterpretedOption_NamePart {
if m != nil { if m != nil {
@@ -1701,7 +1739,7 @@ func (m *UninterpretedOption_NamePart) Reset() { *m = UninterpretedOptio
func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) } func (m *UninterpretedOption_NamePart) String() string { return proto.CompactTextString(m) }
func (*UninterpretedOption_NamePart) ProtoMessage() {} func (*UninterpretedOption_NamePart) ProtoMessage() {}
func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) { func (*UninterpretedOption_NamePart) Descriptor() ([]byte, []int) {
return fileDescriptor0, []int{17, 0} return fileDescriptor0, []int{18, 0}
} }
func (m *UninterpretedOption_NamePart) GetNamePart() string { func (m *UninterpretedOption_NamePart) GetNamePart() string {
@@ -1771,7 +1809,7 @@ type SourceCodeInfo struct {
func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} } func (m *SourceCodeInfo) Reset() { *m = SourceCodeInfo{} }
func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) } func (m *SourceCodeInfo) String() string { return proto.CompactTextString(m) }
func (*SourceCodeInfo) ProtoMessage() {} func (*SourceCodeInfo) ProtoMessage() {}
func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } func (*SourceCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} }
func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location { func (m *SourceCodeInfo) GetLocation() []*SourceCodeInfo_Location {
if m != nil { if m != nil {
@@ -1867,7 +1905,7 @@ type SourceCodeInfo_Location struct {
func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} } func (m *SourceCodeInfo_Location) Reset() { *m = SourceCodeInfo_Location{} }
func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) } func (m *SourceCodeInfo_Location) String() string { return proto.CompactTextString(m) }
func (*SourceCodeInfo_Location) ProtoMessage() {} func (*SourceCodeInfo_Location) ProtoMessage() {}
func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18, 0} } func (*SourceCodeInfo_Location) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19, 0} }
func (m *SourceCodeInfo_Location) GetPath() []int32 { func (m *SourceCodeInfo_Location) GetPath() []int32 {
if m != nil { if m != nil {
@@ -1917,7 +1955,7 @@ type GeneratedCodeInfo struct {
func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} } func (m *GeneratedCodeInfo) Reset() { *m = GeneratedCodeInfo{} }
func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) } func (m *GeneratedCodeInfo) String() string { return proto.CompactTextString(m) }
func (*GeneratedCodeInfo) ProtoMessage() {} func (*GeneratedCodeInfo) ProtoMessage() {}
func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } func (*GeneratedCodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} }
func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation { func (m *GeneratedCodeInfo) GetAnnotation() []*GeneratedCodeInfo_Annotation {
if m != nil { if m != nil {
@@ -1946,7 +1984,7 @@ func (m *GeneratedCodeInfo_Annotation) Reset() { *m = GeneratedCodeInfo_
func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) } func (m *GeneratedCodeInfo_Annotation) String() string { return proto.CompactTextString(m) }
func (*GeneratedCodeInfo_Annotation) ProtoMessage() {} func (*GeneratedCodeInfo_Annotation) ProtoMessage() {}
func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) { func (*GeneratedCodeInfo_Annotation) Descriptor() ([]byte, []int) {
return fileDescriptor0, []int{19, 0} return fileDescriptor0, []int{20, 0}
} }
func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 { func (m *GeneratedCodeInfo_Annotation) GetPath() []int32 {
@@ -1983,6 +2021,7 @@ func init() {
proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto") proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto")
proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange") proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange")
proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange") proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange")
proto.RegisterType((*ExtensionRangeOptions)(nil), "google.protobuf.ExtensionRangeOptions")
proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto") proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto")
proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto") proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto")
proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto") proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto")
@@ -2014,161 +2053,163 @@ func init() {
func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) } func init() { proto.RegisterFile("google/protobuf/descriptor.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 2490 bytes of a gzipped FileDescriptorProto // 2519 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x8e, 0xdb, 0xc6, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0xdd, 0x6e, 0x1b, 0xc7,
0x15, 0x8e, 0x7e, 0x57, 0x3a, 0xd2, 0x6a, 0x67, 0x67, 0x37, 0x36, 0xbd, 0xf9, 0xf1, 0x5a, 0xf9, 0x15, 0x0e, 0x7f, 0x45, 0x1e, 0x52, 0xd4, 0x68, 0xa4, 0xd8, 0x6b, 0xe5, 0xc7, 0x32, 0xf3, 0x63,
0xf1, 0x3a, 0x69, 0xb4, 0xc1, 0xc6, 0x76, 0x9c, 0x4d, 0xe1, 0x42, 0x2b, 0xd1, 0x1b, 0xb9, 0x5a, 0xd9, 0x69, 0xa8, 0x40, 0xb1, 0x1d, 0x47, 0x29, 0xd2, 0x52, 0xe4, 0x5a, 0xa1, 0x4a, 0x91, 0xec,
0x49, 0xa5, 0xb4, 0x8d, 0x9d, 0x1b, 0x62, 0x96, 0x1c, 0x49, 0xb4, 0x29, 0x92, 0x21, 0x29, 0xdb, 0x92, 0x6a, 0x7e, 0x6e, 0x16, 0xa3, 0xdd, 0x21, 0xb9, 0xf6, 0x72, 0x77, 0xb3, 0xbb, 0xb4, 0xad,
0x9b, 0x2b, 0x03, 0xbd, 0x2a, 0xd0, 0x07, 0x28, 0x8a, 0xa2, 0x17, 0xb9, 0x09, 0xd0, 0x07, 0x28, 0xa0, 0x17, 0x06, 0x7a, 0x55, 0xa0, 0x0f, 0x50, 0x14, 0x45, 0x2f, 0x72, 0x13, 0xa0, 0x0f, 0x50,
0xd0, 0xbb, 0x3e, 0x41, 0x81, 0xbc, 0x41, 0x51, 0x14, 0x68, 0xdf, 0xa0, 0xb7, 0xc5, 0xcc, 0x90, 0x20, 0x77, 0x7d, 0x82, 0x02, 0x79, 0x83, 0xa2, 0x28, 0xd0, 0x3e, 0x46, 0x31, 0x33, 0xbb, 0xcb,
0x14, 0xa9, 0x1f, 0x7b, 0x1b, 0xc0, 0xc9, 0x95, 0x34, 0xdf, 0xf9, 0xce, 0x99, 0x33, 0x67, 0xce, 0x5d, 0xfe, 0xc4, 0x6a, 0x80, 0x38, 0x57, 0xe4, 0x7c, 0xe7, 0x3b, 0x67, 0xce, 0x9c, 0x39, 0x33,
0xcc, 0x9c, 0x19, 0xc2, 0xee, 0xc8, 0xb6, 0x47, 0x26, 0xdd, 0x77, 0x5c, 0xdb, 0xb7, 0xcf, 0xa6, 0x73, 0x66, 0x16, 0x76, 0x47, 0xb6, 0x3d, 0x32, 0xe9, 0xbe, 0xe3, 0xda, 0xbe, 0x7d, 0x3e, 0x1d,
0xc3, 0x7d, 0x9d, 0x7a, 0x9a, 0x6b, 0x38, 0xbe, 0xed, 0xd6, 0x38, 0x86, 0x37, 0x04, 0xa3, 0x16, 0xee, 0xeb, 0xd4, 0xd3, 0x5c, 0xc3, 0xf1, 0x6d, 0xb7, 0xc6, 0x31, 0xbc, 0x21, 0x18, 0xb5, 0x90,
0x32, 0xaa, 0x27, 0xb0, 0x79, 0xcf, 0x30, 0x69, 0x33, 0x22, 0xf6, 0xa9, 0x8f, 0xef, 0x40, 0x76, 0x51, 0x3d, 0x85, 0xcd, 0x07, 0x86, 0x49, 0x9b, 0x11, 0xb1, 0x4f, 0x7d, 0x7c, 0x1f, 0xb2, 0x43,
0x68, 0x98, 0x54, 0x4a, 0xed, 0x66, 0xf6, 0x4a, 0x07, 0xef, 0xd6, 0xe6, 0x94, 0x6a, 0x49, 0x8d, 0xc3, 0xa4, 0x52, 0x6a, 0x37, 0xb3, 0x57, 0x3a, 0x78, 0xb3, 0x36, 0xa7, 0x54, 0x4b, 0x6a, 0xf4,
0x1e, 0x83, 0x15, 0xae, 0x51, 0xfd, 0x57, 0x16, 0xb6, 0x96, 0x48, 0x31, 0x86, 0xac, 0x45, 0x26, 0x18, 0xac, 0x70, 0x8d, 0xea, 0xbf, 0xb3, 0xb0, 0xb5, 0x44, 0x8a, 0x31, 0x64, 0x2d, 0x32, 0x61,
0xcc, 0x62, 0x6a, 0xaf, 0xa8, 0xf0, 0xff, 0x58, 0x82, 0x35, 0x87, 0x68, 0x8f, 0xc9, 0x88, 0x4a, 0x16, 0x53, 0x7b, 0x45, 0x85, 0xff, 0xc7, 0x12, 0xac, 0x39, 0x44, 0x7b, 0x44, 0x46, 0x54, 0x4a,
0x69, 0x0e, 0x87, 0x4d, 0xfc, 0x36, 0x80, 0x4e, 0x1d, 0x6a, 0xe9, 0xd4, 0xd2, 0xce, 0xa5, 0xcc, 0x73, 0x38, 0x6c, 0xe2, 0xd7, 0x01, 0x74, 0xea, 0x50, 0x4b, 0xa7, 0x96, 0x76, 0x21, 0x65, 0x76,
0x6e, 0x66, 0xaf, 0xa8, 0xc4, 0x10, 0xfc, 0x21, 0x6c, 0x3a, 0xd3, 0x33, 0xd3, 0xd0, 0xd4, 0x18, 0x33, 0x7b, 0x45, 0x25, 0x86, 0xe0, 0x77, 0x60, 0xd3, 0x99, 0x9e, 0x9b, 0x86, 0xa6, 0xc6, 0x68,
0x0d, 0x76, 0x33, 0x7b, 0x39, 0x05, 0x09, 0x41, 0x73, 0x46, 0xbe, 0x0e, 0x1b, 0x4f, 0x29, 0x79, 0xb0, 0x9b, 0xd9, 0xcb, 0x29, 0x48, 0x08, 0x9a, 0x33, 0xf2, 0x4d, 0xd8, 0x78, 0x42, 0xc9, 0xa3,
0x1c, 0xa7, 0x96, 0x38, 0xb5, 0xc2, 0xe0, 0x18, 0xb1, 0x01, 0xe5, 0x09, 0xf5, 0x3c, 0x32, 0xa2, 0x38, 0xb5, 0xc4, 0xa9, 0x15, 0x06, 0xc7, 0x88, 0x0d, 0x28, 0x4f, 0xa8, 0xe7, 0x91, 0x11, 0x55,
0xaa, 0x7f, 0xee, 0x50, 0x29, 0xcb, 0x47, 0xbf, 0xbb, 0x30, 0xfa, 0xf9, 0x91, 0x97, 0x02, 0xad, 0xfd, 0x0b, 0x87, 0x4a, 0x59, 0x3e, 0xfa, 0xdd, 0x85, 0xd1, 0xcf, 0x8f, 0xbc, 0x14, 0x68, 0x0d,
0xc1, 0xb9, 0x43, 0x71, 0x1d, 0x8a, 0xd4, 0x9a, 0x4e, 0x84, 0x85, 0xdc, 0x8a, 0xf8, 0xc9, 0xd6, 0x2e, 0x1c, 0x8a, 0xeb, 0x50, 0xa4, 0xd6, 0x74, 0x22, 0x2c, 0xe4, 0x56, 0xc4, 0x4f, 0xb6, 0xa6,
0x74, 0x32, 0x6f, 0xa5, 0xc0, 0xd4, 0x02, 0x13, 0x6b, 0x1e, 0x75, 0x9f, 0x18, 0x1a, 0x95, 0xf2, 0x93, 0x79, 0x2b, 0x05, 0xa6, 0x16, 0x98, 0x58, 0xf3, 0xa8, 0xfb, 0xd8, 0xd0, 0xa8, 0x94, 0xe7,
0xdc, 0xc0, 0xf5, 0x05, 0x03, 0x7d, 0x21, 0x9f, 0xb7, 0x11, 0xea, 0xe1, 0x06, 0x14, 0xe9, 0x33, 0x06, 0x6e, 0x2e, 0x18, 0xe8, 0x0b, 0xf9, 0xbc, 0x8d, 0x50, 0x0f, 0x37, 0xa0, 0x48, 0x9f, 0xfa,
0x9f, 0x5a, 0x9e, 0x61, 0x5b, 0xd2, 0x1a, 0x37, 0xf2, 0xde, 0x92, 0x59, 0xa4, 0xa6, 0x3e, 0x6f, 0xd4, 0xf2, 0x0c, 0xdb, 0x92, 0xd6, 0xb8, 0x91, 0xb7, 0x96, 0xcc, 0x22, 0x35, 0xf5, 0x79, 0x13,
0x62, 0xa6, 0x87, 0x6f, 0xc3, 0x9a, 0xed, 0xf8, 0x86, 0x6d, 0x79, 0x52, 0x61, 0x37, 0xb5, 0x57, 0x33, 0x3d, 0x7c, 0x0f, 0xd6, 0x6c, 0xc7, 0x37, 0x6c, 0xcb, 0x93, 0x0a, 0xbb, 0xa9, 0xbd, 0xd2,
0x3a, 0x78, 0x73, 0x69, 0x22, 0x74, 0x05, 0x47, 0x09, 0xc9, 0xb8, 0x05, 0xc8, 0xb3, 0xa7, 0xae, 0xc1, 0xab, 0x4b, 0x13, 0xa1, 0x2b, 0x38, 0x4a, 0x48, 0xc6, 0x2d, 0x40, 0x9e, 0x3d, 0x75, 0x35,
0x46, 0x55, 0xcd, 0xd6, 0xa9, 0x6a, 0x58, 0x43, 0x5b, 0x2a, 0x72, 0x03, 0x57, 0x17, 0x07, 0xc2, 0xaa, 0x6a, 0xb6, 0x4e, 0x55, 0xc3, 0x1a, 0xda, 0x52, 0x91, 0x1b, 0xb8, 0xbe, 0x38, 0x10, 0x4e,
0x89, 0x0d, 0x5b, 0xa7, 0x2d, 0x6b, 0x68, 0x2b, 0x15, 0x2f, 0xd1, 0xc6, 0x97, 0x20, 0xef, 0x9d, 0x6c, 0xd8, 0x3a, 0x6d, 0x59, 0x43, 0x5b, 0xa9, 0x78, 0x89, 0x36, 0xbe, 0x02, 0x79, 0xef, 0xc2,
0x5b, 0x3e, 0x79, 0x26, 0x95, 0x79, 0x86, 0x04, 0xad, 0xea, 0x7f, 0x73, 0xb0, 0x71, 0x91, 0x14, 0xf2, 0xc9, 0x53, 0xa9, 0xcc, 0x33, 0x24, 0x68, 0x55, 0xbf, 0xcd, 0xc3, 0xc6, 0x65, 0x52, 0xec,
0xfb, 0x1c, 0x72, 0x43, 0x36, 0x4a, 0x29, 0xfd, 0xff, 0xc4, 0x40, 0xe8, 0x24, 0x83, 0x98, 0xff, 0x23, 0xc8, 0x0d, 0xd9, 0x28, 0xa5, 0xf4, 0xff, 0x13, 0x03, 0xa1, 0x93, 0x0c, 0x62, 0xfe, 0x07,
0x81, 0x41, 0xac, 0x43, 0xc9, 0xa2, 0x9e, 0x4f, 0x75, 0x91, 0x11, 0x99, 0x0b, 0xe6, 0x14, 0x08, 0x06, 0xb1, 0x0e, 0x25, 0x8b, 0x7a, 0x3e, 0xd5, 0x45, 0x46, 0x64, 0x2e, 0x99, 0x53, 0x20, 0x94,
0xa5, 0xc5, 0x94, 0xca, 0xfe, 0xa0, 0x94, 0x7a, 0x00, 0x1b, 0x91, 0x4b, 0xaa, 0x4b, 0xac, 0x51, 0x16, 0x53, 0x2a, 0xfb, 0x83, 0x52, 0xea, 0x33, 0xd8, 0x88, 0x5c, 0x52, 0x5d, 0x62, 0x8d, 0xc2,
0x98, 0x9b, 0xfb, 0x2f, 0xf3, 0xa4, 0x26, 0x87, 0x7a, 0x0a, 0x53, 0x53, 0x2a, 0x34, 0xd1, 0xc6, 0xdc, 0xdc, 0x7f, 0x9e, 0x27, 0x35, 0x39, 0xd4, 0x53, 0x98, 0x9a, 0x52, 0xa1, 0x89, 0x36, 0x6e,
0x4d, 0x00, 0xdb, 0xa2, 0xf6, 0x50, 0xd5, 0xa9, 0x66, 0x4a, 0x85, 0x15, 0x51, 0xea, 0x32, 0xca, 0x02, 0xd8, 0x16, 0xb5, 0x87, 0xaa, 0x4e, 0x35, 0x53, 0x2a, 0xac, 0x88, 0x52, 0x97, 0x51, 0x16,
0x42, 0x94, 0x6c, 0x81, 0x6a, 0x26, 0xfe, 0x6c, 0x96, 0x6a, 0x6b, 0x2b, 0x32, 0xe5, 0x44, 0x2c, 0xa2, 0x64, 0x0b, 0x54, 0x33, 0xf1, 0x87, 0xb3, 0x54, 0x5b, 0x5b, 0x91, 0x29, 0xa7, 0x62, 0x91,
0xb2, 0x85, 0x6c, 0x3b, 0x85, 0x8a, 0x4b, 0x59, 0xde, 0x53, 0x3d, 0x18, 0x59, 0x91, 0x3b, 0x51, 0x2d, 0x64, 0xdb, 0x19, 0x54, 0x5c, 0xca, 0xf2, 0x9e, 0xea, 0xc1, 0xc8, 0x8a, 0xdc, 0x89, 0xda,
0x7b, 0xe9, 0xc8, 0x94, 0x40, 0x4d, 0x0c, 0x6c, 0xdd, 0x8d, 0x37, 0xf1, 0x3b, 0x10, 0x01, 0x2a, 0x73, 0x47, 0xa6, 0x04, 0x6a, 0x62, 0x60, 0xeb, 0x6e, 0xbc, 0x89, 0xdf, 0x80, 0x08, 0x50, 0x79,
0x4f, 0x2b, 0xe0, 0xbb, 0x50, 0x39, 0x04, 0x3b, 0x64, 0x42, 0x77, 0xee, 0x40, 0x25, 0x19, 0x1e, 0x5a, 0x01, 0xdf, 0x85, 0xca, 0x21, 0xd8, 0x21, 0x13, 0xba, 0xf3, 0x15, 0x54, 0x92, 0xe1, 0xc1,
0xbc, 0x0d, 0x39, 0xcf, 0x27, 0xae, 0xcf, 0xb3, 0x30, 0xa7, 0x88, 0x06, 0x46, 0x90, 0xa1, 0x96, 0xdb, 0x90, 0xf3, 0x7c, 0xe2, 0xfa, 0x3c, 0x0b, 0x73, 0x8a, 0x68, 0x60, 0x04, 0x19, 0x6a, 0xe9,
0xce, 0x77, 0xb9, 0x9c, 0xc2, 0xfe, 0xee, 0x7c, 0x0a, 0xeb, 0x89, 0xee, 0x2f, 0xaa, 0x58, 0xfd, 0x7c, 0x97, 0xcb, 0x29, 0xec, 0x2f, 0xfe, 0xe5, 0x6c, 0xc0, 0x19, 0x3e, 0xe0, 0xb7, 0x17, 0x67,
0x7d, 0x1e, 0xb6, 0x97, 0xe5, 0xdc, 0xd2, 0xf4, 0xbf, 0x04, 0x79, 0x6b, 0x3a, 0x39, 0xa3, 0xae, 0x34, 0x61, 0x79, 0x7e, 0xdc, 0x3b, 0x1f, 0xc0, 0x7a, 0x62, 0x00, 0x97, 0xed, 0xba, 0xfa, 0x5b,
0x94, 0xe1, 0x16, 0x82, 0x16, 0xae, 0x43, 0xce, 0x24, 0x67, 0xd4, 0x94, 0xb2, 0xbb, 0xa9, 0xbd, 0x78, 0x79, 0xa9, 0x69, 0xfc, 0x19, 0x6c, 0x4f, 0x2d, 0xc3, 0xf2, 0xa9, 0xeb, 0xb8, 0x94, 0x65,
0xca, 0xc1, 0x87, 0x17, 0xca, 0xea, 0x5a, 0x9b, 0xa9, 0x28, 0x42, 0x13, 0xdf, 0x85, 0x6c, 0xb0, 0xac, 0xe8, 0x4a, 0xfa, 0xcf, 0xda, 0x8a, 0x9c, 0x3b, 0x8b, 0xb3, 0x85, 0x15, 0x65, 0x6b, 0xba,
0xc5, 0x31, 0x0b, 0x1f, 0x5c, 0xcc, 0x02, 0xcb, 0x45, 0x85, 0xeb, 0xe1, 0x37, 0xa0, 0xc8, 0x7e, 0x08, 0xde, 0x2e, 0x16, 0xfe, 0xbb, 0x86, 0x9e, 0x3d, 0x7b, 0xf6, 0x2c, 0x5d, 0xfd, 0x63, 0x1e,
0x45, 0x6c, 0xf3, 0xdc, 0xe7, 0x02, 0x03, 0x58, 0x5c, 0xf1, 0x0e, 0x14, 0x78, 0x9a, 0xe9, 0x34, 0xb6, 0x97, 0xad, 0x99, 0xa5, 0xcb, 0xf7, 0x0a, 0xe4, 0xad, 0xe9, 0xe4, 0x9c, 0xba, 0x3c, 0x48,
0x3c, 0x1a, 0xa2, 0x36, 0x9b, 0x18, 0x9d, 0x0e, 0xc9, 0xd4, 0xf4, 0xd5, 0x27, 0xc4, 0x9c, 0x52, 0x39, 0x25, 0x68, 0xe1, 0x3a, 0xe4, 0x4c, 0x72, 0x4e, 0x4d, 0x29, 0xbb, 0x9b, 0xda, 0xab, 0x1c,
0x9e, 0x30, 0x45, 0xa5, 0x1c, 0x80, 0xbf, 0x66, 0x18, 0xbe, 0x0a, 0x25, 0x91, 0x95, 0x86, 0xa5, 0xbc, 0x73, 0xa9, 0x55, 0x59, 0x6b, 0x33, 0x15, 0x45, 0x68, 0xe2, 0x8f, 0x21, 0x1b, 0x6c, 0xd1,
0xd3, 0x67, 0x7c, 0xf7, 0xc9, 0x29, 0x22, 0x51, 0x5b, 0x0c, 0x61, 0xdd, 0x3f, 0xf2, 0x6c, 0x2b, 0xcc, 0xc2, 0xed, 0xcb, 0x59, 0x60, 0x6b, 0x49, 0xe1, 0x7a, 0xf8, 0x15, 0x28, 0xb2, 0x5f, 0x91,
0x9c, 0x5a, 0xde, 0x05, 0x03, 0x78, 0xf7, 0x9f, 0xce, 0x6f, 0x7c, 0x6f, 0x2d, 0x1f, 0xde, 0x7c, 0x1b, 0x79, 0xee, 0x73, 0x81, 0x01, 0x2c, 0x2f, 0xf0, 0x0e, 0x14, 0xf8, 0x32, 0xd1, 0x69, 0x78,
0x2e, 0x56, 0xff, 0x92, 0x86, 0x2c, 0x5f, 0x6f, 0x1b, 0x50, 0x1a, 0x3c, 0xec, 0xc9, 0x6a, 0xb3, 0xb4, 0x45, 0x6d, 0x96, 0x58, 0x3a, 0x1d, 0x92, 0xa9, 0xe9, 0xab, 0x8f, 0x89, 0x39, 0xa5, 0x3c,
0x7b, 0x7a, 0xd4, 0x96, 0x51, 0x0a, 0x57, 0x00, 0x38, 0x70, 0xaf, 0xdd, 0xad, 0x0f, 0x50, 0x3a, 0xe1, 0x8b, 0x4a, 0x39, 0x00, 0x7f, 0xc3, 0x30, 0x7c, 0x1d, 0x4a, 0x62, 0x55, 0x19, 0x96, 0x4e,
0x6a, 0xb7, 0x3a, 0x83, 0xdb, 0x37, 0x51, 0x26, 0x52, 0x38, 0x15, 0x40, 0x36, 0x4e, 0xf8, 0xe4, 0x9f, 0xf2, 0xdd, 0x33, 0xa7, 0x88, 0x85, 0xd6, 0x62, 0x08, 0xeb, 0xfe, 0xa1, 0x67, 0x5b, 0x61,
0x00, 0xe5, 0x30, 0x82, 0xb2, 0x30, 0xd0, 0x7a, 0x20, 0x37, 0x6f, 0xdf, 0x44, 0xf9, 0x24, 0xf2, 0x6a, 0xf2, 0x2e, 0x18, 0xc0, 0xbb, 0xff, 0x60, 0x7e, 0xe3, 0x7e, 0x6d, 0xf9, 0xf0, 0xe6, 0x73,
0xc9, 0x01, 0x5a, 0xc3, 0xeb, 0x50, 0xe4, 0xc8, 0x51, 0xb7, 0xdb, 0x46, 0x85, 0xc8, 0x66, 0x7f, 0xaa, 0xfa, 0xb7, 0x34, 0x64, 0xf9, 0x7e, 0xb1, 0x01, 0xa5, 0xc1, 0xe7, 0x3d, 0x59, 0x6d, 0x76,
0xa0, 0xb4, 0x3a, 0xc7, 0xa8, 0x18, 0xd9, 0x3c, 0x56, 0xba, 0xa7, 0x3d, 0x04, 0x91, 0x85, 0x13, 0xcf, 0x8e, 0xda, 0x32, 0x4a, 0xe1, 0x0a, 0x00, 0x07, 0x1e, 0xb4, 0xbb, 0xf5, 0x01, 0x4a, 0x47,
0xb9, 0xdf, 0xaf, 0x1f, 0xcb, 0xa8, 0x14, 0x31, 0x8e, 0x1e, 0x0e, 0xe4, 0x3e, 0x2a, 0x27, 0xdc, 0xed, 0x56, 0x67, 0x70, 0xef, 0x0e, 0xca, 0x44, 0x0a, 0x67, 0x02, 0xc8, 0xc6, 0x09, 0xef, 0x1f,
0xfa, 0xe4, 0x00, 0xad, 0x47, 0x5d, 0xc8, 0x9d, 0xd3, 0x13, 0x54, 0xc1, 0x9b, 0xb0, 0x2e, 0xba, 0xa0, 0x1c, 0x46, 0x50, 0x16, 0x06, 0x5a, 0x9f, 0xc9, 0xcd, 0x7b, 0x77, 0x50, 0x3e, 0x89, 0xbc,
0x08, 0x9d, 0xd8, 0x98, 0x83, 0x6e, 0xdf, 0x44, 0x68, 0xe6, 0x88, 0xb0, 0xb2, 0x99, 0x00, 0x6e, 0x7f, 0x80, 0xd6, 0xf0, 0x3a, 0x14, 0x39, 0x72, 0xd4, 0xed, 0xb6, 0x51, 0x21, 0xb2, 0xd9, 0x1f,
0xdf, 0x44, 0xb8, 0xda, 0x80, 0x1c, 0xcf, 0x2e, 0x8c, 0xa1, 0xd2, 0xae, 0x1f, 0xc9, 0x6d, 0xb5, 0x28, 0xad, 0xce, 0x31, 0x2a, 0x46, 0x36, 0x8f, 0x95, 0xee, 0x59, 0x0f, 0x41, 0x64, 0xe1, 0x54,
0xdb, 0x1b, 0xb4, 0xba, 0x9d, 0x7a, 0x1b, 0xa5, 0x66, 0x98, 0x22, 0xff, 0xea, 0xb4, 0xa5, 0xc8, 0xee, 0xf7, 0xeb, 0xc7, 0x32, 0x2a, 0x45, 0x8c, 0xa3, 0xcf, 0x07, 0x72, 0x1f, 0x95, 0x13, 0x6e,
0x4d, 0x94, 0x8e, 0x63, 0x3d, 0xb9, 0x3e, 0x90, 0x9b, 0x28, 0x53, 0xd5, 0x60, 0x7b, 0xd9, 0x3e, 0xbd, 0x7f, 0x80, 0xd6, 0xa3, 0x2e, 0xe4, 0xce, 0xd9, 0x29, 0xaa, 0xe0, 0x4d, 0x58, 0x17, 0x5d,
0xb3, 0x74, 0x65, 0xc4, 0xa6, 0x38, 0xbd, 0x62, 0x8a, 0xb9, 0xad, 0x85, 0x29, 0xfe, 0x36, 0x05, 0x84, 0x4e, 0x6c, 0xcc, 0x41, 0xf7, 0xee, 0x20, 0x34, 0x73, 0x44, 0x58, 0xd9, 0x4c, 0x00, 0xf7,
0x5b, 0x4b, 0xf6, 0xda, 0xa5, 0x9d, 0xfc, 0x02, 0x72, 0x22, 0x45, 0xc5, 0xe9, 0x73, 0x63, 0xe9, 0xee, 0x20, 0x5c, 0x6d, 0x40, 0x8e, 0x67, 0x17, 0xc6, 0x50, 0x69, 0xd7, 0x8f, 0xe4, 0xb6, 0xda,
0xa6, 0xcd, 0x13, 0x76, 0xe1, 0x04, 0xe2, 0x7a, 0xf1, 0x13, 0x38, 0xb3, 0xe2, 0x04, 0x66, 0x26, 0xed, 0x0d, 0x5a, 0xdd, 0x4e, 0xbd, 0x8d, 0x52, 0x33, 0x4c, 0x91, 0x7f, 0x7d, 0xd6, 0x52, 0xe4,
0x16, 0x9c, 0xfc, 0x4d, 0x0a, 0xa4, 0x55, 0xb6, 0x5f, 0xb2, 0x51, 0xa4, 0x13, 0x1b, 0xc5, 0xe7, 0x26, 0x4a, 0xc7, 0xb1, 0x9e, 0x5c, 0x1f, 0xc8, 0x4d, 0x94, 0xa9, 0x6a, 0xb0, 0xbd, 0x6c, 0x9f,
0xf3, 0x0e, 0x5c, 0x5b, 0x3d, 0x86, 0x05, 0x2f, 0xbe, 0x4b, 0xc1, 0xa5, 0xe5, 0x85, 0xca, 0x52, 0x5c, 0xba, 0x32, 0x62, 0x53, 0x9c, 0x5e, 0x31, 0xc5, 0xdc, 0xd6, 0xc2, 0x14, 0x7f, 0x9d, 0x82,
0x1f, 0xee, 0x42, 0x7e, 0x42, 0xfd, 0xb1, 0x1d, 0x1e, 0xd6, 0xef, 0x2f, 0x39, 0x02, 0x98, 0x78, 0xad, 0x25, 0x67, 0xc5, 0xd2, 0x4e, 0x7e, 0x01, 0x39, 0x91, 0xa2, 0xe2, 0xf4, 0xbc, 0xb5, 0xf4,
0x3e, 0x56, 0x81, 0x56, 0xfc, 0x0c, 0xc9, 0xac, 0xaa, 0x36, 0x84, 0x37, 0x0b, 0x9e, 0xfe, 0x36, 0xd0, 0xe1, 0x09, 0xbb, 0x70, 0x82, 0x72, 0xbd, 0x78, 0x05, 0x91, 0x59, 0x51, 0x41, 0x30, 0x13,
0x0d, 0xaf, 0x2f, 0x35, 0xbe, 0xd4, 0xd1, 0xb7, 0x00, 0x0c, 0xcb, 0x99, 0xfa, 0xe2, 0x40, 0x16, 0x0b, 0x4e, 0xfe, 0x2e, 0x05, 0xd2, 0x2a, 0xdb, 0xcf, 0xd9, 0x28, 0xd2, 0x89, 0x8d, 0xe2, 0xa3,
0x79, 0x07, 0x6e, 0xac, 0x1e, 0xc3, 0x82, 0x17, 0xdf, 0xa4, 0xe0, 0xca, 0xf2, 0x42, 0x6b, 0xa9,
0x0f, 0x1f, 0x43, 0x7e, 0x42, 0xfd, 0xb1, 0x1d, 0x16, 0x1b, 0x6f, 0x2f, 0x39, 0xc2, 0x98, 0x78,
0x3e, 0x56, 0x81, 0x56, 0xfc, 0x0c, 0xcc, 0xac, 0xaa, 0x96, 0x84, 0x37, 0x0b, 0x9e, 0xfe, 0x3e,
0x0d, 0x2f, 0x2f, 0x35, 0xbe, 0xd4, 0xd1, 0xd7, 0x00, 0x0c, 0xcb, 0x99, 0xfa, 0xa2, 0xa0, 0x10,
0xfb, 0x53, 0x91, 0x23, 0x7c, 0xed, 0xb3, 0xbd, 0x67, 0xea, 0x47, 0xf2, 0x0c, 0x97, 0x83, 0x80, 0xfb, 0x53, 0x91, 0x23, 0x7c, 0xed, 0xb3, 0xbd, 0x67, 0xea, 0x47, 0xf2, 0x0c, 0x97, 0x83, 0x80,
0x38, 0xe1, 0xce, 0xcc, 0xd1, 0x2c, 0x77, 0xf4, 0xed, 0x15, 0x23, 0x5d, 0x38, 0xeb, 0x3e, 0x06, 0x38, 0xe1, 0xfe, 0xcc, 0xd1, 0x2c, 0x77, 0xf4, 0xf5, 0x15, 0x23, 0x5d, 0x38, 0xab, 0xdf, 0x03,
0xa4, 0x99, 0x06, 0xb5, 0x7c, 0xd5, 0xf3, 0x5d, 0x4a, 0x26, 0x86, 0x35, 0xe2, 0x1b, 0x70, 0xe1, 0xa4, 0x99, 0x06, 0xb5, 0x7c, 0xd5, 0xf3, 0x5d, 0x4a, 0x26, 0x86, 0x35, 0xe2, 0x1b, 0x70, 0xe1,
0x30, 0x37, 0x24, 0xa6, 0x47, 0x95, 0x0d, 0x21, 0xee, 0x87, 0x52, 0xa6, 0xc1, 0x4f, 0x19, 0x37, 0x30, 0x37, 0x24, 0xa6, 0x47, 0x95, 0x0d, 0x21, 0xee, 0x87, 0x52, 0xa6, 0xc1, 0xcf, 0x38, 0x37,
0xa6, 0x91, 0x4f, 0x68, 0x08, 0x71, 0xa4, 0x51, 0xfd, 0x6b, 0x01, 0x4a, 0xb1, 0xb2, 0x0e, 0x5f, 0xa6, 0x91, 0x4f, 0x68, 0x08, 0x71, 0xa4, 0x51, 0xfd, 0xb6, 0x00, 0xa5, 0x58, 0x59, 0x8a, 0x6f,
0x83, 0xf2, 0x23, 0xf2, 0x84, 0xa8, 0x61, 0xa9, 0x2e, 0x22, 0x51, 0x62, 0x58, 0x2f, 0x28, 0xd7, 0x40, 0xf9, 0x21, 0x79, 0x4c, 0xd4, 0xf0, 0xaa, 0x21, 0x22, 0x51, 0x62, 0x58, 0x2f, 0xb8, 0x6e,
0x3f, 0x86, 0x6d, 0x4e, 0xb1, 0xa7, 0x3e, 0x75, 0x55, 0xcd, 0x24, 0x9e, 0xc7, 0x83, 0x56, 0xe0, 0xbc, 0x07, 0xdb, 0x9c, 0x62, 0x4f, 0x7d, 0xea, 0xaa, 0x9a, 0x49, 0x3c, 0x8f, 0x07, 0xad, 0xc0,
0x54, 0xcc, 0x64, 0x5d, 0x26, 0x6a, 0x84, 0x12, 0x7c, 0x0b, 0xb6, 0xb8, 0xc6, 0x64, 0x6a, 0xfa, 0xa9, 0x98, 0xc9, 0xba, 0x4c, 0xd4, 0x08, 0x25, 0xf8, 0x2e, 0x6c, 0x71, 0x8d, 0xc9, 0xd4, 0xf4,
0x86, 0x63, 0x52, 0x95, 0x5d, 0x1e, 0x3c, 0xbe, 0x11, 0x47, 0x9e, 0x6d, 0x32, 0xc6, 0x49, 0x40, 0x0d, 0xc7, 0xa4, 0x2a, 0xbb, 0xfc, 0x78, 0x7c, 0x23, 0x8e, 0x3c, 0xdb, 0x64, 0x8c, 0xd3, 0x80,
0x60, 0x1e, 0x79, 0xb8, 0x09, 0x6f, 0x71, 0xb5, 0x11, 0xb5, 0xa8, 0x4b, 0x7c, 0xaa, 0xd2, 0xaf, 0xc0, 0x3c, 0xf2, 0x70, 0x13, 0x5e, 0xe3, 0x6a, 0x23, 0x6a, 0x51, 0x97, 0xf8, 0x54, 0xa5, 0x5f,
0xa7, 0xc4, 0xf4, 0x54, 0x62, 0xe9, 0xea, 0x98, 0x78, 0x63, 0x69, 0x9b, 0x19, 0x38, 0x4a, 0x4b, 0x4e, 0x89, 0xe9, 0xa9, 0xc4, 0xd2, 0xd5, 0x31, 0xf1, 0xc6, 0xd2, 0x36, 0x33, 0x70, 0x94, 0x96,
0x29, 0xe5, 0x0a, 0x23, 0x1e, 0x07, 0x3c, 0x99, 0xd3, 0xea, 0x96, 0xfe, 0x05, 0xf1, 0xc6, 0xf8, 0x52, 0xca, 0x35, 0x46, 0x3c, 0x0e, 0x78, 0x32, 0xa7, 0xd5, 0x2d, 0xfd, 0x13, 0xe2, 0x8d, 0xf1,
0x10, 0x2e, 0x71, 0x2b, 0x9e, 0xef, 0x1a, 0xd6, 0x48, 0xd5, 0xc6, 0x54, 0x7b, 0xac, 0x4e, 0xfd, 0x21, 0x5c, 0xe1, 0x56, 0x3c, 0xdf, 0x35, 0xac, 0x91, 0xaa, 0x8d, 0xa9, 0xf6, 0x48, 0x9d, 0xfa,
0xe1, 0x1d, 0xe9, 0x8d, 0x78, 0xff, 0xdc, 0xc3, 0x3e, 0xe7, 0x34, 0x18, 0xe5, 0xd4, 0x1f, 0xde, 0xc3, 0xfb, 0xd2, 0x2b, 0xf1, 0xfe, 0xb9, 0x87, 0x7d, 0xce, 0x69, 0x30, 0xca, 0x99, 0x3f, 0xbc,
0xc1, 0x7d, 0x28, 0xb3, 0xc9, 0x98, 0x18, 0xdf, 0x50, 0x75, 0x68, 0xbb, 0xfc, 0x64, 0xa9, 0x2c, 0x8f, 0xfb, 0x50, 0x66, 0x93, 0x31, 0x31, 0xbe, 0xa2, 0xea, 0xd0, 0x76, 0xf9, 0xc9, 0x52, 0x59,
0x59, 0xd9, 0xb1, 0x08, 0xd6, 0xba, 0x81, 0xc2, 0x89, 0xad, 0xd3, 0xc3, 0x5c, 0xbf, 0x27, 0xcb, 0xb2, 0xb2, 0x63, 0x11, 0xac, 0x75, 0x03, 0x85, 0x53, 0x5b, 0xa7, 0x87, 0xb9, 0x7e, 0x4f, 0x96,
0x4d, 0xa5, 0x14, 0x5a, 0xb9, 0x67, 0xbb, 0x2c, 0xa1, 0x46, 0x76, 0x14, 0xe0, 0x92, 0x48, 0xa8, 0x9b, 0x4a, 0x29, 0xb4, 0xf2, 0xc0, 0x76, 0x59, 0x42, 0x8d, 0xec, 0x28, 0xc0, 0x25, 0x91, 0x50,
0x91, 0x1d, 0x86, 0xf7, 0x16, 0x6c, 0x69, 0x9a, 0x18, 0xb3, 0xa1, 0xa9, 0x41, 0x89, 0xef, 0x49, 0x23, 0x3b, 0x0c, 0xef, 0x5d, 0xd8, 0xd2, 0x34, 0x31, 0x66, 0x43, 0x53, 0x83, 0x2b, 0x8a, 0x27,
0x28, 0x11, 0x2c, 0x4d, 0x3b, 0x16, 0x84, 0x20, 0xc7, 0x3d, 0xfc, 0x19, 0xbc, 0x3e, 0x0b, 0x56, 0xa1, 0x44, 0xb0, 0x34, 0xed, 0x58, 0x10, 0x82, 0x1c, 0xf7, 0xf0, 0x87, 0xf0, 0xf2, 0x2c, 0x58,
0x5c, 0x71, 0x73, 0x61, 0x94, 0xf3, 0xaa, 0xb7, 0x60, 0xcb, 0x39, 0x5f, 0x54, 0xc4, 0x89, 0x1e, 0x71, 0xc5, 0xcd, 0x85, 0x51, 0xce, 0xab, 0xde, 0x85, 0x2d, 0xe7, 0x62, 0x51, 0x11, 0x27, 0x7a,
0x9d, 0xf3, 0x79, 0xb5, 0x4f, 0x61, 0xdb, 0x19, 0x3b, 0x8b, 0x7a, 0x5b, 0x71, 0x3d, 0xec, 0x8c, 0x74, 0x2e, 0xe6, 0xd5, 0x3e, 0x80, 0x6d, 0x67, 0xec, 0x2c, 0xea, 0xdd, 0x8e, 0xeb, 0x61, 0x67,
0x9d, 0x79, 0xc5, 0xf7, 0xf8, 0x7d, 0xcf, 0xa5, 0x1a, 0xf1, 0xa9, 0x2e, 0x5d, 0x8e, 0xd3, 0x63, 0xec, 0xcc, 0x2b, 0xbe, 0xc5, 0xef, 0xab, 0x2e, 0xd5, 0x88, 0x4f, 0x75, 0xe9, 0x6a, 0x9c, 0x1e,
0x02, 0xbc, 0x0f, 0x48, 0xd3, 0x54, 0x6a, 0x91, 0x33, 0x93, 0xaa, 0xc4, 0xa5, 0x16, 0xf1, 0xa4, 0x13, 0xe0, 0x7d, 0x40, 0x9a, 0xa6, 0x52, 0x8b, 0x9c, 0x9b, 0x54, 0x25, 0x2e, 0xb5, 0x88, 0x27,
0xab, 0x71, 0x72, 0x45, 0xd3, 0x64, 0x2e, 0xad, 0x73, 0x21, 0xfe, 0x00, 0x36, 0xed, 0xb3, 0x47, 0x5d, 0x8f, 0x93, 0x2b, 0x9a, 0x26, 0x73, 0x69, 0x9d, 0x0b, 0xf1, 0x6d, 0xd8, 0xb4, 0xcf, 0x1f,
0x9a, 0x48, 0x49, 0xd5, 0x71, 0xe9, 0xd0, 0x78, 0x26, 0xbd, 0xcb, 0xe3, 0xbb, 0xc1, 0x04, 0x3c, 0x6a, 0x22, 0x25, 0x55, 0xc7, 0xa5, 0x43, 0xe3, 0xa9, 0xf4, 0x26, 0x8f, 0xef, 0x06, 0x13, 0xf0,
0x21, 0x7b, 0x1c, 0xc6, 0x37, 0x00, 0x69, 0xde, 0x98, 0xb8, 0x0e, 0xaf, 0x09, 0x3c, 0x87, 0x68, 0x84, 0xec, 0x71, 0x18, 0xdf, 0x02, 0xa4, 0x79, 0x63, 0xe2, 0x3a, 0xbc, 0x26, 0xf0, 0x1c, 0xa2,
0x54, 0x7a, 0x4f, 0x50, 0x05, 0xde, 0x09, 0x61, 0xb6, 0x24, 0xbc, 0xa7, 0xc6, 0xd0, 0x0f, 0x2d, 0x51, 0xe9, 0x2d, 0x41, 0x15, 0x78, 0x27, 0x84, 0xd9, 0x92, 0xf0, 0x9e, 0x18, 0x43, 0x3f, 0xb4,
0x5e, 0x17, 0x4b, 0x82, 0x63, 0x81, 0xb5, 0x3d, 0x40, 0x2c, 0x14, 0x89, 0x8e, 0xf7, 0x38, 0xad, 0x78, 0x53, 0x2c, 0x09, 0x8e, 0x05, 0xd6, 0xf6, 0x00, 0xb1, 0x50, 0x24, 0x3a, 0xde, 0xe3, 0xb4,
0xe2, 0x8c, 0x9d, 0x78, 0xbf, 0xef, 0xc0, 0x3a, 0x63, 0xce, 0x3a, 0xbd, 0x21, 0xea, 0x19, 0x67, 0x8a, 0x33, 0x76, 0xe2, 0xfd, 0xbe, 0x01, 0xeb, 0x8c, 0x39, 0xeb, 0xf4, 0x96, 0xa8, 0x67, 0x9c,
0x1c, 0xeb, 0xf1, 0x01, 0x6c, 0x4f, 0x2d, 0xc3, 0xf2, 0xa9, 0xeb, 0xb8, 0x94, 0x5d, 0x26, 0xc4, 0x71, 0xac, 0xc7, 0x1f, 0xad, 0xb4, 0xac, 0x1e, 0x42, 0x39, 0x9e, 0x9f, 0xb8, 0x08, 0x22, 0x43,
0x8e, 0x20, 0xfd, 0x7b, 0x6d, 0xc5, 0x75, 0xe0, 0x34, 0xce, 0x16, 0x89, 0xa8, 0x6c, 0x4d, 0x17, 0x51, 0x8a, 0x9d, 0xf5, 0x8d, 0x6e, 0x93, 0x9d, 0xd2, 0x5f, 0xc8, 0x28, 0xcd, 0xaa, 0x85, 0x76,
0xc1, 0xea, 0x21, 0x94, 0xe3, 0xf9, 0x89, 0x8b, 0x20, 0x32, 0x14, 0xa5, 0xd8, 0x59, 0xdf, 0xe8, 0x6b, 0x20, 0xab, 0xca, 0x59, 0x67, 0xd0, 0x3a, 0x95, 0x51, 0x26, 0x56, 0x96, 0x9e, 0x64, 0x0b,
0x36, 0xd9, 0x29, 0xfd, 0x95, 0x8c, 0xd2, 0xac, 0x5a, 0x68, 0xb7, 0x06, 0xb2, 0xaa, 0x9c, 0x76, 0x6f, 0xa3, 0x9b, 0xd5, 0xef, 0xd2, 0x50, 0x49, 0xde, 0x33, 0xf0, 0xcf, 0xe1, 0x6a, 0xf8, 0x28,
0x06, 0xad, 0x13, 0x19, 0x65, 0x3e, 0x28, 0x16, 0xfe, 0xb3, 0x86, 0x9e, 0x3f, 0x7f, 0xfe, 0x3c, 0xe0, 0x51, 0x5f, 0x7d, 0x62, 0xb8, 0x7c, 0xe1, 0x4c, 0x88, 0xa8, 0xb3, 0xa3, 0xa9, 0xdb, 0x0e,
0x7d, 0x3f, 0x5b, 0x78, 0x1f, 0x5d, 0xaf, 0x7e, 0x9f, 0x86, 0x4a, 0xb2, 0x4e, 0xc7, 0x3f, 0x87, 0x58, 0x7d, 0xea, 0x7f, 0x6a, 0xb8, 0x6c, 0x59, 0x4c, 0x88, 0x8f, 0xdb, 0x70, 0xdd, 0xb2, 0x55,
0xcb, 0xe1, 0xa5, 0xda, 0xa3, 0xbe, 0xfa, 0xd4, 0x70, 0xf9, 0xc2, 0x99, 0x10, 0x51, 0xe9, 0x46, 0xcf, 0x27, 0x96, 0x4e, 0x5c, 0x5d, 0x9d, 0x3d, 0xc7, 0xa8, 0x44, 0xd3, 0xa8, 0xe7, 0xd9, 0xe2,
0x53, 0xb7, 0x1d, 0xb0, 0xfa, 0xd4, 0xff, 0xd2, 0x70, 0xd9, 0xb2, 0x98, 0x10, 0x1f, 0xb7, 0xe1, 0xc0, 0x8a, 0xac, 0xbc, 0x6a, 0xd9, 0xfd, 0x80, 0x3c, 0xdb, 0xc9, 0xeb, 0x01, 0x75, 0x2e, 0xcd,
0xaa, 0x65, 0xab, 0x9e, 0x4f, 0x2c, 0x9d, 0xb8, 0xba, 0x3a, 0x7b, 0xce, 0x50, 0x89, 0xa6, 0x51, 0x32, 0xab, 0xd2, 0xec, 0x15, 0x28, 0x4e, 0x88, 0xa3, 0x52, 0xcb, 0x77, 0x2f, 0x78, 0x75, 0x59,
0xcf, 0xb3, 0xc5, 0x81, 0x15, 0x59, 0x79, 0xd3, 0xb2, 0xfb, 0x01, 0x79, 0xb6, 0x93, 0xd7, 0x03, 0x50, 0x0a, 0x13, 0xe2, 0xc8, 0xac, 0xfd, 0x42, 0x8a, 0xfc, 0x93, 0x6c, 0xa1, 0x80, 0x8a, 0x27,
0xea, 0x5c, 0x9a, 0x65, 0x56, 0xa5, 0xd9, 0x1b, 0x50, 0x9c, 0x10, 0x47, 0xa5, 0x96, 0xef, 0x9e, 0xd9, 0x42, 0x11, 0x41, 0xf5, 0x5f, 0x19, 0x28, 0xc7, 0xab, 0x4d, 0x56, 0xbc, 0x6b, 0xfc, 0x64,
0xf3, 0xea, 0xb2, 0xa0, 0x14, 0x26, 0xc4, 0x91, 0x59, 0xfb, 0xd5, 0xcd, 0x44, 0x32, 0x9a, 0x05, 0x49, 0xf1, 0xbd, 0xe7, 0x8d, 0xef, 0xad, 0x4d, 0x6b, 0x0d, 0x76, 0xe4, 0x1c, 0xe6, 0x45, 0x0d,
0x54, 0xbc, 0x9f, 0x2d, 0x14, 0x11, 0x54, 0xff, 0x99, 0x81, 0x72, 0xbc, 0xda, 0x64, 0xc5, 0xbb, 0xa8, 0x08, 0x4d, 0x76, 0xdc, 0xb3, 0xdd, 0x86, 0x8a, 0x7b, 0x4d, 0x41, 0x09, 0x5a, 0xf8, 0x18,
0xc6, 0x4f, 0x96, 0x14, 0xdf, 0x7b, 0xde, 0x79, 0x61, 0x6d, 0x5a, 0x6b, 0xb0, 0x23, 0xe7, 0x30, 0xf2, 0x0f, 0x3d, 0x6e, 0x3b, 0xcf, 0x6d, 0xbf, 0xf9, 0xfd, 0xb6, 0x4f, 0xfa, 0xdc, 0x78, 0xf1,
0x2f, 0x6a, 0x40, 0x45, 0x68, 0xb2, 0xe3, 0x9e, 0xed, 0x36, 0x54, 0xdc, 0x2c, 0x0a, 0x4a, 0xd0, 0xa4, 0xaf, 0x76, 0xba, 0xca, 0x69, 0xbd, 0xad, 0x04, 0xea, 0xf8, 0x1a, 0x64, 0x4d, 0xf2, 0xd5,
0xc2, 0xc7, 0x90, 0x7f, 0xe4, 0x71, 0xdb, 0x79, 0x6e, 0xfb, 0xdd, 0x17, 0xdb, 0xbe, 0xdf, 0xe7, 0x45, 0xf2, 0x70, 0xe2, 0xd0, 0x65, 0x27, 0xe1, 0x1a, 0x64, 0x9f, 0x50, 0xf2, 0x28, 0x79, 0x24,
0xc6, 0x8b, 0xf7, 0xfb, 0x6a, 0xa7, 0xab, 0x9c, 0xd4, 0xdb, 0x4a, 0xa0, 0x8e, 0xaf, 0x40, 0xd6, 0x70, 0xe8, 0x47, 0x5c, 0x0c, 0xfb, 0x90, 0xe3, 0xf1, 0xc2, 0x00, 0x41, 0xc4, 0xd0, 0x4b, 0xb8,
0x24, 0xdf, 0x9c, 0x27, 0x0f, 0x27, 0x0e, 0x5d, 0x74, 0x12, 0xae, 0x40, 0xf6, 0x29, 0x25, 0x8f, 0x00, 0xd9, 0x46, 0x57, 0x61, 0x0b, 0x02, 0x41, 0x59, 0xa0, 0x6a, 0xaf, 0x25, 0x37, 0x64, 0x94,
0x93, 0x47, 0x02, 0x87, 0x5e, 0xe1, 0x62, 0xd8, 0x87, 0x1c, 0x8f, 0x17, 0x06, 0x08, 0x22, 0x86, 0xae, 0xde, 0x85, 0xbc, 0x08, 0x02, 0x5b, 0x2c, 0x51, 0x18, 0xd0, 0x4b, 0x41, 0x33, 0xb0, 0x91,
0x5e, 0xc3, 0x05, 0xc8, 0x36, 0xba, 0x0a, 0x5b, 0x10, 0x08, 0xca, 0x02, 0x55, 0x7b, 0x2d, 0xb9, 0x0a, 0xa5, 0x67, 0xa7, 0x47, 0xb2, 0x82, 0xd2, 0xc9, 0xa9, 0xce, 0xa2, 0x5c, 0xd5, 0x83, 0x72,
0x21, 0xa3, 0x74, 0xf5, 0x16, 0xe4, 0x45, 0x10, 0xd8, 0x62, 0x89, 0xc2, 0x80, 0x5e, 0x0b, 0x9a, 0xbc, 0xdc, 0x7c, 0x31, 0x57, 0xc9, 0xbf, 0xa7, 0xa0, 0x14, 0x2b, 0x1f, 0x59, 0xe1, 0x42, 0x4c,
0x81, 0x8d, 0x54, 0x28, 0x3d, 0x3d, 0x39, 0x92, 0x15, 0x94, 0x4e, 0x4e, 0x75, 0x16, 0xe5, 0xaa, 0xd3, 0x7e, 0xa2, 0x12, 0xd3, 0x20, 0x5e, 0x90, 0x1a, 0xc0, 0xa1, 0x3a, 0x43, 0x2e, 0x3b, 0x75,
0x1e, 0x94, 0xe3, 0xe5, 0xe6, 0x8f, 0x92, 0x65, 0xd5, 0xbf, 0xa5, 0xa0, 0x14, 0x2b, 0x1f, 0x59, 0x2f, 0x68, 0x89, 0xe4, 0x50, 0xbe, 0xfa, 0x97, 0x14, 0xa0, 0xf9, 0x02, 0x74, 0xce, 0xcd, 0xd4,
0xe1, 0x42, 0x4c, 0xd3, 0x7e, 0xaa, 0x12, 0xd3, 0x20, 0x5e, 0x90, 0x1a, 0xc0, 0xa1, 0x3a, 0x43, 0x4f, 0xe9, 0x66, 0xf5, 0xcf, 0x29, 0xa8, 0x24, 0xab, 0xce, 0x39, 0xf7, 0x6e, 0xfc, 0xa4, 0xee,
0x2e, 0x3a, 0x75, 0x3f, 0xd2, 0x12, 0xc9, 0xa1, 0x7c, 0xf5, 0x4f, 0x29, 0x40, 0xf3, 0x05, 0xe8, 0xfd, 0x33, 0x0d, 0xeb, 0x89, 0x5a, 0xf3, 0xb2, 0xde, 0x7d, 0x09, 0x9b, 0x86, 0x4e, 0x27, 0x8e,
0x9c, 0x9b, 0xa9, 0x9f, 0xd2, 0xcd, 0xea, 0x1f, 0x53, 0x50, 0x49, 0x56, 0x9d, 0x73, 0xee, 0x5d, 0xed, 0x53, 0x4b, 0xbb, 0x50, 0x4d, 0xfa, 0x98, 0x9a, 0x52, 0x95, 0x6f, 0x1a, 0xfb, 0xdf, 0x5f,
0xfb, 0x49, 0xdd, 0xfb, 0x47, 0x1a, 0xd6, 0x13, 0xb5, 0xe6, 0x45, 0xbd, 0xfb, 0x1a, 0x36, 0x0d, 0xcd, 0xd6, 0x5a, 0x33, 0xbd, 0x36, 0x53, 0x3b, 0xdc, 0x6a, 0x35, 0xe5, 0xd3, 0x5e, 0x77, 0x20,
0x9d, 0x4e, 0x1c, 0xdb, 0xa7, 0x96, 0x76, 0xae, 0x9a, 0xf4, 0x09, 0x35, 0xa5, 0x2a, 0xdf, 0x34, 0x77, 0x1a, 0x9f, 0xab, 0x67, 0x9d, 0x5f, 0x75, 0xba, 0x9f, 0x76, 0x14, 0x64, 0xcc, 0xd1, 0x7e,
0xf6, 0x5f, 0x5c, 0xcd, 0xd6, 0x5a, 0x33, 0xbd, 0x36, 0x53, 0x3b, 0xdc, 0x6a, 0x35, 0xe5, 0x93, 0xc4, 0x65, 0xdf, 0x03, 0x34, 0xef, 0x14, 0xbe, 0x0a, 0xcb, 0xdc, 0x42, 0x2f, 0xe1, 0x2d, 0xd8,
0x5e, 0x77, 0x20, 0x77, 0x1a, 0x0f, 0xd5, 0xd3, 0xce, 0x2f, 0x3b, 0xdd, 0x2f, 0x3b, 0x0a, 0x32, 0xe8, 0x74, 0xd5, 0x7e, 0xab, 0x29, 0xab, 0xf2, 0x83, 0x07, 0x72, 0x63, 0xd0, 0x17, 0xd7, 0xfb,
0xe6, 0x68, 0xaf, 0x70, 0xd9, 0xf7, 0x00, 0xcd, 0x3b, 0x85, 0x2f, 0xc3, 0x32, 0xb7, 0xd0, 0x6b, 0x88, 0x3d, 0x48, 0x2c, 0xf0, 0xea, 0x9f, 0x32, 0xb0, 0xb5, 0xc4, 0x13, 0x5c, 0x0f, 0x6e, 0x16,
0x78, 0x0b, 0x36, 0x3a, 0x5d, 0xb5, 0xdf, 0x6a, 0xca, 0xaa, 0x7c, 0xef, 0x9e, 0xdc, 0x18, 0xf4, 0xe2, 0xb2, 0xf3, 0xee, 0x65, 0xbc, 0xaf, 0xb1, 0x82, 0xa0, 0x47, 0x5c, 0x3f, 0xb8, 0x88, 0xdc,
0xc5, 0xf5, 0x3e, 0x62, 0x0f, 0x12, 0x0b, 0xbc, 0xfa, 0x87, 0x0c, 0x6c, 0x2d, 0xf1, 0x04, 0xd7, 0x02, 0x16, 0x25, 0xcb, 0x37, 0x86, 0x06, 0x75, 0x83, 0xd7, 0x10, 0x71, 0xdd, 0xd8, 0x98, 0xe1,
0x83, 0x9b, 0x85, 0xb8, 0xec, 0x7c, 0x74, 0x11, 0xef, 0x6b, 0xac, 0x20, 0xe8, 0x11, 0xd7, 0x0f, 0xe2, 0x41, 0xe4, 0x67, 0x80, 0x1d, 0xdb, 0x33, 0x7c, 0xe3, 0x31, 0x55, 0x0d, 0x2b, 0x7c, 0x3a,
0x2e, 0x22, 0x37, 0x80, 0x45, 0xc9, 0xf2, 0x8d, 0xa1, 0x41, 0xdd, 0xe0, 0x35, 0x44, 0x5c, 0x37, 0x61, 0xd7, 0x8f, 0xac, 0x82, 0x42, 0x49, 0xcb, 0xf2, 0x23, 0xb6, 0x45, 0x47, 0x64, 0x8e, 0xcd,
0x36, 0x66, 0xb8, 0x78, 0x10, 0xf9, 0x19, 0x60, 0xc7, 0xf6, 0x0c, 0xdf, 0x78, 0x42, 0x55, 0xc3, 0x36, 0xf3, 0x8c, 0x82, 0x42, 0x49, 0xc4, 0xbe, 0x01, 0x65, 0xdd, 0x9e, 0xb2, 0x9a, 0x4c, 0xf0,
0x0a, 0x9f, 0x4e, 0xd8, 0xf5, 0x23, 0xab, 0xa0, 0x50, 0xd2, 0xb2, 0xfc, 0x88, 0x6d, 0xd1, 0x11, 0xd8, 0xd9, 0x91, 0x52, 0x4a, 0x02, 0x8b, 0x28, 0x41, 0xb5, 0x3d, 0x7b, 0xb3, 0x29, 0x2b, 0x25,
0x99, 0x63, 0xb3, 0xcd, 0x3c, 0xa3, 0xa0, 0x50, 0x12, 0xb1, 0xaf, 0x41, 0x59, 0xb7, 0xa7, 0xac, 0x81, 0x09, 0xca, 0x4d, 0xd8, 0x20, 0xa3, 0x91, 0xcb, 0x8c, 0x87, 0x86, 0xc4, 0xfd, 0xa1, 0x12,
0x26, 0x13, 0x3c, 0x76, 0x76, 0xa4, 0x94, 0x92, 0xc0, 0x22, 0x4a, 0x50, 0x6d, 0xcf, 0xde, 0x6c, 0xc1, 0x9c, 0xb8, 0x73, 0x02, 0x85, 0x30, 0x0e, 0xec, 0xa8, 0x66, 0x91, 0x50, 0x1d, 0xf1, 0x6e,
0xca, 0x4a, 0x49, 0x60, 0x82, 0x72, 0x1d, 0x36, 0xc8, 0x68, 0xe4, 0x32, 0xe3, 0xa1, 0x21, 0x71, 0x97, 0xde, 0x2b, 0x2a, 0x05, 0x2b, 0x14, 0xde, 0x80, 0xb2, 0xe1, 0xa9, 0xb3, 0x27, 0xe8, 0xf4,
0x7f, 0xa8, 0x44, 0x30, 0x27, 0xee, 0xdc, 0x87, 0x42, 0x18, 0x07, 0x76, 0x54, 0xb3, 0x48, 0xa8, 0x6e, 0x7a, 0xaf, 0xa0, 0x94, 0x0c, 0x2f, 0x7a, 0xbe, 0xab, 0x7e, 0x93, 0x86, 0x4a, 0xf2, 0x09,
0x8e, 0x78, 0x39, 0x4b, 0xef, 0x15, 0x95, 0x82, 0x15, 0x0a, 0xaf, 0x41, 0xd9, 0xf0, 0xd4, 0xd9, 0x1d, 0x37, 0xa1, 0x60, 0xda, 0x1a, 0xe1, 0xa9, 0x25, 0xbe, 0xdf, 0xec, 0x3d, 0xe7, 0xd5, 0xbd,
0x13, 0x6e, 0x7a, 0x37, 0xbd, 0x57, 0x50, 0x4a, 0x86, 0x17, 0xbd, 0xd9, 0x55, 0xbf, 0x4b, 0x43, 0xd6, 0x0e, 0xf8, 0x4a, 0xa4, 0xb9, 0xf3, 0x8f, 0x14, 0x14, 0x42, 0x18, 0x5f, 0x81, 0xac, 0x43,
0x25, 0xf9, 0x04, 0x8d, 0x9b, 0x50, 0x30, 0x6d, 0x8d, 0xf0, 0xd4, 0x12, 0xdf, 0x3f, 0xf6, 0x5e, 0xfc, 0x31, 0x37, 0x97, 0x3b, 0x4a, 0xa3, 0x94, 0xc2, 0xdb, 0x0c, 0xf7, 0x1c, 0x62, 0xf1, 0x14,
0xf2, 0x6a, 0x5d, 0x6b, 0x07, 0x7c, 0x25, 0xd2, 0xdc, 0xf9, 0x7b, 0x0a, 0x0a, 0x21, 0x8c, 0x2f, 0x08, 0x70, 0xd6, 0x66, 0xf3, 0x6a, 0x52, 0xa2, 0xf3, 0xcb, 0x89, 0x3d, 0x99, 0x50, 0xcb, 0xf7,
0x41, 0xd6, 0x21, 0xfe, 0x98, 0x9b, 0xcb, 0x1d, 0xa5, 0x51, 0x4a, 0xe1, 0x6d, 0x86, 0x7b, 0x0e, 0xc2, 0x79, 0x0d, 0xf0, 0x46, 0x00, 0xe3, 0x77, 0x60, 0xd3, 0x77, 0x89, 0x61, 0x26, 0xb8, 0x59,
0xb1, 0x78, 0x0a, 0x04, 0x38, 0x6b, 0xb3, 0x79, 0x35, 0x29, 0xd1, 0xf9, 0xe5, 0xc4, 0x9e, 0x4c, 0xce, 0x45, 0xa1, 0x20, 0x22, 0x1f, 0xc2, 0xb5, 0xd0, 0xae, 0x4e, 0x7d, 0xa2, 0x8d, 0xa9, 0x3e,
0xa8, 0xe5, 0x7b, 0xe1, 0xbc, 0x06, 0x78, 0x23, 0x80, 0xf1, 0x87, 0xb0, 0xe9, 0xbb, 0xc4, 0x30, 0x53, 0xca, 0xf3, 0xf7, 0xd9, 0xab, 0x01, 0xa1, 0x19, 0xc8, 0x43, 0xdd, 0xea, 0x77, 0x29, 0xd8,
0x13, 0xdc, 0x2c, 0xe7, 0xa2, 0x50, 0x10, 0x91, 0x0f, 0xe1, 0x4a, 0x68, 0x57, 0xa7, 0x3e, 0xd1, 0x0c, 0xaf, 0x53, 0x7a, 0x14, 0xac, 0x53, 0x00, 0x62, 0x59, 0xb6, 0x1f, 0x0f, 0xd7, 0x62, 0x2a,
0xc6, 0x54, 0x9f, 0x29, 0xe5, 0xf9, 0xfb, 0xe6, 0xe5, 0x80, 0xd0, 0x0c, 0xe4, 0xa1, 0x6e, 0xf5, 0x2f, 0xe8, 0xd5, 0xea, 0x91, 0x92, 0x12, 0x33, 0xb0, 0x33, 0x01, 0x98, 0x49, 0x56, 0x86, 0xed,
0xfb, 0x14, 0x6c, 0x86, 0xd7, 0x29, 0x3d, 0x0a, 0xd6, 0x09, 0x00, 0xb1, 0x2c, 0xdb, 0x8f, 0x87, 0x3a, 0x94, 0x82, 0xef, 0x23, 0xfc, 0x23, 0x9b, 0xb8, 0x80, 0x83, 0x80, 0xd8, 0xbd, 0x0b, 0x6f,
0x6b, 0x31, 0x95, 0x17, 0xf4, 0x6a, 0xf5, 0x48, 0x49, 0x89, 0x19, 0xd8, 0x99, 0x00, 0xcc, 0x24, 0x43, 0xee, 0x9c, 0x8e, 0x0c, 0x2b, 0x78, 0xf5, 0x14, 0x8d, 0xf0, 0x25, 0x37, 0x1b, 0xbd, 0xe4,
0x2b, 0xc3, 0x76, 0x15, 0x4a, 0xc1, 0xf7, 0x05, 0xfe, 0x91, 0x4a, 0x5c, 0xc0, 0x41, 0x40, 0xec, 0x1e, 0xfd, 0x21, 0x05, 0x5b, 0x9a, 0x3d, 0x99, 0xf7, 0xf7, 0x08, 0xcd, 0xbd, 0x02, 0x78, 0x9f,
0xde, 0x85, 0xb7, 0x21, 0x77, 0x46, 0x47, 0x86, 0x15, 0xbc, 0x7a, 0x8a, 0x46, 0xf8, 0x96, 0x9a, 0xa4, 0xbe, 0xf8, 0x78, 0x64, 0xf8, 0xe3, 0xe9, 0x79, 0x4d, 0xb3, 0x27, 0xfb, 0x23, 0xdb, 0x24,
0x8d, 0xde, 0x52, 0x8f, 0x7e, 0x97, 0x82, 0x2d, 0xcd, 0x9e, 0xcc, 0xfb, 0x7b, 0x84, 0xe6, 0x5e, 0xd6, 0x68, 0xf6, 0x95, 0x90, 0xff, 0xd1, 0xde, 0x1d, 0x51, 0xeb, 0xdd, 0x91, 0x1d, 0xfb, 0x66,
0x01, 0xbc, 0x2f, 0x52, 0x5f, 0xdd, 0x1d, 0x19, 0xfe, 0x78, 0x7a, 0x56, 0xd3, 0xec, 0xc9, 0xfe, 0xf8, 0xd1, 0xec, 0xef, 0xd7, 0xe9, 0xcc, 0x71, 0xef, 0xe8, 0xaf, 0xe9, 0x9d, 0x63, 0xd1, 0x57,
0xc8, 0x36, 0x89, 0x35, 0x9a, 0x7d, 0x65, 0xe3, 0x7f, 0xb4, 0x8f, 0x46, 0xd4, 0xfa, 0x68, 0x64, 0x2f, 0x8c, 0x8d, 0x42, 0x87, 0x26, 0xd5, 0xd8, 0x78, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x0c,
0xc7, 0xbe, 0xb9, 0x7d, 0x3e, 0xfb, 0xfb, 0x6d, 0x3a, 0x73, 0xdc, 0x3b, 0xfa, 0x73, 0x7a, 0xe7, 0xab, 0xb6, 0x37, 0x7e, 0x1c, 0x00, 0x00,
0x58, 0xf4, 0xd5, 0x0b, 0x63, 0xa3, 0xd0, 0xa1, 0x49, 0x35, 0x36, 0xde, 0xff, 0x05, 0x00, 0x00,
0xff, 0xff, 0xa2, 0xc3, 0x4e, 0x18, 0xbe, 0x1b, 0x00, 0x00,
} }

28
vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto сгенерированный поставляемый
Просмотреть файл

@@ -101,6 +101,8 @@ message DescriptorProto {
message ExtensionRange { message ExtensionRange {
optional int32 start = 1; optional int32 start = 1;
optional int32 end = 2; optional int32 end = 2;
optional ExtensionRangeOptions options = 3;
} }
repeated ExtensionRange extension_range = 5; repeated ExtensionRange extension_range = 5;
@@ -121,6 +123,14 @@ message DescriptorProto {
repeated string reserved_name = 10; repeated string reserved_name = 10;
} }
message ExtensionRangeOptions {
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
// Clients can define custom options in extensions of this message. See above.
extensions 1000 to max;
}
// Describes a field within a message. // Describes a field within a message.
message FieldDescriptorProto { message FieldDescriptorProto {
enum Type { enum Type {
@@ -351,7 +361,7 @@ message FileOptions {
optional bool cc_generic_services = 16 [default=false]; optional bool cc_generic_services = 16 [default=false];
optional bool java_generic_services = 17 [default=false]; optional bool java_generic_services = 17 [default=false];
optional bool py_generic_services = 18 [default=false]; optional bool py_generic_services = 18 [default=false];
optional bool php_generic_services = 19 [default=false]; optional bool php_generic_services = 42 [default=false];
// Is this file deprecated? // Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations // Depending on the target platform, this can emit Deprecated annotations
@@ -483,13 +493,15 @@ message FieldOptions {
// The jstype option determines the JavaScript type used for values of the // The jstype option determines the JavaScript type used for values of the
// field. The option is permitted only for 64 bit integral and fixed types // field. The option is permitted only for 64 bit integral and fixed types
// (int64, uint64, sint64, fixed64, sfixed64). By default these types are // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
// represented as JavaScript strings. This avoids loss of precision that can // is represented as JavaScript string, which avoids loss of precision that
// happen when a large value is converted to a floating point JavaScript // can happen when a large value is converted to a floating point JavaScript.
// numbers. Specifying JS_NUMBER for the jstype causes the generated // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
// JavaScript code to use the JavaScript "number" type instead of strings. // use the JavaScript "number" type. The behavior of the default option
// This option is an enum to permit additional types to be added, // JS_NORMAL is implementation dependent.
// e.g. goog.math.Integer. //
// This option is an enum to permit additional types to be added, e.g.
// goog.math.Integer.
optional JSType jstype = 6 [default = JS_NORMAL]; optional JSType jstype = 6 [default = JS_NORMAL];
enum JSType { enum JSType {
// Use the default type. // Use the default type.

63
vendor/github.com/golang/protobuf/protoc-gen-go/generator/generator.go сгенерированный поставляемый
Просмотреть файл

@@ -1984,7 +1984,7 @@ func (g *Generator) generateMessage(message *Descriptor) {
case typename == "string": case typename == "string":
def = strconv.Quote(def) def = strconv.Quote(def)
case typename == "[]byte": case typename == "[]byte":
def = "[]byte(" + strconv.Quote(def) + ")" def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
kind = "var " kind = "var "
case def == "inf", def == "-inf", def == "nan": case def == "inf", def == "-inf", def == "nan":
// These names are known to, and defined by, the protocol language. // These names are known to, and defined by, the protocol language.
@@ -2508,6 +2508,67 @@ func (g *Generator) generateMessage(message *Descriptor) {
g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], ccTypeName, fullName) g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], ccTypeName, fullName)
} }
var escapeChars = [256]byte{
'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
}
// unescape reverses the "C" escaping that protoc does for default values of bytes fields.
// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape
// sequences are conveyed, unmodified, into the decoded result.
func unescape(s string) string {
// NB: Sadly, we can't use strconv.Unquote because protoc will escape both
// single and double quotes, but strconv.Unquote only allows one or the
// other (based on actual surrounding quotes of its input argument).
var out []byte
for len(s) > 0 {
// regular character, or too short to be valid escape
if s[0] != '\\' || len(s) < 2 {
out = append(out, s[0])
s = s[1:]
} else if c := escapeChars[s[1]]; c != 0 {
// escape sequence
out = append(out, c)
s = s[2:]
} else if s[1] == 'x' || s[1] == 'X' {
// hex escape, e.g. "\x80
if len(s) < 4 {
// too short to be valid
out = append(out, s[:2]...)
s = s[2:]
continue
}
v, err := strconv.ParseUint(s[2:4], 16, 8)
if err != nil {
out = append(out, s[:4]...)
} else {
out = append(out, byte(v))
}
s = s[4:]
} else if '0' <= s[1] && s[1] <= '7' {
// octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164"
// so consume up to 2 more bytes or up to end-of-string
n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567"))
if n > 3 {
n = 3
}
v, err := strconv.ParseUint(s[1:1+n], 8, 8)
if err != nil {
out = append(out, s[:1+n]...)
} else {
out = append(out, byte(v))
}
s = s[1+n:]
} else {
// bad escape, just propagate the slash as-is
out = append(out, s[0])
s = s[1:]
}
}
return string(out)
}
func (g *Generator) generateExtension(ext *ExtensionDescriptor) { func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
ccTypeName := ext.DescName() ccTypeName := ext.DescName()

29
vendor/github.com/golang/protobuf/protoc-gen-go/generator/name_test.go сгенерированный поставляемый
Просмотреть файл

@@ -83,3 +83,32 @@ func TestGoPackageOption(t *testing.T) {
} }
} }
} }
func TestUnescape(t *testing.T) {
tests := []struct {
in string
out string
}{
// successful cases, including all kinds of escapes
{"", ""},
{"foo bar baz frob nitz", "foo bar baz frob nitz"},
{`\000\001\002\003\004\005\006\007`, string([]byte{0, 1, 2, 3, 4, 5, 6, 7})},
{`\a\b\f\n\r\t\v\\\?\'\"`, string([]byte{'\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '?', '\'', '"'})},
{`\x10\x20\x30\x40\x50\x60\x70\x80`, string([]byte{16, 32, 48, 64, 80, 96, 112, 128})},
// variable length octal escapes
{`\0\018\222\377\3\04\005\6\07`, string([]byte{0, 1, '8', 0222, 255, 3, 4, 5, 6, 7})},
// malformed escape sequences left as is
{"foo \\g bar", "foo \\g bar"},
{"foo \\xg0 bar", "foo \\xg0 bar"},
{"\\", "\\"},
{"\\x", "\\x"},
{"\\xf", "\\xf"},
{"\\777", "\\777"}, // overflows byte
}
for _, tc := range tests {
s := unescape(tc.in)
if s != tc.out {
t.Errorf("doUnescape(%q) = %q; should have been %q", tc.in, s, tc.out)
}
}
}

1
vendor/github.com/golang/protobuf/protoc-gen-go/plugin/plugin.proto сгенерированный поставляемый
Просмотреть файл

@@ -91,6 +91,7 @@ message CodeGeneratorRequest {
// The version number of protocol compiler. // The version number of protocol compiler.
optional Version compiler_version = 3; optional Version compiler_version = 3;
} }
// The plugin writes an encoded CodeGeneratorResponse to stdout. // The plugin writes an encoded CodeGeneratorResponse to stdout.

10
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go сгенерированный поставляемый
Просмотреть файл

@@ -62,6 +62,16 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// any.Unpack(foo) // any.Unpack(foo)
// ... // ...
// //
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use // The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack // 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/' // methods only use the fully qualified type name after the last '/'

10
vendor/github.com/golang/protobuf/ptypes/any/any.proto сгенерированный поставляемый
Просмотреть файл

@@ -74,6 +74,16 @@ option objc_class_prefix = "GPB";
// any.Unpack(foo) // any.Unpack(foo)
// ... // ...
// //
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := ptypes.MarshalAny(foo)
// ...
// foo := &pb.Foo{}
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use // The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack // 'type.googleapis.com/full.type.name' as the type URL and the unpack
// methods only use the fully qualified type name after the last '/' // methods only use the fully qualified type name after the last '/'

50
vendor/github.com/gorilla/mux/README.md сгенерированный поставляемый
Просмотреть файл

@@ -15,7 +15,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`. * It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers. * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
* URL hosts and paths can have variables with an optional regular expression. * URL hosts, paths and query values can have variables with an optional regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining references to resources. * Registered URLs can be built, or "reversed", which helps maintaining references to resources.
* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching. * Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
@@ -24,9 +24,9 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Install](#install) * [Install](#install)
* [Examples](#examples) * [Examples](#examples)
* [Matching Routes](#matching-routes) * [Matching Routes](#matching-routes)
* [Listing Routes](#listing-routes)
* [Static Files](#static-files) * [Static Files](#static-files)
* [Registered URLs](#registered-urls) * [Registered URLs](#registered-urls)
* [Walking Routes](#walking-routes)
* [Full Example](#full-example) * [Full Example](#full-example)
--- ---
@@ -168,7 +168,6 @@ s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details" // "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler) s.HandleFunc("/{key}/details", ProductDetailsHandler)
``` ```
### Listing Routes ### Listing Routes
Routes on a mux can be listed using the Router.Walk method—useful for generating documentation: Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
@@ -191,9 +190,9 @@ func handler(w http.ResponseWriter, r *http.Request) {
func main() { func main() {
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/", handler) r.HandleFunc("/", handler)
r.Methods("POST").HandleFunc("/products", handler) r.HandleFunc("/products", handler).Methods("POST")
r.Methods("GET").HandleFunc("/articles", handler) r.HandleFunc("/articles", handler).Methods("GET")
r.Methods("GET", "PUT").HandleFunc("/articles/{id}", handler) r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate() t, err := route.GetPathTemplate()
if err != nil { if err != nil {
@@ -269,19 +268,21 @@ url, err := r.Get("article").URL("category", "technology", "id", "42")
"/articles/technology/42" "/articles/technology/42"
``` ```
This also works for host variables: This also works for host and query value variables:
```go ```go
r := mux.NewRouter() r := mux.NewRouter()
r.Host("{subdomain}.domain.com"). r.Host("{subdomain}.domain.com").
Path("/articles/{category}/{id:[0-9]+}"). Path("/articles/{category}/{id:[0-9]+}").
Queries("filter", "{filter}").
HandlerFunc(ArticleHandler). HandlerFunc(ArticleHandler).
Name("article") Name("article")
// url.String() will be "http://news.domain.com/articles/technology/42" // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news", url, err := r.Get("article").URL("subdomain", "news",
"category", "technology", "category", "technology",
"id", "42") "id", "42",
"filter", "gorilla")
``` ```
All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match. All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
@@ -319,6 +320,37 @@ url, err := r.Get("article").URL("subdomain", "news",
"id", "42") "id", "42")
``` ```
### Walking Routes
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
the following prints all of the registered routes:
```go
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
p, err := route.GetPathRegexp()
if err != nil {
return err
}
m, err := route.GetMethods()
if err != nil {
return err
}
fmt.Println(strings.Join(m, ","), t, p)
return nil
})
```
## Full Example ## Full Example
Here's a complete, runnable example of a small `mux` based server: Here's a complete, runnable example of a small `mux` based server:

12
vendor/github.com/gorilla/mux/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -12,8 +12,8 @@ or other conditions. The main features are:
* Requests can be matched based on URL host, path, path prefix, schemes, * Requests can be matched based on URL host, path, path prefix, schemes,
header and query values, HTTP methods or using custom matchers. header and query values, HTTP methods or using custom matchers.
* URL hosts and paths can have variables with an optional regular * URL hosts, paths and query values can have variables with an optional
expression. regular expression.
* Registered URLs can be built, or "reversed", which helps maintaining * Registered URLs can be built, or "reversed", which helps maintaining
references to resources. references to resources.
* Routes can be used as subrouters: nested routes are only tested if the * Routes can be used as subrouters: nested routes are only tested if the
@@ -188,18 +188,20 @@ key/value pairs for the route variables. For the previous route, we would do:
"/articles/technology/42" "/articles/technology/42"
This also works for host variables: This also works for host and query value variables:
r := mux.NewRouter() r := mux.NewRouter()
r.Host("{subdomain}.domain.com"). r.Host("{subdomain}.domain.com").
Path("/articles/{category}/{id:[0-9]+}"). Path("/articles/{category}/{id:[0-9]+}").
Queries("filter", "{filter}").
HandlerFunc(ArticleHandler). HandlerFunc(ArticleHandler).
Name("article") Name("article")
// url.String() will be "http://news.domain.com/articles/technology/42" // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news", url, err := r.Get("article").URL("subdomain", "news",
"category", "technology", "category", "technology",
"id", "42") "id", "42",
"filter", "gorilla")
All variables defined in the route are required, and their values must All variables defined in the route are required, and their values must
conform to the corresponding patterns. These requirements guarantee that a conform to the corresponding patterns. These requirements guarantee that a

48
vendor/github.com/gorilla/mux/mux.go сгенерированный поставляемый
Просмотреть файл

@@ -13,6 +13,10 @@ import (
"strings" "strings"
) )
var (
ErrMethodMismatch = errors.New("method is not allowed")
)
// NewRouter returns a new router instance. // NewRouter returns a new router instance.
func NewRouter() *Router { func NewRouter() *Router {
return &Router{namedRoutes: make(map[string]*Route), KeepContext: false} return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
@@ -39,6 +43,10 @@ func NewRouter() *Router {
type Router struct { type Router struct {
// Configurable Handler to be used when no route matches. // Configurable Handler to be used when no route matches.
NotFoundHandler http.Handler NotFoundHandler http.Handler
// Configurable Handler to be used when the request method does not match the route.
MethodNotAllowedHandler http.Handler
// Parent route, if this is a subrouter. // Parent route, if this is a subrouter.
parent parentRoute parent parentRoute
// Routes to be matched, in order. // Routes to be matched, in order.
@@ -65,6 +73,11 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
} }
} }
if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
match.Handler = r.MethodNotAllowedHandler
return true
}
// Closest match for a router (includes sub-routers) // Closest match for a router (includes sub-routers)
if r.NotFoundHandler != nil { if r.NotFoundHandler != nil {
match.Handler = r.NotFoundHandler match.Handler = r.NotFoundHandler
@@ -105,9 +118,15 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
req = setVars(req, match.Vars) req = setVars(req, match.Vars)
req = setCurrentRoute(req, match.Route) req = setCurrentRoute(req, match.Route)
} }
if handler == nil && match.MatchErr == ErrMethodMismatch {
handler = methodNotAllowedHandler()
}
if handler == nil { if handler == nil {
handler = http.NotFoundHandler() handler = http.NotFoundHandler()
} }
if !r.KeepContext { if !r.KeepContext {
defer contextClear(req) defer contextClear(req)
} }
@@ -176,6 +195,13 @@ func (r *Router) UseEncodedPath() *Router {
// parentRoute // parentRoute
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
func (r *Router) getBuildScheme() string {
if r.parent != nil {
return r.parent.getBuildScheme()
}
return ""
}
// getNamedRoutes returns the map where named routes are registered. // getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route { func (r *Router) getNamedRoutes() map[string]*Route {
if r.namedRoutes == nil { if r.namedRoutes == nil {
@@ -299,10 +325,6 @@ type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error { func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
for _, t := range r.routes { for _, t := range r.routes {
if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
continue
}
err := walkFn(t, r, ancestors) err := walkFn(t, r, ancestors)
if err == SkipRouter { if err == SkipRouter {
continue continue
@@ -312,10 +334,12 @@ func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
} }
for _, sr := range t.matchers { for _, sr := range t.matchers {
if h, ok := sr.(*Router); ok { if h, ok := sr.(*Router); ok {
ancestors = append(ancestors, t)
err := h.walk(walkFn, ancestors) err := h.walk(walkFn, ancestors)
if err != nil { if err != nil {
return err return err
} }
ancestors = ancestors[:len(ancestors)-1]
} }
} }
if h, ok := t.handler.(*Router); ok { if h, ok := t.handler.(*Router); ok {
@@ -339,6 +363,11 @@ type RouteMatch struct {
Route *Route Route *Route
Handler http.Handler Handler http.Handler
Vars map[string]string Vars map[string]string
// MatchErr is set to appropriate matching error
// It is set to ErrMethodMismatch if there is a mismatch in
// the request method and route method
MatchErr error
} }
type contextKey int type contextKey int
@@ -458,7 +487,7 @@ func mapFromPairsToString(pairs ...string) (map[string]string, error) {
return m, nil return m, nil
} }
// mapFromPairsToRegex converts variadic string paramers to a // mapFromPairsToRegex converts variadic string parameters to a
// string to regex map. // string to regex map.
func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) { func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
length, err := checkPairs(pairs...) length, err := checkPairs(pairs...)
@@ -540,3 +569,12 @@ func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]s
} }
return true return true
} }
// methodNotAllowed replies to the request with an HTTP status code 405.
func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
}
// methodNotAllowedHandler returns a simple request handler
// that replies to each request with a status code 405.
func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }

145
vendor/github.com/gorilla/mux/mux_test.go сгенерированный поставляемый
Просмотреть файл

@@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"reflect"
"strings" "strings"
"testing" "testing"
) )
@@ -35,6 +36,7 @@ type routeTest struct {
scheme string // the expected scheme of the built URL scheme string // the expected scheme of the built URL
host string // the expected host of the built URL host string // the expected host of the built URL
path string // the expected path of the built URL path string // the expected path of the built URL
query string // the expected query string of the built URL
pathTemplate string // the expected path template of the route pathTemplate string // the expected path template of the route
hostTemplate string // the expected host template of the route hostTemplate string // the expected host template of the route
methods []string // the expected route methods methods []string // the expected route methods
@@ -743,6 +745,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{}, vars: map[string]string{},
host: "", host: "",
path: "", path: "",
query: "foo=bar&baz=ding",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -752,6 +755,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{}, vars: map[string]string{},
host: "", host: "",
path: "", path: "",
query: "foo=bar&baz=ding",
pathTemplate: `/api`, pathTemplate: `/api`,
hostTemplate: `www.example.com`, hostTemplate: `www.example.com`,
shouldMatch: true, shouldMatch: true,
@@ -763,6 +767,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{}, vars: map[string]string{},
host: "", host: "",
path: "", path: "",
query: "foo=bar&baz=ding",
pathTemplate: `/api`, pathTemplate: `/api`,
hostTemplate: `www.example.com`, hostTemplate: `www.example.com`,
shouldMatch: true, shouldMatch: true,
@@ -783,6 +788,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "bar"}, vars: map[string]string{"v1": "bar"},
host: "", host: "",
path: "", path: "",
query: "foo=bar",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -792,6 +798,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "bar", "v2": "ding"}, vars: map[string]string{"v1": "bar", "v2": "ding"},
host: "", host: "",
path: "", path: "",
query: "foo=bar&baz=ding",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -801,6 +808,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "10"}, vars: map[string]string{"v1": "10"},
host: "", host: "",
path: "", path: "",
query: "foo=10",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -819,6 +827,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1"}, vars: map[string]string{"v1": "1"},
host: "", host: "",
path: "", path: "",
query: "foo=1",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -828,6 +837,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1"}, vars: map[string]string{"v1": "1"},
host: "", host: "",
path: "", path: "",
query: "foo=1",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -846,6 +856,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v1": "1a"}, vars: map[string]string{"v1": "1a"},
host: "", host: "",
path: "", path: "",
query: "foo=1a",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -864,6 +875,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "bar"}, vars: map[string]string{"v-1": "bar"},
host: "", host: "",
path: "", path: "",
query: "foo=bar",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -873,6 +885,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "bar", "v-2": "ding"}, vars: map[string]string{"v-1": "bar", "v-2": "ding"},
host: "", host: "",
path: "", path: "",
query: "foo=bar&baz=ding",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -882,6 +895,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "10"}, vars: map[string]string{"v-1": "10"},
host: "", host: "",
path: "", path: "",
query: "foo=10",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -891,6 +905,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"v-1": "1a"}, vars: map[string]string{"v-1": "1a"},
host: "", host: "",
path: "", path: "",
query: "foo=1a",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -900,6 +915,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{}, vars: map[string]string{},
host: "", host: "",
path: "", path: "",
query: "foo=",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -918,6 +934,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{}, vars: map[string]string{},
host: "", host: "",
path: "", path: "",
query: "foo=",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -945,6 +962,7 @@ func TestQueries(t *testing.T) {
vars: map[string]string{"foo": ""}, vars: map[string]string{"foo": ""},
host: "", host: "",
path: "", path: "",
query: "foo=",
shouldMatch: true, shouldMatch: true,
}, },
{ {
@@ -956,6 +974,16 @@ func TestQueries(t *testing.T) {
path: "", path: "",
shouldMatch: false, shouldMatch: false,
}, },
{
title: "Queries route with pattern, match, escaped value",
route: new(Route).Queries("foo", "{v1}"),
request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
vars: map[string]string{"v1": "%bar& /=?"},
host: "",
path: "",
query: "foo=%25bar%26+%2F%3D%3F",
shouldMatch: true,
},
} }
for _, test := range tests { for _, test := range tests {
@@ -1187,6 +1215,28 @@ func TestSubRouter(t *testing.T) {
pathTemplate: `/{category}`, pathTemplate: `/{category}`,
shouldMatch: true, shouldMatch: true,
}, },
{
title: "Build with scheme on parent router",
route: new(Route).Schemes("ftp").Host("google.com").Subrouter().Path("/"),
request: newRequest("GET", "ftp://google.com/"),
scheme: "ftp",
host: "google.com",
path: "/",
pathTemplate: `/`,
hostTemplate: `google.com`,
shouldMatch: true,
},
{
title: "Prefer scheme on child route when building URLs",
route: new(Route).Schemes("https", "ftp").Host("google.com").Subrouter().Schemes("ftp").Path("/"),
request: newRequest("GET", "ftp://google.com/"),
scheme: "ftp",
host: "google.com",
path: "/",
pathTemplate: `/`,
hostTemplate: `google.com`,
shouldMatch: true,
},
} }
for _, test := range tests { for _, test := range tests {
@@ -1382,11 +1432,55 @@ func TestWalkNested(t *testing.T) {
l2 := l1.PathPrefix("/l").Subrouter() l2 := l1.PathPrefix("/l").Subrouter()
l2.Path("/a") l2.Path("/a")
paths := []string{"/g", "/g/o", "/g/o/r", "/g/o/r/i", "/g/o/r/i/l", "/g/o/r/i/l/l", "/g/o/r/i/l/l/a"} testCases := []struct {
path string
ancestors []*Route
}{
{"/g", []*Route{}},
{"/g/o", []*Route{g.parent.(*Route)}},
{"/g/o/r", []*Route{g.parent.(*Route), o.parent.(*Route)}},
{"/g/o/r/i", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route)}},
{"/g/o/r/i/l", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route)}},
{"/g/o/r/i/l/l", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route), l1.parent.(*Route)}},
{"/g/o/r/i/l/l/a", []*Route{g.parent.(*Route), o.parent.(*Route), r.parent.(*Route), i.parent.(*Route), l1.parent.(*Route), l2.parent.(*Route)}},
}
idx := 0
err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
path := testCases[idx].path
tpl := route.regexp.path.template
if tpl != path {
t.Errorf(`Expected %s got %s`, path, tpl)
}
currWantAncestors := testCases[idx].ancestors
if !reflect.DeepEqual(currWantAncestors, ancestors) {
t.Errorf(`Expected %+v got %+v`, currWantAncestors, ancestors)
}
idx++
return nil
})
if err != nil {
panic(err)
}
if idx != len(testCases) {
t.Errorf("Expected %d routes, found %d", len(testCases), idx)
}
}
func TestWalkSubrouters(t *testing.T) {
router := NewRouter()
g := router.Path("/g").Subrouter()
o := g.PathPrefix("/o").Subrouter()
o.Methods("GET")
o.Methods("PUT")
// all 4 routes should be matched, but final 2 routes do not have path templates
paths := []string{"/g", "/g/o", "", ""}
idx := 0 idx := 0
err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error { err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
path := paths[idx] path := paths[idx]
tpl := route.regexp.path.template tpl, _ := route.GetPathTemplate()
if tpl != path { if tpl != path {
t.Errorf(`Expected %s got %s`, path, tpl) t.Errorf(`Expected %s got %s`, path, tpl)
} }
@@ -1492,6 +1586,7 @@ func testRoute(t *testing.T, test routeTest) {
route := test.route route := test.route
vars := test.vars vars := test.vars
shouldMatch := test.shouldMatch shouldMatch := test.shouldMatch
query := test.query
shouldRedirect := test.shouldRedirect shouldRedirect := test.shouldRedirect
uri := url.URL{ uri := url.URL{
Scheme: test.scheme, Scheme: test.scheme,
@@ -1561,6 +1656,13 @@ func testRoute(t *testing.T, test routeTest) {
return return
} }
} }
if query != "" {
u, _ := route.URL(mapToPairs(match.Vars)...)
if query != u.RawQuery {
t.Errorf("(%v) URL query not equal: expected %v, got %v", test.title, query, u.RawQuery)
return
}
}
if shouldRedirect && match.Handler == nil { if shouldRedirect && match.Handler == nil {
t.Errorf("(%v) Did not redirect", test.title) t.Errorf("(%v) Did not redirect", test.title)
return return
@@ -1769,3 +1871,42 @@ func newRequest(method, url string) *http.Request {
} }
return req return req
} }
func TestNoMatchMethodErrorHandler(t *testing.T) {
func1 := func(w http.ResponseWriter, r *http.Request) {}
r := NewRouter()
r.HandleFunc("/", func1).Methods("GET", "POST")
req, _ := http.NewRequest("PUT", "http://localhost/", nil)
match := new(RouteMatch)
matched := r.Match(req, match)
if matched {
t.Error("Should not have matched route for methods")
}
if match.MatchErr != ErrMethodMismatch {
t.Error("Should get ErrMethodMismatch error")
}
resp := NewRecorder()
r.ServeHTTP(resp, req)
if resp.Code != 405 {
t.Errorf("Expecting code %v", 405)
}
// Add matching route
r.HandleFunc("/", func1).Methods("PUT")
match = new(RouteMatch)
matched = r.Match(req, match)
if !matched {
t.Error("Should have matched route for methods")
}
if match.MatchErr != nil {
t.Error("Should not have any matching error. Found:", match.MatchErr)
}
}

8
vendor/github.com/gorilla/mux/old_test.go сгенерированный поставляемый
Просмотреть файл

@@ -121,12 +121,7 @@ func TestRouteMatchers(t *testing.T) {
var routeMatch RouteMatch var routeMatch RouteMatch
matched := router.Match(request, &routeMatch) matched := router.Match(request, &routeMatch)
if matched != shouldMatch { if matched != shouldMatch {
// Need better messages. :) t.Errorf("Expected: %v\nGot: %v\nRequest: %v %v", shouldMatch, matched, request.Method, url)
if matched {
t.Errorf("Should match.")
} else {
t.Errorf("Should not match.")
}
} }
if matched { if matched {
@@ -188,7 +183,6 @@ func TestRouteMatchers(t *testing.T) {
match(true) match(true)
// 2nd route -------------------------------------------------------------- // 2nd route --------------------------------------------------------------
// Everything match. // Everything match.
reset2() reset2()
match(true) match(true)

5
vendor/github.com/gorilla/mux/regexp.go сгенерированный поставляемый
Просмотреть файл

@@ -35,7 +35,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
// Now let's parse it. // Now let's parse it.
defaultPattern := "[^/]+" defaultPattern := "[^/]+"
if matchQuery { if matchQuery {
defaultPattern = "[^?&]*" defaultPattern = ".*"
} else if matchHost { } else if matchHost {
defaultPattern = "[^.]+" defaultPattern = "[^.]+"
matchPrefix = false matchPrefix = false
@@ -178,6 +178,9 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
if !ok { if !ok {
return "", fmt.Errorf("mux: missing route variable %q", v) return "", fmt.Errorf("mux: missing route variable %q", v)
} }
if r.matchQuery {
value = url.QueryEscape(value)
}
urlValues[k] = value urlValues[k] = value
} }
rv := fmt.Sprintf(r.reverse, urlValues...) rv := fmt.Sprintf(r.reverse, urlValues...)

50
vendor/github.com/gorilla/mux/route.go сгенерированный поставляемый
Просмотреть файл

@@ -52,12 +52,27 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if r.buildOnly || r.err != nil { if r.buildOnly || r.err != nil {
return false return false
} }
var matchErr error
// Match everything. // Match everything.
for _, m := range r.matchers { for _, m := range r.matchers {
if matched := m.Match(req, match); !matched { if matched := m.Match(req, match); !matched {
if _, ok := m.(methodMatcher); ok {
matchErr = ErrMethodMismatch
continue
}
matchErr = nil
return false return false
} }
} }
if matchErr != nil {
match.MatchErr = matchErr
return false
}
match.MatchErr = nil
// Yay, we have a match. Let's collect some info about it. // Yay, we have a match. Let's collect some info about it.
if match.Route == nil { if match.Route == nil {
match.Route = r match.Route = r
@@ -68,6 +83,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
if match.Vars == nil { if match.Vars == nil {
match.Vars = make(map[string]string) match.Vars = make(map[string]string)
} }
// Set variables. // Set variables.
if r.regexp != nil { if r.regexp != nil {
r.regexp.setMatch(req, match, r) r.regexp.setMatch(req, match, r)
@@ -482,13 +498,14 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
return nil, err return nil, err
} }
var scheme, host, path string var scheme, host, path string
queries := make([]string, 0, len(r.regexp.queries))
if r.regexp.host != nil { if r.regexp.host != nil {
if host, err = r.regexp.host.url(values); err != nil { if host, err = r.regexp.host.url(values); err != nil {
return nil, err return nil, err
} }
scheme = "http" scheme = "http"
if r.buildScheme != "" { if s := r.getBuildScheme(); s != "" {
scheme = r.buildScheme scheme = s
} }
} }
if r.regexp.path != nil { if r.regexp.path != nil {
@@ -496,10 +513,18 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
return nil, err return nil, err
} }
} }
for _, q := range r.regexp.queries {
var query string
if query, err = q.url(values); err != nil {
return nil, err
}
queries = append(queries, query)
}
return &url.URL{ return &url.URL{
Scheme: scheme, Scheme: scheme,
Host: host, Host: host,
Path: path, Path: path,
RawQuery: strings.Join(queries, "&"),
}, nil }, nil
} }
@@ -525,8 +550,8 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
Scheme: "http", Scheme: "http",
Host: host, Host: host,
} }
if r.buildScheme != "" { if s := r.getBuildScheme(); s != "" {
u.Scheme = r.buildScheme u.Scheme = s
} }
return u, nil return u, nil
} }
@@ -640,11 +665,22 @@ func (r *Route) buildVars(m map[string]string) map[string]string {
// parentRoute allows routes to know about parent host and path definitions. // parentRoute allows routes to know about parent host and path definitions.
type parentRoute interface { type parentRoute interface {
getBuildScheme() string
getNamedRoutes() map[string]*Route getNamedRoutes() map[string]*Route
getRegexpGroup() *routeRegexpGroup getRegexpGroup() *routeRegexpGroup
buildVars(map[string]string) map[string]string buildVars(map[string]string) map[string]string
} }
func (r *Route) getBuildScheme() string {
if r.buildScheme != "" {
return r.buildScheme
}
if r.parent != nil {
return r.parent.getBuildScheme()
}
return ""
}
// getNamedRoutes returns the map where named routes are registered. // getNamedRoutes returns the map where named routes are registered.
func (r *Route) getNamedRoutes() map[string]*Route { func (r *Route) getNamedRoutes() map[string]*Route {
if r.parent == nil { if r.parent == nil {

2
vendor/github.com/hashicorp/hcl/decoder.go сгенерированный поставляемый
Просмотреть файл

@@ -137,7 +137,7 @@ func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) e
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
switch n := node.(type) { switch n := node.(type) {
case *ast.LiteralType: case *ast.LiteralType:
if n.Token.Type == token.FLOAT { if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER {
v, err := strconv.ParseFloat(n.Token.Text, 64) v, err := strconv.ParseFloat(n.Token.Text, 64)
if err != nil { if err != nil {
return err return err

9
vendor/github.com/hashicorp/hcl/decoder_test.go сгенерированный поставляемый
Просмотреть файл

@@ -73,6 +73,7 @@ func TestDecode_interface(t *testing.T) {
false, false,
map[string]interface{}{ map[string]interface{}{
"a": 1.02, "a": 1.02,
"b": 2,
}, },
}, },
{ {
@@ -811,6 +812,7 @@ func TestDecode_intString(t *testing.T) {
func TestDecode_float32(t *testing.T) { func TestDecode_float32(t *testing.T) {
var value struct { var value struct {
A float32 `hcl:"a"` A float32 `hcl:"a"`
B float32 `hcl:"b"`
} }
err := Decode(&value, testReadFile(t, "float.hcl")) err := Decode(&value, testReadFile(t, "float.hcl"))
@@ -821,11 +823,15 @@ func TestDecode_float32(t *testing.T) {
if got, want := value.A, float32(1.02); got != want { if got, want := value.A, float32(1.02); got != want {
t.Fatalf("wrong result %#v; want %#v", got, want) t.Fatalf("wrong result %#v; want %#v", got, want)
} }
if got, want := value.B, float32(2); got != want {
t.Fatalf("wrong result %#v; want %#v", got, want)
}
} }
func TestDecode_float64(t *testing.T) { func TestDecode_float64(t *testing.T) {
var value struct { var value struct {
A float64 `hcl:"a"` A float64 `hcl:"a"`
B float64 `hcl:"b"`
} }
err := Decode(&value, testReadFile(t, "float.hcl")) err := Decode(&value, testReadFile(t, "float.hcl"))
@@ -836,6 +842,9 @@ func TestDecode_float64(t *testing.T) {
if got, want := value.A, float64(1.02); got != want { if got, want := value.A, float64(1.02); got != want {
t.Fatalf("wrong result %#v; want %#v", got, want) t.Fatalf("wrong result %#v; want %#v", got, want)
} }
if got, want := value.B, float64(2); got != want {
t.Fatalf("wrong result %#v; want %#v", got, want)
}
} }
func TestDecode_intStringAliased(t *testing.T) { func TestDecode_intStringAliased(t *testing.T) {

14
vendor/github.com/hashicorp/hcl/hcl/parser/parser.go сгенерированный поставляемый
Просмотреть файл

@@ -197,9 +197,12 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) {
keyStr = append(keyStr, k.Token.Text) keyStr = append(keyStr, k.Token.Text)
} }
return nil, fmt.Errorf( return nil, &PosError{
"key '%s' expected start of object ('{') or assignment ('=')", Pos: p.tok.Pos,
strings.Join(keyStr, " ")) Err: fmt.Errorf(
"key '%s' expected start of object ('{') or assignment ('=')",
strings.Join(keyStr, " ")),
}
} }
// do a look-ahead for line comment // do a look-ahead for line comment
@@ -319,7 +322,10 @@ func (p *Parser) objectType() (*ast.ObjectType, error) {
// No error, scan and expect the ending to be a brace // No error, scan and expect the ending to be a brace
if tok := p.scan(); tok.Type != token.RBRACE { if tok := p.scan(); tok.Type != token.RBRACE {
return nil, fmt.Errorf("object expected closing RBRACE got: %s", tok.Type) return nil, &PosError{
Pos: tok.Pos,
Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type),
}
} }
o.List = l o.List = l

1
vendor/github.com/hashicorp/hcl/test-fixtures/float.hcl сгенерированный поставляемый
Просмотреть файл

@@ -1 +1,2 @@
a = 1.02 a = 1.02
b = 2

3
vendor/github.com/hashicorp/hcl/test-fixtures/float.json сгенерированный поставляемый
Просмотреть файл

@@ -1,3 +1,4 @@
{ {
"a": 1.02 "a": 1.02,
"b": 2
} }

4
vendor/github.com/hashicorp/memberlist/memberlist.go сгенерированный поставляемый
Просмотреть файл

@@ -127,7 +127,7 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
return nt, nil return nt, nil
} }
if strings.Contains(err.Error(), "address already in use") { if strings.Contains(err.Error(), "address already in use") {
logger.Printf("[DEBUG] Got bind error: %v", err) logger.Printf("[DEBUG] memberlist: Got bind error: %v", err)
continue continue
} }
} }
@@ -154,7 +154,7 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
port := nt.GetAutoBindPort() port := nt.GetAutoBindPort()
conf.BindPort = port conf.BindPort = port
conf.AdvertisePort = port conf.AdvertisePort = port
logger.Printf("[DEBUG] Using dynamic bind port %d", port) logger.Printf("[DEBUG] memberlist: Using dynamic bind port %d", port)
} }
transport = nt transport = nt
} }

1
vendor/github.com/lib/pq/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -5,6 +5,7 @@ go:
- 1.6.x - 1.6.x
- 1.7.x - 1.7.x
- 1.8.x - 1.8.x
- 1.9.x
- master - master
sudo: true sudo: true

34
vendor/github.com/lib/pq/conn.go сгенерированный поставляемый
Просмотреть файл

@@ -706,7 +706,7 @@ func (noRows) RowsAffected() (int64, error) {
// Decides which column formats to use for a prepared statement. The input is // Decides which column formats to use for a prepared statement. The input is
// an array of type oids, one element per result column. // an array of type oids, one element per result column.
func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, colFmtData []byte) { func decideColumnFormats(colTyps []fieldDesc, forceText bool) (colFmts []format, colFmtData []byte) {
if len(colTyps) == 0 { if len(colTyps) == 0 {
return nil, colFmtDataAllText return nil, colFmtDataAllText
} }
@@ -718,8 +718,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
allBinary := true allBinary := true
allText := true allText := true
for i, o := range colTyps { for i, t := range colTyps {
switch o { switch t.OID {
// This is the list of types to use binary mode for when receiving them // This is the list of types to use binary mode for when receiving them
// through a prepared statement. If a type appears in this list, it // through a prepared statement. If a type appears in this list, it
// must also be implemented in binaryDecode in encode.go. // must also be implemented in binaryDecode in encode.go.
@@ -1155,7 +1155,7 @@ type stmt struct {
colNames []string colNames []string
colFmts []format colFmts []format
colFmtData []byte colFmtData []byte
colTyps []oid.Oid colTyps []fieldDesc
paramTyps []oid.Oid paramTyps []oid.Oid
closed bool closed bool
} }
@@ -1318,7 +1318,7 @@ type rows struct {
cn *conn cn *conn
finish func() finish func()
colNames []string colNames []string
colTyps []oid.Oid colTyps []fieldDesc
colFmts []format colFmts []format
done bool done bool
rb readBuf rb readBuf
@@ -1406,7 +1406,7 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
dest[i] = nil dest[i] = nil
continue continue
} }
dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i], rs.colFmts[i]) dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i])
} }
return return
case 'T': case 'T':
@@ -1573,7 +1573,7 @@ func (cn *conn) readParseResponse() {
} }
} }
func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []oid.Oid) { func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc) {
for { for {
t, r := cn.recv1() t, r := cn.recv1()
switch t { switch t {
@@ -1599,7 +1599,7 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
} }
} }
func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []oid.Oid) { func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) {
t, r := cn.recv1() t, r := cn.recv1()
switch t { switch t {
case 'T': case 'T':
@@ -1695,31 +1695,33 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
} }
} }
func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []oid.Oid) { func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) {
n := r.int16() n := r.int16()
colNames = make([]string, n) colNames = make([]string, n)
colTyps = make([]oid.Oid, n) colTyps = make([]fieldDesc, n)
for i := range colNames { for i := range colNames {
colNames[i] = r.string() colNames[i] = r.string()
r.next(6) r.next(6)
colTyps[i] = r.oid() colTyps[i].OID = r.oid()
r.next(6) colTyps[i].Len = r.int16()
colTyps[i].Mod = r.int32()
// format code not known when describing a statement; always 0 // format code not known when describing a statement; always 0
r.next(2) r.next(2)
} }
return return
} }
func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []oid.Oid) { func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) {
n := r.int16() n := r.int16()
colNames = make([]string, n) colNames = make([]string, n)
colFmts = make([]format, n) colFmts = make([]format, n)
colTyps = make([]oid.Oid, n) colTyps = make([]fieldDesc, n)
for i := range colNames { for i := range colNames {
colNames[i] = r.string() colNames[i] = r.string()
r.next(6) r.next(6)
colTyps[i] = r.oid() colTyps[i].OID = r.oid()
r.next(6) colTyps[i].Len = r.int16()
colTyps[i].Mod = r.int32()
colFmts[i] = format(r.int16()) colFmts[i] = format(r.int16())
} }
return return

12
vendor/github.com/lib/pq/encode.go сгенерированный поставляемый
Просмотреть файл

@@ -367,8 +367,15 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
timeSep := daySep + 3 timeSep := daySep + 3
day := p.mustAtoi(str, daySep+1, timeSep) day := p.mustAtoi(str, daySep+1, timeSep)
minLen := monSep + len("01-01") + 1
isBC := strings.HasSuffix(str, " BC")
if isBC {
minLen += 3
}
var hour, minute, second int var hour, minute, second int
if len(str) > monSep+len("01-01")+1 { if len(str) > minLen {
p.expect(str, ' ', timeSep) p.expect(str, ' ', timeSep)
minSep := timeSep + 3 minSep := timeSep + 3
p.expect(str, ':', minSep) p.expect(str, ':', minSep)
@@ -424,7 +431,8 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec) tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
} }
var isoYear int var isoYear int
if remainderIdx+3 <= len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
if isBC {
isoYear = 1 - year isoYear = 1 - year
remainderIdx += 3 remainderIdx += 3
} else { } else {

9
vendor/github.com/lib/pq/encode_test.go сгенерированный поставляемый
Просмотреть файл

@@ -37,6 +37,8 @@ var timeTests = []struct {
}{ }{
{"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, {"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
{"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, {"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
{"0001-12-31 BC", time.Date(0, time.December, 31, 0, 0, 0, 0, time.FixedZone("", 0))},
{"2001-02-03 BC", time.Date(-2000, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
{"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))}, {"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
{"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))}, {"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))},
{"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))}, {"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))},
@@ -86,15 +88,22 @@ func TestParseTs(t *testing.T) {
} }
var timeErrorTests = []string{ var timeErrorTests = []string{
"BC",
" BC",
"2001", "2001",
"2001-2-03", "2001-2-03",
"2001-02-3", "2001-02-3",
"2001-02-03 ", "2001-02-03 ",
"2001-02-03 B",
"2001-02-03 04", "2001-02-03 04",
"2001-02-03 04:", "2001-02-03 04:",
"2001-02-03 04:05", "2001-02-03 04:05",
"2001-02-03 04:05 B",
"2001-02-03 04:05 BC",
"2001-02-03 04:05:", "2001-02-03 04:05:",
"2001-02-03 04:05:6", "2001-02-03 04:05:6",
"2001-02-03 04:05:06 B",
"2001-02-03 04:05:06BC",
"2001-02-03 04:05:06.123 B", "2001-02-03 04:05:06.123 B",
} }

59
vendor/github.com/lib/pq/oid/gen.go сгенерированный поставляемый
Просмотреть файл

@@ -10,10 +10,22 @@ import (
"log" "log"
"os" "os"
"os/exec" "os/exec"
"strings"
_ "github.com/lib/pq" _ "github.com/lib/pq"
) )
// OID represent a postgres Object Identifier Type.
type OID struct {
ID int
Type string
}
// Name returns an upper case version of the oid type.
func (o OID) Name() string {
return strings.ToUpper(o.Type)
}
func main() { func main() {
datname := os.Getenv("PGDATABASE") datname := os.Getenv("PGDATABASE")
sslmode := os.Getenv("PGSSLMODE") sslmode := os.Getenv("PGSSLMODE")
@@ -30,6 +42,25 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
rows, err := db.Query(`
SELECT typname, oid
FROM pg_type WHERE oid < 10000
ORDER BY oid;
`)
if err != nil {
log.Fatal(err)
}
oids := make([]*OID, 0)
for rows.Next() {
var oid OID
if err = rows.Scan(&oid.Type, &oid.ID); err != nil {
log.Fatal(err)
}
oids = append(oids, &oid)
}
if err = rows.Err(); err != nil {
log.Fatal(err)
}
cmd := exec.Command("gofmt") cmd := exec.Command("gofmt")
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
w, err := cmd.StdinPipe() w, err := cmd.StdinPipe()
@@ -45,30 +76,18 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit") fmt.Fprintln(w, "// Code generated by gen.go. DO NOT EDIT.")
fmt.Fprintln(w, "\npackage oid") fmt.Fprintln(w, "\npackage oid")
fmt.Fprintln(w, "const (") fmt.Fprintln(w, "const (")
rows, err := db.Query(` for _, oid := range oids {
SELECT typname, oid fmt.Fprintf(w, "T_%s Oid = %d\n", oid.Type, oid.ID)
FROM pg_type WHERE oid < 10000
ORDER BY oid;
`)
if err != nil {
log.Fatal(err)
}
var name string
var oid int
for rows.Next() {
err = rows.Scan(&name, &oid)
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid)
}
if err = rows.Err(); err != nil {
log.Fatal(err)
} }
fmt.Fprintln(w, ")") fmt.Fprintln(w, ")")
fmt.Fprintln(w, "var TypeName = map[Oid]string{")
for _, oid := range oids {
fmt.Fprintf(w, "T_%s: \"%s\",\n", oid.Type, oid.Name())
}
fmt.Fprintln(w, "}")
w.Close() w.Close()
cmd.Wait() cmd.Wait()
} }

172
vendor/github.com/lib/pq/oid/types.go сгенерированный поставляемый
Просмотреть файл

@@ -1,4 +1,4 @@
// generated by 'go run gen.go'; do not edit // Code generated by gen.go. DO NOT EDIT.
package oid package oid
@@ -171,3 +171,173 @@ const (
T_regrole Oid = 4096 T_regrole Oid = 4096
T__regrole Oid = 4097 T__regrole Oid = 4097
) )
var TypeName = map[Oid]string{
T_bool: "BOOL",
T_bytea: "BYTEA",
T_char: "CHAR",
T_name: "NAME",
T_int8: "INT8",
T_int2: "INT2",
T_int2vector: "INT2VECTOR",
T_int4: "INT4",
T_regproc: "REGPROC",
T_text: "TEXT",
T_oid: "OID",
T_tid: "TID",
T_xid: "XID",
T_cid: "CID",
T_oidvector: "OIDVECTOR",
T_pg_ddl_command: "PG_DDL_COMMAND",
T_pg_type: "PG_TYPE",
T_pg_attribute: "PG_ATTRIBUTE",
T_pg_proc: "PG_PROC",
T_pg_class: "PG_CLASS",
T_json: "JSON",
T_xml: "XML",
T__xml: "_XML",
T_pg_node_tree: "PG_NODE_TREE",
T__json: "_JSON",
T_smgr: "SMGR",
T_index_am_handler: "INDEX_AM_HANDLER",
T_point: "POINT",
T_lseg: "LSEG",
T_path: "PATH",
T_box: "BOX",
T_polygon: "POLYGON",
T_line: "LINE",
T__line: "_LINE",
T_cidr: "CIDR",
T__cidr: "_CIDR",
T_float4: "FLOAT4",
T_float8: "FLOAT8",
T_abstime: "ABSTIME",
T_reltime: "RELTIME",
T_tinterval: "TINTERVAL",
T_unknown: "UNKNOWN",
T_circle: "CIRCLE",
T__circle: "_CIRCLE",
T_money: "MONEY",
T__money: "_MONEY",
T_macaddr: "MACADDR",
T_inet: "INET",
T__bool: "_BOOL",
T__bytea: "_BYTEA",
T__char: "_CHAR",
T__name: "_NAME",
T__int2: "_INT2",
T__int2vector: "_INT2VECTOR",
T__int4: "_INT4",
T__regproc: "_REGPROC",
T__text: "_TEXT",
T__tid: "_TID",
T__xid: "_XID",
T__cid: "_CID",
T__oidvector: "_OIDVECTOR",
T__bpchar: "_BPCHAR",
T__varchar: "_VARCHAR",
T__int8: "_INT8",
T__point: "_POINT",
T__lseg: "_LSEG",
T__path: "_PATH",
T__box: "_BOX",
T__float4: "_FLOAT4",
T__float8: "_FLOAT8",
T__abstime: "_ABSTIME",
T__reltime: "_RELTIME",
T__tinterval: "_TINTERVAL",
T__polygon: "_POLYGON",
T__oid: "_OID",
T_aclitem: "ACLITEM",
T__aclitem: "_ACLITEM",
T__macaddr: "_MACADDR",
T__inet: "_INET",
T_bpchar: "BPCHAR",
T_varchar: "VARCHAR",
T_date: "DATE",
T_time: "TIME",
T_timestamp: "TIMESTAMP",
T__timestamp: "_TIMESTAMP",
T__date: "_DATE",
T__time: "_TIME",
T_timestamptz: "TIMESTAMPTZ",
T__timestamptz: "_TIMESTAMPTZ",
T_interval: "INTERVAL",
T__interval: "_INTERVAL",
T__numeric: "_NUMERIC",
T_pg_database: "PG_DATABASE",
T__cstring: "_CSTRING",
T_timetz: "TIMETZ",
T__timetz: "_TIMETZ",
T_bit: "BIT",
T__bit: "_BIT",
T_varbit: "VARBIT",
T__varbit: "_VARBIT",
T_numeric: "NUMERIC",
T_refcursor: "REFCURSOR",
T__refcursor: "_REFCURSOR",
T_regprocedure: "REGPROCEDURE",
T_regoper: "REGOPER",
T_regoperator: "REGOPERATOR",
T_regclass: "REGCLASS",
T_regtype: "REGTYPE",
T__regprocedure: "_REGPROCEDURE",
T__regoper: "_REGOPER",
T__regoperator: "_REGOPERATOR",
T__regclass: "_REGCLASS",
T__regtype: "_REGTYPE",
T_record: "RECORD",
T_cstring: "CSTRING",
T_any: "ANY",
T_anyarray: "ANYARRAY",
T_void: "VOID",
T_trigger: "TRIGGER",
T_language_handler: "LANGUAGE_HANDLER",
T_internal: "INTERNAL",
T_opaque: "OPAQUE",
T_anyelement: "ANYELEMENT",
T__record: "_RECORD",
T_anynonarray: "ANYNONARRAY",
T_pg_authid: "PG_AUTHID",
T_pg_auth_members: "PG_AUTH_MEMBERS",
T__txid_snapshot: "_TXID_SNAPSHOT",
T_uuid: "UUID",
T__uuid: "_UUID",
T_txid_snapshot: "TXID_SNAPSHOT",
T_fdw_handler: "FDW_HANDLER",
T_pg_lsn: "PG_LSN",
T__pg_lsn: "_PG_LSN",
T_tsm_handler: "TSM_HANDLER",
T_anyenum: "ANYENUM",
T_tsvector: "TSVECTOR",
T_tsquery: "TSQUERY",
T_gtsvector: "GTSVECTOR",
T__tsvector: "_TSVECTOR",
T__gtsvector: "_GTSVECTOR",
T__tsquery: "_TSQUERY",
T_regconfig: "REGCONFIG",
T__regconfig: "_REGCONFIG",
T_regdictionary: "REGDICTIONARY",
T__regdictionary: "_REGDICTIONARY",
T_jsonb: "JSONB",
T__jsonb: "_JSONB",
T_anyrange: "ANYRANGE",
T_event_trigger: "EVENT_TRIGGER",
T_int4range: "INT4RANGE",
T__int4range: "_INT4RANGE",
T_numrange: "NUMRANGE",
T__numrange: "_NUMRANGE",
T_tsrange: "TSRANGE",
T__tsrange: "_TSRANGE",
T_tstzrange: "TSTZRANGE",
T__tstzrange: "_TSTZRANGE",
T_daterange: "DATERANGE",
T__daterange: "_DATERANGE",
T_int8range: "INT8RANGE",
T__int8range: "_INT8RANGE",
T_pg_shseclabel: "PG_SHSECLABEL",
T_regnamespace: "REGNAMESPACE",
T__regnamespace: "_REGNAMESPACE",
T_regrole: "REGROLE",
T__regrole: "_REGROLE",
}

93
vendor/github.com/lib/pq/rows.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,93 @@
package pq
import (
"math"
"reflect"
"time"
"github.com/lib/pq/oid"
)
const headerSize = 4
type fieldDesc struct {
// The object ID of the data type.
OID oid.Oid
// The data type size (see pg_type.typlen).
// Note that negative values denote variable-width types.
Len int
// The type modifier (see pg_attribute.atttypmod).
// The meaning of the modifier is type-specific.
Mod int
}
func (fd fieldDesc) Type() reflect.Type {
switch fd.OID {
case oid.T_int8:
return reflect.TypeOf(int64(0))
case oid.T_int4:
return reflect.TypeOf(int32(0))
case oid.T_int2:
return reflect.TypeOf(int16(0))
case oid.T_varchar, oid.T_text:
return reflect.TypeOf("")
case oid.T_bool:
return reflect.TypeOf(false)
case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz:
return reflect.TypeOf(time.Time{})
case oid.T_bytea:
return reflect.TypeOf([]byte(nil))
default:
return reflect.TypeOf(new(interface{})).Elem()
}
}
func (fd fieldDesc) Name() string {
return oid.TypeName[fd.OID]
}
func (fd fieldDesc) Length() (length int64, ok bool) {
switch fd.OID {
case oid.T_text, oid.T_bytea:
return math.MaxInt64, true
case oid.T_varchar, oid.T_bpchar:
return int64(fd.Mod - headerSize), true
default:
return 0, false
}
}
func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) {
switch fd.OID {
case oid.T_numeric, oid.T__numeric:
mod := fd.Mod - headerSize
precision = int64((mod >> 16) & 0xffff)
scale = int64(mod & 0xffff)
return precision, scale, true
default:
return 0, 0, false
}
}
// ColumnTypeScanType returns the value type that can be used to scan types into.
func (rs *rows) ColumnTypeScanType(index int) reflect.Type {
return rs.colTyps[index].Type()
}
// ColumnTypeDatabaseTypeName return the database system type name.
func (rs *rows) ColumnTypeDatabaseTypeName(index int) string {
return rs.colTyps[index].Name()
}
// ColumnTypeLength returns the length of the column type if the column is a
// variable length type. If the column is not a variable length type ok
// should return false.
func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) {
return rs.colTyps[index].Length()
}
// ColumnTypePrecisionScale should return the precision and scale for decimal
// types. If not applicable, ok should be false.
func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
return rs.colTyps[index].PrecisionScale()
}

220
vendor/github.com/lib/pq/rows_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,220 @@
// +build go1.8
package pq
import (
"math"
"reflect"
"testing"
"github.com/lib/pq/oid"
)
func TestDataTypeName(t *testing.T) {
tts := []struct {
typ oid.Oid
name string
}{
{oid.T_int8, "INT8"},
{oid.T_int4, "INT4"},
{oid.T_int2, "INT2"},
{oid.T_varchar, "VARCHAR"},
{oid.T_text, "TEXT"},
{oid.T_bool, "BOOL"},
{oid.T_numeric, "NUMERIC"},
{oid.T_date, "DATE"},
{oid.T_time, "TIME"},
{oid.T_timetz, "TIMETZ"},
{oid.T_timestamp, "TIMESTAMP"},
{oid.T_timestamptz, "TIMESTAMPTZ"},
{oid.T_bytea, "BYTEA"},
}
for i, tt := range tts {
dt := fieldDesc{OID: tt.typ}
if name := dt.Name(); name != tt.name {
t.Errorf("(%d) got: %s want: %s", i, name, tt.name)
}
}
}
func TestDataType(t *testing.T) {
tts := []struct {
typ oid.Oid
kind reflect.Kind
}{
{oid.T_int8, reflect.Int64},
{oid.T_int4, reflect.Int32},
{oid.T_int2, reflect.Int16},
{oid.T_varchar, reflect.String},
{oid.T_text, reflect.String},
{oid.T_bool, reflect.Bool},
{oid.T_date, reflect.Struct},
{oid.T_time, reflect.Struct},
{oid.T_timetz, reflect.Struct},
{oid.T_timestamp, reflect.Struct},
{oid.T_timestamptz, reflect.Struct},
{oid.T_bytea, reflect.Slice},
}
for i, tt := range tts {
dt := fieldDesc{OID: tt.typ}
if kind := dt.Type().Kind(); kind != tt.kind {
t.Errorf("(%d) got: %s want: %s", i, kind, tt.kind)
}
}
}
func TestDataTypeLength(t *testing.T) {
tts := []struct {
typ oid.Oid
len int
mod int
length int64
ok bool
}{
{oid.T_int4, 0, -1, 0, false},
{oid.T_varchar, 65535, 9, 5, true},
{oid.T_text, 65535, -1, math.MaxInt64, true},
{oid.T_bytea, 65535, -1, math.MaxInt64, true},
}
for i, tt := range tts {
dt := fieldDesc{OID: tt.typ, Len: tt.len, Mod: tt.mod}
if l, k := dt.Length(); k != tt.ok || l != tt.length {
t.Errorf("(%d) got: %d, %t want: %d, %t", i, l, k, tt.length, tt.ok)
}
}
}
func TestDataTypePrecisionScale(t *testing.T) {
tts := []struct {
typ oid.Oid
mod int
precision, scale int64
ok bool
}{
{oid.T_int4, -1, 0, 0, false},
{oid.T_numeric, 589830, 9, 2, true},
{oid.T_text, -1, 0, 0, false},
}
for i, tt := range tts {
dt := fieldDesc{OID: tt.typ, Mod: tt.mod}
p, s, k := dt.PrecisionScale()
if k != tt.ok {
t.Errorf("(%d) got: %t want: %t", i, k, tt.ok)
}
if p != tt.precision {
t.Errorf("(%d) wrong precision got: %d want: %d", i, p, tt.precision)
}
if s != tt.scale {
t.Errorf("(%d) wrong scale got: %d want: %d", i, s, tt.scale)
}
}
}
func TestRowsColumnTypes(t *testing.T) {
columnTypesTests := []struct {
Name string
TypeName string
Length struct {
Len int64
OK bool
}
DecimalSize struct {
Precision int64
Scale int64
OK bool
}
ScanType reflect.Type
}{
{
Name: "a",
TypeName: "INT4",
Length: struct {
Len int64
OK bool
}{
Len: 0,
OK: false,
},
DecimalSize: struct {
Precision int64
Scale int64
OK bool
}{
Precision: 0,
Scale: 0,
OK: false,
},
ScanType: reflect.TypeOf(int32(0)),
}, {
Name: "bar",
TypeName: "TEXT",
Length: struct {
Len int64
OK bool
}{
Len: math.MaxInt64,
OK: true,
},
DecimalSize: struct {
Precision int64
Scale int64
OK bool
}{
Precision: 0,
Scale: 0,
OK: false,
},
ScanType: reflect.TypeOf(""),
},
}
db := openTestConn(t)
defer db.Close()
rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar, 1.28::numeric(9, 2) AS dec")
if err != nil {
t.Fatal(err)
}
columns, err := rows.ColumnTypes()
if err != nil {
t.Fatal(err)
}
if len(columns) != 3 {
t.Errorf("expected 3 columns found %d", len(columns))
}
for i, tt := range columnTypesTests {
c := columns[i]
if c.Name() != tt.Name {
t.Errorf("(%d) got: %s, want: %s", i, c.Name(), tt.Name)
}
if c.DatabaseTypeName() != tt.TypeName {
t.Errorf("(%d) got: %s, want: %s", i, c.DatabaseTypeName(), tt.TypeName)
}
l, ok := c.Length()
if l != tt.Length.Len {
t.Errorf("(%d) got: %d, want: %d", i, l, tt.Length.Len)
}
if ok != tt.Length.OK {
t.Errorf("(%d) got: %t, want: %t", i, ok, tt.Length.OK)
}
p, s, ok := c.DecimalSize()
if p != tt.DecimalSize.Precision {
t.Errorf("(%d) got: %d, want: %d", i, p, tt.DecimalSize.Precision)
}
if s != tt.DecimalSize.Scale {
t.Errorf("(%d) got: %d, want: %d", i, s, tt.DecimalSize.Scale)
}
if ok != tt.DecimalSize.OK {
t.Errorf("(%d) got: %t, want: %t", i, ok, tt.DecimalSize.OK)
}
if c.ScanType() != tt.ScanType {
t.Errorf("(%d) got: %v, want: %v", i, c.ScanType(), tt.ScanType)
}
}
}

1
vendor/github.com/magiconair/properties/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -5,4 +5,5 @@ go:
- 1.6.x - 1.6.x
- 1.7.x - 1.7.x
- 1.8.x - 1.8.x
- 1.9.x
- tip - tip

5
vendor/github.com/magiconair/properties/CHANGELOG.md сгенерированный поставляемый
Просмотреть файл

@@ -1,5 +1,10 @@
## Changelog ## Changelog
### Unreleased
* [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled
Thanks to @mgurov for the fix.
### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017 ### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017
* [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically * [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically

3
vendor/github.com/magiconair/properties/properties.go сгенерированный поставляемый
Просмотреть файл

@@ -511,6 +511,9 @@ func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
if p.DisableExpansion { if p.DisableExpansion {
prev, ok = p.Get(key) prev, ok = p.Get(key)
p.m[key] = value p.m[key] = value
if !ok {
p.k = append(p.k, key)
}
return prev, ok, nil return prev, ok, nil
} }

13
vendor/github.com/magiconair/properties/properties_test.go сгенерированный поставляемый
Просмотреть файл

@@ -458,6 +458,19 @@ func TestDisableExpansion(t *testing.T) {
assert.Equal(t, p.MustGet("keyB"), "${keyA}") assert.Equal(t, p.MustGet("keyB"), "${keyA}")
} }
func TestDisableExpansionStillUpdatesKeys(t *testing.T) {
p := NewProperties()
p.MustSet("p1", "a")
assert.Equal(t, p.Keys(), []string{"p1"})
assert.Equal(t, p.String(), "p1 = a\n")
p.DisableExpansion = true
p.MustSet("p2", "b")
assert.Equal(t, p.Keys(), []string{"p1", "p2"})
assert.Equal(t, p.String(), "p1 = a\np2 = b\n")
}
func TestMustGet(t *testing.T) { func TestMustGet(t *testing.T) {
input := "key = value\nkey2 = ghi" input := "key = value\nkey2 = ghi"
p := mustParse(t, input) p := mustParse(t, input)

1
vendor/github.com/mattermost/html2text/LICENSE сгенерированный поставляемый
Просмотреть файл

@@ -1,6 +1,7 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Jay Taylor Copyright (c) 2015 Jay Taylor
Modified work: Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

1
vendor/github.com/miekg/dns/CONTRIBUTORS сгенерированный поставляемый
Просмотреть файл

@@ -7,3 +7,4 @@ Marek Majkowski
Peter van Dijk Peter van Dijk
Omri Bahumi Omri Bahumi
Alex Sergeyev Alex Sergeyev
James Hartig

340
vendor/github.com/miekg/dns/client.go сгенерированный поставляемый
Просмотреть файл

@@ -9,6 +9,7 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"net" "net"
"strings"
"time" "time"
) )
@@ -27,11 +28,15 @@ type Conn struct {
// A Client defines parameters for a DNS client. // A Client defines parameters for a DNS client.
type Client struct { type Client struct {
Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
UDPSize uint16 // minimum receive buffer for UDP messages UDPSize uint16 // minimum receive buffer for UDP messages
TLSConfig *tls.Config // TLS connection configuration TLSConfig *tls.Config // TLS connection configuration
Timeout time.Duration // a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout and WriteTimeout when non-zero Dialer *net.Dialer // a net.Dialer used to set local address, timeouts and more
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds - overridden by Timeout when that value is non-zero // Timeout is a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout,
// WriteTimeout when non-zero. Can be overridden with net.Dialer.Timeout (see Client.ExchangeWithDialer and
// Client.Dialer) or context.Context.Deadline (see the deprecated ExchangeContext)
Timeout time.Duration
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
@@ -44,140 +49,11 @@ type Client struct {
// will it fall back to TCP in case of truncation. // will it fall back to TCP in case of truncation.
// See client.Exchange for more information on setting larger buffer sizes. // See client.Exchange for more information on setting larger buffer sizes.
func Exchange(m *Msg, a string) (r *Msg, err error) { func Exchange(m *Msg, a string) (r *Msg, err error) {
var co *Conn client := Client{Net: "udp"}
co, err = DialTimeout("udp", a, dnsTimeout) r, _, err = client.Exchange(m, a)
if err != nil {
return nil, err
}
defer co.Close()
opt := m.IsEdns0()
// If EDNS0 is used use that for size.
if opt != nil && opt.UDPSize() >= MinMsgSize {
co.UDPSize = opt.UDPSize()
}
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
if err = co.WriteMsg(m); err != nil {
return nil, err
}
co.SetReadDeadline(time.Now().Add(dnsTimeout))
r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err return r, err
} }
// ExchangeContext performs a synchronous UDP query, like Exchange. It
// additionally obeys deadlines from the passed Context.
func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error) {
// Combine context deadline with built-in timeout. Context chooses whichever
// is sooner.
timeoutCtx, cancel := context.WithTimeout(ctx, dnsTimeout)
defer cancel()
deadline, _ := timeoutCtx.Deadline()
co := new(Conn)
dialer := net.Dialer{}
co.Conn, err = dialer.DialContext(timeoutCtx, "udp", a)
if err != nil {
return nil, err
}
defer co.Conn.Close()
opt := m.IsEdns0()
// If EDNS0 is used use that for size.
if opt != nil && opt.UDPSize() >= MinMsgSize {
co.UDPSize = opt.UDPSize()
}
co.SetWriteDeadline(deadline)
if err = co.WriteMsg(m); err != nil {
return nil, err
}
co.SetReadDeadline(deadline)
r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err
}
// ExchangeConn performs a synchronous query. It sends the message m via the connection
// c and waits for a reply. The connection c is not closed by ExchangeConn.
// This function is going away, but can easily be mimicked:
//
// co := &dns.Conn{Conn: c} // c is your net.Conn
// co.WriteMsg(m)
// in, _ := co.ReadMsg()
// co.Close()
//
func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
println("dns: this function is deprecated")
co := new(Conn)
co.Conn = c
if err = co.WriteMsg(m); err != nil {
return nil, err
}
r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err
}
// Exchange performs a synchronous query. It sends the message m to the address
// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
//
// c := new(dns.Client)
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
//
// Exchange does not retry a failed query, nor will it fall back to TCP in
// case of truncation.
// It is up to the caller to create a message that allows for larger responses to be
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
// buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit
// of 512 bytes.
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
return c.ExchangeContext(context.Background(), m, a)
}
// ExchangeContext acts like Exchange, but honors the deadline on the provided
// context, if present. If there is both a context deadline and a configured
// timeout on the client, the earliest of the two takes effect.
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (
r *Msg,
rtt time.Duration,
err error) {
if !c.SingleInflight {
return c.exchange(ctx, m, a)
}
// This adds a bunch of garbage, TODO(miek).
t := "nop"
if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
t = t1
}
cl := "nop"
if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
cl = cl1
}
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
return c.exchange(ctx, m, a)
})
if r != nil && shared {
r = r.Copy()
}
if err != nil {
return r, rtt, err
}
return r, rtt, nil
}
func (c *Client) dialTimeout() time.Duration { func (c *Client) dialTimeout() time.Duration {
if c.Timeout != 0 { if c.Timeout != 0 {
return c.Timeout return c.Timeout
@@ -202,40 +78,87 @@ func (c *Client) writeTimeout() time.Duration {
return dnsTimeout return dnsTimeout
} }
func (c *Client) exchange(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) { func (c *Client) Dial(address string) (conn *Conn, err error) {
var co *Conn // create a new dialer with the appropriate timeout
var d net.Dialer
if c.Dialer == nil {
d = net.Dialer{}
} else {
d = net.Dialer(*c.Dialer)
}
d.Timeout = c.getTimeoutForRequest(c.writeTimeout())
network := "udp" network := "udp"
tls := false useTLS := false
switch c.Net { switch c.Net {
case "tcp-tls": case "tcp-tls":
network = "tcp" network = "tcp"
tls = true useTLS = true
case "tcp4-tls": case "tcp4-tls":
network = "tcp4" network = "tcp4"
tls = true useTLS = true
case "tcp6-tls": case "tcp6-tls":
network = "tcp6" network = "tcp6"
tls = true useTLS = true
default: default:
if c.Net != "" { if c.Net != "" {
network = c.Net network = c.Net
} }
} }
var deadline time.Time conn = new(Conn)
if c.Timeout != 0 { if useTLS {
deadline = time.Now().Add(c.Timeout) conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig)
}
dialDeadline := deadlineOrTimeoutOrCtx(ctx, deadline, c.dialTimeout())
dialTimeout := dialDeadline.Sub(time.Now())
if tls {
co, err = DialTimeoutWithTLS(network, a, c.TLSConfig, dialTimeout)
} else { } else {
co, err = DialTimeout(network, a, dialTimeout) conn.Conn, err = d.Dial(network, address)
} }
if err != nil {
return nil, err
}
return conn, nil
}
// Exchange performs a synchronous query. It sends the message m to the address
// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
//
// c := new(dns.Client)
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
//
// Exchange does not retry a failed query, nor will it fall back to TCP in
// case of truncation.
// It is up to the caller to create a message that allows for larger responses to be
// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
// buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit
// of 512 bytes
// To specify a local address or a timeout, the caller has to set the `Client.Dialer`
// attribute appropriately
func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) {
if !c.SingleInflight {
return c.exchange(m, address)
}
t := "nop"
if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
t = t1
}
cl := "nop"
if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
cl = cl1
}
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
return c.exchange(m, address)
})
if r != nil && shared {
r = r.Copy()
}
return r, rtt, err
}
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
var co *Conn
co, err = c.Dial(a)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
@@ -253,12 +176,13 @@ func (c *Client) exchange(ctx context.Context, m *Msg, a string) (r *Msg, rtt ti
} }
co.TsigSecret = c.TsigSecret co.TsigSecret = c.TsigSecret
co.SetWriteDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.writeTimeout())) // write with the appropriate write timeout
co.SetWriteDeadline(time.Now().Add(c.getTimeoutForRequest(c.writeTimeout())))
if err = co.WriteMsg(m); err != nil { if err = co.WriteMsg(m); err != nil {
return nil, 0, err return nil, 0, err
} }
co.SetReadDeadline(deadlineOrTimeoutOrCtx(ctx, deadline, c.readTimeout())) co.SetReadDeadline(time.Now().Add(c.getTimeoutForRequest(c.readTimeout())))
r, err = co.ReadMsg() r, err = co.ReadMsg()
if err == nil && r.Id != m.Id { if err == nil && r.Id != m.Id {
err = ErrId err = ErrId
@@ -352,7 +276,7 @@ func tcpMsgLen(t io.Reader) (int, error) {
return 0, err return 0, err
} }
// As seen with my local router/switch, retursn 1 byte on the above read, // As seen with my local router/switch, returns 1 byte on the above read,
// resulting a a ShortRead. Just write it out (instead of loop) and read the // resulting a a ShortRead. Just write it out (instead of loop) and read the
// other byte. // other byte.
if n == 1 { if n == 1 {
@@ -467,6 +391,24 @@ func (co *Conn) Write(p []byte) (n int, err error) {
return n, err return n, err
} }
// Return the appropriate timeout for a specific request
func (c *Client) getTimeoutForRequest(timeout time.Duration) time.Duration {
var requestTimeout time.Duration
if c.Timeout != 0 {
requestTimeout = c.Timeout
} else {
requestTimeout = timeout
}
// net.Dialer.Timeout has priority if smaller than the timeouts computed so
// far
if c.Dialer != nil && c.Dialer.Timeout != 0 {
if c.Dialer.Timeout < requestTimeout {
requestTimeout = c.Dialer.Timeout
}
}
return requestTimeout
}
// Dial connects to the address on the named network. // Dial connects to the address on the named network.
func Dial(network, address string) (conn *Conn, err error) { func Dial(network, address string) (conn *Conn, err error) {
conn = new(Conn) conn = new(Conn)
@@ -477,10 +419,44 @@ func Dial(network, address string) (conn *Conn, err error) {
return conn, nil return conn, nil
} }
// ExchangeContext performs a synchronous UDP query, like Exchange. It
// additionally obeys deadlines from the passed Context.
func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error) {
client := Client{Net: "udp"}
r, _, err = client.ExchangeContext(ctx, m, a)
// ignorint rtt to leave the original ExchangeContext API unchanged, but
// this function will go away
return r, err
}
// ExchangeConn performs a synchronous query. It sends the message m via the connection
// c and waits for a reply. The connection c is not closed by ExchangeConn.
// This function is going away, but can easily be mimicked:
//
// co := &dns.Conn{Conn: c} // c is your net.Conn
// co.WriteMsg(m)
// in, _ := co.ReadMsg()
// co.Close()
//
func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
println("dns: ExchangeConn: this function is deprecated")
co := new(Conn)
co.Conn = c
if err = co.WriteMsg(m); err != nil {
return nil, err
}
r, err = co.ReadMsg()
if err == nil && r.Id != m.Id {
err = ErrId
}
return r, err
}
// DialTimeout acts like Dial but takes a timeout. // DialTimeout acts like Dial but takes a timeout.
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) { func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
conn = new(Conn)
conn.Conn, err = net.DialTimeout(network, address, timeout) client := Client{Net: "udp", Dialer: &net.Dialer{Timeout: timeout}}
conn, err = client.Dial(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -489,8 +465,12 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er
// DialWithTLS connects to the address on the named network with TLS. // DialWithTLS connects to the address on the named network with TLS.
func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) { func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) {
conn = new(Conn) if !strings.HasSuffix(network, "-tls") {
conn.Conn, err = tls.Dial(network, address, tlsConfig) network += "-tls"
}
client := Client{Net: network, TLSConfig: tlsConfig}
conn, err = client.Dial(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -499,33 +479,29 @@ func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, er
// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout. // DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) { func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) {
var dialer net.Dialer if !strings.HasSuffix(network, "-tls") {
dialer.Timeout = timeout network += "-tls"
}
conn = new(Conn) client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig}
conn.Conn, err = tls.DialWithDialer(&dialer, network, address, tlsConfig) conn, err = client.Dial(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conn, nil return conn, nil
} }
// deadlineOrTimeout chooses between the provided deadline and timeout // ExchangeContext acts like Exchange, but honors the deadline on the provided
// by always preferring the deadline so long as it's non-zero (regardless // context, if present. If there is both a context deadline and a configured
// of which is bigger), and returns the equivalent deadline value. // timeout on the client, the earliest of the two takes effect.
func deadlineOrTimeout(deadline time.Time, timeout time.Duration) time.Time { func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
if deadline.IsZero() { var timeout time.Duration
return time.Now().Add(timeout) if deadline, ok := ctx.Deadline(); !ok {
timeout = 0
} else {
timeout = deadline.Sub(time.Now())
} }
return deadline // not passing the context to the underlying calls, as the API does not support
} // context. For timeouts you should set up Client.Dialer and call Client.Exchange.
c.Dialer = &net.Dialer{Timeout: timeout}
// deadlineOrTimeoutOrCtx returns the earliest of: a context deadline, or the return c.Exchange(m, a)
// output of deadlineOrtimeout.
func deadlineOrTimeoutOrCtx(ctx context.Context, deadline time.Time, timeout time.Duration) time.Time {
result := deadlineOrTimeout(deadline, timeout)
if ctxDeadline, ok := ctx.Deadline(); ok && ctxDeadline.Before(result) {
result = ctxDeadline
}
return result
} }

168
vendor/github.com/miekg/dns/client_test.go сгенерированный поставляемый
Просмотреть файл

@@ -11,6 +11,29 @@ import (
"time" "time"
) )
func TestDialUDP(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
s, addrstr, err := RunLocalUDPServer("[::1]:0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
conn, err := c.Dial(addrstr)
if err != nil {
t.Fatalf("failed to dial: %v", err)
}
if conn == nil {
t.Fatalf("conn is nil")
}
}
func TestClientSync(t *testing.T) { func TestClientSync(t *testing.T) {
HandleFunc("miek.nl.", HelloServer) HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.") defer HandleRemove("miek.nl.")
@@ -27,9 +50,12 @@ func TestClientSync(t *testing.T) {
c := new(Client) c := new(Client)
r, _, err := c.Exchange(m, addrstr) r, _, err := c.Exchange(m, addrstr)
if err != nil { if err != nil {
t.Errorf("failed to exchange: %v", err) t.Fatalf("failed to exchange: %v", err)
} }
if r != nil && r.Rcode != RcodeSuccess { if r == nil {
t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r) t.Errorf("failed to get an valid answer\n%v", r)
} }
// And now with plain Exchange(). // And now with plain Exchange().
@@ -42,7 +68,42 @@ func TestClientSync(t *testing.T) {
} }
} }
func TestClientTLSSync(t *testing.T) { func TestClientLocalAddress(t *testing.T) {
HandleFunc("miek.nl.", HelloServerEchoAddrPort)
defer HandleRemove("miek.nl.")
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
laddr := net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345, Zone: ""}
c.Dialer = &net.Dialer{LocalAddr: &laddr}
r, _, err := c.Exchange(m, addrstr)
if err != nil {
t.Errorf("failed to exchange: %v", err)
}
if r != nil && r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
}
if len(r.Extra) != 1 {
t.Errorf("failed to get additional answers\n%v", r)
}
txt := r.Extra[0].(*TXT)
if txt == nil {
t.Errorf("invalid TXT response\n%v", txt)
}
if len(txt.Txt) != 1 || txt.Txt[0] != "127.0.0.1:12345" {
t.Errorf("invalid TXT response\n%v", txt.Txt)
}
}
func TestClientTLSSyncV4(t *testing.T) {
HandleFunc("miek.nl.", HelloServer) HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.") defer HandleRemove("miek.nl.")
@@ -65,6 +126,8 @@ func TestClientTLSSync(t *testing.T) {
m.SetQuestion("miek.nl.", TypeSOA) m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client) c := new(Client)
// test tcp-tls
c.Net = "tcp-tls" c.Net = "tcp-tls"
c.TLSConfig = &tls.Config{ c.TLSConfig = &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
@@ -72,9 +135,88 @@ func TestClientTLSSync(t *testing.T) {
r, _, err := c.Exchange(m, addrstr) r, _, err := c.Exchange(m, addrstr)
if err != nil { if err != nil {
t.Errorf("failed to exchange: %v", err) t.Fatalf("failed to exchange: %v", err)
} }
if r != nil && r.Rcode != RcodeSuccess { if r == nil {
t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
}
// test tcp4-tls
c.Net = "tcp4-tls"
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Fatalf("failed to exchange: %v", err)
}
if r == nil {
t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
}
}
func TestClientTLSSyncV6(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
if err != nil {
t.Fatalf("unable to build certificate: %v", err)
}
config := tls.Config{
Certificates: []tls.Certificate{cert},
}
s, addrstr, err := RunLocalTLSServer("[::1]:0", &config)
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
// test tcp-tls
c.Net = "tcp-tls"
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
r, _, err := c.Exchange(m, addrstr)
if err != nil {
t.Fatalf("failed to exchange: %v", err)
}
if r == nil {
t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
}
// test tcp6-tls
c.Net = "tcp6-tls"
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Fatalf("failed to exchange: %v", err)
}
if r == nil {
t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r) t.Errorf("failed to get an valid answer\n%v", r)
} }
} }
@@ -120,11 +262,11 @@ func TestClientEDNS0(t *testing.T) {
c := new(Client) c := new(Client)
r, _, err := c.Exchange(m, addrstr) r, _, err := c.Exchange(m, addrstr)
if err != nil { if err != nil {
t.Errorf("failed to exchange: %v", err) t.Fatalf("failed to exchange: %v", err)
} }
if r != nil && r.Rcode != RcodeSuccess { if r != nil && r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r) t.Errorf("failed to get a valid answer\n%v", r)
} }
} }
@@ -171,11 +313,14 @@ func TestClientEDNS0Local(t *testing.T) {
c := new(Client) c := new(Client)
r, _, err := c.Exchange(m, addrstr) r, _, err := c.Exchange(m, addrstr)
if err != nil { if err != nil {
t.Errorf("failed to exchange: %s", err) t.Fatalf("failed to exchange: %s", err)
} }
if r != nil && r.Rcode != RcodeSuccess { if r == nil {
t.Error("failed to get a valid answer") t.Fatal("response is nil")
}
if r.Rcode != RcodeSuccess {
t.Fatal("failed to get a valid answer")
t.Logf("%v\n", r) t.Logf("%v\n", r)
} }
@@ -513,6 +658,9 @@ func TestConcurrentExchanges(t *testing.T) {
for i := 0; i < len(r); i++ { for i := 0; i < len(r); i++ {
go func(i int) { go func(i int) {
r[i], _, _ = c.Exchange(m.Copy(), addrstr) r[i], _, _ = c.Exchange(m.Copy(), addrstr)
if r[i] == nil {
t.Fatalf("response %d is nil", i)
}
wg.Done() wg.Done()
}(i) }(i)
} }

2
vendor/github.com/miekg/dns/dnsutil/util.go сгенерированный поставляемый
Просмотреть файл

@@ -11,7 +11,7 @@ import (
"github.com/miekg/dns" "github.com/miekg/dns"
) )
// AddDomain adds origin to s if s is not already a FQDN. // AddOrigin adds origin to s if s is not already a FQDN.
// Note that the result may not be a FQDN. If origin does not end // Note that the result may not be a FQDN. If origin does not end
// with a ".", the result won't either. // with a ".", the result won't either.
// This implements the zonefile convention (specified in RFC 1035, // This implements the zonefile convention (specified in RFC 1035,

30
vendor/github.com/miekg/dns/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -1,7 +1,7 @@
/* /*
Package dns implements a full featured interface to the Domain Name System. Package dns implements a full featured interface to the Domain Name System.
Server- and client-side programming is supported. Server- and client-side programming is supported.
The package allows complete control over what is send out to the DNS. The package The package allows complete control over what is sent out to the DNS. The package
API follows the less-is-more principle, by presenting a small, clean interface. API follows the less-is-more principle, by presenting a small, clean interface.
The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers, The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
@@ -14,7 +14,7 @@ Basic usage pattern for creating a new resource record:
r := new(dns.MX) r := new(dns.MX)
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
Class: dns.ClassINET, Ttl: 3600} Class: dns.ClassINET, Ttl: 3600}
r.Preference = 10 r.Preference = 10
r.Mx = "mx.miek.nl." r.Mx = "mx.miek.nl."
@@ -22,16 +22,16 @@ Or directly from a string:
mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.") mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
Or when the default TTL (3600) and class (IN) suit you: Or when the default origin (.) and TTL (3600) and class (IN) suit you:
mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.") mx, err := dns.NewRR("miek.nl MX 10 mx.miek.nl")
Or even: Or even:
mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek") mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
In the DNS messages are exchanged, these messages contain resource In the DNS messages are exchanged, these messages contain resource
records (sets). Use pattern for creating a message: records (sets). Use pattern for creating a message:
m := new(dns.Msg) m := new(dns.Msg)
m.SetQuestion("miek.nl.", dns.TypeMX) m.SetQuestion("miek.nl.", dns.TypeMX)
@@ -51,7 +51,7 @@ The following is slightly more verbose, but more flexible:
m1.Question = make([]dns.Question, 1) m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET} m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
After creating a message it can be send. After creating a message it can be sent.
Basic use pattern for synchronous querying the DNS at a Basic use pattern for synchronous querying the DNS at a
server configured on 127.0.0.1 and port 53: server configured on 127.0.0.1 and port 53:
@@ -63,7 +63,23 @@ class) is as easy as setting:
c.SingleInflight = true c.SingleInflight = true
If these "advanced" features are not needed, a simple UDP query can be send, More advanced options are availabe using a net.Dialer and the corresponding API.
For example it is possible to set a timeout, or to specify a source IP address
and port to use for the connection:
c := new(dns.Client)
laddr := net.UDPAddr{
IP: net.ParseIP("[::1]"),
Port: 12345,
Zone: "",
}
d := net.Dialer{
Timeout: 200 * time.Millisecond,
LocalAddr: &laddr,
}
in, rtt, err := c.ExchangeWithDialer(&d, m1, "8.8.8.8:53")
If these "advanced" features are not needed, a simple UDP query can be sent,
with: with:
in, err := dns.Exchange(m1, "127.0.0.1:53") in, err := dns.Exchange(m1, "127.0.0.1:53")

15
vendor/github.com/miekg/dns/edns.go сгенерированный поставляемый
Просмотреть файл

@@ -21,6 +21,7 @@ const (
EDNS0EXPIRE = 0x9 // EDNS0 expire EDNS0EXPIRE = 0x9 // EDNS0 expire
EDNS0COOKIE = 0xa // EDNS0 Cookie EDNS0COOKIE = 0xa // EDNS0 Cookie
EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828) EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (RFC7828)
EDNS0PADDING = 0xc // EDNS0 padding (RFC7830)
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891) EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891) EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
@@ -74,6 +75,8 @@ func (rr *OPT) String() string {
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
case *EDNS0_LOCAL: case *EDNS0_LOCAL:
s += "\n; LOCAL OPT: " + o.String() s += "\n; LOCAL OPT: " + o.String()
case *EDNS0_PADDING:
s += "\n; PADDING: " + o.String()
} }
} }
return s return s
@@ -595,3 +598,15 @@ func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
} }
return return
} }
// EDNS0_PADDING option is used to add padding to a request/response. The default
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
// compression is applied before encryption which may break signatures.
type EDNS0_PADDING struct {
Padding []byte
}
func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }

7
vendor/github.com/miekg/dns/internal/socket/cmsghdr.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,7 @@
// +build linux
package socket
func (h *cmsghdr) len() int { return int(h.Len) }
func (h *cmsghdr) lvl() int { return int(h.Level) }
func (h *cmsghdr) typ() int { return int(h.Type) }

20
vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_32bit.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,20 @@
// +build arm mips mipsle 386
// +build linux
package socket
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofCmsghdr = 0xc
)
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

20
vendor/github.com/miekg/dns/internal/socket/cmsghdr_linux_64bit.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,20 @@
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
// +build linux
package socket
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofCmsghdr = 0x10
)
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint64(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}

13
vendor/github.com/miekg/dns/internal/socket/cmsghdr_other.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
// +build !linux
package socket
type cmsghdr struct{}
const sizeofCmsghdr = 0
func (h *cmsghdr) len() int { return 0 }
func (h *cmsghdr) lvl() int { return 0 }
func (h *cmsghdr) typ() int { return 0 }
func (h *cmsghdr) set(l, lvl, typ int) {}

118
vendor/github.com/miekg/dns/internal/socket/controlmessage.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,118 @@
package socket
import (
"errors"
"unsafe"
)
func controlHeaderLen() int {
return roundup(sizeofCmsghdr)
}
func controlMessageLen(dataLen int) int {
return roundup(sizeofCmsghdr) + dataLen
}
// returns the whole length of control message.
func ControlMessageSpace(dataLen int) int {
return roundup(sizeofCmsghdr) + roundup(dataLen)
}
// A ControlMessage represents the head message in a stream of control
// messages.
//
// A control message comprises of a header, data and a few padding
// fields to conform to the interface to the kernel.
//
// See RFC 3542 for further information.
type ControlMessage []byte
// Data returns the data field of the control message at the head.
func (m ControlMessage) Data(dataLen int) []byte {
l := controlHeaderLen()
if len(m) < l || len(m) < l+dataLen {
return nil
}
return m[l : l+dataLen]
}
// ParseHeader parses and returns the header fields of the control
// message at the head.
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
l := controlHeaderLen()
if len(m) < l {
return 0, 0, 0, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
}
// Next returns the control message at the next.
func (m ControlMessage) Next(dataLen int) ControlMessage {
l := ControlMessageSpace(dataLen)
if len(m) < l {
return nil
}
return m[l:]
}
// MarshalHeader marshals the header fields of the control message at
// the head.
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
if len(m) < controlHeaderLen() {
return errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(dataLen), lvl, typ)
return nil
}
// Marshal marshals the control message at the head, and returns the next
// control message.
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
l := len(data)
if len(m) < ControlMessageSpace(l) {
return nil, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(l), lvl, typ)
if l > 0 {
copy(m.Data(l), data)
}
return m.Next(l), nil
}
// Parse parses as a single or multiple control messages.
func (m ControlMessage) Parse() ([]ControlMessage, error) {
var ms []ControlMessage
for len(m) >= controlHeaderLen() {
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
l := h.len()
if l <= 0 {
return nil, errors.New("invalid header length")
}
if uint64(l) < uint64(controlHeaderLen()) {
return nil, errors.New("invalid message length")
}
if uint64(l) > uint64(len(m)) {
return nil, errors.New("short buffer")
}
ms = append(ms, ControlMessage(m[:l]))
ll := l - controlHeaderLen()
if len(m) >= ControlMessageSpace(ll) {
m = m[ControlMessageSpace(ll):]
} else {
m = m[controlMessageLen(ll):]
}
}
return ms, nil
}
// NewControlMessage returns a new stream of control messages.
func NewControlMessage(dataLen []int) ControlMessage {
var l int
for i := range dataLen {
l += ControlMessageSpace(dataLen[i])
}
return make([]byte, l)
}

103
vendor/github.com/miekg/dns/internal/socket/controlmessage_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,103 @@
// +build linux
package socket
import (
"bytes"
"testing"
)
type mockControl struct {
Level int
Type int
Data []byte
}
func TestControlMessage(t *testing.T) {
for _, tt := range []struct {
cs []mockControl
}{
{
[]mockControl{
{Level: 1, Type: 1},
},
},
{
[]mockControl{
{Level: 2, Type: 2, Data: []byte{0xfe}},
},
},
{
[]mockControl{
{Level: 3, Type: 3, Data: []byte{0xfe, 0xff, 0xff, 0xfe}},
},
},
{
[]mockControl{
{Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}},
},
},
{
[]mockControl{
{Level: 4, Type: 4, Data: []byte{0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe}},
{Level: 2, Type: 2, Data: []byte{0xfe}},
},
},
} {
var w []byte
var tailPadLen int
mm := NewControlMessage([]int{0})
for i, c := range tt.cs {
m := NewControlMessage([]int{len(c.Data)})
l := len(m) - len(mm)
if i == len(tt.cs)-1 && l > len(c.Data) {
tailPadLen = l - len(c.Data)
}
w = append(w, m...)
}
var err error
ww := make([]byte, len(w))
copy(ww, w)
m := ControlMessage(ww)
for _, c := range tt.cs {
if err = m.MarshalHeader(c.Level, c.Type, len(c.Data)); err != nil {
t.Fatalf("(%v).MarshalHeader() = %v", tt.cs, err)
}
copy(m.Data(len(c.Data)), c.Data)
m = m.Next(len(c.Data))
}
m = ControlMessage(w)
for _, c := range tt.cs {
m, err = m.Marshal(c.Level, c.Type, c.Data)
if err != nil {
t.Fatalf("(%v).Marshal() = %v", tt.cs, err)
}
}
if !bytes.Equal(ww, w) {
t.Fatalf("got %#v; want %#v", ww, w)
}
ws := [][]byte{w}
if tailPadLen > 0 {
// Test a message with no tail padding.
nopad := w[:len(w)-tailPadLen]
ws = append(ws, [][]byte{nopad}...)
}
for _, w := range ws {
ms, err := ControlMessage(w).Parse()
if err != nil {
t.Fatalf("(%v).Parse() = %v", tt.cs, err)
}
for i, m := range ms {
lvl, typ, dataLen, err := m.ParseHeader()
if err != nil {
t.Fatalf("(%v).ParseHeader() = %v", tt.cs, err)
}
if lvl != tt.cs[i].Level || typ != tt.cs[i].Type || dataLen != len(tt.cs[i].Data) {
t.Fatalf("%v: got %d, %d, %d; want %d, %d, %d", tt.cs[i], lvl, typ, dataLen, tt.cs[i].Level, tt.cs[i].Type, len(tt.cs[i].Data))
}
}
}
}
}

4
vendor/github.com/miekg/dns/internal/socket/socket.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,4 @@
// Package socket contains ControlMessage parsing code from
// golang.org/x/net/internal/socket. Instead of supporting all possible
// architectures, we're only supporting linux 32/64 bit.
package socket

14
vendor/github.com/miekg/dns/internal/socket/sys.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,14 @@
package socket
import "unsafe"
var (
kernelAlign = func() int {
var p uintptr
return int(unsafe.Sizeof(p))
}()
)
func roundup(l int) int {
return (l + kernelAlign - 1) & ^(kernelAlign - 1)
}

7
vendor/github.com/miekg/dns/msg_helpers.go сгенерированный поставляемый
Просмотреть файл

@@ -458,6 +458,13 @@ Option:
} }
edns = append(edns, e) edns = append(edns, e)
off += int(optlen) off += int(optlen)
case EDNS0PADDING:
e := new(EDNS0_PADDING)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err
}
edns = append(edns, e)
off += int(optlen)
default: default:
e := new(EDNS0_LOCAL) e := new(EDNS0_LOCAL)
e.Code = code e.Code = code

188
vendor/github.com/miekg/dns/parse_test.go сгенерированный поставляемый
Просмотреть файл

@@ -8,6 +8,7 @@ import (
"math/rand" "math/rand"
"net" "net"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
@@ -571,81 +572,88 @@ test IN CNAME test.a.example.com.
t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9)) t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
} }
func ExampleParseZone() { func TestOmittedTTL(t *testing.T) {
zone := `$ORIGIN . zone := `
$TTL 3600 ; 1 hour $ORIGIN example.com.
name IN SOA a6.nstld.com. hostmaster.nic.name. ( example.com. 42 IN SOA ns1.example.com. hostmaster.example.com. 1 86400 60 86400 3600 ; TTL=42 SOA
203362132 ; serial example.com. NS 2 ; TTL=42 absolute owner name
300 ; refresh (5 minutes) @ MD 3 ; TTL=42 current-origin owner name
300 ; retry (5 minutes) MF 4 ; TTL=42 leading-space implied owner name
1209600 ; expire (2 weeks) 43 TYPE65280 \# 1 05 ; TTL=43 implied owner name explicit TTL
300 ; minimum (5 minutes) MB 6 ; TTL=43 leading-tab implied owner name
) $TTL 1337
$TTL 10800 ; 3 hours example.com. 88 MG 7 ; TTL=88 explicit TTL
name. 10800 IN NS name. example.com. MR 8 ; TTL=1337 after first $TTL
IN NS g6.nstld.com. $TTL 314
7200 NS h6.nstld.com. 1 TXT 9 ; TTL=1 implied owner name explicit TTL
3600 IN NS j6.nstld.com. example.com. DNAME 10 ; TTL=314 after second $TTL
IN 3600 NS k6.nstld.com.
NS l6.nstld.com.
NS a6.nstld.com.
NS c6.nstld.com.
NS d6.nstld.com.
NS f6.nstld.com.
NS m6.nstld.com.
(
NS m7.nstld.com.
)
$ORIGIN name.
0-0onlus NS ns7.ehiweb.it.
NS ns8.ehiweb.it.
0-g MX 10 mx01.nic
MX 10 mx02.nic
MX 10 mx03.nic
MX 10 mx04.nic
$ORIGIN 0-g.name
moutamassey NS ns01.yahoodomains.jp.
NS ns02.yahoodomains.jp.
` `
to := ParseZone(strings.NewReader(zone), "", "testzone") reCaseFromComment := regexp.MustCompile(`TTL=(\d+)\s+(.*)`)
for x := range to { records := ParseZone(strings.NewReader(zone), "", "")
fmt.Println(x.RR) var i int
for record := range records {
i++
if record.Error != nil {
t.Error(record.Error)
continue
}
expected := reCaseFromComment.FindStringSubmatch(record.Comment)
expectedTTL, _ := strconv.ParseUint(expected[1], 10, 32)
ttl := record.RR.Header().Ttl
if ttl != uint32(expectedTTL) {
t.Errorf("%s: expected TTL %d, got %d", expected[2], expectedTTL, ttl)
}
}
if i != 10 {
t.Errorf("expected %d records, got %d", 5, i)
} }
// Output:
// name. 3600 IN SOA a6.nstld.com. hostmaster.nic.name. 203362132 300 300 1209600 300
// name. 10800 IN NS name.
// name. 10800 IN NS g6.nstld.com.
// name. 7200 IN NS h6.nstld.com.
// name. 3600 IN NS j6.nstld.com.
// name. 3600 IN NS k6.nstld.com.
// name. 10800 IN NS l6.nstld.com.
// name. 10800 IN NS a6.nstld.com.
// name. 10800 IN NS c6.nstld.com.
// name. 10800 IN NS d6.nstld.com.
// name. 10800 IN NS f6.nstld.com.
// name. 10800 IN NS m6.nstld.com.
// name. 10800 IN NS m7.nstld.com.
// 0-0onlus.name. 10800 IN NS ns7.ehiweb.it.
// 0-0onlus.name. 10800 IN NS ns8.ehiweb.it.
// 0-g.name. 10800 IN MX 10 mx01.nic.name.
// 0-g.name. 10800 IN MX 10 mx02.nic.name.
// 0-g.name. 10800 IN MX 10 mx03.nic.name.
// 0-g.name. 10800 IN MX 10 mx04.nic.name.
// moutamassey.0-g.name.name. 10800 IN NS ns01.yahoodomains.jp.
// moutamassey.0-g.name.name. 10800 IN NS ns02.yahoodomains.jp.
} }
func ExampleHIP() { func TestRelativeNameErrors(t *testing.T) {
h := `www.example.com IN HIP ( 2 200100107B1A74DF365639CC39F1D578 var badZones = []struct {
AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p label string
9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQ zoneContents string
b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D expectedErr string
rvs.example.com. )` }{
if hip, err := NewRR(h); err == nil { {
fmt.Println(hip.String()) "relative owner name without origin",
"example.com 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600",
"bad owner name",
},
{
"relative owner name in RDATA",
"example.com. 3600 IN SOA ns hostmaster 1 86400 60 86400 3600",
"bad SOA Ns",
},
{
"origin reference without origin",
"@ 3600 IN SOA ns.example.com. hostmaster.example.com. 1 86400 60 86400 3600",
"bad owner name",
},
{
"relative owner name in $INCLUDE",
"$INCLUDE file.db example.com",
"bad origin name",
},
{
"relative owner name in $ORIGIN",
"$ORIGIN example.com",
"bad origin name",
},
}
for _, errorCase := range badZones {
entries := ParseZone(strings.NewReader(errorCase.zoneContents), "", "")
for entry := range entries {
if entry.Error == nil {
t.Errorf("%s: expected error, got nil", errorCase.label)
continue
}
err := entry.Error.err
if err != errorCase.expectedErr {
t.Errorf("%s: expected error `%s`, got `%s`", errorCase.label, errorCase.expectedErr, err)
}
}
} }
// Output:
// www.example.com. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com.
} }
func TestHIP(t *testing.T) { func TestHIP(t *testing.T) {
@@ -686,24 +694,6 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
} }
} }
func ExampleSOA() {
s := "example.com. 1000 SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100"
if soa, err := NewRR(s); err == nil {
fmt.Println(soa.String())
}
// Output:
// example.com. 1000 IN SOA master.example.com. admin.example.com. 1 4294967294 4294967293 4294967295 100
}
func TestLineNumberError(t *testing.T) {
s := "example.com. 1000 SOA master.example.com. admin.example.com. monkey 4294967294 4294967293 4294967295 100"
if _, err := NewRR(s); err != nil {
if err.Error() != "dns: bad SOA zone parameter: \"monkey\" at line: 1:68" {
t.Error("not expecting this error: ", err)
}
}
}
// Test with no known RR on the line // Test with no known RR on the line
func TestLineNumberError2(t *testing.T) { func TestLineNumberError2(t *testing.T) {
tests := map[string]string{ tests := map[string]string{
@@ -801,28 +791,6 @@ func TestLowercaseTokens(t *testing.T) {
} }
} }
func ExampleParseZone_generate() {
// From the manual: http://www.bind9.net/manual/bind/9.3.2/Bv9ARM.ch06.html#id2566761
zone := "$GENERATE 1-2 0 NS SERVER$.EXAMPLE.\n$GENERATE 1-8 $ CNAME $.0"
to := ParseZone(strings.NewReader(zone), "0.0.192.IN-ADDR.ARPA.", "")
for x := range to {
if x.Error == nil {
fmt.Println(x.RR.String())
}
}
// Output:
// 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER1.EXAMPLE.
// 0.0.0.192.IN-ADDR.ARPA. 3600 IN NS SERVER2.EXAMPLE.
// 1.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 1.0.0.0.192.IN-ADDR.ARPA.
// 2.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 2.0.0.0.192.IN-ADDR.ARPA.
// 3.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 3.0.0.0.192.IN-ADDR.ARPA.
// 4.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 4.0.0.0.192.IN-ADDR.ARPA.
// 5.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 5.0.0.0.192.IN-ADDR.ARPA.
// 6.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 6.0.0.0.192.IN-ADDR.ARPA.
// 7.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 7.0.0.0.192.IN-ADDR.ARPA.
// 8.0.0.192.IN-ADDR.ARPA. 3600 IN CNAME 8.0.0.0.192.IN-ADDR.ARPA.
}
func TestSRVPacking(t *testing.T) { func TestSRVPacking(t *testing.T) {
msg := Msg{} msg := Msg{}

2
vendor/github.com/miekg/dns/privaterr_test.go сгенерированный поставляемый
Просмотреть файл

@@ -143,7 +143,7 @@ func (rd *VERSION) Len() int {
} }
var smallzone = `$ORIGIN example.org. var smallzone = `$ORIGIN example.org.
@ SOA sns.dns.icann.org. noc.dns.icann.org. ( @ 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. (
2014091518 7200 3600 1209600 3600 2014091518 7200 3600 1209600 3600
) )
A 1.2.3.4 A 1.2.3.4

129
vendor/github.com/miekg/dns/scan.go сгенерированный поставляемый
Просмотреть файл

@@ -105,6 +105,12 @@ type Token struct {
Comment string Comment string
} }
// ttlState describes the state necessary to fill in an omitted RR TTL
type ttlState struct {
ttl uint32 // ttl is the current default TTL
isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive
}
// NewRR reads the RR contained in the string s. Only the first RR is // NewRR reads the RR contained in the string s. Only the first RR is
// returned. If s contains no RR, return nil with no error. The class // returned. If s contains no RR, return nil with no error. The class
// defaults to IN and TTL defaults to 3600. The full zone file syntax // defaults to IN and TTL defaults to 3600. The full zone file syntax
@@ -120,7 +126,8 @@ func NewRR(s string) (RR, error) {
// ReadRR reads the RR contained in q. // ReadRR reads the RR contained in q.
// See NewRR for more documentation. // See NewRR for more documentation.
func ReadRR(q io.Reader, filename string) (RR, error) { func ReadRR(q io.Reader, filename string) (RR, error) {
r := <-parseZoneHelper(q, ".", filename, 1) defttl := &ttlState{defaultTtl, false}
r := <-parseZoneHelper(q, ".", defttl, filename, 1)
if r == nil { if r == nil {
return nil, nil return nil, nil
} }
@@ -132,10 +139,10 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
} }
// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the // ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
// returned channel, which consist out the parsed RR, a potential comment or an error. // returned channel, each consisting of either a parsed RR and optional comment
// If there is an error the RR is nil. The string file is only used // or a nil RR and an error. The string file is only used
// in error reporting. The string origin is used as the initial origin, as // in error reporting. The string origin is used as the initial origin, as
// if the file would start with: $ORIGIN origin . // if the file would start with an $ORIGIN directive.
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported. // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
// The channel t is closed by ParseZone when the end of r is reached. // The channel t is closed by ParseZone when the end of r is reached.
// //
@@ -157,16 +164,16 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
// The text "; this is comment" is returned in Token.Comment. Comments inside the // The text "; this is comment" is returned in Token.Comment. Comments inside the
// RR are discarded. Comments on a line by themselves are discarded too. // RR are discarded. Comments on a line by themselves are discarded too.
func ParseZone(r io.Reader, origin, file string) chan *Token { func ParseZone(r io.Reader, origin, file string) chan *Token {
return parseZoneHelper(r, origin, file, 10000) return parseZoneHelper(r, origin, nil, file, 10000)
} }
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token { func parseZoneHelper(r io.Reader, origin string, defttl *ttlState, file string, chansize int) chan *Token {
t := make(chan *Token, chansize) t := make(chan *Token, chansize)
go parseZone(r, origin, file, t, 0) go parseZone(r, origin, defttl, file, t, 0)
return t return t
} }
func parseZone(r io.Reader, origin, f string, t chan *Token, include int) { func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *Token, include int) {
defer func() { defer func() {
if include == 0 { if include == 0 {
close(t) close(t)
@@ -186,18 +193,16 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
// After detecting these, we know the zRrtype so we can jump to functions // After detecting these, we know the zRrtype so we can jump to functions
// handling the rdata for each of these types. // handling the rdata for each of these types.
if origin == "" { if origin != "" {
origin = "." origin = Fqdn(origin)
} if _, ok := IsDomainName(origin); !ok {
origin = Fqdn(origin) t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
if _, ok := IsDomainName(origin); !ok { return
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}} }
return
} }
st := zExpectOwnerDir // initial state st := zExpectOwnerDir // initial state
var h RR_Header var h RR_Header
var defttl uint32 = defaultTtl
var prevName string var prevName string
for l := range c { for l := range c {
// Lexer spotted an error already // Lexer spotted an error already
@@ -209,27 +214,21 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
switch st { switch st {
case zExpectOwnerDir: case zExpectOwnerDir:
// We can also expect a directive, like $TTL or $ORIGIN // We can also expect a directive, like $TTL or $ORIGIN
h.Ttl = defttl if defttl != nil {
h.Ttl = defttl.ttl
}
h.Class = ClassINET h.Class = ClassINET
switch l.value { switch l.value {
case zNewline: case zNewline:
st = zExpectOwnerDir st = zExpectOwnerDir
case zOwner: case zOwner:
h.Name = l.token h.Name = l.token
if l.token[0] == '@' { name, ok := toAbsoluteName(l.token, origin)
h.Name = origin
prevName = h.Name
st = zExpectOwnerBl
break
}
if h.Name[l.length-1] != '.' {
h.Name = appendOrigin(h.Name, origin)
}
_, ok := IsDomainName(l.token)
if !ok { if !ok {
t <- &Token{Error: &ParseError{f, "bad owner name", l}} t <- &Token{Error: &ParseError{f, "bad owner name", l}}
return return
} }
h.Name = name
prevName = h.Name prevName = h.Name
st = zExpectOwnerBl st = zExpectOwnerBl
case zDirTtl: case zDirTtl:
@@ -258,8 +257,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
h.Ttl = ttl h.Ttl = ttl
// Don't about the defttl, we should take the $TTL value if defttl == nil || !defttl.isByDirective {
// defttl = ttl defttl = &ttlState{ttl, false}
}
st = zExpectAnyNoTtlBl st = zExpectAnyNoTtlBl
default: default:
@@ -282,20 +282,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
case zBlank: case zBlank:
l := <-c l := <-c
if l.value == zString { if l.value == zString {
if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err { name, ok := toAbsoluteName(l.token, origin)
if !ok {
t <- &Token{Error: &ParseError{f, "bad origin name", l}} t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return return
} }
// a new origin is specified. neworigin = name
if l.token[l.length-1] != '.' {
if origin != "." { // Prevent .. endings
neworigin = l.token + "." + origin
} else {
neworigin = l.token + origin
}
} else {
neworigin = l.token
}
} }
case zNewline, zEOF: case zNewline, zEOF:
// Ok // Ok
@@ -313,7 +305,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}} t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
return return
} }
parseZone(r1, l.token, neworigin, t, include+1) parseZone(r1, neworigin, defttl, l.token, t, include+1)
st = zExpectOwnerDir st = zExpectOwnerDir
case zExpectDirTtlBl: case zExpectDirTtlBl:
if l.value != zBlank { if l.value != zBlank {
@@ -335,7 +327,7 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return return
} }
defttl = ttl defttl = &ttlState{ttl, true}
st = zExpectOwnerDir st = zExpectOwnerDir
case zExpectDirOriginBl: case zExpectDirOriginBl:
if l.value != zBlank { if l.value != zBlank {
@@ -351,19 +343,12 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
if e, _ := slurpRemainder(c, f); e != nil { if e, _ := slurpRemainder(c, f); e != nil {
t <- &Token{Error: e} t <- &Token{Error: e}
} }
if _, ok := IsDomainName(l.token); !ok { name, ok := toAbsoluteName(l.token, origin)
if !ok {
t <- &Token{Error: &ParseError{f, "bad origin name", l}} t <- &Token{Error: &ParseError{f, "bad origin name", l}}
return return
} }
if l.token[l.length-1] != '.' { origin = name
if origin != "." { // Prevent .. endings
origin = l.token + "." + origin
} else {
origin = l.token + origin
}
} else {
origin = l.token
}
st = zExpectOwnerDir st = zExpectOwnerDir
case zExpectDirGenerateBl: case zExpectDirGenerateBl:
if l.value != zBlank { if l.value != zBlank {
@@ -390,6 +375,10 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
case zExpectAny: case zExpectAny:
switch l.value { switch l.value {
case zRrtpe: case zRrtpe:
if defttl == nil {
t <- &Token{Error: &ParseError{f, "missing TTL with no previous value", l}}
return
}
h.Rrtype = l.torc h.Rrtype = l.torc
st = zExpectRdata st = zExpectRdata
case zClass: case zClass:
@@ -402,7 +391,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
h.Ttl = ttl h.Ttl = ttl
// defttl = ttl // don't set the defttl here if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
st = zExpectAnyNoTtlBl st = zExpectAnyNoTtlBl
default: default:
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}} t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
@@ -441,7 +432,9 @@ func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
return return
} }
h.Ttl = ttl h.Ttl = ttl
// defttl = ttl // don't set the def ttl anymore if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
st = zExpectRrtypeBl st = zExpectRrtypeBl
case zRrtpe: case zRrtpe:
h.Rrtype = l.torc h.Rrtype = l.torc
@@ -918,6 +911,34 @@ func stringToCm(token string) (e, m uint8, ok bool) {
return return
} }
func toAbsoluteName(name, origin string) (absolute string, ok bool) {
// check for an explicit origin reference
if name == "@" {
// require a nonempty origin
if origin == "" {
return "", false
}
return origin, true
}
// require a valid domain name
_, ok = IsDomainName(name)
if !ok || name == "" {
return "", false
}
// check if name is already absolute
if name[len(name)-1] == '.' {
return name, true
}
// require a nonempty origin
if origin == "" {
return "", false
}
return appendOrigin(name, origin), true
}
func appendOrigin(name, origin string) string { func appendOrigin(name, origin string) string {
if origin == "." { if origin == "." {
return name + origin return name + origin

592
vendor/github.com/miekg/dns/scan_rr.go сгенерированный поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

5
vendor/github.com/miekg/dns/scan_test.go сгенерированный поставляемый
Просмотреть файл

@@ -21,13 +21,16 @@ func TestParseZoneInclude(t *testing.T) {
t.Fatalf("could not close tmpfile %q: %s", tmpfile.Name(), err) t.Fatalf("could not close tmpfile %q: %s", tmpfile.Name(), err)
} }
zone := "$INCLUDE " + tmpfile.Name() zone := "$ORIGIN example.org.\n$INCLUDE " + tmpfile.Name()
tok := ParseZone(strings.NewReader(zone), "", "") tok := ParseZone(strings.NewReader(zone), "", "")
for x := range tok { for x := range tok {
if x.Error != nil { if x.Error != nil {
t.Fatalf("expected no error, but got %s", x.Error) t.Fatalf("expected no error, but got %s", x.Error)
} }
if x.RR.Header().Name != "foo.example.org." {
t.Fatalf("expected %s, but got %s", "foo.example.org.", x.RR.Header().Name)
}
} }
os.Remove(tmpfile.Name()) os.Remove(tmpfile.Name())

10
vendor/github.com/miekg/dns/server_test.go сгенерированный поставляемый
Просмотреть файл

@@ -30,6 +30,16 @@ func HelloServerBadID(w ResponseWriter, req *Msg) {
w.WriteMsg(m) w.WriteMsg(m)
} }
func HelloServerEchoAddrPort(w ResponseWriter, req *Msg) {
m := new(Msg)
m.SetReply(req)
remoteAddr := w.RemoteAddr().String()
m.Extra = make([]RR, 1)
m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{remoteAddr}}
w.WriteMsg(m)
}
func AnotherHelloServer(w ResponseWriter, req *Msg) { func AnotherHelloServer(w ResponseWriter, req *Msg) {
m := new(Msg) m := new(Msg)
m.SetReply(req) m.SetReply(req)

15
vendor/github.com/miekg/dns/udp.go сгенерированный поставляемый
Просмотреть файл

@@ -27,8 +27,19 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
return n, &SessionUDP{raddr, oob[:oobn]}, err return n, &SessionUDP{raddr, oob[:oobn]}, err
} }
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr. // WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) { func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr) oob := correctSource(session.context)
n, _, err := conn.WriteMsgUDP(b, oob, session.raddr)
return n, err return n, err
} }
// correctSource takes oob data and returns new oob data with the Src equal to the Dst
func correctSource(oob []byte) []byte {
dst, err := parseUDPSocketDst(oob)
// If the destination could not be determined, ignore.
if err != nil || dst == nil {
return nil
}
return marshalUDPSocketSrc(dst)
}

115
vendor/github.com/miekg/dns/udp_linux.go сгенерированный поставляемый
Просмотреть файл

@@ -13,8 +13,34 @@ package dns
import ( import (
"net" "net"
"syscall" "syscall"
"unsafe"
"github.com/miekg/dns/internal/socket"
) )
const (
sizeofInet6Pktinfo = 0x14
sizeofInetPktinfo = 0xc
protocolIP = 0
protocolIPv6 = 41
)
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type inetControlMessage struct {
Src net.IP // source address, specifying only
Dst net.IP // destination address, receiving only
}
// setUDPSocketOptions sets the UDP socket options. // setUDPSocketOptions sets the UDP socket options.
// This function is implemented on a per platform basis. See udp_*.go for more details // This function is implemented on a per platform basis. See udp_*.go for more details
func setUDPSocketOptions(conn *net.UDPConn) error { func setUDPSocketOptions(conn *net.UDPConn) error {
@@ -103,3 +129,92 @@ func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
defer file.Close() defer file.Close()
return syscall.Getsockname(int(file.Fd())) return syscall.Getsockname(int(file.Fd()))
} }
// marshalInetPacketInfo marshals a ipv4 control message, returning
// the byte slice for the next marshal, if any
func marshalInetPacketInfo(b []byte, cm *inetControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(protocolIP, syscall.IP_PKTINFO, sizeofInetPktinfo)
if cm != nil {
pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.Spec_dst[:], ip)
}
}
return m.Next(sizeofInetPktinfo)
}
// marshalInet6PacketInfo marshals a ipv6 control message, returning
// the byte slice for the next marshal, if any
func marshalInet6PacketInfo(b []byte, cm *inetControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(protocolIPv6, syscall.IPV6_PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
}
return m.Next(sizeofInet6Pktinfo)
}
func parseInetPacketInfo(cm *inetControlMessage, b []byte) {
pi := (*inetPktinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv4len {
cm.Dst = make(net.IP, net.IPv4len)
}
copy(cm.Dst, pi.Addr[:])
}
func parseInet6PacketInfo(cm *inetControlMessage, b []byte) {
pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, pi.Addr[:])
}
// parseUDPSocketDst takes out-of-band data from ReadMsgUDP and parses it for
// the Dst address
func parseUDPSocketDst(oob []byte) (net.IP, error) {
cm := new(inetControlMessage)
ms, err := socket.ControlMessage(oob).Parse()
if err != nil {
return nil, err
}
for _, m := range ms {
lvl, typ, l, err := m.ParseHeader()
if err != nil {
return nil, err
}
if lvl == protocolIPv6 { // IPv6
if typ == syscall.IPV6_PKTINFO && l >= sizeofInet6Pktinfo {
parseInet6PacketInfo(cm, m.Data(l))
}
} else if lvl == protocolIP { // IPv4
if typ == syscall.IP_PKTINFO && l >= sizeofInetPktinfo {
parseInetPacketInfo(cm, m.Data(l))
}
}
}
return cm.Dst, nil
}
// marshalUDPSocketSrc takes the given src address and returns out-of-band data
// to give to WriteMsgUDP
func marshalUDPSocketSrc(src net.IP) []byte {
var oob []byte
// If the dst is definitely an ipv6, then use ipv6 control to respond
// otherwise use ipv4 because the ipv6 marshal ignores ipv4 messages.
// See marshalInet6PacketInfo
cm := new(inetControlMessage)
cm.Src = src
if src.To4() == nil {
oob = make([]byte, socket.ControlMessageSpace(sizeofInet6Pktinfo))
marshalInet6PacketInfo(oob, cm)
} else {
oob = make([]byte, socket.ControlMessageSpace(sizeofInetPktinfo))
marshalInetPacketInfo(oob, cm)
}
return oob
}

68
vendor/github.com/miekg/dns/udp_linux_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,68 @@
// +build linux,!appengine
package dns
import (
"bytes"
"net"
"testing"
)
func TestParseUDPSocketDst(t *testing.T) {
// dst is :ffff:100.100.100.100
oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0}
dst, err := parseUDPSocketDst(oob)
if err != nil {
t.Fatalf("error parsing ipv6 oob: %v", err)
}
dst4 := dst.To4()
if dst4 == nil {
t.Errorf("failed to parse ipv4: %v", dst)
} else if dst4.String() != "100.100.100.100" {
t.Errorf("unexpected ipv4: %v", dst4)
}
// dst is 2001:db8::1
oob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}
dst, err = parseUDPSocketDst(oob)
if err != nil {
t.Fatalf("error parsing ipv6 oob: %v", err)
}
dst6 := dst.To16()
if dst6 == nil {
t.Errorf("failed to parse ipv6: %v", dst)
} else if dst6.String() != "2001:db8::1" {
t.Errorf("unexpected ipv6: %v", dst4)
}
// dst is 100.100.100.100 but was received on 10.10.10.10
oob = []byte{28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10, 10, 100, 100, 100, 100, 0, 0, 0, 0}
dst, err = parseUDPSocketDst(oob)
if err != nil {
t.Fatalf("error parsing ipv4 oob: %v", err)
}
dst4 = dst.To4()
if dst4 == nil {
t.Errorf("failed to parse ipv4: %v", dst)
} else if dst4.String() != "100.100.100.100" {
t.Errorf("unexpected ipv4: %v", dst4)
}
}
func TestMarshalUDPSocketSrc(t *testing.T) {
// src is 100.100.100.100
exoob := []byte{28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 100, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0}
oob := marshalUDPSocketSrc(net.ParseIP("100.100.100.100"))
if !bytes.Equal(exoob, oob) {
t.Errorf("expected ipv4 oob:\n%v", exoob)
t.Errorf("actual ipv4 oob:\n%v", oob)
}
// src is 2001:db8::1
exoob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}
oob = marshalUDPSocketSrc(net.ParseIP("2001:db8::1"))
if !bytes.Equal(exoob, oob) {
t.Errorf("expected ipv6 oob:\n%v", exoob)
t.Errorf("actual ipv6 oob:\n%v", oob)
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше