diff --git a/Makefile b/Makefile index 3ad83bd6..37ff9a4d 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ WEBROOT=~/src/github.com/kubernetes/website K8SROOT=~/src/github.com/kubernetes/kubernetes MINOR_VERSION=11 -APISRC=gen-apidocs/generators/build -APIDST=$(WEBROOT)/docs/reference/generated/kubernetes-api/v1.$(MINOR_VERSION) -APISRCFONT=$(APISRC)/node_modules/font-awesome +APISRC=gen-apidocs/generators +APIDST=$(WEBROOT)/static/docs/reference/generated/kubernetes-api/v1.$(MINOR_VERSION) +APISRCFONT=$(APISRC)/build/node_modules/font-awesome APIDSTFONT=$(APIDST)/node_modules/font-awesome CLISRC=gen-kubectldocs/generators/build @@ -15,13 +15,6 @@ CLIDSTFONT=$(CLIDST)/node_modules/font-awesome default: @echo "Support commands:\ncli api comp copycli copyapi copycomp updateapispec" -brodocs: - docker build . -t pwittrock/brodocs - docker push pwittrock/brodocs - -updateapispec: - cp $(K8SROOT)/api/openapi-spec/swagger.json gen-apidocs/generators/openapi-spec/swagger.json - # Build kubectl docs cleancli: sudo rm -f main @@ -45,10 +38,6 @@ copycli: cli cp $(CLISRC)/node_modules/jquery/dist/jquery.min.js $(CLIDST)/node_modules/jquery/dist/jquery.min.js cp $(CLISRCFONT)/css/font-awesome.min.css $(CLIDSTFONT)/css/font-awesome.min.css -api: cleanapi - go run gen-apidocs/main.go --config-dir=gen-apidocs/generators --munge-groups=false - docker run -v $(shell pwd)/gen-apidocs/generators/includes:/source -v $(shell pwd)/gen-apidocs/generators/build:/build -v $(shell pwd)/gen-apidocs/generators/:/manifest pwittrock/brodocs - # Build kube component docs cleancomp: rm -rf $(shell pwd)/gen-compdocs/build @@ -67,31 +56,33 @@ copycomp: cp $(shell pwd)/gen-compdocs/build/* $(WEBROOT)/docs/reference/generated/ # Build api docs +updateapispec: + cp $(K8SROOT)/api/openapi-spec/swagger.json gen-apidocs/generators/openapi-spec/swagger.json + +api: cleanapi + go run gen-apidocs/main.go --config-dir=gen-apidocs/generators --munge-groups=false + +# NOTE: The following "sudo" may go away when we remove docker based api doc generator cleanapi: - sudo rm -f main sudo rm -rf $(shell pwd)/gen-apidocs/generators/build sudo rm -rf $(shell pwd)/gen-apidocs/generators/includes - sudo rm -rf $(shell pwd)/gen-apidocs/generators/manifest.json copyapi: - cp $(APISRC)/index.html $(APIDST)/index.html - cp $(APISRC)/navData.js $(APIDST)/navData.js - cp $(APISRC)/scroll.js $(APIDST)/scroll.js - cp $(APISRC)/stylesheet.css $(APIDST)/stylesheet.css - cp $(APISRC)/tabvisibility.js $(APIDST)/tabvisibility.js - cp $(APISRC)/node_modules/bootstrap/dist/css/bootstrap.min.css $(APIDST)/node_modules/bootstrap/dist/css/bootstrap.min.css - cp $(APISRC)/node_modules/highlight.js/styles/default.css $(APIDST)/node_modules/highlight.js/styles/default.css - cp $(APISRC)/node_modules/jquery.scrollto/jquery.scrollTo.min.js $(APIDST)/node_modules/jquery.scrollto/jquery.scrollTo.min.js - cp $(APISRC)/node_modules/jquery/dist/jquery.min.js $(APIDST)/node_modules/jquery/dist/jquery.min.js - cp $(APISRCFONT)/css/font-awesome.css $(APIDSTFONT)/css/font-awesome.css - cp $(APISRCFONT)/css/font-awesome.css.map $(APIDSTFONT)/css/font-awesome.css.map - cp $(APISRCFONT)/css/font-awesome.min.css $(APIDSTFONT)/css/font-awesome.min.css - cp $(APISRCFONT)/fonts/FontAwesome.otf $(APIDSTFONT)/fonts/FontAwesome.otf - cp $(APISRCFONT)/fonts/fontawesome-webfont.eot $(APIDSTFONT)/fonts/fontawesome-webfont.eot - cp $(APISRCFONT)/fonts/fontawesome-webfont.svg $(APIDSTFONT)/fonts/fontawesome-webfont.svg - cp $(APISRCFONT)/fonts/fontawesome-webfont.ttf $(APIDSTFONT)/fonts/fontawesome-webfont.ttf - cp $(APISRCFONT)/fonts/fontawesome-webfont.woff $(APIDSTFONT)/fonts/fontawesome-webfont.woff - cp $(APISRCFONT)/fonts/fontawesome-webfont.woff2 $(APIDSTFONT)/fonts/fontawesome-webfont.woff2 + cp $(APISRC)/build/index.html $(APIDST)/index.html + cp $(APISRC)/build/navData.js $(APIDST)/navData.js + cp $(APISRC)/static/scroll.js $(APIDST)/scroll.js + mkdir -p $(APIDST)/css + cp $(APISRC)/static/stylesheet.css $(APIDST)/css/stylesheet.css + cp $(APISRC)/static/bootstrap.min.css $(APIDST)/css/bootstrap.min.css + cp $(APISRC)/static/jquery.scrollTo.min.js $(APIDST)/jquery.scrollTo.min.js + cp $(APISRC)/static/font-awesome.min.css $(APIDST)/css/font-awesome.min.css + mkdir -p $(APIDST)/fonts + cp $(APISRC)/static/FontAwesome.otf $(APIDST)/fonts/FontAwesome.otf + cp $(APISRC)/static/fontawesome-webfont.eot $(APIDST)/fonts/fontawesome-webfont.eot + cp $(APISRC)/static/fontawesome-webfont.svg $(APIDST)/fonts/fontawesome-webfont.svg + cp $(APISRC)/static/fontawesome-webfont.ttf $(APIDST)/fonts/fontawesome-webfont.ttf + cp $(APISRC)/static/fontawesome-webfont.woff $(APIDST)/fonts/fontawesome-webfont.woff + cp $(APISRC)/static/fontawesome-webfont.woff2 $(APIDST)/fonts/fontawesome-webfont.woff2 # Build resource docs resource: cleanapi @@ -104,3 +95,39 @@ copyresource: resource rm -rf gen-apidocs/generators/build/manifest.json rm -rf $(WEBROOT)/docs/resources-reference/v1.$(MINOR_VERSION)/* cp -r gen-apidocs/generators/build/* $(WEBROOT)/docs/resources-reference/v1.$(MINOR_VERSION)/ + + +# Brodocs way of API generation, to be removed +cleanbrodocsapi: + sudo rm -rf $(shell pwd)/gen-apidocs/generators/build + sudo rm -rf $(shell pwd)/gen-apidocs/generators/includes + sudo rm -rf $(shell pwd)/gen-apidocs/generators/manifest.json + +brodocsapi: cleanbrodocsapi + go run gen-apidocs/main.go --config-dir=gen-apidocs/generators --munge-groups=false --backend=brodocs + docker run -v $(shell pwd)/gen-apidocs/generators/includes:/source -v $(shell pwd)/gen-apidocs/generators/build:/build -v $(shell pwd)/gen-apidocs/generators/:/manifest pwittrock/brodocs + +brodocs: + docker build . -t pwittrock/brodocs + docker push pwittrock/brodocs + +copybrodocsapi: + cp $(APISRC)/build/index.html $(APIDST)/index.html + cp $(APISRC)/build/navData.js $(APIDST)/navData.js + cp $(APISRC)/build/scroll.js $(APIDST)/scroll.js + cp $(APISRC)/build/stylesheet.css $(APIDST)/stylesheet.css + cp $(APISRC)/build/tabvisibility.js $(APIDST)/tabvisibility.js + cp $(APISRC)/build/node_modules/bootstrap/dist/css/bootstrap.min.css $(APIDST)/node_modules/bootstrap/dist/css/bootstrap.min.css + cp $(APISRC)/build/node_modules/highlight.js/styles/default.css $(APIDST)/node_modules/highlight.js/styles/default.css + cp $(APISRC)/build/node_modules/jquery.scrollto/jquery.scrollTo.min.js $(APIDST)/node_modules/jquery.scrollto/jquery.scrollTo.min.js + cp $(APISRC)/build/node_modules/jquery/dist/jquery.min.js $(APIDST)/node_modules/jquery/dist/jquery.min.js + cp $(APISRCFONT)/css/font-awesome.css $(APIDSTFONT)/css/font-awesome.css + cp $(APISRCFONT)/css/font-awesome.css.map $(APIDSTFONT)/css/font-awesome.css.map + cp $(APISRCFONT)/css/font-awesome.min.css $(APIDSTFONT)/css/font-awesome.min.css + cp $(APISRCFONT)/fonts/FontAwesome.otf $(APIDSTFONT)/fonts/FontAwesome.otf + cp $(APISRCFONT)/fonts/fontawesome-webfont.eot $(APIDSTFONT)/fonts/fontawesome-webfont.eot + cp $(APISRCFONT)/fonts/fontawesome-webfont.svg $(APIDSTFONT)/fonts/fontawesome-webfont.svg + cp $(APISRCFONT)/fonts/fontawesome-webfont.ttf $(APIDSTFONT)/fonts/fontawesome-webfont.ttf + cp $(APISRCFONT)/fonts/fontawesome-webfont.woff $(APIDSTFONT)/fonts/fontawesome-webfont.woff + cp $(APISRCFONT)/fonts/fontawesome-webfont.woff2 $(APIDSTFONT)/fonts/fontawesome-webfont.woff2 + diff --git a/gen-apidocs/generators/api/api_version.go b/gen-apidocs/generators/api/api.go similarity index 67% rename from gen-apidocs/generators/api/api_version.go rename to gen-apidocs/generators/api/api.go index 822e8eb9..1f63f980 100644 --- a/gen-apidocs/generators/api/api_version.go +++ b/gen-apidocs/generators/api/api.go @@ -18,9 +18,35 @@ package api import ( "regexp" + "strings" ) -type ApiVersion string +func (a ApiGroup) String() string { + return string(a) +} + +func (a ApiGroups) Len() int { return len(a) } +func (a ApiGroups) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ApiGroups) Less(i, j int) bool { + // "apps" group APIs are newer than "extensions" group APIs + if a[i].String() == "apps" && a[j].String() == "extensions" { + return false + } + if a[j].String() == "apps" && a[i].String() == "extensions" { + return true + } + return strings.Compare(a[i].String(), a[j].String()) < 0 +} + +func (a ApiVersions) Len() int { return len(a) } +func (a ApiVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ApiVersions) Less(i, j int) bool { + return a[i].LessThan(a[j]) +} + +func (k ApiKind) String() string { + return string(k) +} func (this ApiVersion) LessThan(that ApiVersion) bool { re := regexp.MustCompile("(v\\d+)(alpha|beta|)(\\d*)") @@ -52,14 +78,9 @@ func (this ApiVersion) LessThan(that ApiVersion) bool { } // The string with the higher number comes first (or in the case of alpha/beta, beta comes first) if v1 != v2 { - //fmt.Printf("Less than %v (%s %s) this: %s %v that: %s %v\n", v1 < v2, v1, v2, this, thisMatches, that, thatMatches) return v1 > v2 } } - // They have the same value return false } -func (a ApiVersion) String() string { - return string(a) -} diff --git a/gen-apidocs/generators/api/api_group.go b/gen-apidocs/generators/api/api_group.go deleted file mode 100644 index 3b4124f6..00000000 --- a/gen-apidocs/generators/api/api_group.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package api - -import "strings" - -type ApiGroup string - -type ApiGroups []ApiGroup - -func (a ApiGroup) String() string { - return string(a) -} - -func (a ApiGroups) Len() int { return len(a) } -func (a ApiGroups) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a ApiGroups) Less(i, j int) bool { - // "apps" group APIs are newer than "extensions" group APIs - if a[i].String() == "apps" && a[j].String() == "extensions" { - return false - } - if a[j].String() == "apps" && a[i].String() == "extensions" { - return true - } - return strings.Compare(a[i].String(), a[j].String()) < 0 -} - -type ApiVersions []ApiVersion - -func (a ApiVersions) Len() int { return len(a) } -func (a ApiVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a ApiVersions) Less(i, j int) bool { - return a[i].LessThan(a[j]) -} diff --git a/gen-apidocs/generators/api/api_kind.go b/gen-apidocs/generators/api/api_kind.go deleted file mode 100644 index f90fd7c0..00000000 --- a/gen-apidocs/generators/api/api_kind.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package api - -type ApiKind string - -func (a ApiKind) String() string { - return string(a) -} diff --git a/gen-apidocs/generators/api/config.go b/gen-apidocs/generators/api/config.go index 7198b4a8..46ac91d8 100644 --- a/gen-apidocs/generators/api/config.go +++ b/gen-apidocs/generators/api/config.go @@ -20,15 +20,14 @@ import ( "flag" "fmt" "gopkg.in/yaml.v2" + "html" "io/ioutil" "log" "os" "path/filepath" - "regexp" "sort" "strings" "unicode" - "html" "github.com/go-openapi/loads" ) @@ -38,78 +37,25 @@ var ConfigDir = flag.String("config-dir", "", "Directory contain api files.") var UseTags = flag.Bool("use-tags", false, "If true, use the openapi tags instead of the config yaml.") var MungeGroups = flag.Bool("munge-groups", true, "If true, munge the group names for the operations to match.") -func (config *Config) genConfigFromTags(specs []*loads.Document) { - log.Printf("Using openapi extension tags to configure.") - - config.ExampleLocation = "examples" - // build the apis from the groups that are observed - groupsMap := map[ApiGroup]DefinitionList{} - for _, definition := range config.Definitions.GetAllDefinitions() { - if strings.HasSuffix(definition.Name, "List") { - continue - } - if strings.HasSuffix(definition.Name, "Status") { - continue - } - if strings.HasPrefix(definition.Description(), "Deprecated. Please use") { - // Don't look at deprecated types - continue - } - config.initDefExample(definition) // Init the example yaml - g := definition.Group - groupsMap[g] = append(groupsMap[g], definition) - } - groupsList := ApiGroups{} - for g := range groupsMap { - groupsList = append(groupsList, g) - } - sort.Sort(groupsList) - for _, g := range groupsList { - groupName := strings.Title(string(g)) - config.ApiGroups = append(config.ApiGroups, ApiGroup(groupName)) - rc := ResourceCategory{} - rc.Include = string(g) - rc.Name = groupName - defList := groupsMap[g] - sort.Sort(defList) - for _, d := range defList { - r := &Resource{} - r.Name = d.Name - r.Group = string(d.Group) - r.Version = string(d.Version) - r.Definition = d - rc.Resources = append(rc.Resources, r) - } - config.ResourceCategories = append(config.ResourceCategories, rc) - } -} - func NewConfig() *Config { - config := loadYamlConfig() + config := LoadConfigFromYAML() specs := LoadOpenApiSpec() // Initialize all of the operations - config.Definitions = GetDefinitions(specs) + config.Definitions = NewDefinitions(specs) if *UseTags { // Initialize the config and ToC from the tags on definitions config.genConfigFromTags(specs) } else { // Initialization for ToC resources only - vistToc := func(resource *Resource, definition *Definition) { - definition.InToc = true // Mark as in Toc - resource.Definition = definition - config.initDefExample(definition) // Init the example yaml - } - config.VisitResourcesInToc(config.Definitions, vistToc) + config.visitResourcesInToc() } - // Get the map of operations appearing in the open-api spec keyed by id - config.InitOperations(specs) - + config.initOperations(specs) - // In the descriptions, replace unicode escape sequences with HTML entities. - config.createDescriptionsWithEntities() + // replace unicode escape sequences with HTML entities. + config.escapeDescriptions() config.CleanUp() @@ -136,93 +82,64 @@ func NewConfig() *Config { return config } -func verifyBlacklisted(operation Operation) { - switch { - case strings.Contains(operation.ID, "connectCoreV1Patch"): - //case strings.Contains(operation.ID, "NamespacedScheduledJob"): - //case strings.Contains(operation.ID, "ScheduledJobForAllNamespaces"): - //case strings.Contains(operation.ID, "ScheduledJobListForAllNamespaces"): - case strings.Contains(operation.ID, "V1beta1NamespacedReplicationControllerDummyScale"): - case strings.Contains(operation.ID, "NamespacedPodAttach"): - case strings.Contains(operation.ID, "NamespacedPodWithPath"): - case strings.Contains(operation.ID, "proxyCoreV1"): - //case strings.Contains(operation.ID, "NamespacedScaleScale"): - //case strings.Contains(operation.ID, "NamespacedBindingBinding"): - case strings.Contains(operation.ID, "NamespacedPodExe"): - case strings.Contains(operation.ID, "logFileHandler"): - case strings.Contains(operation.ID, "logFileListHandler"): - case strings.Contains(operation.ID, "replaceCoreV1NamespaceFinalize"): - //case strings.Contains(operation.ID, "NamespacedEvictionEviction"): - case strings.Contains(operation.ID, "getCodeVersion"): - case strings.Contains(operation.ID, "V1beta1CertificateSigningRequestApproval"): - default: - //panic(fmt.Sprintf("No Definition found for %s [%s]. \n", operation.ID, operation.Path)) - fmt.Printf("No Definition found for %s [%s]. \n", operation.ID, operation.Path) - } -} +func (c *Config) genConfigFromTags(specs []*loads.Document) { + log.Printf("Using OpenAPI extension tags to configure.") -// /apis///namespaces/{namespace}//{name}/ -var matchNamespaced = regexp.MustCompile( - `^/apis/([A-Za-z0-9\.]+)/([A-Za-z0-9]+)/namespaces/\{namespace\}/([A-Za-z0-9\.]+)/\{name\}/([A-Za-z0-9\.]+)$`) -var matchUnnamespaced = regexp.MustCompile( - `^/apis/([A-Za-z0-9\.]+)/([A-Za-z0-9]+)/([A-Za-z0-9\.]+)/\{name\}/([A-Za-z0-9\.]+)$`) - -func GetMethod(o *Operation) string { - switch o.HttpMethod { - case "GET": - return "List" - case "POST": - return "Create" - case "PATCH": - return "Patch" - case "DELETE": - return "Delete" - case "PUT": - return "Update" + c.ExampleLocation = "examples" + // build the apis from the observed groups + groupsMap := map[ApiGroup]DefinitionList{} + for _, d := range c.Definitions.All { + if strings.HasSuffix(d.Name, "List") { + continue + } + if strings.HasSuffix(d.Name, "Status") { + continue + } + if strings.HasPrefix(d.Description(), "Deprecated. Please use") { + // Don't look at deprecated types + continue + } + d.initExample(c) + g := d.Group + groupsMap[g] = append(groupsMap[g], d) } - return "" -} -func GetGroupVersionKindSub(o *Operation) (string, string, string, string) { - if matchNamespaced.MatchString(o.Path) { - m := matchNamespaced.FindStringSubmatch(o.Path) - //fmt.Printf("Match %s\n", o.Path) - group := m[1] - group = strings.Split(group, ".")[0] - version := m[2] - resource := m[3] - subresource := m[4] - return group, version, resource, subresource - - } else if matchUnnamespaced.MatchString(o.Path) { - m := matchUnnamespaced.FindStringSubmatch(o.Path) - //fmt.Printf("Match %s\n", o.Path) - group := m[1] - version := m[2] - resource := m[3] - subresource := m[4] - return group, version, resource, subresource + groupsList := ApiGroups{} + for g := range groupsMap { + groupsList = append(groupsList, g) } - return "", "", "", "" -} -func GetResourceName(d *Definition) string { - if len(d.Resource) > 0 { - return d.Resource - } - resource := strings.ToLower(d.Name) - if strings.HasSuffix(resource, "y") { - return strings.TrimSuffix(resource, "y") + "ies" + sort.Sort(groupsList) + + for _, g := range groupsList { + groupName := strings.Title(string(g)) + c.ApiGroups = append(c.ApiGroups, ApiGroup(groupName)) + rc := ResourceCategory{ + Include: string(g), + Name: groupName, + } + defList := groupsMap[g] + sort.Sort(defList) + for _, d := range defList { + r := &Resource{ + Name: d.Name, + Group: string(d.Group), + Version: string(d.Version), + Definition: d, + } + rc.Resources = append(rc.Resources, r) + } + c.ResourceCategories = append(c.ResourceCategories, rc) } - return resource + "s" } func (config *Config) initOperationsFromTags(specs []*loads.Document) { if *UseTags { ops := map[string]map[string][]*Operation{} defs := map[string]*Definition{} - for _, c := range config.Definitions.ByGroupVersionKind { - defs[fmt.Sprintf("%s.%s.%s", c.Group, c.Version, GetResourceName(c))] = c + for _, d := range config.Definitions.All { + name := fmt.Sprintf("%s.%s.%s", d.Group, d.Version, d.GetResourceName()) + defs[name] = d } VisitOperations(specs, func(operation Operation) { @@ -232,14 +149,14 @@ func (config *Config) initOperationsFromTags(specs []*loads.Document) { op := operation o := &op config.Operations[operation.ID] = o - group, version, resource, sub := GetGroupVersionKindSub(o) + group, version, kind, sub := o.GetGroupVersionKindSub() if sub == "status" { return } if len(group) == 0 { return } - key := fmt.Sprintf("%s.%s.%s", group, version, resource) + key := fmt.Sprintf("%s.%s.%s", group, version, kind) o.Definition = defs[key] // Index by group and subresource @@ -262,10 +179,9 @@ func (config *Config) initOperationsFromTags(specs []*loads.Document) { for _, s := range subs { cat := &OperationCategory{} cat.Name = strings.Title(s) + " Operations" - oplist := subMap[s] - for _, op := range oplist { + for _, op := range subMap[s] { ot := OperationType{} - ot.Name = GetMethod(op) + " " + strings.Title(s) + ot.Name = op.GetMethod() + " " + strings.Title(s) op.Type = ot cat.Operations = append(cat.Operations, op) } @@ -275,13 +191,13 @@ func (config *Config) initOperationsFromTags(specs []*loads.Document) { } } -// GetOperations returns all Operations found in the Documents -func (config *Config) InitOperations(specs []*loads.Document) { - o := Operations{} +// initOperations returns all Operations found in the Documents +func (c *Config) initOperations(specs []*loads.Document) { + ops := Operations{} - config.GroupMap = map[string]string{} - VisitOperations(specs, func(operation Operation) { - o[operation.ID] = &operation + c.GroupMap = map[string]string{} + VisitOperations(specs, func(op Operation) { + ops[op.ID] = &op // Build a map of the group names to the group name appearing in operation ids // This is necessary because the group will appear without the domain @@ -290,7 +206,7 @@ func (config *Config) InitOperations(specs []*loads.Document) { // don't agree on the name of the group. // TODO: Fix this by getting the group-version-kind in the resource if *MungeGroups { - if v, f := operation.op.Extensions[typeKey]; f { + if v, ok := op.op.Extensions[typeKey]; ok { gvk := v.(map[string]interface{}) group, ok := gvk["group"].(string) if !ok { @@ -300,28 +216,28 @@ func (config *Config) InitOperations(specs []*loads.Document) { for _, s := range strings.Split(group, ".") { groupId = groupId + strings.Title(s) } - config.GroupMap[strings.Title(strings.Split(group, ".")[0])] = groupId + c.GroupMap[strings.Title(strings.Split(group, ".")[0])] = groupId } } }) - config.Operations = o - config.mapOperationsToDefinitions() - config.initOperationsFromTags(specs) + c.Operations = ops + c.mapOperationsToDefinitions() + c.initOperationsFromTags(specs) - VisitOperations(specs, func(operation Operation) { - if o, found := config.Operations[operation.ID]; !found || o.Definition == nil { - verifyBlacklisted(operation) + VisitOperations(specs, func(target Operation) { + if op, ok := c.Operations[target.ID]; !ok || op.Definition == nil { + op.VerifyBlackListed() } }) - config.Definitions.initializeOperationParameters(config.Operations) + c.initOperationParameters() // Clear the operations. We still have to calculate the operations because that is how we determine // the API Group for each definition. if !*BuildOps { - config.Operations = Operations{} - config.OperationCategories = []OperationCategory{} - for _, d := range config.Definitions.GetAllDefinitions() { + c.Operations = Operations{} + c.OperationCategories = []OperationCategory{} + for _, d := range c.Definitions.All { d.OperationCategories = []*OperationCategory{} } } @@ -329,7 +245,7 @@ func (config *Config) InitOperations(specs []*loads.Document) { // CleanUp sorts and dedups fields func (c *Config) CleanUp() { - for _, d := range c.Definitions.GetAllDefinitions() { + for _, d := range c.Definitions.All { sort.Sort(d.AppearsIn) sort.Sort(d.Fields) dedup := SortDefinitionsByName{} @@ -348,8 +264,8 @@ func (c *Config) CleanUp() { } } -// loadYamlConfig reads the config yaml file into a struct -func loadYamlConfig() *Config { +// LoadConfigFromYAML reads the config yaml file into a struct +func LoadConfigFromYAML() *Config { f := filepath.Join(*ConfigDir, "config.yaml") config := &Config{} @@ -450,67 +366,99 @@ func loadYamlConfig() *Config { return config } -// initOpExample reads the example config for each operation and sets it -func (config *Config) initOpExample(o *Operation) { - path := o.Type.Name + ".yaml" - path = filepath.Join(*ConfigDir, config.ExampleLocation, o.Definition.Name, path) - path = strings.Replace(path, " ", "_", -1) - path = strings.ToLower(path) - content, err := ioutil.ReadFile(path) - if err != nil { - return - } - err = yaml.Unmarshal(content, &o.ExampleConfig) - if err != nil { - panic(fmt.Sprintf("Could not Unmarshal ExampleConfig yaml: %s\n", content)) - } -} -func (config *Config) GetDefExampleFile(d *Definition) string { - return strings.Replace(strings.ToLower(filepath.Join(*ConfigDir, config.ExampleLocation, d.Name, d.Name+".yaml")), " ", "_", -1) -} +const ( + PATH = "path" + QUERY = "query" + BODY = "body" +) -func (config *Config) initDefExample(d *Definition) { - content, err := ioutil.ReadFile(config.GetDefExampleFile(d)) - if err != nil || len(content) <= 0 { - //fmt.Printf("Missing example: %s %v\n", d.Name, err) - return - } - err = yaml.Unmarshal(content, &d.Sample) - if err != nil { - panic(fmt.Sprintf("Could not Unmarshal SampleConfig yaml: %s\n", content)) +func (c *Config) initOperationParameters() { + s := c.Definitions + for _, op := range c.Operations { + pathItem := op.item + + // Path parameters + for _, p := range pathItem.Parameters { + switch p.In { + case PATH: + op.PathParams = append(op.PathParams, s.parameterToField(p)) + case QUERY: + op.QueryParams = append(op.QueryParams, s.parameterToField(p)) + case BODY: + op.BodyParams = append(op.BodyParams, s.parameterToField(p)) + default: + panic("") + } + } + + // Query parameters + for _, p := range op.op.Parameters { + switch p.In { + case PATH: + op.PathParams = append(op.PathParams, s.parameterToField(p)) + case QUERY: + op.QueryParams = append(op.QueryParams, s.parameterToField(p)) + case BODY: + op.BodyParams = append(op.BodyParams, s.parameterToField(p)) + default: + panic("") + } + } + + for code, response := range op.op.Responses.StatusCodeResponses { + if response.Schema == nil { + // fmt.Printf("Nil Schema for response: %+v\n", op.Path) + continue + } + r := &HttpResponse{ + Field: Field{ + Description: strings.Replace(response.Description, "\n", " ", -1), + Type: GetTypeName(*response.Schema), + Name: fmt.Sprintf("%d", code), + }, + Code: fmt.Sprintf("%d", code), + } + if IsComplex(*response.Schema) { + r.Definition, _ = s.GetForSchema(*response.Schema) + if r.Definition != nil { + r.Definition.FoundInOperation = true + } + } + op.HttpResponses = append(op.HttpResponses, r) + } } } -func (config *Config) getOperationId(match string, group string, version ApiVersion, kind string) string { +func (c *Config) getOperationId(match string, group string, version ApiVersion, kind string) string { // Lookup the name of the group as the operation expects it (different than the resource) - if g, f := config.GroupMap[group]; f { + if g, ok := c.GroupMap[group]; ok { group = g } - // Substitute the api definition group-version-kind into the operation template and look for a match - v, k := doScaleIdHack(string(version), kind, match) + ver := []rune(string(version)) + ver[0] = unicode.ToUpper(ver[0]) + match = strings.Replace(match, "${group}", string(group), -1) - match = strings.Replace(match, "${version}", v, -1) - match = strings.Replace(match, "${resource}", k, -1) + match = strings.Replace(match, "${version}", string(ver), -1) + match = strings.Replace(match, "${resource}", kind, -1) return match } -func (config *Config) setOperation(match, namespaceRep string, - ot *OperationType, oc *OperationCategory, definition *Definition) { +func (c *Config) setOperation(match, namespace string, ot *OperationType, oc *OperationCategory, d *Definition) { - key := strings.Replace(match, "(Namespaced)?", namespaceRep, -1) - if o, found := config.Operations[key]; found { + key := strings.Replace(match, "(Namespaced)?", namespace, -1) + if o, ok := c.Operations[key]; ok { // Each operation should have exactly 1 definition if o.Definition != nil { panic(fmt.Sprintf( "Found multiple matching defintions [%s/%s/%s, %s/%s/%s] for operation key: %s", - definition.Group, definition.Version, definition.Name, o.Definition.Group, o.Definition.Version, o.Definition.Name, key)) + d.Group, d.Version, d.Name, o.Definition.Group, o.Definition.Version, o.Definition.Name, key)) } o.Type = *ot - o.Definition = definition + o.Definition = d + o.initExample(c) oc.Operations = append(oc.Operations, o) - config.initOpExample(o) // When using tags for the configuration, everything with an operation goes in the ToC if *UseTags && !o.Definition.IsOldVersion { @@ -520,102 +468,74 @@ func (config *Config) setOperation(match, namespaceRep string, } // mapOperationsToDefinitions adds operations to the definitions they operate -// This is done by - for each definition - look at all potentially matching operations from operation categories -func (config *Config) mapOperationsToDefinitions() { - // Look for matching operations for each definition - for _, definition := range config.Definitions.GetAllDefinitions() { - // Inlined definitions don't have operations - if definition.IsInlined { +func (c *Config) mapOperationsToDefinitions() { + for _, d := range c.Definitions.All { + if d.IsInlined { continue } - // Iterate through categories - for i := range config.OperationCategories { - oc := config.OperationCategories[i] - - // Iterate through possible operation matches + for i := range c.OperationCategories { + oc := c.OperationCategories[i] for j := range oc.OperationTypes { - // Iterate through possible api groups since we don't know the api group of the definition ot := oc.OperationTypes[j] - - operationId := config.getOperationId(ot.Match, definition.GetOperationGroupName(), definition.Version, definition.Name) - // Look for a matching operation and set on the definition if found - config.setOperation(operationId, "Namespaced", &ot, &oc, definition) - config.setOperation(operationId, "", &ot, &oc, definition) + operationId := c.getOperationId(ot.Match, d.GetOperationGroupName(), d.Version, d.Name) + c.setOperation(operationId, "Namespaced", &ot, &oc, d) + c.setOperation(operationId, "", &ot, &oc, d) } - // If we found operations for this category, add the category to the definition if len(oc.Operations) > 0 { - definition.OperationCategories = append(definition.OperationCategories, &oc) + d.OperationCategories = append(d.OperationCategories, &oc) } } } } -func doScaleIdHack(version, name, match string) (string, string) { - // Hack to get around ids - // if strings.HasSuffix(match, "${resource}Scale") && name != "Scale" { - // - // fmt.Println() - // fmt.Println("doScaleIdHack: ", version, name, match) - - // Scale names don't generate properly - // name = strings.ToLower(name) + "s" - // out := []rune(name) - // out[0] = unicode.ToUpper(out[0]) - // name = string(out) - // } - out := []rune(version) - out[0] = unicode.ToUpper(out[0]) - version = string(out) - - return version, name -} - -func (config *Config) createDescriptionsWithEntities () { - - // The OpenAPI spec has escape sequences like \u003c. When the spec is unmarshaled, - // the escape sequences get converted to ordinary characters. For example, - // \u003c gets converted to a regular < character. But we can't use regular < - // and > characters in our HTML document. This function replaces these regular - // characters with HTML entities: <, >, &, ', and ". - - for _, definition := range config.Definitions.GetAllDefinitions() { - d := definition.Description() - d = html.EscapeString(d) - definition.DescriptionWithEntities = d - - for _,field := range definition.Fields { - d := field.Description - d = html.EscapeString(d) - field.DescriptionWithEntities = d +// The OpenAPI spec has escape sequences like \u003c. When the spec is unmarshaled, +// the escape sequences get converted to ordinary characters. For example, +// \u003c gets converted to a regular < character. But we can't use regular < +// and > characters in our HTML document. This function replaces these regular +// characters with HTML entities: <, >, &, ', and ". +func (c *Config) escapeDescriptions() { + for _, d := range c.Definitions.All { + d.DescriptionWithEntities = html.EscapeString(d.Description()) + + for _, f := range d.Fields { + f.DescriptionWithEntities = html.EscapeString(f.Description) } } - for _, operation := range config.Operations { - - for _, field := range operation.BodyParams { - d := field.Description - d = html.EscapeString(d) - field.DescriptionWithEntities = d + for _, op := range c.Operations { + for _, p := range op.BodyParams { + p.DescriptionWithEntities = html.EscapeString(p.Description) } - - for _, field := range operation.QueryParams { - d := field.Description - d = html.EscapeString(d) - field.DescriptionWithEntities = d + for _, p := range op.QueryParams { + p.DescriptionWithEntities = html.EscapeString(p.Description) } - - for _, field := range operation.PathParams { - d := field.Description - d = html.EscapeString(d) - field.DescriptionWithEntities = d + for _, p := range op.PathParams { + p.DescriptionWithEntities = html.EscapeString(p.Description) } + for _, r := range op.HttpResponses { + r.DescriptionWithEntities = html.EscapeString(r.Description) + } + } +} - for _, resp := range operation.HttpResponses { - d := resp.Description - d = html.EscapeString(d) - resp.DescriptionWithEntities = d +// For each resource in the ToC, look up its definition and visit it. +func (c *Config) visitResourcesInToc() { + missing := false + for _, cat := range c.ResourceCategories { + for _, r := range cat.Resources { + if d, ok := c.Definitions.GetByVersionKind(r.Group, r.Version, r.Name); ok { + d.InToc = true // Mark as in Toc + d.initExample(c) + r.Definition = d + } else { + fmt.Printf("Could not find definition for resource in TOC: %s %s %s.\n", r.Group, r.Version, r.Name) + missing = true + } } } + if missing { + fmt.Printf("All known definitions: %v\n", c.Definitions.All) + } } diff --git a/gen-apidocs/generators/api/definition.go b/gen-apidocs/generators/api/definition.go index b9fed019..3cae42f4 100644 --- a/gen-apidocs/generators/api/definition.go +++ b/gen-apidocs/generators/api/definition.go @@ -18,168 +18,183 @@ package api import ( "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "path/filepath" "sort" "strings" - "errors" "github.com/go-openapi/loads" "github.com/go-openapi/spec" ) -// Definitions indexes open-api definitions -type Definitions struct { - ByGroupVersionKind map[string]*Definition - ByKind map[string]SortDefinitionsByVersion -} +func NewDefinitions(specs []*loads.Document) Definitions { + s := Definitions{ + All: map[string]*Definition{}, + ByKind: map[string]SortDefinitionsByVersion{}, + } -func (d *Definitions) GetAllDefinitions() map[string]*Definition { - return d.ByGroupVersionKind + LoadDefinitions(specs, &s) + s.initialize() + return s } -func (d *Definition) GroupDisplayName() string { - if len(d.GroupFullName) > 0 { - return d.GroupFullName +func (s *Definitions) initialize() { + // initialize fields for all definitions + for _, d := range s.All { + s.InitializeFields(d) } - if len(d.Group) <= 0 || d.Group == "core" { - return "Core" + + for _, d := range s.All { + s.ByKind[d.Name] = append(s.ByKind[d.Name], d) } - return string(d.Group) -} -func (d *Definitions) GetOtherVersions(this *Definition) []*Definition { - defs := d.ByKind[this.Name] - others := []*Definition{} - for _, def := range defs { - if def.Version != this.Version { - others = append(others, def) + // If there are multiple versions for an object. Mark all by the newest as old + // Sort the ByKind index in by version with newer versions coming before older versions. + for k, l := range s.ByKind { + if len(l) <= 1 { + continue + } + sort.Sort(l) + // Mark all version as old + for i, d := range l { + if len(l) > 1 { + if i > 0 { + fmt.Printf("%s.%s.%s", d.Group, d.Version, k) + if len(l) > i-1 { + fmt.Printf(",") + } + } else { + fmt.Printf("Current Version: %s.%s.%s", d.Group, d.Version, k) + if len(l) > i-1 { + fmt.Printf(" Old Versions: [") + } + } + } + if i > 0 { + d.IsOldVersion = true + } + } + if len(l) > 1 { + fmt.Printf("]\n") } } - return others -} -// GetByVersionKind looks up a definition using its primary key (version,kind) -func (d *Definitions) GetByVersionKind(group, version, kind string) (*Definition, bool) { - key := &Definition{Group: ApiGroup(group), Version: ApiVersion(version), Kind: ApiKind(kind)} - r, f := d.ByGroupVersionKind[key.Key()] - return r, f -} + // Initialize OtherVersions + for _, d := range s.All { + defs := s.ByKind[d.Name] + others := []*Definition{} + for _, def := range defs { + if def.Version != d.Version { + others = append(others, def) + } + } + d.OtherVersions = others + } -// GetByKey looks up a definition from its key (version.kind) -func (d *Definitions) GetByKey(key string) (*Definition, bool) { - r, f := d.ByGroupVersionKind[key] - return r, f + // Initialize AppearsIn and FoundInField + for _, d := range s.All { + for _, r := range s.getReferences(d) { + r.AppearsIn = append(r.AppearsIn, d) + r.FoundInField = true + } + } + + // Initialize Inline, IsInlined + // Note: examples of inline definitions are "Spec", "Status", "List", etc + for _, d := range s.All { + for _, name := range GetInlinedDefinitionNames(d.Name) { + if cr, ok := s.GetByVersionKind(string(d.Group), string(d.Version), name); ok { + d.Inline = append(d.Inline, cr) + cr.IsInlined = true + cr.FoundInField = true + } + } + } } -// IsComplex returns true if the schema is for a complex (non-primitive) defintions -func (d *Definitions) IsComplex(s spec.Schema) bool { - _, _, k := GetDefinitionVersionKind(s) - return len(k) > 0 +func (s *Definitions) getReferences(d *Definition) []*Definition { + refs := []*Definition{} + // Find all of the resources referenced by this definition + for _, p := range d.schema.Properties { + if !IsComplex(p) { + // Skip primitive types and collections of primitive types + continue + } + // Look up the definition for the referenced resource + if schema, ok := s.GetForSchema(p); ok { + refs = append(refs, schema) + } else { + g, v, k := GetDefinitionVersionKind(p) + fmt.Printf("Could not locate referenced property of %s: %s (%s/%s).\n", d.Name, g, k, v) + } + } + return refs } -func (d *Definitions) GetForSchema(s spec.Schema) (*Definition, bool) { - g, v, k := GetDefinitionVersionKind(s) - if len(k) <= 0 { - return nil, false +func (s *Definitions) parameterToField(param spec.Parameter) *Field { + f := &Field{ + Name: param.Name, + Description: strings.Replace(param.Description, "\n", " ", -1), } - return d.GetByVersionKind(g, v, k) + if param.Schema != nil { + f.Type = GetTypeName(*param.Schema) + if fieldType, ok := s.GetForSchema(*param.Schema); ok { + f.Definition = fieldType + } + } + return f } -func (d *Definitions) Put(defintion *Definition) { - d.ByGroupVersionKind[defintion.Key()] = defintion +// GetByVersionKind looks up a definition using its primary key (version,kind) +func (s *Definitions) GetByVersionKind(group, version, kind string) (*Definition, bool) { + key := &Definition{Group: ApiGroup(group), Version: ApiVersion(version), Kind: ApiKind(kind)} + r, f := s.All[key.Key()] + return r, f } -// Initializes the fields for all definitions -func (d *Definitions) InitializeFieldsForAll() { - for _, definition := range d.GetAllDefinitions() { - d.InitializeFields(definition) +func (s *Definitions) GetForSchema(schema spec.Schema) (*Definition, bool) { + g, v, k := GetDefinitionVersionKind(schema) + if len(k) <= 0 { + return nil, false } + return s.GetByVersionKind(g, v, k) } -const patchStrategyKey = "x-kubernetes-patch-strategy" -const patchMergeKeyKey = "x-kubernetes-patch-merge-key" -const resourceNameKey = "x-kubernetes-resource" -const typeKey = "x-kubernetes-group-version-kind" - // Initializes the fields for a definition -func (d *Definitions) InitializeFields(definition *Definition) { - for fieldName, property := range definition.schema.Properties { - def := strings.Replace(property.Description, "\n", " ", -1) - field := &Field{ +func (s *Definitions) InitializeFields(d *Definition) { + for fieldName, property := range d.schema.Properties { + des := strings.Replace(property.Description, "\n", " ", -1) + f := &Field{ Name: fieldName, Type: GetTypeName(property), - Description: escapeAsterisks(def), + Description: EscapeAsterisks(des), } if len(property.Extensions) > 0 { - if ps, f := property.Extensions.GetString(patchStrategyKey); f { - field.PatchStrategy = ps + if ps, ok := property.Extensions.GetString(patchStrategyKey); ok { + f.PatchStrategy = ps } - if pmk, f := property.Extensions.GetString(patchMergeKeyKey); f { - field.PatchMergeKey = pmk + if pmk, ok := property.Extensions.GetString(patchMergeKeyKey); ok { + f.PatchMergeKey = pmk } } - if fieldDefinition, found := d.GetForSchema(property); found { - field.Definition = fieldDefinition + if fd, ok := s.GetForSchema(property); ok { + f.Definition = fd } - definition.Fields = append(definition.Fields, field) + d.Fields = append(d.Fields, f) } } -func (d *Definitions) InitializeOtherVersions() { - for _, definition := range d.GetAllDefinitions() { - definition.OtherVersions = d.GetOtherVersions(definition) +func (d *Definition) GroupDisplayName() string { + if len(d.GroupFullName) > 0 { + return d.GroupFullName } + if len(d.Group) <= 0 || d.Group == "core" { + return "Core" + } + return string(d.Group) } - -type DefinitionList []*Definition - -func (a DefinitionList) Len() int { return len(a) } -func (a DefinitionList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a DefinitionList) Less(i, j int) bool { - return strings.Compare(a[i].Name, a[j].Name) < 0 -} - -type Definition struct { - // open-api schema for the definition - schema spec.Schema - // Display name of the definition (e.g. Deployment) - Name string - Group ApiGroup - ShowGroup bool - // Api version of the definition (e.g. v1beta1) - Version ApiVersion - Kind ApiKind - DescriptionWithEntities string - GroupFullName string - - // InToc is true if this definition should appear in the table of contents - InToc bool - IsInlined bool - IsOldVersion bool - - FoundInField bool - FoundInOperation bool - - // Inline is a list of definitions that should appear inlined with this one in the documentations - Inline SortDefinitionsByName - - // AppearsIn is a list of definition that this one appears in - e.g. PodSpec in Pod - AppearsIn SortDefinitionsByName - - OperationCategories []*OperationCategory - - // Fields is a list of fields in this definition - Fields Fields - - OtherVersions SortDefinitionsByName - NewerVersions SortDefinitionsByName - - Sample SampleConfig - - FullName string - Resource string -} - func (d *Definition) GetOperationGroupName() string { if strings.ToLower(d.Group.String()) == "rbac" { return "RbacAuthorization" @@ -191,10 +206,14 @@ func (d *Definition) Key() string { return fmt.Sprintf("%s.%s.%s", d.Group, d.Version, d.Kind) } +func (d *Definition) LinkID() string { + link := fmt.Sprintf("%s-%s-%s", d.Name, d.Version, d.Group) + return strings.ToLower(link) +} + func (d *Definition) MdLink() string { groupName := strings.Replace(strings.ToLower(d.GroupFullName), ".", "-", -1) return fmt.Sprintf("[%s](#%s-%s-%s)", d.Name, strings.ToLower(d.Name), d.Version, groupName) - } func (d *Definition) HrefLink() string { @@ -203,8 +222,8 @@ func (d *Definition) HrefLink() string { } func (d *Definition) FullHrefLink() string { - groupName := strings.Replace(strings.ToLower(d.GroupFullName), ".", "-", -1) - return fmt.Sprintf("%s %s/%s", strings.ToLower(d.Name), + groupName := strings.Replace(strings.ToLower(string(d.Group)), ".", "-", -1) + return fmt.Sprintf("%s [%s/%s]", strings.ToLower(d.Name), d.Version, groupName, d.Name, d.Group, d.Version) } @@ -213,141 +232,31 @@ func (d *Definition) VersionLink() string { return fmt.Sprintf("%s", strings.ToLower(d.Name), d.Version, groupName, d.Version) } -// handle '*', 'a/*', '*/b', '*/*' cases -func escapeAsterisks(des string) string { - s := strings.Replace(des, "'*'", `'\*'`, -1) - s = strings.Replace(s, "/*'", `/\*'`, -1) - s = strings.Replace(s, "'*/", `'\*/`, -1) - s = strings.Replace(s, "'*/*'", `'\*/\*'`, -1) - return s -} - -func (d Definition) Description() string { - return escapeAsterisks(d.schema.Description) +func (d *Definition) Description() string { + return EscapeAsterisks(d.schema.Description) } -// TODO: Rework this function because it is ugly -func guessGVK(name string) (group, version, kind string) { - parts := strings.Split(name, ".") - if len(parts) < 4 { - fmt.Printf("Error: Could not find version and type for definition %s.\n", name) - return "", "", "" +func (d *Definition) GetResourceName() string { + if len(d.Resource) > 0 { + return d.Resource } - - if parts[len(parts)-3] == "api" { - // e.g. "io.k8s.apimachinery.pkg.api.resource.Quantity" - group = "core" - version = parts[len(parts)-2] - kind = parts[len(parts)-1] - } else if parts[len(parts)-4] == "api" { - // e.g. "io.k8s.api.core.v1.Pod" - group = parts[len(parts)-3] - version = parts[len(parts)-2] - kind = parts[len(parts)-1] - } else if parts[len(parts)-4] == "apis" { - // e.g. "io.k8s.apimachinery.pkg.apis.meta.v1.Status" - group = parts[len(parts)-3] - version = parts[len(parts)-2] - kind = parts[len(parts)-1] - } else if parts[len(parts)-3] == "util" || parts[len(parts)-3] == "pkg" { - // e.g. io.k8s.apimachinery.pkg.util.intstr.IntOrString - // e.g. io.k8s.apimachinery.pkg.runtime.RawExtension - return "", "", "" - } else { - // To report error - return "error", "", "" + resource := strings.ToLower(d.Name) + if strings.HasSuffix(resource, "y") { + return strings.TrimSuffix(resource, "y") + "ies" } - return group, version, kind + return resource + "s" } -// return the map from short group name to full group name -func buildGroupMapFromExtension(specs []*loads.Document) map[string]string { - mapping := map[string]string{} - mapping["apiregistration"] = "apiregistration.k8s.io" - mapping["apiextensions"] = "apiextensions.k8s.io" - mapping["meta"] = "meta" - mapping["core"] = "core" - - for _, spec := range specs { - for name, spec := range spec.Spec().Definitions { - group, _, _ := guessGVK(name) - if _, found := mapping[group]; found { - continue - } - // special groups where group name from extension is empty! - if group == "meta" || group == "core" { - continue - } - - // full group not exposed as x-kubernetes- openapi extensions - // from kube-aggregator project or apiextensions-apiserver project - if group == "apiregistration" || group == "apiextensions" { - continue - } - - if extension, found := spec.Extensions[typeKey]; found { - gvks, ok := extension.([]interface{}) - if ok { - for _, item := range gvks { - gvk, ok := item.(map[string]interface{}) - if ok { - mapping[group] = gvk["group"].(string) - break - } - } - } - } - } +func (d *Definition) initExample(config *Config) { + path := filepath.Join(*ConfigDir, config.ExampleLocation, d.Name, d.Name + ".yaml") + file := strings.Replace(strings.ToLower(path), " ", "_", -1) + content, err := ioutil.ReadFile(file) + if err != nil || len(content) <= 0 { + return } - return mapping -} - -func VisitDefinitions(specs []*loads.Document, fn func(definition *Definition)) { - groups := map[string]string{} - groupMapping := buildGroupMapFromExtension(specs) - for _, spec := range specs { - for name, spec := range spec.Spec().Definitions { - resource := "" - if r, found := spec.Extensions.GetString(resourceNameKey); found { - resource = r - } - - // This actually skips the following groups - // 'io.k8s.kubernetes.pkg.api.*' - // 'io.k8s.kubernetes.pkg.apis.*' - if strings.HasPrefix(spec.Description, "Deprecated. Please use") { - // old 1.7 definitions - continue - } - if strings.Contains(name, "JSONSchemaPropsOrStringArray") { - continue - } - - group, version, kind := guessGVK(name) - if group == "" { - continue - } else if group == "error" { - panic(errors.New(fmt.Sprintf("Could not locate group for %s", name))) - } - groups[group] = "" - - full_group, found := groupMapping[group] - if !found { - // fall back to group name if no mapping found - full_group = group - } - - fn(&Definition{ - schema: spec, - Name: kind, - Version: ApiVersion(version), - Kind: ApiKind(kind), - Group: ApiGroup(group), - GroupFullName: full_group, - ShowGroup: true, - Resource: resource, - }) - } + err = yaml.Unmarshal(content, &d.Sample) + if err != nil { + panic(fmt.Sprintf("Could not Unmarshal SampleConfig yaml: %s\n", content)) } } @@ -363,51 +272,8 @@ func (d *Definition) GetSamples() []ExampleText { return r } -func GetDefinitions(specs []*loads.Document) Definitions { - d := Definitions{ - ByGroupVersionKind: map[string]*Definition{}, - ByKind: map[string]SortDefinitionsByVersion{}, - } - VisitDefinitions(specs, func(definition *Definition) { - d.Put(definition) - }) - d.InitializeFieldsForAll() - for _, def := range d.GetAllDefinitions() { - d.ByKind[def.Name] = append(d.ByKind[def.Name], def) - } - - // If there are multiple versions for an object. Mark all by the newest as old - // Sort the ByKind index in by version with newer versions coming before older versions. - for k, l := range d.ByKind { - if len(l) <= 1 { - continue - } - sort.Sort(l) - // Mark all version as old - for i, d := range l { - if len(l) > 1 { - if i > 0 { - fmt.Printf("%s.%s.%s", d.Group, d.Version, k) - if len(l) > i-1 { - fmt.Printf(",") - } - } else { - fmt.Printf("Current Version: %s.%s.%s", d.Group, d.Version, k) - if len(l) > i-1 { - fmt.Printf(" Old Versions: [") - } - } - } - if i > 0 { - d.IsOldVersion = true - } - } - if len(l) > 1 { - fmt.Printf("]\n") - } - } - d.InitializeOtherVersions() - d.initAppearsIn() - d.initInlinedDefinitions() - return d +func (a DefinitionList) Len() int { return len(a) } +func (a DefinitionList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a DefinitionList) Less(i, j int) bool { + return strings.Compare(a[i].Name, a[j].Name) < 0 } diff --git a/gen-apidocs/generators/api/examples.go b/gen-apidocs/generators/api/examples.go index b5ca8ed4..e32db5cb 100644 --- a/gen-apidocs/generators/api/examples.go +++ b/gen-apidocs/generators/api/examples.go @@ -17,33 +17,23 @@ limitations under the License. package api import ( - //"gopkg.in/yaml.v2" - "encoding/json" "fmt" "strings" ) -type ExampleProvider interface { - GetTab() string - GetRequestMessage() string - GetResponseMessage() string - GetRequestType() string - GetResponseType() string - GetSampleType() string - GetSample(d *Definition) string - GetRequest(o *Operation) string - GetResponse(o *Operation) string -} - var ExampleProviders = []ExampleProvider{ KubectlExample{}, CurlExample{}, } -var EmptyExampleProviders = []ExampleProvider { +var EmptyExampleProviders = []ExampleProvider{ EmptyExample{}, } +var _ ExampleProvider = &EmptyExample{} +var _ ExampleProvider = &CurlExample{} +var _ ExampleProvider = &KubectlExample{} + func GetExampleProviders() []ExampleProvider { if *BuildOps { return ExampleProviders @@ -52,11 +42,6 @@ func GetExampleProviders() []ExampleProvider { } } -type EmptyExample struct { -} - -var _ ExampleProvider = &EmptyExample{} - func (ce EmptyExample) GetSample(d *Definition) string { return d.Sample.Sample } @@ -93,11 +78,6 @@ func (ce EmptyExample) GetResponse(o *Operation) string { return "" } -var _ ExampleProvider = &CurlExample{} - -type CurlExample struct { -} - func (ce CurlExample) GetSample(d *Definition) string { return d.Sample.Sample } @@ -130,7 +110,7 @@ func (ce CurlExample) GetRequest(o *Operation) string { c := o.ExampleConfig y := c.Request if len(y) <= 0 && len(c.Name) <= 0 { - return "Coming Soon" + return "" } switch o.Type.Name { @@ -168,7 +148,7 @@ func (ce CurlExample) GetResponse(o *Operation) string { c := o.ExampleConfig j := o.ExampleConfig.Response if len(j) <= 0 && len(c.Name) <= 0 { - return "Coming Soon" + return "" } switch o.Type.Name { case "Create": @@ -189,10 +169,6 @@ func (ce CurlExample) GetResponse(o *Operation) string { return "" } -var _ ExampleProvider = &KubectlExample{} - -type KubectlExample struct{} - func (ke KubectlExample) GetSample(d *Definition) string { return d.Sample.Sample } @@ -226,7 +202,7 @@ func (ke KubectlExample) GetRequest(o *Operation) string { t := strings.ToLower(o.Definition.Name) y := c.Request if len(y) <= 0 && len(c.Name) <= 0 { - return "Coming Soon" + return "" } switch o.Type.Name { case "Create": @@ -253,7 +229,7 @@ func (ke KubectlExample) GetResponse(o *Operation) string { t := strings.ToLower(o.Definition.Name) j := o.ExampleConfig.Response if len(j) <= 0 && len(c.Name) <= 0 { - return "Coming Soon" + return "" } switch o.Type.Name { case "Create": @@ -273,18 +249,3 @@ func (ke KubectlExample) GetResponse(o *Operation) string { } return "" } - -func GetName(parsed map[string]interface{}) string { - meta := parsed["metadata"].(map[string]interface{}) - name := meta["name"].(string) - return name -} - -func ParseJson(j []byte) map[string]interface{} { - var parsed interface{} - err := json.Unmarshal(j, &parsed) - if err != nil { - panic(fmt.Sprintf("Could not parse json %s y: %v\n", j, err)) - } - return parsed.(map[string]interface{}) -} diff --git a/gen-apidocs/generators/api/field.go b/gen-apidocs/generators/api/field.go deleted file mode 100644 index ba573546..00000000 --- a/gen-apidocs/generators/api/field.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package api - -import "strings" - -type Fields []*Field - -func (a Fields) Len() int { return len(a) } -func (a Fields) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a Fields) Less(i, j int) bool { return a[i].Name < a[j].Name } - -type Field struct { - Name string - Type string - Description string - DescriptionWithEntities string - // Optional Definition for complex types - Definition *Definition - - // Patch semantics - PatchStrategy string - PatchMergeKey string -} - -func (f Field) Link() string { - if f.Definition != nil { - return strings.Replace(f.Type, f.Definition.Name, f.Definition.MdLink(), -1) - } else { - return f.Type - } -} diff --git a/gen-apidocs/generators/api/init.go b/gen-apidocs/generators/api/init.go deleted file mode 100644 index 99bb814c..00000000 --- a/gen-apidocs/generators/api/init.go +++ /dev/null @@ -1,163 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package api - -import ( - "fmt" - "github.com/go-openapi/spec" - "strings" -) - -var INLINE_DEFINITIONS = []InlineDefinition{ - {Name: "Spec", Match: "${resource}Spec"}, - {Name: "Status", Match: "${resource}Status"}, - {Name: "List", Match: "${resource}List"}, - {Name: "Strategy", Match: "${resource}Strategy"}, - {Name: "Rollback", Match: "${resource}Rollback"}, - {Name: "RollingUpdate", Match: "RollingUpdate${resource}"}, - {Name: "EventSource", Match: "${resource}EventSource"}, -} - -const ( - path = "path" - query = "query" - body = "body" -) - -// Inline definitions for "Spec", "Status", "List", etc for definitions -func (definitions Definitions) initInlinedDefinitions() Definitions { - for _, d := range definitions.GetAllDefinitions() { - for _, name := range definitions.GetInlinedDefinitionNames(d.Name) { - if cr, found := definitions.GetByVersionKind(string(d.Group), string(d.Version), name); found { - d.Inline = append(d.Inline, cr) - cr.IsInlined = true - cr.FoundInField = true - } - } - } - return definitions -} - -// Build the "Appears In" index for definitions -func (definitions Definitions) initAppearsIn() Definitions { - for _, d := range definitions.GetAllDefinitions() { - for _, child := range getDefinitionFieldDefinitions(d, definitions) { - child.AppearsIn = append(child.AppearsIn, d) - child.FoundInField = true - } - } - return definitions -} - -func getDefinitionFieldDefinitions(definition *Definition, definitions Definitions) []*Definition { - children := []*Definition{} - // Find all of the resources referenced by this definition - for _, p := range definition.schema.Properties { - if !definitions.IsComplex(p) { - // Skip primitive types and collections of primitive types - continue - } - // Look up the definition for the referenced resource - if child, found := definitions.GetForSchema(p); found { - children = append(children, child) - } else { - g, v, k := GetDefinitionVersionKind(p) - fmt.Printf("Could not locate referenced property of %s: %s (%s/%s).\n", definition.Name, g, k, v) - } - } - return children -} - -func (c *Definitions) GetInlinedDefinitionNames(parent string) []string { - names := []string{} - for _, id := range INLINE_DEFINITIONS { - name := strings.Replace(id.Match, "${resource}", parent, -1) - names = append(names, name) - } - return names -} - -func (definitions *Definitions) initializeOperationParameters(operations Operations) { - for _, operation := range operations { - pathItem := operation.item - - // Path parameters - for _, p := range pathItem.Parameters { - switch p.In { - case path: - operation.PathParams = append(operation.PathParams, definitions.parameterToField(p)) - case query: - operation.QueryParams = append(operation.QueryParams, definitions.parameterToField(p)) - case body: - operation.BodyParams = append(operation.BodyParams, definitions.parameterToField(p)) - default: - panic("") - } - } - - // Query parameters - for _, p := range operation.op.Parameters { - switch p.In { - case path: - operation.PathParams = append(operation.PathParams, definitions.parameterToField(p)) - case query: - operation.QueryParams = append(operation.QueryParams, definitions.parameterToField(p)) - case body: - operation.BodyParams = append(operation.BodyParams, definitions.parameterToField(p)) - default: - panic("") - } - } - - for code, response := range operation.op.Responses.StatusCodeResponses { - if response.Schema == nil { - //fmt.Printf("Nil Schema for response: %+v\n", operation.Path) - continue - } - r := &HttpResponse{ - Field: Field{ - Description: strings.Replace(response.Description, "\n", " ", -1), - Type: GetTypeName(*response.Schema), - Name: fmt.Sprintf("%d", code), - }, - Code: fmt.Sprintf("%d", code), - } - if definitions.IsComplex(*response.Schema) { - //var f bool - r.Definition, _ = definitions.GetForSchema(*response.Schema) - if r.Definition != nil { - r.Definition.FoundInOperation = true - } - } - operation.HttpResponses = append(operation.HttpResponses, r) - } - } -} - -func (definitions *Definitions) parameterToField(parameter spec.Parameter) *Field { - field := &Field{ - Name: parameter.Name, - Description: strings.Replace(parameter.Description, "\n", " ", -1), - } - if parameter.Schema != nil { - field.Type = GetTypeName(*parameter.Schema) - if fieldType, f := definitions.GetForSchema(*parameter.Schema); f { - field.Definition = fieldType - } - } - return field -} diff --git a/gen-apidocs/generators/api/open_api.go b/gen-apidocs/generators/api/open_api.go index 28ff321a..62937016 100644 --- a/gen-apidocs/generators/api/open_api.go +++ b/gen-apidocs/generators/api/open_api.go @@ -17,13 +17,22 @@ limitations under the License. package api import ( + "errors" "fmt" "os" "path/filepath" + "strings" "github.com/go-openapi/loads" ) +const ( + patchStrategyKey = "x-kubernetes-patch-strategy" + patchMergeKeyKey = "x-kubernetes-patch-merge-key" + resourceNameKey = "x-kubernetes-resource" + typeKey = "x-kubernetes-group-version-kind" +) + // Loads all of the open-api documents func LoadOpenApiSpec() []*loads.Document { dir := filepath.Join(*ConfigDir, "openapi-spec/") @@ -47,3 +56,99 @@ func LoadOpenApiSpec() []*loads.Document { } return docs } + +// return the map from short group name to full group name +func buildGroupMap(specs []*loads.Document) map[string]string { + mapping := map[string]string{} + mapping["apiregistration"] = "apiregistration.k8s.io" + mapping["apiextensions"] = "apiextensions.k8s.io" + mapping["certificates"] = "certificates.k8s.io" + mapping["meta"] = "meta" + mapping["core"] = "core" + mapping["extensions"] = "extensions" + + for _, spec := range specs { + for name, spec := range spec.Spec().Definitions { + group, _, _ := GuessGVK(name) + if _, found := mapping[group]; found { + continue + } + // special groups where group name from extension is empty! + if group == "meta" || group == "core" { + continue + } + + // full group not exposed as x-kubernetes- openapi extensions + // from kube-aggregator project or apiextensions-apiserver project + if group == "apiregistration" || group == "apiextensions" { + continue + } + + if extension, found := spec.Extensions[typeKey]; found { + gvks, ok := extension.([]interface{}) + if ok { + for _, item := range gvks { + gvk, ok := item.(map[string]interface{}) + if ok { + mapping[group] = gvk["group"].(string) + break + } + } + } + } + } + } + return mapping +} + +func LoadDefinitions(specs []*loads.Document, s *Definitions) { + groups := map[string]string{} + groupMapping := buildGroupMap(specs) + for _, spec := range specs { + for name, spec := range spec.Spec().Definitions { + resource := "" + if r, ok := spec.Extensions.GetString(resourceNameKey); ok { + resource = r + } + + // This actually skips the following groupsi, i.e. old definitions + // 'io.k8s.kubernetes.pkg.api.*' + // 'io.k8s.kubernetes.pkg.apis.*' + if strings.HasPrefix(spec.Description, "Deprecated. Please use") { + continue + } + + // NOTE: + if strings.Contains(name, "JSONSchemaPropsOrStringArray") { + continue + } + + group, version, kind := GuessGVK(name) + if group == "" { + continue + } else if group == "error" { + panic(errors.New(fmt.Sprintf("Could not locate group for %s", name))) + } + groups[group] = "" + + full_group, found := groupMapping[group] + if !found { + // fall back to group name if no mapping found + full_group = group + } + + d := &Definition{ + schema: spec, + Name: kind, + Version: ApiVersion(version), + Kind: ApiKind(kind), + Group: ApiGroup(group), + GroupFullName: full_group, + ShowGroup: true, + Resource: resource, + } + + s.All[d.Key()] = d + } + } +} diff --git a/gen-apidocs/generators/api/operation.go b/gen-apidocs/generators/api/operation.go index ce78c510..d7e8ea34 100644 --- a/gen-apidocs/generators/api/operation.go +++ b/gen-apidocs/generators/api/operation.go @@ -19,73 +19,35 @@ package api import ( "flag" "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "path/filepath" + "regexp" "strings" - "github.com/go-openapi/spec" "github.com/go-openapi/loads" + "github.com/go-openapi/spec" ) var BuildOps = flag.Bool("build-operations", true, "If true build operations in the docs.") -// OperationCategory defines a group of related operations -type OperationCategory struct { - // Name is the display name of this group - Name string `yaml:",omitempty"` - // Operations are the collection of Operations in this group - OperationTypes []OperationType `yaml:"operation_types,omitempty"` - // Default is true if this is the default operation group for operations that do not match any other groups - Default bool `yaml:",omitempty"` - - Operations []*Operation -} - -// Operation defines a highlevel operation type such as Read, Replace, Patch -type OperationType struct { - // Name is the display name of this operation - Name string `yaml:",omitempty"` - // Match is the regular expression of operation IDs that match this group where '${resource}' matches the resource name. - Match string `yaml:",omitempty"` -} - // GetOperationId returns the ID of the operation for the given definition -func (ot OperationType) GetOperationId(definition string) string { - return strings.Replace(ot.Match, "${resource}", definition, -1) -} - -type Operations map[string]*Operation - -type Operation struct { - item spec.PathItem - op *spec.Operation - ID string - Type OperationType - Path string - HttpMethod string - Definition *Definition - BodyParams Fields - QueryParams Fields - PathParams Fields - HttpResponses HttpResponses - - ExampleConfig ExampleConfig -} - -type ExampleText struct { - Tab string - Type string - Text string - Msg string +func (ot OperationType) GetOperationId(d string) string { + return strings.Replace(ot.Match, "${resource}", d, -1) } func (o *Operation) GetExampleRequests() []ExampleText { r := []ExampleText{} for _, p := range GetExampleProviders() { - r = append(r, ExampleText{ - Tab: p.GetTab(), - Type: p.GetRequestType(), - Text: p.GetRequest(o), - Msg: p.GetRequestMessage(), - }) + text := p.GetRequest(o) + if len(text) > 0 { + r = append(r, ExampleText{ + Tab: p.GetTab(), + Type: p.GetRequestType(), + Text: p.GetRequest(o), + Msg: p.GetRequestMessage(), + }) + } } return r } @@ -93,12 +55,15 @@ func (o *Operation) GetExampleRequests() []ExampleText { func (o *Operation) GetExampleResponses() []ExampleText { r := []ExampleText{} for _, p := range GetExampleProviders() { - r = append(r, ExampleText{ - Tab: p.GetTab(), - Type: p.GetResponseType(), - Text: p.GetResponse(o), - Msg: p.GetResponseMessage(), - }) + text := p.GetResponse(o) + if len(text) > 0 { + r = append(r, ExampleText{ + Tab: p.GetTab(), + Type: p.GetResponseType(), + Text: p.GetResponse(o), + Msg: p.GetResponseMessage(), + }) + } } return r } @@ -107,19 +72,11 @@ func (o *Operation) Description() string { return o.op.Description } -type HttpResponses []*HttpResponse - func (a HttpResponses) Len() int { return len(a) } func (a HttpResponses) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a HttpResponses) Less(i, j int) bool { - return a[i].Code < a[j].Code -} - -type HttpResponse struct { - Field - Code string -} +func (a HttpResponses) Less(i, j int) bool { return a[i].Code < a[j].Code } +// VisitOperations calls fn once for each operation found in the collection of Documents // VisitOperations calls fn once for each operation found in the collection of Documents func VisitOperations(specs []*loads.Document, fn func(operation Operation)) { for _, d := range specs { @@ -159,6 +116,72 @@ func getOperationsForItem(pathItem spec.PathItem) map[string]*spec.Operation { } } -func (operation *Operation) GetDisplayHttp() string { - return fmt.Sprintf("%s %s", operation.HttpMethod, operation.Path) +func (o *Operation) GetDisplayHttp() string { + return fmt.Sprintf("%s %s", o.HttpMethod, o.Path) +} + +func (o *Operation) VerifyBlackListed() { + switch { + case strings.Contains(o.ID, "connectCoreV1Patch"): + case strings.Contains(o.ID, "createCoreV1NamespacedPodBinding"): + case strings.Contains(o.ID, "getCodeVersion"): + case strings.Contains(o.ID, "logFileHandler"): + case strings.Contains(o.ID, "logFileListHandler"): + case strings.Contains(o.ID, "NamespacedPodAttach"): + case strings.Contains(o.ID, "NamespacedPodExec"): + case strings.Contains(o.ID, "replaceCoreV1NamespaceFinalize"): + case strings.Contains(o.ID, "V1beta1CertificateSigningRequestApproval"): + case strings.Contains(o.ID, "V1beta1NamespacedReplicationControllerDummyScale"): + default: + fmt.Printf("No Definition found for %s [%s]. \n", o.ID, o.Path) + } +} + +func (o *Operation) GetMethod() string { + switch o.HttpMethod { + case "GET": + return "List" + case "POST": + return "Create" + case "PATCH": + return "Patch" + case "DELETE": + return "Delete" + case "PUT": + return "Update" + } + return "" +} + +// /apis///namespaces/{namespace}//{name}/ +var matchNamespaced = regexp.MustCompile( + `^/apis/([A-Za-z0-9\.]+)/([A-Za-z0-9]+)/namespaces/\{namespace\}/([A-Za-z0-9\.]+)/\{name\}/([A-Za-z0-9\.]+)$`) +var matchUnnamespaced = regexp.MustCompile( + `^/apis/([A-Za-z0-9\.]+)/([A-Za-z0-9]+)/([A-Za-z0-9\.]+)/\{name\}/([A-Za-z0-9\.]+)$`) + +func (o *Operation) GetGroupVersionKindSub() (string, string, string, string) { + if matchNamespaced.MatchString(o.Path) { + m := matchNamespaced.FindStringSubmatch(o.Path) + return strings.Split(m[1], ".")[0], m[2], m[3], m[4] + } else if matchUnnamespaced.MatchString(o.Path) { + m := matchUnnamespaced.FindStringSubmatch(o.Path) + return m[1], m[2], m[3], m[4] + } + return "", "", "", "" +} + +// initExample reads the example config for an operation +func (o *Operation) initExample(config *Config) { + path := o.Type.Name + ".yaml" + path = filepath.Join(*ConfigDir, config.ExampleLocation, o.Definition.Name, path) + path = strings.Replace(path, " ", "_", -1) + path = strings.ToLower(path) + content, err := ioutil.ReadFile(path) + if err != nil { + return + } + err = yaml.Unmarshal(content, &o.ExampleConfig) + if err != nil { + panic(fmt.Sprintf("Could not Unmarshal ExampleConfig yaml: %s\n", content)) + } } diff --git a/gen-apidocs/generators/api/sort.go b/gen-apidocs/generators/api/sort.go deleted file mode 100644 index 5b27c31a..00000000 --- a/gen-apidocs/generators/api/sort.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package api - -import "strings" - -type SortDefinitionsByName []*Definition - -func (a SortDefinitionsByName) Len() int { return len(a) } -func (a SortDefinitionsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a SortDefinitionsByName) Less(i, j int) bool { - if a[i].Name == a[j].Name { - if a[i].Version.String() == a[j].Version.String() { - return a[i].Group.String() < a[j].Group.String() - } - return a[i].Version.LessThan(a[j].Version) - } - return a[i].Name < a[j].Name -} - -type SortDefinitionsByVersion []*Definition - -func (a SortDefinitionsByVersion) Len() int { return len(a) } -func (a SortDefinitionsByVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a SortDefinitionsByVersion) Less(i, j int) bool { - switch { - case a[i].Version == a[j].Version: - return strings.Compare(a[i].Group.String(), a[j].Group.String()) < 0 - default: - return a[i].Version.LessThan(a[j].Version) - } -} diff --git a/gen-apidocs/generators/api/types.go b/gen-apidocs/generators/api/types.go index 42f5be5c..5d5cab13 100644 --- a/gen-apidocs/generators/api/types.go +++ b/gen-apidocs/generators/api/types.go @@ -17,18 +17,107 @@ limitations under the License. package api import ( - "fmt" + "strings" + + "github.com/go-openapi/spec" ) +type ApiGroup string +type ApiGroups []ApiGroup + +type ApiKind string + +type ApiVersion string +type ApiVersions []ApiVersion +func (a ApiVersion) String() string { + return string(a) +} + +type SortDefinitionsByName []*Definition + +func (a SortDefinitionsByName) Len() int { return len(a) } +func (a SortDefinitionsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SortDefinitionsByName) Less(i, j int) bool { + if a[i].Name == a[j].Name { + if a[i].Version.String() == a[j].Version.String() { + return a[i].Group.String() < a[j].Group.String() + } + return a[i].Version.LessThan(a[j].Version) + } + return a[i].Name < a[j].Name +} + +type SortDefinitionsByVersion []*Definition + +func (a SortDefinitionsByVersion) Len() int { return len(a) } +func (a SortDefinitionsByVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SortDefinitionsByVersion) Less(i, j int) bool { + switch { + case a[i].Version == a[j].Version: + return strings.Compare(a[i].Group.String(), a[j].Group.String()) < 0 + default: + return a[i].Version.LessThan(a[j].Version) + } +} + +type Definition struct { + // open-api schema for the definition + schema spec.Schema + // Display name of the definition (e.g. Deployment) + Name string + Group ApiGroup + ShowGroup bool + + // Api version of the definition (e.g. v1beta1) + Version ApiVersion + Kind ApiKind + DescriptionWithEntities string + GroupFullName string + + // InToc is true if this definition should appear in the table of contents + InToc bool + IsInlined bool + IsOldVersion bool + + FoundInField bool + FoundInOperation bool + + // Inline is a list of definitions that should appear inlined with this one in the documentations + Inline SortDefinitionsByName + + // AppearsIn is a list of definition that this one appears in - e.g. PodSpec in Pod + AppearsIn SortDefinitionsByName + + OperationCategories []*OperationCategory + + // Fields is a list of fields in this definition + Fields Fields + + OtherVersions SortDefinitionsByName + NewerVersions SortDefinitionsByName + + Sample SampleConfig + + FullName string + Resource string +} + +// Definitions indexes open-api definitions +type Definitions struct { + All map[string]*Definition + ByKind map[string]SortDefinitionsByVersion +} + +type DefinitionList []*Definition + type Config struct { ApiGroups []ApiGroup `yaml:"api_groups,omitempty"` ExampleLocation string `yaml:"example_location,omitempty"` OperationCategories []OperationCategory `yaml:"operation_categories,omitempty"` ResourceCategories []ResourceCategory `yaml:"resource_categories,omitempty"` - // Used to map the group as the resource sees it to the group - // as the operation sees it - GroupMap map[string]string + // Used to map the group as the resource sees it to the group as the operation sees it + GroupMap map[string]string Definitions Definitions Operations Operations @@ -36,45 +125,118 @@ type Config struct { // InlineDefinition defines a definition that should be inlined when displaying a Concept instead of appearing the in "Definitions" type InlineDefinition struct { - // Name is the name of the definition category Name string `yaml:",omitempty"` - // Match the regular expression of defintion names that match this group where '${resource}' matches the resource name. - // e.g. if Match == "${resource}Spec" then DeploymentSpec would be inlined into the "Deployment" Concept Match string `yaml:",omitempty"` } -func (c Config) GetTopLevelConcepts() []string { - s := []string{} - for _, c := range c.ResourceCategories { - for _, r := range c.Resources { - s = append(s, r.Name) - } +type Field struct { + Name string + Type string + Description string + DescriptionWithEntities string + + Definition *Definition // Optional Definition for complex types + + PatchStrategy string + PatchMergeKey string +} + +type Fields []*Field + +func (a Fields) Len() int { return len(a) } +func (a Fields) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a Fields) Less(i, j int) bool { return a[i].Name < a[j].Name } + +func (f Field) Link() string { + if f.Definition != nil { + return strings.Replace(f.Type, f.Definition.Name, f.Definition.MdLink(), -1) + } else { + return f.Type } - return s } -///////////////////////////////////////////////////// -// Resources -///////////////////////////////////////////////////// -type Resources []*Resource +func (f Field) FullLink() string { + if f.Definition != nil { + return strings.Replace(f.Type, f.Definition.Name, f.Definition.HrefLink(), -1) + } else { + return f.Type + } +} -// ResourceCategory defines a category of Concepts -type ResourceCategory struct { +// Operation defines a highlevel operation type such as Read, Replace, Patch +type OperationType struct { + // Name is the display name of this operation + Name string `yaml:",omitempty"` + // Match is the regular expression of operation IDs that match this group where '${resource}' matches the resource name. + Match string `yaml:",omitempty"` +} + +type ExampleText struct { + Tab string + Type string + Text string + Msg string +} + +type HttpResponse struct { + Field + Code string +} + +type HttpResponses []*HttpResponse + +type Operation struct { + item spec.PathItem + op *spec.Operation + ID string + Type OperationType + Path string + HttpMethod string + Definition *Definition + BodyParams Fields + QueryParams Fields + PathParams Fields + HttpResponses HttpResponses + + ExampleConfig ExampleConfig +} + +type Operations map[string]*Operation + +// OperationCategory defines a group of related operations +type OperationCategory struct { // Name is the display name of this group Name string `yaml:",omitempty"` - // Include is the name of the _resource.md file to include in the index.html.md - Include string `yaml:",omitempty"` - // Resources are the collection of Resources in this group - Resources Resources `yaml:",omitempty"` - // LinkToMd is the relative path to the md file containing the contents that clicking on this should link to - LinkToMd string `yaml:"link_to_md,omitempty"` + // Operations are the collection of Operations in this group + OperationTypes []OperationType `yaml:"operation_types,omitempty"` + // Default is true if this is the default operation group for operations that do not match any other groups + Default bool `yaml:",omitempty"` + + Operations []*Operation +} + +type ExampleProvider interface { + GetTab() string + GetRequestMessage() string + GetResponseMessage() string + GetRequestType() string + GetResponseType() string + GetSampleType() string + GetSample(d *Definition) string + GetRequest(o *Operation) string + GetResponse(o *Operation) string } +type EmptyExample struct{} +type CurlExample struct{} +type KubectlExample struct{} + type Resource struct { // Name is the display name of this Resource Name string `yaml:",omitempty"` Version string `yaml:",omitempty"` Group string `yaml:",omitempty"` + // InlineDefinition is a list of definitions to show along side this resource when displaying it InlineDefinition []string `yaml:inline_definition",omitempty"` // DescriptionWarning is a warning message to show along side this resource when displaying it @@ -94,6 +256,20 @@ type Resource struct { Definition *Definition } +type Resources []*Resource + +// ResourceCategory defines a category of Concepts +type ResourceCategory struct { + // Name is the display name of this group + Name string `yaml:",omitempty"` + // Include is the name of the _resource.md file to include in the index.html.md + Include string `yaml:",omitempty"` + // Resources are the collection of Resources in this group + Resources Resources `yaml:",omitempty"` + // LinkToMd is the relative path to the md file containing the contents that clicking on this should link to + LinkToMd string `yaml:"link_to_md,omitempty"` +} + type ExampleConfig struct { Name string `yaml:",omitempty"` Namespace string `yaml:",omitempty"` @@ -109,21 +285,3 @@ type SampleConfig struct { } type ResourceVisitor func(resource *Resource, d *Definition) - -// For each resource in the ToC, look up its definition and visit it. -func (c *Config) VisitResourcesInToc(definitions Definitions, fn ResourceVisitor) { - missing := false - for _, cat := range c.ResourceCategories { - for _, resource := range cat.Resources { - if definition, found := definitions.GetByVersionKind(resource.Group, resource.Version, resource.Name); found { - fn(resource, definition) - } else { - fmt.Printf("Could not find definition for resource appearing in TOC: %s %s %s.\n", resource.Group, resource.Version, resource.Name) - missing = true - } - } - } - if missing { - fmt.Printf("All known definitions: %v\n", definitions.GetAllDefinitions()) - } -} diff --git a/gen-apidocs/generators/api/util.go b/gen-apidocs/generators/api/util.go index a7de2ddb..0152fb5d 100644 --- a/gen-apidocs/generators/api/util.go +++ b/gen-apidocs/generators/api/util.go @@ -24,10 +24,17 @@ import ( "github.com/go-openapi/spec" ) -func GetGroupVersionKind() { - +var INLINE_DEFINITIONS = []InlineDefinition{ + {Name: "Spec", Match: "${resource}Spec"}, + {Name: "Status", Match: "${resource}Status"}, + {Name: "List", Match: "${resource}List"}, + {Name: "Strategy", Match: "${resource}Strategy"}, + {Name: "Rollback", Match: "${resource}Rollback"}, + {Name: "RollingUpdate", Match: "RollingUpdate${resource}"}, + {Name: "EventSource", Match: "${resource}EventSource"}, } + // GetDefinitionVersionKind returns the api version and kind for the spec. This is the primary key of a Definition. func GetDefinitionVersionKind(s spec.Schema) (string, string, string) { // Get the reference for complex types @@ -89,9 +96,6 @@ func GetTypeName(s spec.Schema) string { // IsArray returns true if the type is an array type. func IsArray(s spec.Schema) bool { - //if s == nil { - // return false - //} return len(s.Type) > 0 && s.Type[0] == "array" } @@ -99,3 +103,63 @@ func IsArray(s spec.Schema) bool { func IsDefinition(s spec.Schema) bool { return len(s.SchemaProps.Ref.GetPointer().String()) > 0 } + +// handle '*', 'a/*', '*/b', '*/*' cases +func EscapeAsterisks(des string) string { + s := strings.Replace(des, "'*'", `'\*'`, -1) + s = strings.Replace(s, "/*'", `/\*'`, -1) + s = strings.Replace(s, "'*/", `'\*/`, -1) + s = strings.Replace(s, "'*/*'", `'\*/\*'`, -1) + return s +} + +// IsComplex returns true if the schema is for a complex (non-primitive) defintions +func IsComplex(schema spec.Schema) bool { + _, _, k := GetDefinitionVersionKind(schema) + return len(k) > 0 +} + +// GuessGVK makes a guess about the (Group, Version, Kind) tuple based on +// resource name +// TODO: Rework this function because it is ugly +func GuessGVK(name string) (group, version, kind string) { + parts := strings.Split(name, ".") + if len(parts) < 4 { + fmt.Printf("Error: Could not find version and type for definition %s.\n", name) + return "", "", "" + } + + if parts[len(parts)-3] == "api" { + // e.g. "io.k8s.apimachinery.pkg.api.resource.Quantity" + group = "core" + version = parts[len(parts)-2] + kind = parts[len(parts)-1] + } else if parts[len(parts)-4] == "api" { + // e.g. "io.k8s.api.core.v1.Pod" + group = parts[len(parts)-3] + version = parts[len(parts)-2] + kind = parts[len(parts)-1] + } else if parts[len(parts)-4] == "apis" { + // e.g. "io.k8s.apimachinery.pkg.apis.meta.v1.Status" + group = parts[len(parts)-3] + version = parts[len(parts)-2] + kind = parts[len(parts)-1] + } else if parts[len(parts)-3] == "util" || parts[len(parts)-3] == "pkg" { + // e.g. io.k8s.apimachinery.pkg.util.intstr.IntOrString + // e.g. io.k8s.apimachinery.pkg.runtime.RawExtension + return "", "", "" + } else { + // To report error + return "error", "", "" + } + return group, version, kind +} + +func GetInlinedDefinitionNames(parent string) []string { + names := []string{} + for _, id := range INLINE_DEFINITIONS { + name := strings.Replace(id.Match, "${resource}", parent, -1) + names = append(names, name) + } + return names +} diff --git a/gen-apidocs/generators/config.yaml b/gen-apidocs/generators/config.yaml index 1d63708b..bae886fc 100644 --- a/gen-apidocs/generators/config.yaml +++ b/gen-apidocs/generators/config.yaml @@ -32,7 +32,7 @@ inline_definitions: - name: EventSource match: ${resource}Source resource_categories: - - name: "Workloads Apis" + - name: "Workloads APIs" include: "workloads" resources: - name: Container @@ -66,7 +66,7 @@ resource_categories: - name: StatefulSet version: v1 group: apps - - name: "Service Apis" + - name: "Service APIs" include: "servicediscovery" resources: - name: Endpoints @@ -78,7 +78,7 @@ resource_categories: - name: Service version: v1 group: core - - name: "Config & Storage Apis" + - name: "Config and Storage APIs" include: "config" resources: - name: ConfigMap @@ -100,7 +100,7 @@ resource_categories: - name: VolumeAttachment version: v1beta1 group: storage - - name: "Metadata Apis" + - name: "Metadata APIs" include: "meta" resources: - name: ControllerRevision @@ -134,9 +134,8 @@ resource_categories: version: v1beta1 group: policy - name: PriorityClass - version: v1alpha1 + version: v1beta1 group: scheduling - description_warning: "Alpha objects should not be used in production and may not be compatible with future versions of the resource type." - name: PodPreset version: v1alpha1 group: settings @@ -144,7 +143,7 @@ resource_categories: - name: PodSecurityPolicy version: v1beta1 group: extensions - - name: "Cluster Apis" + - name: "Cluster APIs" include: "cluster" resources: - name: APIService diff --git a/gen-apidocs/generators/files.go b/gen-apidocs/generators/files.go deleted file mode 100644 index d3788d7e..00000000 --- a/gen-apidocs/generators/files.go +++ /dev/null @@ -1,313 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package generators - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - "text/template" - - "github.com/kubernetes-incubator/reference-docs/gen-apidocs/generators/api" -) - -func WriteTemplates(config *api.Config) { - if _, err := os.Stat(*api.ConfigDir + "/includes"); os.IsNotExist(err) { - os.Mkdir(*api.ConfigDir+"/includes", os.FileMode(0700)) - } - - // Write the index file importing each of the top level concept files - WriteIndexFile(config) - - //// Write each concept file imported by the index file - WriteConceptFiles(config) - - //// Write each definition file imported by the index file - WriteDefinitionFiles(config) -} - -func getStaticIncludesDir() string { - return filepath.Join(*api.ConfigDir, "static_includes") -} - -func WriteStaticFile(title, location string) { - staticFileTemplate, err := template.New("static-file-template").Parse(DefaultHeader) - if err != nil { - panic(fmt.Errorf("Could not parse %v %s", err, DefaultHeader)) - } - - f := filepath.Join(getStaticIncludesDir(), location) - _, err = os.Stat(f) - if err == nil { - // Don't create the file if it exists - return - } - - if !os.IsNotExist(err) { - panic(fmt.Sprintf("Could not stat file %s %v", f, err)) - } - fmt.Printf("Creating %s file\n", f) - file, err := os.Create(f) - if err != nil { - panic(err) - } - file.Close() - - file, err = os.OpenFile(f, os.O_WRONLY, 0) - if err != nil { - fmt.Println(err) - } - err = staticFileTemplate.Execute(file, title) - if err != nil { - fmt.Println(err) - } - file.Close() -} - -func WriteIndexFile(config *api.Config) { - includes := []string{} - - manifest := Manifest{} - - manifest.Copyright = "Copyright 2016 The Kubernetes Authors." - - WriteStaticFile("Overview", "_overview.md") - WriteStaticFile("Old Versions", "_oldversions.md") - WriteStaticFile("Definitions", "_definitions.md") - for _, c := range config.ResourceCategories { - name := "_" + c.Include + ".md" - WriteStaticFile(c.Include, name) - } - - if !*api.BuildOps { - manifest.Title = "Kubernetes Resource Reference Docs" - } else { - manifest.Title = "Kubernetes API Reference Docs" - manifest.Docs = append(manifest.Docs, Doc{"_overview.md"}) - } - - // Copy over the includes - err := filepath.Walk(getStaticIncludesDir(), func(path string, info os.FileInfo, err error) error { - if !info.IsDir() { - to := filepath.Join(*api.ConfigDir, "includes", filepath.Base(path)) - return os.Link(path, to) - } - return nil - }) - if err != nil { - fmt.Printf("Failed to copy includes %v.\n", err) - return - } - - // Add Toc Imports - for _, c := range config.ResourceCategories { - includes = append(includes, c.Include) - name := "_" + c.Include + ".md" - manifest.Docs = append(manifest.Docs, Doc{name}) - WriteStaticFile(c.Include, name) - - for _, r := range c.Resources { - if r.Definition == nil { - fmt.Printf("Warning: Missing definition for item in ToC %s\n", r.Name) - continue - } - - includes = append(includes, GetConceptImport(r.Definition)) - manifest.Docs = append(manifest.Docs, Doc{"_" + GetConceptImport(r.Definition) + ".md"}) - } - } - - // Add other definition imports - definitions := api.SortDefinitionsByName{} - for _, definition := range config.Definitions.GetAllDefinitions() { - - // Don't add definitions for top level resources in the toc or inlined resources - if definition.InToc || definition.IsInlined || definition.IsOldVersion { - continue - } - definitions = append(definitions, definition) - } - sort.Sort(definitions) - manifest.Docs = append(manifest.Docs, Doc{"_definitions.md"}) - includes = append(includes, "definitions") - for _, d := range definitions { - //definitions[i] = GetDefinitionImport(name) - manifest.Docs = append(manifest.Docs, Doc{"_" + GetDefinitionImport(d) + ".md"}) - includes = append(includes, GetDefinitionImport(d)) - } - - // Add definitions for older version of objects - definitions = api.SortDefinitionsByName{} - for _, definition := range config.Definitions.GetAllDefinitions() { - // Don't add definitions for top level resources in the toc or inlined resources - if definition.IsOldVersion { - definitions = append(definitions, definition) - } - } - sort.Sort(definitions) - manifest.Docs = append(manifest.Docs, Doc{"_oldversions.md"}) - includes = append(includes, "oldversions") - for _, d := range definitions { - // Skip Inlined definitions - if d.IsInlined { - continue - } - manifest.Docs = append(manifest.Docs, Doc{"_" + GetConceptImport(d) + ".md"}) - includes = append(includes, GetConceptImport(d)) - } - - // Write out the json manifest - jsonbytes, err := json.MarshalIndent(manifest, "", " ") - if err != nil { - fmt.Printf("Could not Marshal manfiest %+v due to error: %v.\n", manifest, err) - } else { - jsonfile, err := os.Create(*api.ConfigDir + "/" + JsonOutputFile) - if err != nil { - fmt.Printf("Could not create file %s due to error: %v.\n", JsonOutputFile, err) - } else { - defer jsonfile.Close() - _, err := jsonfile.Write(jsonbytes) - if err != nil { - fmt.Printf("Failed to write bytes %s to file %s: %v.\n", jsonbytes, JsonOutputFile, err) - } - } - } -} - -const DefaultHeader = ` -# {{.}} - ------------- - -` - -func WriteConceptFiles(config *api.Config) { - // Setup the template to be instantiated - t, err := template.New("concept.template").Parse(ConceptTemplate) - if err != nil { - fmt.Printf("Failed to parse template: %v", err) - os.Exit(1) - } - - // Write concepts for old versions - for _, d := range config.Definitions.GetAllDefinitions() { - if !d.IsOldVersion { - continue - } - r := &api.Resource{Definition: d, Name: d.Name} - WriteTemplate(t, r, GetConceptFilePath(d)) - } - // Write concepts for items in the Toc - for _, rc := range config.ResourceCategories { - for _, r := range rc.Resources { - WriteTemplate(t, r, GetConceptFilePath(r.Definition)) - } - } -} - -func WriteDefinitionFiles(config *api.Config) { - // Setup the template to be instantiated - t, err := template.New("definition.template").Parse(DefinitionTemplate) - if err != nil { - fmt.Printf("Failed to parse template: %v", err) - os.Exit(1) - } - - for _, definition := range config.Definitions.GetAllDefinitions() { - // Skip things already present in concept docs - if definition.InToc || definition.IsInlined || definition.IsOldVersion { - continue - } - WriteTemplate(t, definition, GetDefinitionFilePath(definition)) - } -} - -func WriteTemplate(t *template.Template, data interface{}, path string) { - conceptFile, err := os.Create(path) - defer conceptFile.Close() - if err != nil { - os.Stderr.WriteString(fmt.Sprintf("%v", err)) - os.Exit(1) - } - err = t.Execute(conceptFile, data) - if err != nil { - os.Stderr.WriteString(fmt.Sprintf("%v", err)) - os.Exit(1) - } -} - -func getLink(s string) string { - return "#" + strings.ToLower(strings.Replace(s, " ", "-", -1)) -} - -func getImport(s string) string { - return "generated_" + strings.ToLower(strings.Replace(s, ".", "_", 50)) -} - -func toFileName(s string) string { - return fmt.Sprintf("%s/includes/_%s.md", *api.ConfigDir, s) -} - -func GetDefinitionImport(d *api.Definition) string { - return fmt.Sprintf("%s_%s_%s_definition", getImport(d.Name), d.Version, d.Group) -} - -func GetDefinitionFilePath(d *api.Definition) string { - return toFileName(GetDefinitionImport(d)) -} - -// GetConceptImport returns the name to import in the index.html.md file -func GetConceptImport(d *api.Definition) string { - return fmt.Sprintf("%s_%s_%s_concept", getImport(d.Name), d.Version, d.Group) -} - -// GetConceptFilePath returns the filepath to write when instantiating a concept template -func GetConceptFilePath(d *api.Definition) string { - return toFileName(GetConceptImport(d)) -} - -type Manifest struct { - ExampleTabs []ExampleTab `json:"example_tabs,omitempty"` - TableOfContents TableOfContents `json:"table_of_contents,omitempty"` - Docs []Doc `json:"docs,omitempty"` - Title string `json:"title,omitempty"` - Copyright string `json:"copyright,omitempty"` -} - -type TableOfContents struct { - Items []TableOfContentsItem `json:"body_md_files,omitempty"` -} - -type TableOfContentsItem struct { - DisplayName string `json:"display_name,omitempty"` - Type string `json:"type,omitempty"` - Link string `json:"link,omitempty"` - Items []TableOfContentsItem `json:"items,omitempty"` -} - -type Doc struct { - Filename string `json:"filename,omitempty"` -} - -type ExampleTab struct { - DisplayName string `json:"display_name,omitempty"` - SyntaxType string `json:"syntax_type,omitempty"` - HoverText string `json:"hover_text,omitempty"` -} diff --git a/gen-apidocs/generators/gen.go b/gen-apidocs/generators/gen.go deleted file mode 100644 index 5db13a52..00000000 --- a/gen-apidocs/generators/gen.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -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. -*/ - -package generators - -import "github.com/kubernetes-incubator/reference-docs/gen-apidocs/generators/api" - -func GenerateFiles() { - // Load the yaml config - config := api.NewConfig() - - PrintInfo(config) - WriteTemplates(config) -} diff --git a/gen-apidocs/generators/html.go b/gen-apidocs/generators/html.go new file mode 100644 index 00000000..3a988428 --- /dev/null +++ b/gen-apidocs/generators/html.go @@ -0,0 +1,608 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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. +*/ + +package generators + +import ( + "fmt" + "html" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/kubernetes-incubator/reference-docs/gen-apidocs/generators/api" +) + +type TOCItem struct { + Level int + Title string + Link string + File string + SubSections []*TOCItem +} + +type TOC struct { + Title string + Copyright string + Sections []*TOCItem +} + +type HTMLWriter struct { + Config *api.Config + TOC TOC + CurrentSection *TOCItem +} + +func NewHTMLWriter(config *api.Config, copyright, title string) DocWriter { + writer := HTMLWriter{ + Config: config, + TOC: TOC{ + Copyright: copyright, + Title: title, + Sections: []*TOCItem{}, + }, + } + return &writer +} + +func (h *HTMLWriter) Extension() string { + return ".html" +} + +func (h *HTMLWriter) WriteOverview() { + fn := "_overview.html" + writeStaticFile("Overview", fn, h.DefaultStaticContent("Overview")) + item := TOCItem { + Level: 1, + Title: "Overview", + Link: "-strong-api-overview-strong-", + File: fn, + } + h.TOC.Sections = append(h.TOC.Sections, &item) + h.CurrentSection = &item +} + +func (h *HTMLWriter) WriteResourceCategory(name, file string) { + writeStaticFile(name, file + ".html", h.DefaultStaticContent(name)) + link := strings.Replace(strings.ToLower(name), " ", "-", -1) + item := TOCItem { + Level: 1, + Title: strings.ToUpper(name), + Link: "-strong-" + link + "-strong-", + File: file + ".html", + } + h.TOC.Sections = append(h.TOC.Sections, &item) + h.CurrentSection = &item +} + +func (h *HTMLWriter) DefaultStaticContent(title string) string { + titleID := strings.ToLower(strings.Replace(title, " ", "-", -1)) + return fmt.Sprintf("

%s

\n", titleID, title) +} + +func (h *HTMLWriter) writeOtherVersions(w io.Writer, d *api.Definition) { + if d.OtherVersions.Len() == 0 { + return + } + + fmt.Fprint(w, "
Other API versions of this object exist:\n") + for _, v := range d.OtherVersions { + fmt.Fprintf(w, "%s\n", v.VersionLink()) + } + fmt.Fprintf(w, "
\n") +} + +func (h *HTMLWriter) writeAppearsIn(w io.Writer, d *api.Definition) { + if d.AppearsIn.Len() != 0 { + fmt.Fprintf(w, "
Appears In:\n
    \n") + for _, a := range d.AppearsIn { + fmt.Fprintf(w, "
  • %s
  • \n", a.FullHrefLink()) + } + fmt.Fprintf(w, "
\n
\n") + } +} + +func (h *HTMLWriter) writeFields(w io.Writer, d *api.Definition) { + fmt.Fprintf(w, "\n\n\n") + + for _, field := range d.Fields { + fmt.Fprintf(w, "\n", field.DescriptionWithEntities) + } + fmt.Fprintf(w, "\n
FieldDescription
%s", field.Name) + if field.Link() != "" { + fmt.Fprintf(w, "
%s", field.FullLink()) + } + if field.PatchStrategy != "" { + fmt.Fprintf(w, "
patch strategy: %s", field.PatchStrategy) + } + if field.PatchMergeKey != "" { + fmt.Fprintf(w, "
patch merge key: %s", field.PatchMergeKey) + } + fmt.Fprintf(w, "
%s
\n") +} + +func (h *HTMLWriter) WriteDefinitionsOverview() { + writeStaticFile("Definitions", "_definitions.html", h.DefaultStaticContent("Definitions")) + item := TOCItem { + Level: 1, + Title: "DEFINITIONS", + Link: "-strong-definitions-strong-", + File: "_definitions.html", + } + h.TOC.Sections = append(h.TOC.Sections, &item) + h.CurrentSection = &item +} + +func (h *HTMLWriter) WriteDefinition(d *api.Definition) { + fn := "_" + definitionFileName(d) + ".html" + path := *api.ConfigDir + "/includes/" + fn + f, err := os.Create(path) + defer f.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + nvg := fmt.Sprintf("%s %s %s", d.Name, d.Version, d.Group) + linkID := getLink(nvg) + fmt.Fprintf(f, "

%s

\n", linkID, nvg) + fmt.Fprintf(f, "\n\n\n") + fmt.Fprintf(f, "\n", + d.GroupDisplayName(), d.Version, d.Name) + fmt.Fprintf(f, "\n
GroupVersionKind
%s%s%s
\n") + + fmt.Fprintf(f, "

%s

\n", d.DescriptionWithEntities) + h.writeOtherVersions(f, d) + h.writeAppearsIn(f, d) + h.writeFields(f, d) + + item := TOCItem { + Level: 2, + Title: nvg, + Link: linkID, + File: fn, + } + h.CurrentSection.SubSections = append(h.CurrentSection.SubSections, &item) +} + +func (h *HTMLWriter) writeSample(w io.Writer, d *api.Definition) { + if d.Sample.Sample == "" { + return + } + + note := d.Sample.Note + for _, s := range d.GetSamples() { + sType := strings.Split(s.Tab, ":")[1] + linkID := sType + "-" + d.LinkID() + fmt.Fprintf(w, "\n", sType) + } + + for _, s := range d.GetSamples() { + sType := strings.Split(s.Tab, ":")[1] + linkID := sType + "-" + d.LinkID() + lType := strings.Split(s.Type, ":")[1] + lang := strings.Split(lType, "_")[1] + fmt.Fprintf(w, "
\n", linkID) + fmt.Fprintf(w, "
\n
%s
\n", note) + fmt.Fprintf(w, "
\n
", sType)
+		fmt.Fprintf(w, "\n", lang)
+		// TODO: Add language highlight
+		fmt.Fprintf(w, "%s\n
\n", html.EscapeString(s.Text)) + } +} + +func (h *HTMLWriter) writeOperationSample(w io.Writer, req bool, op string, examples []api.ExampleText) { + // e.Tab bdocs-tab:kubectl | bdocs-tab:curl + // e.Msg `kubectl` Command | Output | Response Body | `curl` Command (*requires `kubectl proxy` to be running*) + // e.Type bdocs-tab:kubectl_shell + // e.Text + + for _, e := range examples { + eType := strings.Split(e.Tab, ":")[1] + var sampleID string + var btnText string + if req { + sampleID = "req-" + eType + "-" + op + btnText = eType + " request" + } else { + sampleID = "res-" + eType + "-" + op + btnText = eType + " response" + } + fmt.Fprintf(w, "\n", btnText) + } + + for _, e := range examples { + eType := strings.Split(e.Tab, ":")[1] + var sampleID string + if req { + sampleID = "req-" + eType + "-" + op + } else { + sampleID = "res-" + eType + "-" + op + } + msg := e.Msg + if eType == "curl" && strings.Contains(msg, "proxy") { + msg = "curl command (requires kubectl proxy to be running)" + } else if eType == "kubectl" && strings.Contains(msg, "Command") { // `kubectl` command + msg = "kubectl command" + } + lType := strings.Split(e.Type, ":")[1] + lang := strings.Split(lType, "_")[1] + fmt.Fprintf(w, "
\n", sampleID) + fmt.Fprintf(w, "
\n
%s
\n", msg) + fmt.Fprintf(w, "
\n
", eType)
+		fmt.Fprintf(w, "\n", lang)
+		// TODO: Add language highlight
+		fmt.Fprintf(w, "%s\n
\n", e.Text) + } +} + +func (h *HTMLWriter) writeParams(w io.Writer, title string, params api.Fields) { + fmt.Fprintf(w, "

%s

\n", title) + fmt.Fprintf(w, "\n\n\n") + for _, p := range params { + fmt.Fprintf(w, "\n", p.Description) + } + fmt.Fprintf(w, "\n
ParameterDescription
%s", p.Name) + if p.Link() != "" { + fmt.Fprintf(w, "
%s", p.FullLink()) + } + fmt.Fprintf(w, "
%s
\n") +} + +func (h *HTMLWriter) writeRequestParams(w io.Writer, o *api.Operation) { + // Operation path params + if o.PathParams.Len() > 0 { + h.writeParams(w, "Path Parameters", o.PathParams) + } + + // operation query params + if o.QueryParams.Len() > 0 { + h.writeParams(w, "Query Parameters", o.QueryParams) + } + + // operation body params + if o.BodyParams.Len() > 0 { + h.writeParams(w, "Body Parameters", o.BodyParams) + } +} + +func (h *HTMLWriter) writeResponseParams(w io.Writer, o *api.Operation) { + if o.HttpResponses.Len() == 0 { + return + } + + fmt.Fprintf(w, "

Response

\n") + fmt.Fprintf(w, "\n\n\n") + for _, p := range o.HttpResponses { + fmt.Fprintf(w, "\n", p.Field.Description) + } + fmt.Fprintf(w, "\n
CodeDescription
%s", p.Name) + if p.Field.Link() != "" { + fmt.Fprintf(w, "
%s", p.Field.FullLink()) + } + fmt.Fprintf(w, "
%s
\n") +} + + +func (h *HTMLWriter) WriteResource(r *api.Resource) { + fn := "_" + conceptFileName(r.Definition) + ".html" + path := *api.ConfigDir + "/includes/" + fn + w, err := os.Create(path) + defer w.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + + dvg := fmt.Sprintf("%s %s %s", r.Name, r.Definition.Version, r.Definition.GroupDisplayName()) + linkID := getLink(dvg) + fmt.Fprintf(w, "

%s

\n", linkID, dvg) + + h.writeSample(w, r.Definition) + + // GVK + fmt.Fprintf(w, "\n\n\n") + fmt.Fprintf(w, "\n", + r.Definition.GroupDisplayName(), r.Definition.Version, r.Name) + fmt.Fprintf(w, "\n
GroupVersionKind
%s%s%s
\n") + + if r.DescriptionWarning != "" { + fmt.Fprintf(w, "

Warning:

%s

\n", r.DescriptionWarning) + } + if r.DescriptionNote != "" { + fmt.Fprintf(w, "
%s
\n", r.DescriptionNote) + } + + h.writeOtherVersions(w, r.Definition) + h.writeAppearsIn(w, r.Definition) + h.writeFields(w, r.Definition) + + // Inline + if r.Definition.Inline.Len() > 0 { + for _, d := range r.Definition.Inline { + fmt.Fprintf(w, "

%s %s %s

\n", d.LinkID(), d.Name, d.Version, d.Group) + h.writeAppearsIn(w, d) + h.writeFields(w, d) + } + } + + item := TOCItem { + Level: 1, + Title: dvg, + Link: linkID, + File: fn, + } + h.TOC.Sections = append(h.TOC.Sections, &item) + h.CurrentSection = &item + + // Operations + if len(r.Definition.OperationCategories) == 0 { + return + } + + for _, c := range r.Definition.OperationCategories { + if len(c.Operations) == 0 { + continue + } + catID := strings.Replace(strings.ToLower(c.Name), " ", "-", -1) + "-" + r.Definition.LinkID() + catID = "-strong-" + catID + "-strong-" + fmt.Fprintf(w, "

%s

\n", catID, c.Name) + OCItem := TOCItem { + Level: 2, + Title: c.Name, + Link: catID, + } + h.CurrentSection.SubSections = append(h.CurrentSection.SubSections, &OCItem) + + for _, o := range c.Operations { + opID := strings.Replace(strings.ToLower(o.Type.Name), " ", "-", -1) + "-" + r.Definition.LinkID() + fmt.Fprintf(w, "

%s

\n", opID, o.Type.Name) + OPItem := TOCItem { + Level: 2, + Title: o.Type.Name, + Link: opID, + } + OCItem.SubSections = append(OCItem.SubSections, &OPItem) + + // Example requests + requests := o.GetExampleRequests() + if len(requests) > 0 { + h.writeOperationSample(w, true, opID, requests) + } + // Example responses + responses := o.GetExampleResponses() + if len(responses) > 0 { + h.writeOperationSample(w, false, opID, responses) + } + + fmt.Fprintf(w, "

%s

\n", o.Description()) + fmt.Fprintf(w, "

HTTP Request

\n") + fmt.Fprintf(w, "%s\n", o.GetDisplayHttp()) + + h.writeRequestParams(w, o) + h.writeResponseParams(w, o) + } + } +} + +func (h *HTMLWriter) WriteOldVersionsOverview() { + writeStaticFile("Old Versions", "_oldversions.html", h.DefaultStaticContent("Old Versions")) + item := TOCItem { + Level: 1, + Title: "OLD API VERSIONS", + Link: "-strong-old-api-versions-strong-", + File: "_oldversions.html", + } + h.TOC.Sections = append(h.TOC.Sections, &item) + h.CurrentSection = &item +} + +func (h *HTMLWriter) generateNavContent() string { + nav := "" + for _, sec := range h.TOC.Sections { + // class for level-1 navigation item + nav += "
    \n" + if strings.Contains(sec.Link, "strong") { + nav += fmt.Sprintf("
  • %s
  • \n", + sec.Link, sec.Title) + } else { + nav += fmt.Sprintf("
  • %s
  • \n", + sec.Link, sec.Title) + } + + // close H1 items which have no subsections or strong navs + if len(sec.SubSections) == 0 || (sec.Level == 1 && strings.Contains(sec.Link, "strong")) { + nav += "
\n" + } + + // short circuit to next if no sub-sections + if len(sec.SubSections) == 0 { + continue + } + + // wrapper1 + nav += fmt.Sprintf("
    \n", sec.Link) + for _, sub := range sec.SubSections { + nav += "
      \n" + if strings.Contains(sub.Link, "strong") { + nav += fmt.Sprintf("
    • %s
    • \n", + sub.Level, sub.Link, sub.Title) + } else { + nav += fmt.Sprintf("
    • %s
    • \n", + sub.Level, sub.Link, sub.Title) + } + // close this H1/H2 if possible + if len(sub.SubSections) == 0 { + nav += "
    \n" + continue + } + + // 3rd level + // another wrapper + nav += fmt.Sprintf("
      \n", sub.Link) + for _, subsub := range sub.SubSections { + nav += fmt.Sprintf("
    • %s
    • \n", subsub.Level, subsub.Link, subsub.Title) + if len(subsub.SubSections) == 0 { + continue + } + + fmt.Printf("*** found third level!\n") + nav += fmt.Sprintf("
        \n", subsub.Link) + for _, subsubsub := range subsub.SubSections { + nav += fmt.Sprintf("
      • %s
      • \n", + subsubsub.Level, subsubsub.Link, subsubsub.Title) + } + nav += "
      \n" + } + // end wrapper2 + nav += "
    \n" + nav += "
\n" + } + // end wrapper1 + nav += " \n" + // end top UL + nav += "\n" + } + + return nav +} + +func (h *HTMLWriter) generateNavJS() { + // generate NavData + var tmp string + flatToc := []string{} + os.MkdirAll(*api.ConfigDir + "/build", os.ModePerm) + + navjs, err := os.Create(*api.ConfigDir + "/build/navData.js") + defer navjs.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + + s1 := []string{} + for _, sec := range h.TOC.Sections { + flatToc = append([]string{"\"" + sec.Link + "\""}, flatToc...) + s2 := []string{} + for _, sub := range sec.SubSections { + flatToc = append([]string{"\"" + sub.Link + "\""}, flatToc...) + s3 := []string{} + for _, subsub := range sub.SubSections { + flatToc = append([]string{"\"" + subsub.Link + "\""}, flatToc...) + s4 := []string{} + for _, subsubsub := range subsub.SubSections { + flatToc = append([]string{"\"" + subsubsub.Link + "\""}, flatToc...) + tmp = "{\"section\":\"" + subsubsub.Link + "\"}" + s4 = append([]string{tmp}, s4...) + } + tmp = "{\"section\":\"" + subsub.Link + "\",\"subsections\":[" + strings.Join(s4, ",") + "]}" + s3 = append([]string{tmp}, s3...) + } + tmp = "{\"section\":\"" + sub.Link + "\",\"subsections\":[" + strings.Join(s3, ",") + "]}" + s2 = append([]string{tmp}, s2...) + } + + if strings.Contains(sec.Link, "strong") { + tmp = "{\"section\":\"" + sec.Link + "\",\"subsections\":[]}" + s2res := strings.Join(s2, ",") + if len(s2res) > 0 { + tmp = s2res + "," + tmp + } + } else { + tmp = "{\"section\":\"" + sec.Link + "\",\"subsections\":[" + strings.Join(s2, ",") + "]}" + } + s1 = append([]string{tmp}, s1...) + } + fmt.Fprintf(navjs, "(function(){navData={\"toc\":[" + strings.Join(s1, ",") + "],\"flatToc\":[" + strings.Join(flatToc, ",") + "]};})();") +} + +func (h *HTMLWriter) generateHTML(navContent string) { + html, err := os.Create(*api.ConfigDir + "/build/index.html") + defer html.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + + fmt.Fprintf(html, "\n\n\n\n") + fmt.Fprintf(html, "%s\n", h.TOC.Title) + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n\n") + fmt.Fprintf(html, "
\n") + + // html buffer + buf := "" + for _, sec := range h.TOC.Sections { + fmt.Printf("Collecting %s ... ", sec.File) + content, err := ioutil.ReadFile(filepath.Join(*api.ConfigDir, "includes", sec.File)) + if err == nil { + buf += string(content) + } + fmt.Printf("OK\n") + + for _, sub := range sec.SubSections { + if len(sub.File) > 0 { + subdata, err := ioutil.ReadFile(filepath.Join(*api.ConfigDir, "includes", sub.File)) + fmt.Printf("Collecting %s ... ", sub.File) + if err == nil { + buf += string(subdata) + fmt.Printf("OK\n") + } + } + + for _, subsub := range sub.SubSections { + if len(subsub.File) > 0 { + subsubdata, err := ioutil.ReadFile(filepath.Join(*api.ConfigDir, "includes", subsub.File)) + fmt.Printf("Collecting %s ... ", subsub.File) + if err == nil { + buf += string(subsubdata) + fmt.Printf("OK\n") + } + } + } + } + } + + fmt.Fprintf(html, "%s", navContent) + fmt.Fprintf(html, "
%s
\n", h.TOC.Copyright) + fmt.Fprintf(html, "
\n") + fmt.Fprintf(html, "
\n") + fmt.Fprintf(html, "%s", string(buf)) + fmt.Fprintf(html, "
\n
\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n") + fmt.Fprintf(html, "\n\n") +} + +func (h *HTMLWriter) Finalize() { + // generate NavData + os.MkdirAll(*api.ConfigDir + "/build", os.ModePerm) + + h.generateNavJS() + navContent := h.generateNavContent() + h.generateHTML(navContent) +} diff --git a/gen-apidocs/generators/md.go b/gen-apidocs/generators/md.go new file mode 100644 index 00000000..e7222051 --- /dev/null +++ b/gen-apidocs/generators/md.go @@ -0,0 +1,291 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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. +*/ + +package generators + +import ( + "encoding/json" + "fmt" + "io" + "os" + + "github.com/kubernetes-incubator/reference-docs/gen-apidocs/generators/api" +) + +type Manifest struct { + Docs []Doc `json:"docs,omitempty"` + Title string `json:"title,omitempty"` + Copyright string `json:"copyright,omitempty"` +} + +type MarkdownWriter struct { + Config *api.Config + Manifest Manifest +} + +func NewMarkdownWriter(config *api.Config, copyright, title string) DocWriter { + writer := MarkdownWriter{ + Config: config, + Manifest: Manifest{ + Copyright: copyright, + Title: title, + }, + } + return &writer +} + +func (m *MarkdownWriter) Extension() string { + return ".md" +} + +func (m *MarkdownWriter) DefaultStaticContent(title string) string { + return fmt.Sprintf("# %s\n\n----------\n\n", title) +} + +func (m *MarkdownWriter) WriteOverview() { + writeStaticFile("Overview", "_overview.md", m.DefaultStaticContent("Overview")) + if *api.BuildOps { + m.Manifest.Docs = append(m.Manifest.Docs, Doc{"_overview.md"}) + } +} + +func (m *MarkdownWriter) WriteResourceCategory(name, file string) { + writeStaticFile(name, file + ".md", m.DefaultStaticContent(name)) + m.Manifest.Docs = append(m.Manifest.Docs, Doc{file + ".md"}) +} + +func (m *MarkdownWriter) writeFields(w io.Writer, d *api.Definition) { + fmt.Fprintf(w, "Field | Description\n------------ | -----------\n") + for _, field := range d.Fields { + fmt.Fprintf(w, "`%s`", field.Name) + if field.Link() != "" { + fmt.Fprintf(w, "
*%s*", field.Link()) + } + if field.PatchStrategy != "" { + fmt.Fprintf(w, "
**patch strategy**: *%s*", field.PatchStrategy) + } + if field.PatchMergeKey != "" { + fmt.Fprintf(w, "
**patch merge key**: *%s*", field.PatchMergeKey) + } + fmt.Fprintf(w, " | %s\n", field.DescriptionWithEntities) + } +} + +func (m *MarkdownWriter) writeOtherVersions(w io.Writer, d *api.Definition) { + if d.OtherVersions.Len() != 0 { + fmt.Fprintf(w, "\n\n") + } + fmt.Fprintf(w, "%s\n\n", d.DescriptionWithEntities) +} + +func (m *MarkdownWriter) writeAppearsIn(w io.Writer, d *api.Definition) { + if d.AppearsIn.Len() != 0 { + fmt.Fprintf(w, "\n\n") + } +} + +func (m *MarkdownWriter) WriteDefinition(d *api.Definition) { + fn := "_" + definitionFileName(d) + ".md" + path := *api.ConfigDir + "/includes/" + fn + f, err := os.Create(path) + defer f.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + fmt.Fprintf(f, "## %s %s %s\n\n", d.Name, d.Version, d.Group) + fmt.Fprintf(f, "Group | Version | Kind\n------------ | ---------- | -----------\n") + fmt.Fprintf(f, "`%s` | `%s` | `%s`\n", d.GroupDisplayName(), d.Version, d.Name) + fmt.Fprintf(f, "\n") + + m.writeOtherVersions(f, d) + m.writeAppearsIn(f, d) + m.writeFields(f, d) + m.Manifest.Docs = append(m.Manifest.Docs, Doc{fn}) +} + +func (m *MarkdownWriter) WriteResource(r *api.Resource) { + fn := "_" + conceptFileName(r.Definition) + ".md" + path := *api.ConfigDir + "/includes/" + fn + f, err := os.Create(path) + defer f.Close() + if err != nil { + os.Stderr.WriteString(fmt.Sprintf("%v", err)) + os.Exit(1) + } + + fmt.Fprintf(f, "-----------\n\n") + fmt.Fprintf(f, "# %s %s", r.Name, r.Definition.Version) + if r.Definition.ShowGroup { + fmt.Fprintf(f, " %s\n", r.Definition.GroupDisplayName()) + } else { + fmt.Fprintf(f, "\n") + } + + if r.Definition.Sample.Sample != "" { + note := r.Definition.Sample.Note + for _, t := range r.Definition.GetSamples() { + // 't' is a ExampleText + fmt.Fprintf(f, ">%s %s\n\n", t.Tab, note) + fmt.Fprintf(f, "```%s\n%s\n```\n\n", t.Type, t.Text) + } + } + + // GVK + fmt.Fprintf(f, "Group | Version | Kind\n------------ | ---------- | -----------\n") + fmt.Fprintf(f, "`%s` | `%s` | `%s`\n\n", r.Definition.GroupDisplayName(), r.Definition.Version, r.Name) + + if r.DescriptionWarning != "" { + fmt.Fprintf(f, "\n\n", r.DescriptionWarning) + } + if r.DescriptionNote != "" { + fmt.Fprintf(f, "\n\n", r.DescriptionNote) + } + + m.writeOtherVersions(f, r.Definition) + m.writeAppearsIn(f, r.Definition) + m.writeFields(f, r.Definition) + + fmt.Fprintf(f, "\n") + if r.Definition.Inline.Len() > 0 { + for _, d := range r.Definition.Inline { + fmt.Fprintf(f, "### %s %s %s\n", d.Name, d.Version, d.Group) + m.writeAppearsIn(f, d) + m.writeFields(f, d) + } + } + + if len(r.Definition.OperationCategories) > 0 { + for _, c := range r.Definition.OperationCategories { + if len(c.Operations) > 0 { + fmt.Fprintf(f, "## %s\n", c.Name) + for _, o := range c.Operations { + fmt.Fprintf(f, "\n## %s\n", o.Type.Name) + + // Example requests + requests := o.GetExampleRequests() + if len(requests) > 0 { + for _, r := range requests { + fmt.Fprintf(f, ">%s %s\n\n", r.Tab, r.Msg) + fmt.Fprintf(f, "```%s\n%s```\n\n", r.Type, r.Text) + } + } + // Example responses + responses := o.GetExampleResponses() + if len(responses) > 0 { + for _, r := range responses { + fmt.Fprintf(f, ">%s %s\n\n", r.Tab, r.Msg) + fmt.Fprintf(f, "```%s\n%s```\n\n", r.Type, r.Text) + } + } + + fmt.Fprintf(f, "%s\n", o.Description()) + fmt.Fprintf(f, "\n### HTTP Request\n\n`%s`\n", o.GetDisplayHttp()) + + // Operation path params + if o.PathParams.Len() > 0 { + fmt.Fprintf(f, "\n### Path Parameters\n\n") + fmt.Fprintf(f, "Parameter | Description\n------------ | -----------\n") + for _, p := range o.PathParams { + fmt.Fprintf(f, "`%s`", p.Name) + if p.Link() != "" { + fmt.Fprintf(f, "
*%s*", p.Link()) + } + fmt.Fprintf(f, " | %s\n", p.Description) + } + } + + // operation query params + if o.QueryParams.Len() > 0 { + fmt.Fprintf(f, "\n### Query Parameters\n\n") + fmt.Fprintf(f, "Parameter | Description\n------------ | -----------\n") + for _, p := range o.QueryParams { + fmt.Fprintf(f, "`%s`", p.Name) + if p.Link() != "" { + fmt.Fprintf(f, "
*%s*", p.Link()) + } + fmt.Fprintf(f, " | %s\n", p.Description) + } + } + // operation body params + if o.BodyParams.Len() > 0 { + fmt.Fprintf(f, "\n### Body Parameters\n\n") + fmt.Fprintf(f, "Parameter | Description\n------------ | -----------\n") + for _, p := range o.BodyParams { + fmt.Fprintf(f, "`%s`", p.Name) + if p.Link() != "" { + fmt.Fprintf(f, "
*%s*", p.Link()) + } + fmt.Fprintf(f, " | %s\n", p.Description) + } + } + + // operation response body + if o.HttpResponses.Len() > 0 { + fmt.Fprintf(f, "\n### Response\n\n") + fmt.Fprintf(f, "Code | Description\n------------ | -----------\n") + for _, r := range o.HttpResponses { + fmt.Fprintf(f, "%s ", r.Code) + if r.Field.Link() != "" { + fmt.Fprintf(f, "
*%s*", r.Field.Link()) + } + fmt.Fprintf(f, " | %s\n", r.Field.Description) + } + } + } + } + } + } + + m.Manifest.Docs = append(m.Manifest.Docs, Doc{fn}) +} + +func (m *MarkdownWriter) WriteDefinitionsOverview() { + writeStaticFile("Definitions", "_definitions.md", m.DefaultStaticContent("Definitions")) + m.Manifest.Docs = append(m.Manifest.Docs, Doc{"_definitions.md"}) +} + +func (m *MarkdownWriter) WriteOldVersionsOverview() { + writeStaticFile("Old Versions", "_oldversions.md", m.DefaultStaticContent("Old Versions")) + m.Manifest.Docs = append(m.Manifest.Docs, Doc{"_oldversions.md"}) +} + +func (m *MarkdownWriter) Finalize() { + // Write out the json manifest + jsonbytes, err := json.MarshalIndent(m.Manifest, "", " ") + if err != nil { + fmt.Printf("Could not Marshal manfiest %+v due to error: %v.\n", m.Manifest, err) + } else { + jsonfile, err := os.Create(*api.ConfigDir + "/" + JsonOutputFile) + if err != nil { + fmt.Printf("Could not create file %s due to error: %v.\n", JsonOutputFile, err) + } else { + defer jsonfile.Close() + _, err := jsonfile.Write(jsonbytes) + if err != nil { + fmt.Printf("Failed to write bytes %s to file %s: %v.\n", jsonbytes, JsonOutputFile, err) + } + } + } +} diff --git a/gen-apidocs/generators/openapi-spec/swagger.json b/gen-apidocs/generators/openapi-spec/swagger.json index 75ea188b..3aaf0217 100644 --- a/gen-apidocs/generators/openapi-spec/swagger.json +++ b/gen-apidocs/generators/openapi-spec/swagger.json @@ -2,7 +2,7 @@ "swagger": "2.0", "info": { "title": "Kubernetes", - "version": "v1.10.1" + "version": "v1.11.1" }, "paths": { "/api/": { @@ -20060,6 +20060,41 @@ ] }, "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/{name}/status": { + "get": { + "description": "read status of the specified CustomResourceDefinition", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiextensions_v1beta1" + ], + "operationId": "readApiextensionsV1beta1CustomResourceDefinitionStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "apiextensions.k8s.io", + "kind": "CustomResourceDefinition", + "version": "v1beta1" + } + }, "put": { "description": "replace status of the specified CustomResourceDefinition", "consumes": [ @@ -20111,6 +20146,53 @@ "version": "v1beta1" } }, + "patch": { + "description": "partially update status of the specified CustomResourceDefinition", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiextensions_v1beta1" + ], + "operationId": "patchApiextensionsV1beta1CustomResourceDefinitionStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "apiextensions.k8s.io", + "kind": "CustomResourceDefinition", + "version": "v1beta1" + } + }, "parameters": [ { "uniqueItems": true, @@ -20902,6 +20984,41 @@ ] }, "/apis/apiregistration.k8s.io/v1/apiservices/{name}/status": { + "get": { + "description": "read status of the specified APIService", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiregistration_v1" + ], + "operationId": "readApiregistrationV1APIServiceStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1" + } + }, "put": { "description": "replace status of the specified APIService", "consumes": [ @@ -20953,6 +21070,53 @@ "version": "v1" } }, + "patch": { + "description": "partially update status of the specified APIService", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiregistration_v1" + ], + "operationId": "patchApiregistrationV1APIServiceStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIService" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1" + } + }, "parameters": [ { "uniqueItems": true, @@ -21711,6 +21875,41 @@ ] }, "/apis/apiregistration.k8s.io/v1beta1/apiservices/{name}/status": { + "get": { + "description": "read status of the specified APIService", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiregistration_v1beta1" + ], + "operationId": "readApiregistrationV1beta1APIServiceStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1beta1.APIService" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1beta1" + } + }, "put": { "description": "replace status of the specified APIService", "consumes": [ @@ -21762,6 +21961,53 @@ "version": "v1beta1" } }, + "patch": { + "description": "partially update status of the specified APIService", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "apiregistration_v1beta1" + ], + "operationId": "patchApiregistrationV1beta1APIServiceStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1beta1.APIService" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1beta1" + } + }, "parameters": [ { "uniqueItems": true, @@ -44672,6 +44918,41 @@ ] }, "/apis/certificates.k8s.io/v1beta1/certificatesigningrequests/{name}/status": { + "get": { + "description": "read status of the specified CertificateSigningRequest", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "certificates_v1beta1" + ], + "operationId": "readCertificatesV1beta1CertificateSigningRequestStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.certificates.v1beta1.CertificateSigningRequest" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "certificates.k8s.io", + "kind": "CertificateSigningRequest", + "version": "v1beta1" + } + }, "put": { "description": "replace status of the specified CertificateSigningRequest", "consumes": [ @@ -44723,6 +45004,53 @@ "version": "v1beta1" } }, + "patch": { + "description": "partially update status of the specified CertificateSigningRequest", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "certificates_v1beta1" + ], + "operationId": "patchCertificatesV1beta1CertificateSigningRequestStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.certificates.v1beta1.CertificateSigningRequest" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "certificates.k8s.io", + "kind": "CertificateSigningRequest", + "version": "v1beta1" + } + }, "parameters": [ { "uniqueItems": true, @@ -66189,40 +66517,7 @@ } ] }, - "/apis/settings.k8s.io/": { - "get": { - "description": "get information of a group", - "consumes": [ - "application/json", - "application/yaml", - "application/vnd.kubernetes.protobuf" - ], - "produces": [ - "application/json", - "application/yaml", - "application/vnd.kubernetes.protobuf" - ], - "schemes": [ - "https" - ], - "tags": [ - "settings" - ], - "operationId": "getSettingsAPIGroup", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.APIGroup" - } - }, - "401": { - "description": "Unauthorized" - } - } - } - }, - "/apis/settings.k8s.io/v1alpha1/": { + "/apis/scheduling.k8s.io/v1beta1/": { "get": { "description": "get available resources", "consumes": [ @@ -66239,9 +66534,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "getSettingsV1alpha1APIResources", + "operationId": "getSchedulingV1beta1APIResources", "responses": { "200": { "description": "OK", @@ -66255,9 +66550,9 @@ } } }, - "/apis/settings.k8s.io/v1alpha1/namespaces/{namespace}/podpresets": { + "/apis/scheduling.k8s.io/v1beta1/priorityclasses": { "get": { - "description": "list or watch objects of kind PodPreset", + "description": "list or watch objects of kind PriorityClass", "consumes": [ "*/*" ], @@ -66272,9 +66567,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "listSettingsV1alpha1NamespacedPodPreset", + "operationId": "listSchedulingV1beta1PriorityClass", "parameters": [ { "uniqueItems": true, @@ -66337,7 +66632,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPresetList" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClassList" } }, "401": { @@ -66346,13 +66641,13 @@ }, "x-kubernetes-action": "list", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "post": { - "description": "create a PodPreset", + "description": "create a PriorityClass", "consumes": [ "*/*" ], @@ -66365,16 +66660,16 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "createSettingsV1alpha1NamespacedPodPreset", + "operationId": "createSchedulingV1beta1PriorityClass", "parameters": [ { "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } } ], @@ -66382,19 +66677,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "201": { "description": "Created", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "202": { "description": "Accepted", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "401": { @@ -66403,13 +66698,13 @@ }, "x-kubernetes-action": "post", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "delete": { - "description": "delete collection of PodPreset", + "description": "delete collection of PriorityClass", "consumes": [ "*/*" ], @@ -66422,9 +66717,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "deleteSettingsV1alpha1CollectionNamespacedPodPreset", + "operationId": "deleteSchedulingV1beta1CollectionPriorityClass", "parameters": [ { "uniqueItems": true, @@ -66496,20 +66791,12 @@ }, "x-kubernetes-action": "deletecollection", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "parameters": [ - { - "uniqueItems": true, - "type": "string", - "description": "object name and auth scope, such as for teams and projects", - "name": "namespace", - "in": "path", - "required": true - }, { "uniqueItems": true, "type": "string", @@ -66519,9 +66806,9 @@ } ] }, - "/apis/settings.k8s.io/v1alpha1/namespaces/{namespace}/podpresets/{name}": { + "/apis/scheduling.k8s.io/v1beta1/priorityclasses/{name}": { "get": { - "description": "read the specified PodPreset", + "description": "read the specified PriorityClass", "consumes": [ "*/*" ], @@ -66534,9 +66821,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "readSettingsV1alpha1NamespacedPodPreset", + "operationId": "readSchedulingV1beta1PriorityClass", "parameters": [ { "uniqueItems": true, @@ -66557,7 +66844,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "401": { @@ -66566,13 +66853,13 @@ }, "x-kubernetes-action": "get", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "put": { - "description": "replace the specified PodPreset", + "description": "replace the specified PriorityClass", "consumes": [ "*/*" ], @@ -66585,16 +66872,16 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "replaceSettingsV1alpha1NamespacedPodPreset", + "operationId": "replaceSchedulingV1beta1PriorityClass", "parameters": [ { "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } } ], @@ -66602,13 +66889,13 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "201": { "description": "Created", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "401": { @@ -66617,13 +66904,13 @@ }, "x-kubernetes-action": "put", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "delete": { - "description": "delete a PodPreset", + "description": "delete a PriorityClass", "consumes": [ "*/*" ], @@ -66636,9 +66923,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "deleteSettingsV1alpha1NamespacedPodPreset", + "operationId": "deleteSchedulingV1beta1PriorityClass", "parameters": [ { "name": "body", @@ -66683,13 +66970,13 @@ }, "x-kubernetes-action": "delete", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "patch": { - "description": "partially update the specified PodPreset", + "description": "partially update the specified PriorityClass", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -66704,9 +66991,9 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "patchSettingsV1alpha1NamespacedPodPreset", + "operationId": "patchSchedulingV1beta1PriorityClass", "parameters": [ { "name": "body", @@ -66721,7 +67008,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" } }, "401": { @@ -66730,16 +67017,16 @@ }, "x-kubernetes-action": "patch", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" } }, "parameters": [ { "uniqueItems": true, "type": "string", - "description": "name of the PodPreset", + "description": "name of the PriorityClass", "name": "name", "in": "path", "required": true @@ -66747,10 +67034,85 @@ { "uniqueItems": true, "type": "string", - "description": "object name and auth scope, such as for teams and projects", - "name": "namespace", - "in": "path", - "required": true + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/scheduling.k8s.io/v1beta1/watch/priorityclasses": { + "get": { + "description": "watch individual changes to a list of PriorityClass", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "scheduling_v1beta1" + ], + "operationId": "watchSchedulingV1beta1PriorityClassList", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "watchlist", + "x-kubernetes-group-version-kind": { + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server the server will respond with a 410 ResourceExpired error indicating the client must restart their list without the continue field. This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "name": "continue", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "If true, partially initialized resources are included in the response.", + "name": "includeUninitialized", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "name": "limit", + "in": "query" }, { "uniqueItems": true, @@ -66758,12 +67120,33 @@ "description": "If 'true', then the output is pretty printed.", "name": "pretty", "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" } ] }, - "/apis/settings.k8s.io/v1alpha1/podpresets": { + "/apis/scheduling.k8s.io/v1beta1/watch/priorityclasses/{name}": { "get": { - "description": "list or watch objects of kind PodPreset", + "description": "watch changes to an object of kind PriorityClass", "consumes": [ "*/*" ], @@ -66778,25 +67161,709 @@ "https" ], "tags": [ - "settings_v1alpha1" + "scheduling_v1beta1" ], - "operationId": "listSettingsV1alpha1PodPresetForAllNamespaces", + "operationId": "watchSchedulingV1beta1PriorityClass", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPresetList" + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" } }, "401": { "description": "Unauthorized" } }, - "x-kubernetes-action": "list", + "x-kubernetes-action": "watch", "x-kubernetes-group-version-kind": { - "group": "settings.k8s.io", - "kind": "PodPreset", - "version": "v1alpha1" + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server the server will respond with a 410 ResourceExpired error indicating the client must restart their list without the continue field. This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "name": "continue", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "If true, partially initialized resources are included in the response.", + "name": "includeUninitialized", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "name": "limit", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "name of the PriorityClass", + "name": "name", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ] + }, + "/apis/settings.k8s.io/": { + "get": { + "description": "get information of a group", + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings" + ], + "operationId": "getSettingsAPIGroup", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.APIGroup" + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/apis/settings.k8s.io/v1alpha1/": { + "get": { + "description": "get available resources", + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "getSettingsV1alpha1APIResources", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.APIResourceList" + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/apis/settings.k8s.io/v1alpha1/namespaces/{namespace}/podpresets": { + "get": { + "description": "list or watch objects of kind PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "listSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server the server will respond with a 410 ResourceExpired error indicating the client must restart their list without the continue field. This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "name": "continue", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "If true, partially initialized resources are included in the response.", + "name": "includeUninitialized", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "name": "limit", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPresetList" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "post": { + "description": "create a PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "createSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "post", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "delete": { + "description": "delete collection of PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "deleteSettingsV1alpha1CollectionNamespacedPodPreset", + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server the server will respond with a 410 ResourceExpired error indicating the client must restart their list without the continue field. This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "name": "continue", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "If true, partially initialized resources are included in the response.", + "name": "includeUninitialized", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "name": "limit", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "deletecollection", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/settings.k8s.io/v1alpha1/namespaces/{namespace}/podpresets/{name}": { + "get": { + "description": "read the specified PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "readSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "uniqueItems": true, + "type": "boolean", + "description": "Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'.", + "name": "exact", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Should this value be exported. Export strips fields that a user can not specify.", + "name": "export", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "put": { + "description": "replace the specified PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "replaceSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "put", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "delete": { + "description": "delete a PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "deleteSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions" + } + }, + { + "uniqueItems": true, + "type": "integer", + "description": "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.", + "name": "gracePeriodSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.", + "name": "orphanDependents", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.", + "name": "propagationPolicy", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "delete", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "patch": { + "description": "partially update the specified PodPreset", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "patchSettingsV1alpha1NamespacedPodPreset", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPreset" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "name of the PodPreset", + "name": "name", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/settings.k8s.io/v1alpha1/podpresets": { + "get": { + "description": "list or watch objects of kind PodPreset", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "settings_v1alpha1" + ], + "operationId": "listSettingsV1alpha1PodPresetForAllNamespaces", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.settings.v1alpha1.PodPresetList" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "settings.k8s.io", + "kind": "PodPreset", + "version": "v1alpha1" } }, "parameters": [ @@ -70574,7 +71641,7 @@ "format": "byte" }, "service": { - "description": "`service` is a reference to the service for this webhook. Either `service` or `url` must be specified.\n\nIf the webhook is running within the cluster, then you should use `service`.\n\nIf there is only one port open for the service, that port will be used. If there are multiple ports open, port 443 will be used if it is open, otherwise it is an error.", + "description": "`service` is a reference to the service for this webhook. Either `service` or `url` must be specified.\n\nIf the webhook is running within the cluster, then you should use `service`.\n\nPort 443 will be used if it is open, otherwise it is an error.", "$ref": "#/definitions/io.k8s.api.admissionregistration.v1beta1.ServiceReference" }, "url": { @@ -71239,11 +72306,11 @@ "description": "Spec to control the desired behavior of rolling update.", "properties": { "maxSurge": { - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new RC can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new RC can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods.", + "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" }, "maxUnavailable": { - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", + "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" } } @@ -71797,11 +72864,11 @@ "description": "Spec to control the desired behavior of rolling update.", "properties": { "maxSurge": { - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new RC can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new RC can be scaled up further, ensuring that total number of pods running at any time during the update is atmost 130% of desired pods.", + "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is atmost 130% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" }, "maxUnavailable": { - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", + "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" } } @@ -72744,11 +73811,11 @@ "description": "Spec to control the desired behavior of rolling update.", "properties": { "maxSurge": { - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new RC can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new RC can be scaled up further, ensuring that total number of pods running at any time during the update is atmost 130% of desired pods.", + "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is atmost 130% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" }, "maxUnavailable": { - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", + "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString" } } @@ -75443,6 +76510,30 @@ } } }, + "io.k8s.api.core.v1.CinderPersistentVolumeSource": { + "description": "Represents a cinder volume resource in Openstack. A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling.", + "required": [ + "volumeID" + ], + "properties": { + "fsType": { + "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "type": "string" + }, + "readOnly": { + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "type": "boolean" + }, + "secretRef": { + "description": "Optional: points to a secret object containing parameters used to connect to OpenStack.", + "$ref": "#/definitions/io.k8s.api.core.v1.SecretReference" + }, + "volumeID": { + "description": "volume id used to identify the volume in cinder More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", + "type": "string" + } + } + }, "io.k8s.api.core.v1.CinderVolumeSource": { "description": "Represents a cinder volume resource in Openstack. A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling.", "required": [ @@ -75457,6 +76548,10 @@ "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", "type": "boolean" }, + "secretRef": { + "description": "Optional: points to a secret object containing parameters used to connect to OpenStack.", + "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference" + }, "volumeID": { "description": "volume id used to identify the volume in cinder More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", "type": "string" @@ -75671,6 +76766,36 @@ } ] }, + "io.k8s.api.core.v1.ConfigMapNodeConfigSource": { + "description": "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.", + "required": [ + "namespace", + "name", + "kubeletConfigKey" + ], + "properties": { + "kubeletConfigKey": { + "description": "KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases.", + "type": "string" + }, + "name": { + "description": "Name is the metadata.name of the referenced ConfigMap. This field is required in all cases.", + "type": "string" + }, + "namespace": { + "description": "Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases.", + "type": "string" + }, + "resourceVersion": { + "description": "ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status.", + "type": "string" + }, + "uid": { + "description": "UID is the metadata.UID of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status.", + "type": "string" + } + } + }, "io.k8s.api.core.v1.ConfigMapProjection": { "description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.", "properties": { @@ -76578,7 +77703,7 @@ } }, "io.k8s.api.core.v1.GitRepoVolumeSource": { - "description": "Represents a volume that is populated with the contents of a git repository. Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling.", + "description": "Represents a volume that is populated with the contents of a git repository. Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling.\n\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", "required": [ "repository" ], @@ -77022,13 +78147,13 @@ } }, "io.k8s.api.core.v1.LocalVolumeSource": { - "description": "Local represents directly-attached storage with node affinity", + "description": "Local represents directly-attached storage with node affinity (Beta feature)", "required": [ "path" ], "properties": { "path": { - "description": "The full path to the volume on the node For alpha, this path must be a directory Once block as a source is supported, then this path can point to a block device", + "description": "The full path to the volume on the node. It can be either a directory or block device (disk, partition, ...). Directories can be represented only by PersistentVolume with VolumeMode=Filesystem. Block devices can be represented only by VolumeMode=Block, which also requires the BlockVolume alpha feature gate to be enabled.", "type": "string" } } @@ -77242,25 +78367,32 @@ "io.k8s.api.core.v1.NodeConfigSource": { "description": "NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil.", "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type": "string" + "configMap": { + "description": "ConfigMap is a reference to a Node's ConfigMap", + "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapNodeConfigSource" + } + } + }, + "io.k8s.api.core.v1.NodeConfigStatus": { + "description": "NodeConfigStatus describes the status of the config assigned by Node.Spec.ConfigSource.", + "properties": { + "active": { + "description": "Active reports the checkpointed config the node is actively using. Active will represent either the current version of the Assigned config, or the current LastKnownGood config, depending on whether attempting to use the Assigned config results in an error.", + "$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigSource" }, - "configMapRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ObjectReference" + "assigned": { + "description": "Assigned reports the checkpointed config the node will try to use. When Node.Spec.ConfigSource is updated, the node checkpoints the associated config payload to local disk, along with a record indicating intended config. The node refers to this record to choose its config checkpoint, and reports this record in Assigned. Assigned only updates in the status after the record has been checkpointed to disk. When the Kubelet is restarted, it tries to make the Assigned config the Active config by loading and validating the checkpointed payload identified by Assigned.", + "$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigSource" }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "error": { + "description": "Error describes any problems reconciling the Spec.ConfigSource to the Active config. Errors may occur, for example, attempting to checkpoint Spec.ConfigSource to the local Assigned record, attempting to checkpoint the payload associated with Spec.ConfigSource, attempting to load or validate the Assigned config, etc. Errors may occur at different points while syncing config. Earlier errors (e.g. download or checkpointing errors) will not result in a rollback to LastKnownGood, and may resolve across Kubelet retries. Later errors (e.g. loading or validating a checkpointed config) will result in a rollback to LastKnownGood. In the latter case, it is usually possible to resolve the error by fixing the config assigned in Spec.ConfigSource. You can find additional information for debugging by searching the error message in the Kubelet log. Error is a human-readable description of the error state; machines can check whether or not Error is empty, but should not rely on the stability of the Error text across Kubelet versions.", "type": "string" + }, + "lastKnownGood": { + "description": "LastKnownGood reports the checkpointed config the node will fall back to when it encounters an error attempting to use the Assigned config. The Assigned config becomes the LastKnownGood config when the node determines that the Assigned config is stable and correct. This is currently implemented as a 10-minute soak period starting when the local record of Assigned config is updated. If the Assigned config is Active at the end of this period, it becomes the LastKnownGood. Note that if Spec.ConfigSource is reset to nil (use local defaults), the LastKnownGood is also immediately reset to nil, because the local default config is always assumed good. You should not make assumptions about the node's method of determining config stability and correctness, as this may change or become configurable in the future.", + "$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigSource" } - }, - "x-kubernetes-group-version-kind": [ - { - "group": "", - "kind": "NodeConfigSource", - "version": "v1" - } - ] + } }, "io.k8s.api.core.v1.NodeDaemonEndpoints": { "description": "NodeDaemonEndpoints lists ports opened by daemons running on the Node.", @@ -77345,13 +78477,17 @@ } }, "io.k8s.api.core.v1.NodeSelectorTerm": { - "description": "A null or empty node selector term matches no objects.", - "required": [ - "matchExpressions" - ], + "description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.", "properties": { "matchExpressions": { - "description": "Required. A list of node selector requirements. The requirements are ANDed.", + "description": "A list of node selector requirements by node's labels.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorRequirement" + } + }, + "matchFields": { + "description": "A list of node selector requirements by node's fields.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorRequirement" @@ -77367,7 +78503,7 @@ "$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigSource" }, "externalID": { - "description": "External ID of the node assigned by some machine database (e.g. a cloud provider). Deprecated.", + "description": "Deprecated. Not all kubelets will set this field. Remove field after 1.13. see: https://issues.k8s.io/61966", "type": "string" }, "podCIDR": { @@ -77426,6 +78562,10 @@ "x-kubernetes-patch-merge-key": "type", "x-kubernetes-patch-strategy": "merge" }, + "config": { + "description": "Status of the config assigned to the node via the dynamic Kubelet config feature.", + "$ref": "#/definitions/io.k8s.api.core.v1.NodeConfigStatus" + }, "daemonEndpoints": { "description": "Endpoints of daemons running on the Node.", "$ref": "#/definitions/io.k8s.api.core.v1.NodeDaemonEndpoints" @@ -77845,7 +78985,7 @@ }, "cinder": { "description": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md", - "$ref": "#/definitions/io.k8s.api.core.v1.CinderVolumeSource" + "$ref": "#/definitions/io.k8s.api.core.v1.CinderPersistentVolumeSource" }, "claimRef": { "description": "ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding", @@ -78098,7 +79238,7 @@ "type": "string" }, "type": { - "description": "Type is the type of the condition. Currently only Ready. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", + "description": "Type is the type of the condition. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", "type": "string" } } @@ -78175,6 +79315,18 @@ } ] }, + "io.k8s.api.core.v1.PodReadinessGate": { + "description": "PodReadinessGate contains the reference to a pod condition", + "required": [ + "conditionType" + ], + "properties": { + "conditionType": { + "description": "ConditionType refers to a condition in the pod's condition list with matching type.", + "type": "string" + } + } + }, "io.k8s.api.core.v1.PodSecurityContext": { "description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.", "properties": { @@ -78208,6 +79360,13 @@ "type": "integer", "format": "int64" } + }, + "sysctls": { + "description": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.Sysctl" + } } } }, @@ -78310,6 +79469,13 @@ "description": "If specified, indicates the pod's priority. \"system-node-critical\" and \"system-cluster-critical\" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default.", "type": "string" }, + "readinessGates": { + "description": "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://github.com/kubernetes/community/blob/master/keps/sig-network/0007-pod-ready%2B%2B.md", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.PodReadinessGate" + } + }, "restartPolicy": { "description": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy", "type": "string" @@ -78362,7 +79528,7 @@ } }, "io.k8s.api.core.v1.PodStatus": { - "description": "PodStatus represents information about the status of a pod. Status may trail the actual state of a system.", + "description": "PodStatus represents information about the status of a pod. Status may trail the actual state of a system, especially if the node that hosts the pod cannot contact the control plane.", "properties": { "conditions": { "description": "Current service state of pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", @@ -78400,7 +79566,7 @@ "type": "string" }, "phase": { - "description": "Current condition of the pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase", + "description": "The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The conditions array, the reason and message fields, and the individual container status arrays contain more detail about the pod's status. There are five possible phase values:\n\nPending: The pod has been accepted by the Kubernetes system, but one or more of the container images has not been created. This includes time before being scheduled as well as time spent downloading images over the network, which could take a while. Running: The pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. Succeeded: All containers in the pod have terminated in success, and will not be restarted. Failed: All containers in the pod have terminated, and at least one container has terminated in failure. The container either exited with non-zero status or was terminated by the system. Unknown: For some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase", "type": "string" }, "podIP": { @@ -78966,12 +80132,16 @@ "description": "ResourceQuotaSpec defines the desired hard limits to enforce for Quota.", "properties": { "hard": { - "description": "Hard is the set of desired hard limits for each named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/", + "description": "hard is the set of desired hard limits for each named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/", "type": "object", "additionalProperties": { "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" } }, + "scopeSelector": { + "description": "scopeSelector is also a collection of filters like scopes that must match each object tracked by a quota but expressed using ScopeSelectorOperator in combination with possible values. For a resource to match, both scopes AND scopeSelector (if specified in spec), must be matched.", + "$ref": "#/definitions/io.k8s.api.core.v1.ScopeSelector" + }, "scopes": { "description": "A collection of filters that must match each object tracked by a quota. If not specified, the quota matches all objects.", "type": "array", @@ -79140,6 +80310,42 @@ } } }, + "io.k8s.api.core.v1.ScopeSelector": { + "description": "A scope selector represents the AND of the selectors represented by the scoped-resource selector requirements.", + "properties": { + "matchExpressions": { + "description": "A list of scope selector requirements by scope of the resources.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.ScopedResourceSelectorRequirement" + } + } + } + }, + "io.k8s.api.core.v1.ScopedResourceSelectorRequirement": { + "description": "A scoped-resource selector requirement is a selector that contains values, a scope name, and an operator that relates the scope name and values.", + "required": [ + "scopeName", + "operator" + ], + "properties": { + "operator": { + "description": "Represents a scope's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist.", + "type": "string" + }, + "scopeName": { + "description": "The name of the scope that the selector applies to.", + "type": "string" + }, + "values": { + "description": "An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "io.k8s.api.core.v1.Secret": { "description": "Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.", "properties": { @@ -79457,6 +80663,27 @@ } ] }, + "io.k8s.api.core.v1.ServiceAccountTokenProjection": { + "description": "ServiceAccountTokenProjection represents a projected service account token volume. This projection can be used to insert a service account token into the pods runtime filesystem for use against APIs (Kubernetes API Server or otherwise).", + "required": [ + "path" + ], + "properties": { + "audience": { + "description": "Audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver.", + "type": "string" + }, + "expirationSeconds": { + "description": "ExpirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes.", + "type": "integer", + "format": "int64" + }, + "path": { + "description": "Path is the path relative to the mount point of the file to project the token into.", + "type": "string" + } + } + }, "io.k8s.api.core.v1.ServiceList": { "description": "ServiceList holds a list of services.", "required": [ @@ -79569,7 +80796,7 @@ "x-kubernetes-patch-strategy": "merge" }, "publishNotReadyAddresses": { - "description": "publishNotReadyAddresses, when set to true, indicates that DNS implementations must publish the notReadyAddresses of subsets for the Endpoints associated with the Service. The default value is false. The primary use case for setting this field is to use a StatefulSet's Headless Service to propagate SRV records for its Pods without respect to their readiness for purpose of peer discovery. This field will replace the service.alpha.kubernetes.io/tolerate-unready-endpoints when that annotation is deprecated and all clients have been converted to use this field.", + "description": "publishNotReadyAddresses, when set to true, indicates that DNS implementations must publish the notReadyAddresses of subsets for the Endpoints associated with the Service. The default value is false. The primary use case for setting this field is to use a StatefulSet's Headless Service to propagate SRV records for its Pods without respect to their readiness for purpose of peer discovery.", "type": "boolean" }, "selector": { @@ -79661,6 +80888,23 @@ } } }, + "io.k8s.api.core.v1.Sysctl": { + "description": "Sysctl defines a kernel parameter to be set", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "description": "Name of a property to set", + "type": "string" + }, + "value": { + "description": "Value of a property to set", + "type": "string" + } + } + }, "io.k8s.api.core.v1.TCPSocketAction": { "description": "TCPSocketAction describes an action based on opening a socket", "required": [ @@ -79728,6 +80972,38 @@ } } }, + "io.k8s.api.core.v1.TopologySelectorLabelRequirement": { + "description": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.", + "required": [ + "key", + "values" + ], + "properties": { + "key": { + "description": "The label key that the selector applies to.", + "type": "string" + }, + "values": { + "description": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "io.k8s.api.core.v1.TopologySelectorTerm": { + "description": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.", + "properties": { + "matchLabelExpressions": { + "description": "A list of topology selector requirements by labels.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorLabelRequirement" + } + } + } + }, "io.k8s.api.core.v1.Volume": { "description": "Volume represents a named volume in a pod that may be accessed by any container in the pod.", "required": [ @@ -79783,7 +81059,7 @@ "$ref": "#/definitions/io.k8s.api.core.v1.GCEPersistentDiskVolumeSource" }, "gitRepo": { - "description": "GitRepo represents a git repository at a particular revision.", + "description": "GitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", "$ref": "#/definitions/io.k8s.api.core.v1.GitRepoVolumeSource" }, "glusterfs": { @@ -79917,6 +81193,10 @@ "secret": { "description": "information about the secret data to project", "$ref": "#/definitions/io.k8s.api.core.v1.SecretProjection" + }, + "serviceAccountToken": { + "description": "information about the serviceAccountToken data to project", + "$ref": "#/definitions/io.k8s.api.core.v1.ServiceAccountTokenProjection" } } }, @@ -80103,23 +81383,27 @@ } }, "io.k8s.api.extensions.v1beta1.AllowedFlexVolume": { - "description": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used.", + "description": "AllowedFlexVolume represents a single Flexvolume that is allowed to be used. Deprecated: use AllowedFlexVolume from policy API Group instead.", "required": [ "driver" ], "properties": { "driver": { - "description": "Driver is the name of the Flexvolume driver.", + "description": "driver is the name of the Flexvolume driver.", "type": "string" } } }, "io.k8s.api.extensions.v1beta1.AllowedHostPath": { - "description": "defines the host volume conditions that will be enabled by a policy for pods to use. It requires the path prefix to be defined.", + "description": "AllowedHostPath defines the host volume conditions that will be enabled by a policy for pods to use. It requires the path prefix to be defined. Deprecated: use AllowedHostPath from policy API Group instead.", "properties": { "pathPrefix": { - "description": "is the path prefix that the host volume must match. It does not support `*`. Trailing slashes are trimmed when validating the path prefix with a host path.\n\nExamples: `/foo` would allow `/foo`, `/foo/` and `/foo/bar` `/foo` would not allow `/food` or `/etc/foo`", + "description": "pathPrefix is the path prefix that the host volume must match. It does not support `*`. Trailing slashes are trimmed when validating the path prefix with a host path.\n\nExamples: `/foo` would allow `/foo`, `/foo/` and `/foo/bar` `/foo` would not allow `/food` or `/etc/foo`", "type": "string" + }, + "readOnly": { + "description": "when set to true, will allow host volumes matching the pathPrefix only if all volume mounts are readOnly.", + "type": "boolean" } } }, @@ -80580,17 +81864,17 @@ } }, "io.k8s.api.extensions.v1beta1.FSGroupStrategyOptions": { - "description": "FSGroupStrategyOptions defines the strategy type and options used to create the strategy.", + "description": "FSGroupStrategyOptions defines the strategy type and options used to create the strategy. Deprecated: use FSGroupStrategyOptions from policy API Group instead.", "properties": { "ranges": { - "description": "Ranges are the allowed ranges of fs groups. If you would like to force a single fs group then supply a single range with the same start and end.", + "description": "ranges are the allowed ranges of fs groups. If you would like to force a single fs group then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate what FSGroup is used in the SecurityContext.", + "description": "rule is the strategy that will dictate what FSGroup is used in the SecurityContext.", "type": "string" } } @@ -80627,7 +81911,7 @@ } }, "io.k8s.api.extensions.v1beta1.HostPortRange": { - "description": "Host Port Range defines a range of host ports that will be enabled by a policy for pods to use. It requires both the start and end to be defined.", + "description": "HostPortRange defines a range of host ports that will be enabled by a policy for pods to use. It requires both the start and end to be defined. Deprecated: use HostPortRange from policy API Group instead.", "required": [ "min", "max" @@ -80646,19 +81930,19 @@ } }, "io.k8s.api.extensions.v1beta1.IDRange": { - "description": "ID Range provides a min/max of an allowed range of IDs.", + "description": "IDRange provides a min/max of an allowed range of IDs. Deprecated: use IDRange from policy API Group instead.", "required": [ "min", "max" ], "properties": { "max": { - "description": "Max is the end of the range, inclusive.", + "description": "max is the end of the range, inclusive.", "type": "integer", "format": "int64" }, "min": { - "description": "Min is the start of the range, inclusive.", + "description": "min is the start of the range, inclusive.", "type": "integer", "format": "int64" } @@ -80930,15 +82214,15 @@ "description": "DEPRECATED 1.9 - This group version of NetworkPolicyPeer is deprecated by networking/v1/NetworkPolicyPeer.", "properties": { "ipBlock": { - "description": "IPBlock defines policy on a particular IPBlock", + "description": "IPBlock defines policy on a particular IPBlock. If this field is set then neither of the other fields can be.", "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.IPBlock" }, "namespaceSelector": { - "description": "Selects Namespaces using cluster scoped-labels. This matches all pods in all namespaces selected by this label selector. This field follows standard label selector semantics. If present but empty, this selector selects all namespaces.", + "description": "Selects Namespaces using cluster-scoped labels. This field follows standard label selector semantics; if present but empty, it selects all namespaces.\n\nIf PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector" }, "podSelector": { - "description": "This is a label selector which selects Pods in this namespace. This field follows standard label selector semantics. If present but empty, this selector selects all pods in this namespace.", + "description": "This is a label selector which selects Pods. This field follows standard label selector semantics; if present but empty, it selects all pods.\n\nIf NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects the Pods matching PodSelector in the policy's own Namespace.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector" } } @@ -80990,7 +82274,7 @@ } }, "io.k8s.api.extensions.v1beta1.PodSecurityPolicy": { - "description": "Pod Security Policy governs the ability to make requests that affect the Security Context that will be applied to a pod and container.", + "description": "PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container. Deprecated: use PodSecurityPolicy from policy API Group instead.", "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", @@ -81018,7 +82302,7 @@ ] }, "io.k8s.api.extensions.v1beta1.PodSecurityPolicyList": { - "description": "Pod Security Policy List is a list of PodSecurityPolicy objects.", + "description": "PodSecurityPolicyList is a list of PodSecurityPolicy objects. Deprecated: use PodSecurityPolicyList from policy API Group instead.", "required": [ "items" ], @@ -81028,7 +82312,7 @@ "type": "string" }, "items": { - "description": "Items is a list of schema objects.", + "description": "items is a list of schema objects.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.PodSecurityPolicy" @@ -81052,7 +82336,7 @@ ] }, "io.k8s.api.extensions.v1beta1.PodSecurityPolicySpec": { - "description": "Pod Security Policy Spec defines the policy enforced.", + "description": "PodSecurityPolicySpec defines the policy enforced. Deprecated: use PodSecurityPolicySpec from policy API Group instead.", "required": [ "seLinux", "runAsUser", @@ -81061,43 +82345,57 @@ ], "properties": { "allowPrivilegeEscalation": { - "description": "AllowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.", + "description": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.", "type": "boolean" }, "allowedCapabilities": { - "description": "AllowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both AllowedCapabilities and RequiredDropCapabilities.", + "description": "allowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both allowedCapabilities and requiredDropCapabilities.", "type": "array", "items": { "type": "string" } }, "allowedFlexVolumes": { - "description": "AllowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"Volumes\" field.", + "description": "allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"volumes\" field.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.AllowedFlexVolume" } }, "allowedHostPaths": { - "description": "is a white list of allowed host paths. Empty indicates that all host paths may be used.", + "description": "allowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.AllowedHostPath" } }, + "allowedUnsafeSysctls": { + "description": "allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection.\n\nExamples: e.g. \"foo/*\" allows \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" allows \"foo.bar\", \"foo.baz\", etc.", + "type": "array", + "items": { + "type": "string" + } + }, "defaultAddCapabilities": { - "description": "DefaultAddCapabilities is the default set of capabilities that will be added to the container unless the pod spec specifically drops the capability. You may not list a capability in both DefaultAddCapabilities and RequiredDropCapabilities. Capabilities added here are implicitly allowed, and need not be included in the AllowedCapabilities list.", + "description": "defaultAddCapabilities is the default set of capabilities that will be added to the container unless the pod spec specifically drops the capability. You may not list a capability in both defaultAddCapabilities and requiredDropCapabilities. Capabilities added here are implicitly allowed, and need not be included in the allowedCapabilities list.", "type": "array", "items": { "type": "string" } }, "defaultAllowPrivilegeEscalation": { - "description": "DefaultAllowPrivilegeEscalation controls the default setting for whether a process can gain more privileges than its parent process.", + "description": "defaultAllowPrivilegeEscalation controls the default setting for whether a process can gain more privileges than its parent process.", "type": "boolean" }, + "forbiddenSysctls": { + "description": "forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of forbidden sysctls. Single * means all sysctls are forbidden.\n\nExamples: e.g. \"foo/*\" forbids \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" forbids \"foo.bar\", \"foo.baz\", etc.", + "type": "array", + "items": { + "type": "string" + } + }, "fsGroup": { - "description": "FSGroup is the strategy that will dictate what fs group is used by the SecurityContext.", + "description": "fsGroup is the strategy that will dictate what fs group is used by the SecurityContext.", "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.FSGroupStrategyOptions" }, "hostIPC": { @@ -81124,11 +82422,11 @@ "type": "boolean" }, "readOnlyRootFilesystem": { - "description": "ReadOnlyRootFilesystem when set to true will force containers to run with a read only root file system. If the container specifically requests to run with a non-read only root file system the PSP should deny the pod. If set to false the container may run with a read only root file system if it wishes but it will not be forced to.", + "description": "readOnlyRootFilesystem when set to true will force containers to run with a read only root file system. If the container specifically requests to run with a non-read only root file system the PSP should deny the pod. If set to false the container may run with a read only root file system if it wishes but it will not be forced to.", "type": "boolean" }, "requiredDropCapabilities": { - "description": "RequiredDropCapabilities are the capabilities that will be dropped from the container. These are required to be dropped and cannot be added.", + "description": "requiredDropCapabilities are the capabilities that will be dropped from the container. These are required to be dropped and cannot be added.", "type": "array", "items": { "type": "string" @@ -81143,11 +82441,11 @@ "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.SELinuxStrategyOptions" }, "supplementalGroups": { - "description": "SupplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext.", + "description": "supplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext.", "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.SupplementalGroupsStrategyOptions" }, "volumes": { - "description": "volumes is a white list of allowed volume plugins. Empty indicates that all plugins may be used.", + "description": "volumes is a white list of allowed volume plugins. Empty indicates that no volumes may be used. To allow all volumes you may use '*'.", "type": "array", "items": { "type": "string" @@ -81348,32 +82646,32 @@ } }, "io.k8s.api.extensions.v1beta1.RunAsUserStrategyOptions": { - "description": "Run A sUser Strategy Options defines the strategy type and any options used to create the strategy.", + "description": "RunAsUserStrategyOptions defines the strategy type and any options used to create the strategy. Deprecated: use RunAsUserStrategyOptions from policy API Group instead.", "required": [ "rule" ], "properties": { "ranges": { - "description": "Ranges are the allowed ranges of uids that may be used.", + "description": "ranges are the allowed ranges of uids that may be used. If you would like to force a single uid then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate the allowable RunAsUser values that may be set.", + "description": "rule is the strategy that will dictate the allowable RunAsUser values that may be set.", "type": "string" } } }, "io.k8s.api.extensions.v1beta1.SELinuxStrategyOptions": { - "description": "SELinux Strategy Options defines the strategy type and any options used to create the strategy.", + "description": "SELinuxStrategyOptions defines the strategy type and any options used to create the strategy. Deprecated: use SELinuxStrategyOptions from policy API Group instead.", "required": [ "rule" ], "properties": { "rule": { - "description": "type is the strategy that will dictate the allowable labels that may be set.", + "description": "rule is the strategy that will dictate the allowable labels that may be set.", "type": "string" }, "seLinuxOptions": { @@ -81449,17 +82747,17 @@ } }, "io.k8s.api.extensions.v1beta1.SupplementalGroupsStrategyOptions": { - "description": "SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy.", + "description": "SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy. Deprecated: use SupplementalGroupsStrategyOptions from policy API Group instead.", "properties": { "ranges": { - "description": "Ranges are the allowed ranges of supplemental groups. If you would like to force a single supplemental group then supply a single range with the same start and end.", + "description": "ranges are the allowed ranges of supplemental groups. If you would like to force a single supplemental group then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate what supplemental groups is used in the SecurityContext.", + "description": "rule is the strategy that will dictate what supplemental groups is used in the SecurityContext.", "type": "string" } } @@ -81584,18 +82882,18 @@ ] }, "io.k8s.api.networking.v1.NetworkPolicyPeer": { - "description": "NetworkPolicyPeer describes a peer to allow traffic from. Exactly one of its fields must be specified.", + "description": "NetworkPolicyPeer describes a peer to allow traffic from. Only certain combinations of fields are allowed", "properties": { "ipBlock": { - "description": "IPBlock defines policy on a particular IPBlock", + "description": "IPBlock defines policy on a particular IPBlock. If this field is set then neither of the other fields can be.", "$ref": "#/definitions/io.k8s.api.networking.v1.IPBlock" }, "namespaceSelector": { - "description": "Selects Namespaces using cluster scoped-labels. This matches all pods in all namespaces selected by this label selector. This field follows standard label selector semantics. If present but empty, this selector selects all namespaces.", + "description": "Selects Namespaces using cluster-scoped labels. This field follows standard label selector semantics; if present but empty, it selects all namespaces.\n\nIf PodSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector" }, "podSelector": { - "description": "This is a label selector which selects Pods in this namespace. This field follows standard label selector semantics. If present but empty, this selector selects all pods in this namespace.", + "description": "This is a label selector which selects Pods. This field follows standard label selector semantics; if present but empty, it selects all pods.\n\nIf NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. Otherwise it selects the Pods matching PodSelector in the policy's own Namespace.", "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector" } } @@ -81653,17 +82951,21 @@ ], "properties": { "driver": { - "description": "Driver is the name of the Flexvolume driver.", + "description": "driver is the name of the Flexvolume driver.", "type": "string" } } }, "io.k8s.api.policy.v1beta1.AllowedHostPath": { - "description": "defines the host volume conditions that will be enabled by a policy for pods to use. It requires the path prefix to be defined.", + "description": "AllowedHostPath defines the host volume conditions that will be enabled by a policy for pods to use. It requires the path prefix to be defined.", "properties": { "pathPrefix": { - "description": "is the path prefix that the host volume must match. It does not support `*`. Trailing slashes are trimmed when validating the path prefix with a host path.\n\nExamples: `/foo` would allow `/foo`, `/foo/` and `/foo/bar` `/foo` would not allow `/food` or `/etc/foo`", + "description": "pathPrefix is the path prefix that the host volume must match. It does not support `*`. Trailing slashes are trimmed when validating the path prefix with a host path.\n\nExamples: `/foo` would allow `/foo`, `/foo/` and `/foo/bar` `/foo` would not allow `/food` or `/etc/foo`", "type": "string" + }, + "readOnly": { + "description": "when set to true, will allow host volumes matching the pathPrefix only if all volume mounts are readOnly.", + "type": "boolean" } } }, @@ -81699,20 +83001,20 @@ "description": "FSGroupStrategyOptions defines the strategy type and options used to create the strategy.", "properties": { "ranges": { - "description": "Ranges are the allowed ranges of fs groups. If you would like to force a single fs group then supply a single range with the same start and end.", + "description": "ranges are the allowed ranges of fs groups. If you would like to force a single fs group then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate what FSGroup is used in the SecurityContext.", + "description": "rule is the strategy that will dictate what FSGroup is used in the SecurityContext.", "type": "string" } } }, "io.k8s.api.policy.v1beta1.HostPortRange": { - "description": "Host Port Range defines a range of host ports that will be enabled by a policy for pods to use. It requires both the start and end to be defined.", + "description": "HostPortRange defines a range of host ports that will be enabled by a policy for pods to use. It requires both the start and end to be defined.", "required": [ "min", "max" @@ -81731,19 +83033,19 @@ } }, "io.k8s.api.policy.v1beta1.IDRange": { - "description": "ID Range provides a min/max of an allowed range of IDs.", + "description": "IDRange provides a min/max of an allowed range of IDs.", "required": [ "min", "max" ], "properties": { "max": { - "description": "Max is the end of the range, inclusive.", + "description": "max is the end of the range, inclusive.", "type": "integer", "format": "int64" }, "min": { - "description": "Min is the start of the range, inclusive.", + "description": "min is the start of the range, inclusive.", "type": "integer", "format": "int64" } @@ -81874,7 +83176,7 @@ } }, "io.k8s.api.policy.v1beta1.PodSecurityPolicy": { - "description": "Pod Security Policy governs the ability to make requests that affect the Security Context that will be applied to a pod and container.", + "description": "PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container.", "properties": { "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", @@ -81902,7 +83204,7 @@ ] }, "io.k8s.api.policy.v1beta1.PodSecurityPolicyList": { - "description": "Pod Security Policy List is a list of PodSecurityPolicy objects.", + "description": "PodSecurityPolicyList is a list of PodSecurityPolicy objects.", "required": [ "items" ], @@ -81912,7 +83214,7 @@ "type": "string" }, "items": { - "description": "Items is a list of schema objects.", + "description": "items is a list of schema objects.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.PodSecurityPolicy" @@ -81936,7 +83238,7 @@ ] }, "io.k8s.api.policy.v1beta1.PodSecurityPolicySpec": { - "description": "Pod Security Policy Spec defines the policy enforced.", + "description": "PodSecurityPolicySpec defines the policy enforced.", "required": [ "seLinux", "runAsUser", @@ -81945,43 +83247,57 @@ ], "properties": { "allowPrivilegeEscalation": { - "description": "AllowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.", + "description": "allowPrivilegeEscalation determines if a pod can request to allow privilege escalation. If unspecified, defaults to true.", "type": "boolean" }, "allowedCapabilities": { - "description": "AllowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both AllowedCapabilities and RequiredDropCapabilities.", + "description": "allowedCapabilities is a list of capabilities that can be requested to add to the container. Capabilities in this field may be added at the pod author's discretion. You must not list a capability in both allowedCapabilities and requiredDropCapabilities.", "type": "array", "items": { "type": "string" } }, "allowedFlexVolumes": { - "description": "AllowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"Volumes\" field.", + "description": "allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes is allowed in the \"volumes\" field.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.AllowedFlexVolume" } }, "allowedHostPaths": { - "description": "is a white list of allowed host paths. Empty indicates that all host paths may be used.", + "description": "allowedHostPaths is a white list of allowed host paths. Empty indicates that all host paths may be used.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.AllowedHostPath" } }, + "allowedUnsafeSysctls": { + "description": "allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection.\n\nExamples: e.g. \"foo/*\" allows \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" allows \"foo.bar\", \"foo.baz\", etc.", + "type": "array", + "items": { + "type": "string" + } + }, "defaultAddCapabilities": { - "description": "DefaultAddCapabilities is the default set of capabilities that will be added to the container unless the pod spec specifically drops the capability. You may not list a capability in both DefaultAddCapabilities and RequiredDropCapabilities. Capabilities added here are implicitly allowed, and need not be included in the AllowedCapabilities list.", + "description": "defaultAddCapabilities is the default set of capabilities that will be added to the container unless the pod spec specifically drops the capability. You may not list a capability in both defaultAddCapabilities and requiredDropCapabilities. Capabilities added here are implicitly allowed, and need not be included in the allowedCapabilities list.", "type": "array", "items": { "type": "string" } }, "defaultAllowPrivilegeEscalation": { - "description": "DefaultAllowPrivilegeEscalation controls the default setting for whether a process can gain more privileges than its parent process.", + "description": "defaultAllowPrivilegeEscalation controls the default setting for whether a process can gain more privileges than its parent process.", "type": "boolean" }, + "forbiddenSysctls": { + "description": "forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. Each entry is either a plain sysctl name or ends in \"*\" in which case it is considered as a prefix of forbidden sysctls. Single * means all sysctls are forbidden.\n\nExamples: e.g. \"foo/*\" forbids \"foo/bar\", \"foo/baz\", etc. e.g. \"foo.*\" forbids \"foo.bar\", \"foo.baz\", etc.", + "type": "array", + "items": { + "type": "string" + } + }, "fsGroup": { - "description": "FSGroup is the strategy that will dictate what fs group is used by the SecurityContext.", + "description": "fsGroup is the strategy that will dictate what fs group is used by the SecurityContext.", "$ref": "#/definitions/io.k8s.api.policy.v1beta1.FSGroupStrategyOptions" }, "hostIPC": { @@ -82008,11 +83324,11 @@ "type": "boolean" }, "readOnlyRootFilesystem": { - "description": "ReadOnlyRootFilesystem when set to true will force containers to run with a read only root file system. If the container specifically requests to run with a non-read only root file system the PSP should deny the pod. If set to false the container may run with a read only root file system if it wishes but it will not be forced to.", + "description": "readOnlyRootFilesystem when set to true will force containers to run with a read only root file system. If the container specifically requests to run with a non-read only root file system the PSP should deny the pod. If set to false the container may run with a read only root file system if it wishes but it will not be forced to.", "type": "boolean" }, "requiredDropCapabilities": { - "description": "RequiredDropCapabilities are the capabilities that will be dropped from the container. These are required to be dropped and cannot be added.", + "description": "requiredDropCapabilities are the capabilities that will be dropped from the container. These are required to be dropped and cannot be added.", "type": "array", "items": { "type": "string" @@ -82027,11 +83343,11 @@ "$ref": "#/definitions/io.k8s.api.policy.v1beta1.SELinuxStrategyOptions" }, "supplementalGroups": { - "description": "SupplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext.", + "description": "supplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext.", "$ref": "#/definitions/io.k8s.api.policy.v1beta1.SupplementalGroupsStrategyOptions" }, "volumes": { - "description": "volumes is a white list of allowed volume plugins. Empty indicates that all plugins may be used.", + "description": "volumes is a white list of allowed volume plugins. Empty indicates that no volumes may be used. To allow all volumes you may use '*'.", "type": "array", "items": { "type": "string" @@ -82040,32 +83356,32 @@ } }, "io.k8s.api.policy.v1beta1.RunAsUserStrategyOptions": { - "description": "Run A sUser Strategy Options defines the strategy type and any options used to create the strategy.", + "description": "RunAsUserStrategyOptions defines the strategy type and any options used to create the strategy.", "required": [ "rule" ], "properties": { "ranges": { - "description": "Ranges are the allowed ranges of uids that may be used.", + "description": "ranges are the allowed ranges of uids that may be used. If you would like to force a single uid then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate the allowable RunAsUser values that may be set.", + "description": "rule is the strategy that will dictate the allowable RunAsUser values that may be set.", "type": "string" } } }, "io.k8s.api.policy.v1beta1.SELinuxStrategyOptions": { - "description": "SELinux Strategy Options defines the strategy type and any options used to create the strategy.", + "description": "SELinuxStrategyOptions defines the strategy type and any options used to create the strategy.", "required": [ "rule" ], "properties": { "rule": { - "description": "type is the strategy that will dictate the allowable labels that may be set.", + "description": "rule is the strategy that will dictate the allowable labels that may be set.", "type": "string" }, "seLinuxOptions": { @@ -82078,14 +83394,14 @@ "description": "SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy.", "properties": { "ranges": { - "description": "Ranges are the allowed ranges of supplemental groups. If you would like to force a single supplemental group then supply a single range with the same start and end.", + "description": "ranges are the allowed ranges of supplemental groups. If you would like to force a single supplemental group then supply a single range with the same start and end. Required for MustRunAs.", "type": "array", "items": { "$ref": "#/definitions/io.k8s.api.policy.v1beta1.IDRange" } }, "rule": { - "description": "Rule is the strategy that will dictate what supplemental groups is used in the SecurityContext.", + "description": "rule is the strategy that will dictate what supplemental groups is used in the SecurityContext.", "type": "string" } } @@ -82143,7 +83459,6 @@ "io.k8s.api.rbac.v1.ClusterRoleBinding": { "description": "ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, and adds who information via Subject.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -82327,7 +83642,6 @@ "io.k8s.api.rbac.v1.RoleBinding": { "description": "RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -82531,7 +83845,6 @@ "io.k8s.api.rbac.v1alpha1.ClusterRoleBinding": { "description": "ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, and adds who information via Subject.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -82715,7 +84028,6 @@ "io.k8s.api.rbac.v1alpha1.RoleBinding": { "description": "RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -82919,7 +84231,6 @@ "io.k8s.api.rbac.v1beta1.ClusterRoleBinding": { "description": "ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, and adds who information via Subject.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -83103,7 +84414,6 @@ "io.k8s.api.rbac.v1beta1.RoleBinding": { "description": "RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace.", "required": [ - "subjects", "roleRef" ], "properties": { @@ -83328,6 +84638,80 @@ } ] }, + "io.k8s.api.scheduling.v1beta1.PriorityClass": { + "description": "PriorityClass defines mapping from a priority class name to the priority integer value. The value can be any valid integer.", + "required": [ + "value" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "description": { + "description": "description is an arbitrary string that usually provides guidelines on when this priority class should be used.", + "type": "string" + }, + "globalDefault": { + "description": "globalDefault specifies whether this PriorityClass should be considered as the default priority for pods that do not have any priority class. Only one PriorityClass can be marked as `globalDefault`. However, if more than one PriorityClasses exists with their `globalDefault` field set to true, the smallest value of such global default PriorityClasses will be used as the default priority.", + "type": "boolean" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta" + }, + "value": { + "description": "The value of this priority class. This is the actual priority that pods receive when they have the name of this class in their pod spec.", + "type": "integer", + "format": "int32" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "scheduling.k8s.io", + "kind": "PriorityClass", + "version": "v1beta1" + } + ] + }, + "io.k8s.api.scheduling.v1beta1.PriorityClassList": { + "description": "PriorityClassList is a collection of priority classes.", + "required": [ + "items" + ], + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "items": { + "description": "items is the list of PriorityClasses", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.scheduling.v1beta1.PriorityClass" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "description": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "scheduling.k8s.io", + "kind": "PriorityClassList", + "version": "v1beta1" + } + ] + }, "io.k8s.api.settings.v1alpha1.PodPreset": { "description": "PodPreset is a policy resource that defines additional runtime requirements for a Pod.", "properties": { @@ -83435,6 +84819,13 @@ "description": "AllowVolumeExpansion shows whether the storage class allow volume expand", "type": "boolean" }, + "allowedTopologies": { + "description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorTerm" + } + }, "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", "type": "string" @@ -83666,6 +85057,13 @@ "description": "AllowVolumeExpansion shows whether the storage class allow volume expand", "type": "boolean" }, + "allowedTopologies": { + "description": "Restrict the node topologies where volumes can be dynamically provisioned. Each volume plugin defines its own supported topology specifications. An empty TopologySelectorTerm list means there is no topology restriction. This field is alpha-level and is only honored by servers that enable the DynamicProvisioningScheduling feature.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorTerm" + } + }, "apiVersion": { "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", "type": "string" @@ -83887,6 +85285,41 @@ } } }, + "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition": { + "description": "CustomResourceColumnDefinition specifies a column for server side printing.", + "required": [ + "name", + "type", + "JSONPath" + ], + "properties": { + "JSONPath": { + "description": "JSONPath is a simple JSON path, i.e. with array notation.", + "type": "string" + }, + "description": { + "description": "description is a human readable description of this column.", + "type": "string" + }, + "format": { + "description": "format is an optional OpenAPI type definition for this column. The 'name' format is applied to the primary identifier column to assist in clients identifying column is the resource name. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", + "type": "string" + }, + "name": { + "description": "name is a human readable name for the column.", + "type": "string" + }, + "priority": { + "description": "priority is an integer defining the relative importance of this column compared to others. Lower numbers are considered higher priority. Columns that may be omitted in limited space scenarios should be given a higher priority.", + "type": "integer", + "format": "int32" + }, + "type": { + "description": "type is an OpenAPI type definition for this column. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", + "type": "string" + } + } + }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition": { "description": "CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format \u003c.spec.name\u003e.\u003c.spec.group\u003e.", "properties": { @@ -83909,7 +85342,14 @@ "description": "Status indicates the actual state of the CustomResourceDefinition", "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionStatus" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiextensions.k8s.io", + "kind": "CustomResourceDefinition", + "version": "v1beta1" + } + ] }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionCondition": { "description": "CustomResourceDefinitionCondition contains details for the current condition of this pod.", @@ -83964,7 +85404,14 @@ "metadata": { "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiextensions.k8s.io", + "kind": "CustomResourceDefinitionList", + "version": "v1beta1" + } + ] }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionNames": { "description": "CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition", @@ -84009,11 +85456,17 @@ "description": "CustomResourceDefinitionSpec describes how a user wants their resource to appear", "required": [ "group", - "version", "names", "scope" ], "properties": { + "additionalPrinterColumns": { + "description": "AdditionalPrinterColumns are additional columns shown e.g. in kubectl next to the name. Defaults to a created-at column.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceColumnDefinition" + } + }, "group": { "description": "Group is the group this resource belongs in", "type": "string" @@ -84027,7 +85480,7 @@ "type": "string" }, "subresources": { - "description": "Subresources describes the subresources for CustomResources This field is alpha-level and should only be sent to servers that enable subresources via the CustomResourceSubresources feature gate.", + "description": "Subresources describes the subresources for CustomResources", "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceSubresources" }, "validation": { @@ -84035,8 +85488,15 @@ "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceValidation" }, "version": { - "description": "Version is the version this resource belongs in", + "description": "Version is the version this resource belongs in Should be always first item in Versions field if provided. Optional, but at least one of Version or Versions must be set. Deprecated: Please use `Versions`.", "type": "string" + }, + "versions": { + "description": "Versions is the list of all supported versions for this resource. If Version field is provided, this field is optional. Validation: All versions must use the same validation schema for now. i.e., top level Validation field is applied to all of these versions. Order: The version name will be used to compute the order. If the version string is \"kube-like\", it will sort above non \"kube-like\" version strings, which are ordered lexicographically. \"Kube-like\" versions start with a \"v\", then are followed by a number (the major version), then optionally the string \"alpha\" or \"beta\" and another number (the minor version). These are sorted first by GA \u003e beta \u003e alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.", + "type": "array", + "items": { + "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionVersion" + } } } }, @@ -84044,7 +85504,8 @@ "description": "CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition", "required": [ "conditions", - "acceptedNames" + "acceptedNames", + "storedVersions" ], "properties": { "acceptedNames": { @@ -84057,6 +85518,34 @@ "items": { "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionCondition" } + }, + "storedVersions": { + "description": "StoredVersions are all versions of CustomResources that were ever persisted. Tracking these versions allows a migration path for stored versions in etcd. The field is mutable so the migration controller can first finish a migration to another version (i.e. that no old objects are left in the storage), and then remove the rest of the versions from this list. None of the versions in this list can be removed from the spec.Versions field.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionVersion": { + "required": [ + "name", + "served", + "storage" + ], + "properties": { + "name": { + "description": "Name is the version name, e.g. “v1”, “v2beta1”, etc.", + "type": "string" + }, + "served": { + "description": "Served is a flag enabling/disabling this version from being served via REST APIs", + "type": "boolean" + }, + "storage": { + "description": "Storage flags the version as storage version. There must be exactly one flagged as storage version.", + "type": "boolean" } } }, @@ -84118,16 +85607,7 @@ } }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSON": { - "description": "JSON represents any valid JSON value. These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.", - "required": [ - "Raw" - ], - "properties": { - "Raw": { - "type": "string", - "format": "byte" - } - } + "description": "JSON represents any valid JSON value. These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil." }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps": { "description": "JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).", @@ -84279,65 +85759,23 @@ } }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaPropsOrArray": { - "description": "JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps or an array of JSONSchemaProps. Mainly here for serialization purposes.", - "required": [ - "Schema", - "JSONSchemas" - ], - "properties": { - "JSONSchemas": { - "type": "array", - "items": { - "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps" - } - }, - "Schema": { - "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps" - } - } + "description": "JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps or an array of JSONSchemaProps. Mainly here for serialization purposes." }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaPropsOrBool": { - "description": "JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value. Defaults to true for the boolean property.", - "required": [ - "Allows", - "Schema" - ], - "properties": { - "Allows": { - "type": "boolean" - }, - "Schema": { - "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps" - } - } + "description": "JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value. Defaults to true for the boolean property." }, "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaPropsOrStringArray": { - "description": "JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.", - "required": [ - "Schema", - "Property" - ], - "properties": { - "Property": { - "type": "array", - "items": { - "type": "string" - } - }, - "Schema": { - "$ref": "#/definitions/io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps" - } - } + "description": "JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array." }, "io.k8s.apimachinery.pkg.api.resource.Quantity": { + "description": "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and Int64() accessors.\n\nThe serialization format is:\n\n\u003cquantity\u003e ::= \u003csignedNumber\u003e\u003csuffix\u003e\n (Note that \u003csuffix\u003e may be empty, from the \"\" case in \u003cdecimalSI\u003e.)\n\u003cdigit\u003e ::= 0 | 1 | ... | 9 \u003cdigits\u003e ::= \u003cdigit\u003e | \u003cdigit\u003e\u003cdigits\u003e \u003cnumber\u003e ::= \u003cdigits\u003e | \u003cdigits\u003e.\u003cdigits\u003e | \u003cdigits\u003e. | .\u003cdigits\u003e \u003csign\u003e ::= \"+\" | \"-\" \u003csignedNumber\u003e ::= \u003cnumber\u003e | \u003csign\u003e\u003cnumber\u003e \u003csuffix\u003e ::= \u003cbinarySI\u003e | \u003cdecimalExponent\u003e | \u003cdecimalSI\u003e \u003cbinarySI\u003e ::= Ki | Mi | Gi | Ti | Pi | Ei\n (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n\u003cdecimalSI\u003e ::= m | \"\" | k | M | G | T | P | E\n (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n\u003cdecimalExponent\u003e ::= \"e\" \u003csignedNumber\u003e | \"E\" \u003csignedNumber\u003e\n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n a. No precision is lost\n b. No fractional digits will be emitted\n c. The exponent (or suffix) is as large as possible.\nThe sign will be omitted unless the number is negative.\n\nExamples:\n 1.5 will be serialized as \"1500m\"\n 1.5Gi will be serialized as \"1536Mi\"\n\nNOTE: We reserve the right to amend this canonical format, perhaps to\n allow 1.5 to be canonical.\n or after March 2015.\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation.", "type": "string" }, "io.k8s.apimachinery.pkg.apis.meta.v1.APIGroup": { "description": "APIGroup contains the name, the supported versions, and the preferred version of a group.", "required": [ "name", - "versions", - "serverAddressByClientCIDRs" + "versions" ], "properties": { "apiVersion": { @@ -84589,6 +86027,21 @@ "kind": "DeleteOptions", "version": "v1beta1" }, + { + "group": "apiextensions.k8s.io", + "kind": "DeleteOptions", + "version": "v1beta1" + }, + { + "group": "apiregistration.k8s.io", + "kind": "DeleteOptions", + "version": "v1" + }, + { + "group": "apiregistration.k8s.io", + "kind": "DeleteOptions", + "version": "v1beta1" + }, { "group": "apps", "kind": "DeleteOptions", @@ -84699,6 +86152,11 @@ "kind": "DeleteOptions", "version": "v1alpha1" }, + { + "group": "scheduling.k8s.io", + "kind": "DeleteOptions", + "version": "v1beta1" + }, { "group": "settings.k8s.io", "kind": "DeleteOptions", @@ -84834,6 +86292,7 @@ } }, "io.k8s.apimachinery.pkg.apis.meta.v1.MicroTime": { + "description": "MicroTime is version of Time with microsecond level precision.", "type": "string", "format": "date-time" }, @@ -85083,6 +86542,7 @@ } }, "io.k8s.apimachinery.pkg.apis.meta.v1.Time": { + "description": "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", "type": "string", "format": "date-time" }, @@ -85122,6 +86582,21 @@ "kind": "WatchEvent", "version": "v1beta1" }, + { + "group": "apiextensions.k8s.io", + "kind": "WatchEvent", + "version": "v1beta1" + }, + { + "group": "apiregistration.k8s.io", + "kind": "WatchEvent", + "version": "v1" + }, + { + "group": "apiregistration.k8s.io", + "kind": "WatchEvent", + "version": "v1beta1" + }, { "group": "apps", "kind": "WatchEvent", @@ -85232,6 +86707,11 @@ "kind": "WatchEvent", "version": "v1alpha1" }, + { + "group": "scheduling.k8s.io", + "kind": "WatchEvent", + "version": "v1beta1" + }, { "group": "settings.k8s.io", "kind": "WatchEvent", @@ -85268,6 +86748,7 @@ } }, "io.k8s.apimachinery.pkg.util.intstr.IntOrString": { + "description": "IntOrString is a type that can hold an int32 or a string. When used in JSON or YAML marshalling and unmarshalling, it produces or consumes the inner type. This allows you to have, for example, a JSON field that can accept a name or number.", "type": "string", "format": "int-or-string" }, @@ -85336,7 +86817,14 @@ "description": "Status contains derived information about an API server", "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceStatus" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1" + } + ] }, "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceCondition": { "required": [ @@ -85389,13 +86877,19 @@ "metadata": { "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiregistration.k8s.io", + "kind": "APIServiceList", + "version": "v1" + } + ] }, "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1.APIServiceSpec": { "description": "APIServiceSpec contains information for locating and communicating with a server. Only https is supported, though you are able to disable certificate verification.", "required": [ "service", - "caBundle", "groupPriorityMinimum", "versionPriority" ], @@ -85427,7 +86921,7 @@ "type": "string" }, "versionPriority": { - "description": "VersionPriority controls the ordering of this API version inside of its group. Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). The secondary sort is based on the alphabetical comparison of the name of the object. (v1.bar before v1.foo) Since it's inside of a group, the number can be small, probably in the 10s.", + "description": "VersionPriority controls the ordering of this API version inside of its group. Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). Since it's inside of a group, the number can be small, probably in the 10s. In case of equal version priorities, the version string will be used to compute the order inside a group. If the version string is \"kube-like\", it will sort above non \"kube-like\" version strings, which are ordered lexicographically. \"Kube-like\" versions start with a \"v\", then are followed by a number (the major version), then optionally the string \"alpha\" or \"beta\" and another number (the minor version). These are sorted first by GA \u003e beta \u003e alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.", "type": "integer", "format": "int32" } @@ -85482,7 +86976,14 @@ "description": "Status contains derived information about an API server", "$ref": "#/definitions/io.k8s.kube-aggregator.pkg.apis.apiregistration.v1beta1.APIServiceStatus" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiregistration.k8s.io", + "kind": "APIService", + "version": "v1beta1" + } + ] }, "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1beta1.APIServiceCondition": { "required": [ @@ -85535,13 +87036,19 @@ "metadata": { "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta" } - } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "apiregistration.k8s.io", + "kind": "APIServiceList", + "version": "v1beta1" + } + ] }, "io.k8s.kube-aggregator.pkg.apis.apiregistration.v1beta1.APIServiceSpec": { "description": "APIServiceSpec contains information for locating and communicating with a server. Only https is supported, though you are able to disable certificate verification.", "required": [ "service", - "caBundle", "groupPriorityMinimum", "versionPriority" ], @@ -85573,7 +87080,7 @@ "type": "string" }, "versionPriority": { - "description": "VersionPriority controls the ordering of this API version inside of its group. Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). The secondary sort is based on the alphabetical comparison of the name of the object. (v1.bar before v1.foo) Since it's inside of a group, the number can be small, probably in the 10s.", + "description": "VersionPriority controls the ordering of this API version inside of its group. Must be greater than zero. The primary sort is based on VersionPriority, ordered highest to lowest (20 before 10). Since it's inside of a group, the number can be small, probably in the 10s. In case of equal version priorities, the version string will be used to compute the order inside a group. If the version string is \"kube-like\", it will sort above non \"kube-like\" version strings, which are ordered lexicographically. \"Kube-like\" versions start with a \"v\", then are followed by a number (the major version), then optionally the string \"alpha\" or \"beta\" and another number (the minor version). These are sorted first by GA \u003e beta \u003e alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing major version, then minor version. An example sorted list of versions: v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.", "type": "integer", "format": "int32" } diff --git a/gen-apidocs/generators/static/FontAwesome.otf b/gen-apidocs/generators/static/FontAwesome.otf new file mode 100644 index 00000000..401ec0f3 Binary files /dev/null and b/gen-apidocs/generators/static/FontAwesome.otf differ diff --git a/gen-apidocs/generators/static/bootstrap.min.css b/gen-apidocs/generators/static/bootstrap.min.css new file mode 100644 index 00000000..ed3905e0 --- /dev/null +++ b/gen-apidocs/generators/static/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/gen-apidocs/generators/static/font-awesome.min.css b/gen-apidocs/generators/static/font-awesome.min.css new file mode 100644 index 00000000..540440ce --- /dev/null +++ b/gen-apidocs/generators/static/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/gen-apidocs/generators/static/fontawesome-webfont.eot b/gen-apidocs/generators/static/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/gen-apidocs/generators/static/fontawesome-webfont.eot differ diff --git a/gen-apidocs/generators/static/fontawesome-webfont.svg b/gen-apidocs/generators/static/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/gen-apidocs/generators/static/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gen-apidocs/generators/static/fontawesome-webfont.ttf b/gen-apidocs/generators/static/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/gen-apidocs/generators/static/fontawesome-webfont.ttf differ diff --git a/gen-apidocs/generators/static/fontawesome-webfont.woff b/gen-apidocs/generators/static/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/gen-apidocs/generators/static/fontawesome-webfont.woff differ diff --git a/gen-apidocs/generators/static/fontawesome-webfont.woff2 b/gen-apidocs/generators/static/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/gen-apidocs/generators/static/fontawesome-webfont.woff2 differ diff --git a/gen-apidocs/generators/static/jquery.scrollTo.min.js b/gen-apidocs/generators/static/jquery.scrollTo.min.js new file mode 100644 index 00000000..65a020d9 --- /dev/null +++ b/gen-apidocs/generators/static/jquery.scrollTo.min.js @@ -0,0 +1,7 @@ +/** + * Copyright (c) 2007-2015 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com + * Licensed under MIT + * @author Ariel Flesler + * @version 2.1.2 + */ +;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1=f[g]?0:Math.min(f[g],n));!a&&1= node.offset().top) { + activeElemToken = token; + } + } + if (!prevElemToken) { + getNavElemNode(activeElemToken).addClass('selected'); + prevElemToken = activeElemToken; + return; + } + if (activeElemToken !== prevElemToken) { + getNavElemNode(prevElemToken).removeClass('selected'); + getNavElemNode(activeElemToken).addClass('selected'); + prevElemToken = activeElemToken; + } + return activeElemToken; + } + + function getHeadingNode(token) { + return $('#' + token); + } + + function getNavNode(token) { + return $('#' + token + '-nav'); + } + + function getNavElemNode(token) { + return $('#sidebar-wrapper > ul a[href="#' + token + '"]'); + } + + function checkNodePositions(nodes, flatNodeMap, scrollPosition) { + var activeNode; + for (var i = 0; i < nodes.length; i++) { + var item = nodes[i]; + var node = flatNodeMap[item.section]; + var nodeTop = node.offset().top - 50; + if (scrollPosition >= nodeTop) { + activeNode = {token: item.section, node: node}; + + if (item.subsections) { + activeNode.subsections = item.subsections; + } + break; + } + } + return activeNode; + } + + function scrollToNav(token) { + setTimeout(function() { + var scrollPosition = $(window).scrollTop(); + var activeSectionTokens = scrollActions(scrollPosition); + var activeElemToken = checkActiveElement(flatToc, scrollPosition); + var navNode = $('#sidebar-wrapper > ul a[href="#' + token + '"]'); + $('#sidebar-wrapper').scrollTo(navNode, {duration: 'fast', axis: 'y'}); + }, 200); + } + + $(window).on('hashchange', function(event) { + var scrollPosition = $(window).scrollTop(); + var activeSectionTokens = scrollActions(scrollPosition); + var activeElemToken = checkActiveElement(flatToc, scrollPosition); + var scrollToken = activeSectionTokens.L2 ? activeSectionTokens.L2 : activeSectionTokens.L1; + scrollToNav(scrollToken); + var token = location.hash.slice(1); + }); + + var scrollPosition = $(window).scrollTop(); + scrollActions(scrollPosition); + checkActiveElement(flatToc, scrollPosition); + // TODO: prevent scroll on sidebar from propogating to window + $(window).on('scroll', function(event) { + var scrollPosition = $(window).scrollTop(); + var activeSectionTokens = scrollActions(scrollPosition); + var activeElemToken = checkActiveElement(flatToc, scrollPosition); + }); +}); \ No newline at end of file diff --git a/gen-apidocs/generators/static/stylesheet.css b/gen-apidocs/generators/static/stylesheet.css new file mode 100644 index 00000000..63a34be4 --- /dev/null +++ b/gen-apidocs/generators/static/stylesheet.css @@ -0,0 +1,228 @@ +/* +Kubernetes colors + +kubernetes blue - rgb(50, 109, 230) +dark blue - rgb(51, 113, 227) +dark grey - rgb(48, 48, 48) +light grey - rgb(161, 160, 158) +*/ + +/* User agent CSS overrides */ +#sidebar-wrapper ul, #sidebar-wrapper li { + margin-left: 10px; + padding-left: 0; +} + +.body-content hr { + margin: 2em 0; + border-top: 2px solid dimgrey; + border-bottom: 2px solid antiquewhite; +} + +.body-content table { + margin-bottom: 1em; + width: 100%; + overflow: auto; +} + +.body-content table th, .body-content table td { + text-align: left; + vertical-align: top; + line-height: 1.5; +} + +.body-content table th { + padding: 15px 20px; + border-bottom: 1px solid lightsteelblue; + vertical-align: bottom; +} + +.body-content table td { + padding: 10px; +} + +.body-content table tr:last-child { + border-bottom: 1px solid lightsteelblue; +} + +.body-content table tr:nth-child(odd) > td { + background-color: WhiteSmoke; +} + +.body-content table tr:nth-child(even) > td { + background-color: Gainsboro; +} + +.body-content dt { + font-weight: bold; +} + +.body-content dd { + margin-left: 15px; +} + +.body-content p, .body-content li, .body-content dt, .body-content dd { + line-height: 1.6; + margin-top: 0; +} + +/* Brodoc CSS */ + +body > #wrapper { + display: block; + padding-bottom: 500px; +} + +#sidebar-wrapper { + display: block; + height: 100%; + width: 20%; + position: fixed; + z-index: 1; + top: 0; + left: 0; + background-color: whitesmoke; + border-right: 2px solid slategrey; + overflow-x: hidden; + padding-top: 60px; +} + +#sidebar-wrapper a { + text-decoration: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 0 5px; +} + +#sidebar-wrapper ul { + list-style: none; +} + +#sidebar-wrapper a.selected { + font-style: bold; + color: whitesmoke; + border: 1px solid rgb(161, 160, 158); + background-color: rgb(51, 113, 227); + border-radius: 5px; +} + +#sidebar-wrapper .strong-nav { + font-family: monospace; + font-weight: bold; +} + +#sidebar-wrapper .nav-level-1.strong-nav { + margin-top: 25px; +} + +#sidebar-wrapper .copyright { + padding-left: 10px; + padding-top: 50px; + padding-bottom: 50px; + text-decoration: underline; +} + +#page-content-wrapper { + margin-left: 20%; + padding-top: 60px; +} + +.body-content h1, .body-content h2 { + clear: both; + border-bottom: 3px solid lightslategrey; + padding-top: 20px; +} + +.body-content > h3, .body-content > h4, .body-content > h5, .body-content > h6, .body-content > p, .body-content > aside, .body-content > ul > li, .body-content > ul > li { + padding-top: 20px; +} + +.body-content table tr td:not(:first-child) { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.body-content table tr td a { + word-break: break-word; +} + +.body-content p code { + text-overflow: ellipsis; + color: #802060; + display: inline-block; + font-size: smaller; + word-break: break-word; +} + +.body-content blockquote { + border-left: 0; + border-radius: 5px; +} + +.body-content pre.code-block { + margin-top: 5px; + margin-bottom: 5px; +} + +.body-content blockquote p, .body-content pre { + color: black; + font-size: 13px; +} + +.body-content blockquote.code-block { + background: Wheat; +} + +.body-content pre.code-block code { + word-wrap: normal; + white-space: pre; +} + +.body-content code { + color: Brown !important; +} + +.code-block { + display: none; + width: 60%; + float: left; + clear: right; +} + +.code-block.active { + display: initial; +} + +#code-tabs-wrapper { + width: 55%; + height: 60px; + /* position: fixed; */ + top: 0; + right: 0; +} + +#code-tabs-wrapper .code-tab-list { + float: right; + margin-top: 0; + padding: 0 10px; +} + +#code-tabs-wrapper .code-tab { + color: white; + /* display: inline-block; */ + padding: 0 30px; + background: rgb(48, 48, 48); + border: 1px solid rgb(161, 160, 158); + border-radius: 5px; +} + +#code-tabs-wrapper .tab-selected { + background: rgb(51, 113, 227); + font-style: bold; + border-radius: 5px; +} + +.side-nav a { + color: black; +} diff --git a/gen-apidocs/generators/static_includes/_cluster.html b/gen-apidocs/generators/static_includes/_cluster.html new file mode 100644 index 00000000..a726ccfb --- /dev/null +++ b/gen-apidocs/generators/static_includes/_cluster.html @@ -0,0 +1,5 @@ +

CLUSTER

+ +

Cluster resources are responsible for defining configuration of the cluster itself, and are generally only used by cluster operators.

+ +
diff --git a/gen-apidocs/generators/static_includes/_config.html b/gen-apidocs/generators/static_includes/_config.html new file mode 100644 index 00000000..40df1589 --- /dev/null +++ b/gen-apidocs/generators/static_includes/_config.html @@ -0,0 +1,11 @@ +

CONFIG & STORAGE

+ +

Config and Storage resources are responsible for injecting data into your applications and persisting data externally to your container.

+ +

Common resource types:

+
    +
  • ConfigMaps]for providing text key value pairs injected into the application through environment variables, command line arguments, or files
  • +
  • Secrets for providing binary data injected into the application through files
  • +
  • Volumes for providing a filesystem external to the Container. Maybe shared across Containers within the same Pod and have a lifetime persisting beyond a Container or Pod.
  • +
+
diff --git a/gen-apidocs/generators/static_includes/_definitions.html b/gen-apidocs/generators/static_includes/_definitions.html new file mode 100644 index 00000000..e7bff1bc --- /dev/null +++ b/gen-apidocs/generators/static_includes/_definitions.html @@ -0,0 +1,3 @@ +

DEFINITIONS

+ +

This section contains definitions for objects used in the Kubernetes APIs.

diff --git a/gen-apidocs/generators/static_includes/_meta.html b/gen-apidocs/generators/static_includes/_meta.html new file mode 100644 index 00000000..c0b7546d --- /dev/null +++ b/gen-apidocs/generators/static_includes/_meta.html @@ -0,0 +1,11 @@ +

METADATA

+ +

Metadata resources are responsible for configuring behavior of your other Resources within the Cluster.

+ +

Common resource types:

+
    +
  • HorizontalPodAutoscaler (HPA) for automatically scaling the replicacount of your workloads in response to load.
  • +
  • PodDisruptionBudget for configuring how many replicas in a given workload maybe made concurrently unavailable when performing maintenance.
  • +
  • Event for notification of resource lifecycle events in the cluster.
  • +
+
diff --git a/gen-apidocs/generators/static_includes/_oldversions.html b/gen-apidocs/generators/static_includes/_oldversions.html new file mode 100644 index 00000000..d567dc6c --- /dev/null +++ b/gen-apidocs/generators/static_includes/_oldversions.html @@ -0,0 +1,3 @@ +

OLD API VERSIONS

+ +

This section contains older versions of resources shown above.

diff --git a/gen-apidocs/generators/static_includes/_overview.html b/gen-apidocs/generators/static_includes/_overview.html new file mode 100644 index 00000000..9575b8ff --- /dev/null +++ b/gen-apidocs/generators/static_includes/_overview.html @@ -0,0 +1,88 @@ +

API OVERVIEW

+ +

Welcome to the Kubernetes API. You can use the Kubernetes API to read +and write Kubernetes resource objects via a Kubernetes API endpoint.

+ +

Resource Categories

+ +

This is a high-level overview of the basic types of resources provide by the Kubernetes API and their primary functions.

+

Workloads are objects you use to manage and run your containers on the cluster.

+

Discovery & LB resources are objects you use to "stitch" your workloads together into an externally accessible, load-balanced Service.

+

Config & Storage resources are objects you use to inject initialization data into your applications, and to persist data that is external to your container.

+

Cluster resources objects define how the cluster itself is configured; these are typically used only by cluster operators.

+

Metadata resources are objects you use to configure the behavior of other resources within the cluster, such as HorizontalPodAutoscaler for scaling workloads.

+ +
+ +

Resource Objects

+ +

Resource objects typically have 3 components:

+
    +
  • Resource ObjectMeta: This is metadata about the resource, such as its name, type, api version, annotations, and labels. This contains +fields that maybe updated both by the end user and the system (e.g. annotations).
  • +
  • ResourceSpec: This is defined by the user and describes the desired state of system. Fill this in when creating or updating an object.
  • +
  • ResourceStatus: This is filled in by the server and reports the current state of the system. In most cases, users don't need to change this.
  • +
+ +
+ +

Resource Operations

+ +

Most resources provide the following Operations:

+ +

Create

+ +

Create operations will create the resource in the storage backend. After a resource is create the system will apply +the desired state.

+ +

Update

+ +

Updates come in 2 forms: Replace and Patch: + +

    +
  • Replace: +Replacing a resource object will update the resource by replacing the existing spec with the provided one. For +read-then-write operations this is safe because an optimistic lock failure will occur if the resource was modified +between the read and write. Note: The ResourceStatus will be ignored by the system and will not be updated. +To update the status, one must invoke the specific status update operation.
    + +Note: Replacing a resource object may not result immediately in changes being propagated to downstream objects. For instance +replacing a ConfigMap or Secret resource will not result in all Pods seeing the changes unless the Pods are +restarted out of band.

  • + +
  • Patch: +Patch will apply a change to a specific field. How the change is merged is defined per field. Lists may either be +replaced or merged. Merging lists will not preserve ordering.
    + +Patches will never cause optimistic locking failures, and the last write will win. Patches are recommended +when the full state is not read before an update, or when failing on optimistic locking is undesirable. When patching +complex types, arrays and maps, how the patch is applied is defined on a per-field basis and may either replace +the field's current value, or merge the contents into the current value.
  • +
+ +

Read

+ +

Reads come in 3 forms: Get, List and Watch:

+ +

    +
  • Get: Get will retrieve a specific resource object by name.
  • +
  • List: List will retrieve all resource objects of a specific type within a namespace, and the results can be restricted to resources matching a selector query.
    +List All Namespaces: Like List but retrieves resources across all namespaces.
  • +
  • Watch: Watch will stream results for an object(s) as it is updated. Similar to a callback, watch is used to respond to resource changes.
  • +
+ +

Delete

+ +

Delete will delete a resource. Depending on the specific resource, child objects may or may not be garbage collected by the server. See +notes on specific resource objects for details.

+ +

Additional Operations

+ +

Resources may define additional operations specific to that resource type.

+ +
    +
  • Rollback: Rollback a PodTemplate to a previous version. Only available for some resource types.
  • +
  • Read / Write Scale: Read or Update the number of replicas for the given resource. Only available for some resource types.
  • +
  • Read / Write Status: Read or Update the Status for a resource object. The Status can only changed through these update operations.
  • +
+
diff --git a/gen-apidocs/generators/static_includes/_overview.md b/gen-apidocs/generators/static_includes/_overview.md index 82a4d09b..b85407b6 100644 --- a/gen-apidocs/generators/static_includes/_overview.md +++ b/gen-apidocs/generators/static_includes/_overview.md @@ -58,9 +58,9 @@ Patch will apply a change to a specific field. How the change is merged is defi replaced or merged. Merging lists will not preserve ordering. **Patches will never cause optimistic locking failures, and the last write will win.** Patches are recommended - when the full state is not read before an update, or when failing on optimistic locking is undesirable. *When patching - complex types, arrays and maps, how the patch is applied is defined on a per-field basis and may either replace - the field's current value, or merge the contents into the current value.* +when the full state is not read before an update, or when failing on optimistic locking is undesirable. *When patching +complex types, arrays and maps, how the patch is applied is defined on a per-field basis and may either replace +the field's current value, or merge the contents into the current value.* #### Read diff --git a/gen-apidocs/generators/static_includes/_servicediscovery.html b/gen-apidocs/generators/static_includes/_servicediscovery.html new file mode 100644 index 00000000..ca9ede25 --- /dev/null +++ b/gen-apidocs/generators/static_includes/_servicediscovery.html @@ -0,0 +1,14 @@ +

SERVICE APIs

+ +

Service API resources are responsible for stitching your workloads together into an accessible Loadbalanced Service. By default, +Workloads are only accessible within the cluster, and they must be exposed externally using a either +a *LoadBalancer* or *NodePort* Service. For development, internally accessible +Workloads can be accessed via proxy through the api master using the kubectl proxy command.

+ +

Common resource types:

+ +
    +
  • Services for providing a single ip endpoint loadbalanced across multiple Workload replicas.
  • +
  • Ingress for providing a https(s) endpoint http(s) routed to one or more *Services*.
  • +
+
diff --git a/gen-apidocs/generators/static_includes/_workloads.html b/gen-apidocs/generators/static_includes/_workloads.html new file mode 100644 index 00000000..00e5f64e --- /dev/null +++ b/gen-apidocs/generators/static_includes/_workloads.html @@ -0,0 +1,15 @@ +

WORKLOADS

+ +

Workloads resources are responsible for managing and running your containers on the cluster. Containers are created +by Controllers through Pods. Pods run Containers and provide environmental dependencies such as shared or +persistent storage Volumes and Configuration or Secret +data injected into the container.

+ +

The most common Controllers are:

+
    +
  • Deployments for stateless persistent apps (e.g. HTTP servers).
  • +
  • StatefulSets for stateful persistent apps (e.g. databases).
  • +
  • Jobs for run-to-completion apps (e.g. batch Jobs).
  • +
+ +
diff --git a/gen-apidocs/generators/templates.go b/gen-apidocs/generators/templates.go deleted file mode 100644 index 214442a9..00000000 --- a/gen-apidocs/generators/templates.go +++ /dev/null @@ -1,166 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -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. -*/ - -package generators - -var DefinitionTemplate = ` -{{define "definition.template"}}## {{.Name}} {{.Version}} {{.Group}} - -Group | Version | Kind ------------- | ---------- | ----------- -` + "`{{.GroupDisplayName}}` | `{{.Version}}` | `{{.Name}}`" + ` - -{{if .OtherVersions}}{{end}} - -{{.DescriptionWithEntities}} - -{{if .AppearsIn}}{{end}} - -Field | Description ------------- | ----------- -{{range $field := .Fields}}` + "`{{$field.Name}}`" + `{{if $field.Link}}
*{{$field.Link}}* {{end}} {{if $field.PatchStrategy}}
**patch type**: *{{$field.PatchStrategy}}* {{end}} {{if $field.PatchMergeKey}}
**patch merge key**: *{{$field.PatchMergeKey}}* {{end}} | {{$field.DescriptionWithEntities}} -{{end}} -{{end}} -` - -var ConceptTemplate = ` -{{define "pathparams"}}{{if .PathParams }}### Path Parameters - -Parameter | Description ------------- | ----------- -{{range $param := .PathParams}}` + "`{{$param.Name}}`" + `{{if $param.Link}}
*{{$param.Link}}* {{end}} | {{$param.Description}} -{{end}}{{end}}{{end}} - -{{define "queryparams"}}{{if .QueryParams }}### Query Parameters - -Parameter | Description ------------- | ----------- -{{range $param := .QueryParams}}` + "`{{$param.Name}}`" + `{{if $param.Link}}
*{{$param.Link}}* {{end}} | {{$param.Description}} -{{end}}{{end}}{{end}} - -{{define "bodyparams"}}{{if .BodyParams }}### Body Parameters - -Parameter | Description ------------- | ----------- -{{range $param := .BodyParams}}` + "`{{$param.Name}}`" + `{{if $param.Link}}
*{{$param.Link}}* {{end}} | {{$param.Description}} -{{end}}{{end}}{{end}} - -{{define "responsebody"}}{{if .HttpResponses}}### Response - -Code | Description ------------- | ----------- -{{range $i, $response := .HttpResponses}}{{$response.Code}} {{if $response.Field.Link}}
*{{$response.Field.Link}}* {{end}} | {{$response.Field.Description}} -{{end}}{{end}}{{end}} - -{{define "concept.template"}} - ------------ -# {{.Name}} {{.Definition.Version}} {{if .Definition.ShowGroup}}{{.Definition.GroupDisplayName}}{{end}} - -{{if .Definition.Sample.Sample}}{{$n := .Definition.Sample.Note}}{{range $e := .Definition.GetSamples}}>{{$e.Tab}} {{$n}} - -` + "```" + `{{$e.Type}} - -{{$e.Text}} - -` + "```" + ` -{{end}}{{end}} - -Group | Version | Kind ------------- | ---------- | ----------- -` + "`{{.Definition.GroupDisplayName}}` | `{{.Definition.Version}}` | `{{.Name}}`" + ` - -{{if .DescriptionWarning}}{{end}} -{{if .DescriptionNote}}{{end}} - -{{if .Definition.OtherVersions}}{{end}} - - -{{.Definition.DescriptionWithEntities}} - -{{if .Definition.AppearsIn}}{{end}} - -Field | Description ------------- | ----------- -{{range $field := .Definition.Fields}}` + "`{{$field.Name}}`" + `{{if $field.Link}}
*{{$field.Link}}* {{end}} {{if $field.PatchStrategy}}
**patch type**: *{{$field.PatchStrategy}}* {{end}} {{if $field.PatchMergeKey}}
**patch merge key**: *{{$field.PatchMergeKey}}* {{end}} | {{$field.DescriptionWithEntities}} -{{end}} - -{{if .Definition.Inline}}{{range $inline := .Definition.Inline}}### {{$inline.Name}} {{$inline.Version}} {{$inline.Group}} - -{{if $inline.AppearsIn}}{{end}} - -Field | Description ------------- | ----------- -{{range $field := $inline.Fields}}` + "`{{$field.Name}}`" + `{{if $field.Link}}
*{{$field.Link}}* {{end}} {{if $field.PatchStrategy}}
**patch type**: *{{$field.PatchStrategy}}* {{end}} {{if $field.PatchMergeKey}}
**patch merge key**: *{{$field.PatchMergeKey}}* {{end}} | {{$field.DescriptionWithEntities}} -{{end}} -{{end}}{{end}} - -{{if .Definition.OperationCategories}}{{range $category := .Definition.OperationCategories}}{{if $category.Operations}} -## {{$category.Name}} - -See supported operations below... - -{{range $operation := $category.Operations}}## {{$operation.Type.Name}} - -{{if $operation.GetExampleRequests}}{{range $er := $operation.GetExampleRequests}}>{{$er.Tab}} {{$er.Msg}} - -` + "```" + `{{$er.Type}} - -{{$er.Text}} - -` + "```" + ` - -{{end}}{{end}}{{if $operation.GetExampleResponses}}{{range $er := $operation.GetExampleResponses}}>{{$er.Tab}} {{$er.Msg}} - -` + "```" + `{{$er.Type}} - -{{$er.Text}} - -` + "```" + ` -{{end}}{{end}} - - -{{$operation.Description}} - -### HTTP Request - -` + "`" + `{{$operation.GetDisplayHttp}}` + "`" + ` - -{{template "pathparams" $operation}} -{{template "queryparams" $operation}} -{{template "bodyparams" $operation}} -{{template "responsebody" $operation}} - -{{end}}{{end}}{{end}}{{end}} - -{{end}} - -` diff --git a/gen-apidocs/generators/util.go b/gen-apidocs/generators/util.go index 9985d50d..7031e9b4 100644 --- a/gen-apidocs/generators/util.go +++ b/gen-apidocs/generators/util.go @@ -28,7 +28,7 @@ func PrintInfo(config *api.Config) { definitions := config.Definitions hasOrphaned := false - for name, d := range definitions.GetAllDefinitions() { + for name, d := range definitions.All { if !d.FoundInField && !d.FoundInOperation { if !strings.Contains(name, "meta.v1.APIVersions") && !strings.Contains(name, "meta.v1.Patch") { hasOrphaned = true @@ -38,7 +38,7 @@ func PrintInfo(config *api.Config) { if hasOrphaned { fmt.Printf("----------------------------------\n") fmt.Printf("Orphaned Definitions:\n") - for name, d := range definitions.GetAllDefinitions() { + for name, d := range definitions.All { if !d.FoundInField && !d.FoundInOperation { if !strings.Contains(name, "meta.v1.APIVersions") && !strings.Contains(name, "meta.v1.Patch") { fmt.Printf("[%s]\n", name) @@ -51,7 +51,7 @@ func PrintInfo(config *api.Config) { } missingFromToc := false - for _, d := range definitions.GetAllDefinitions() { + for _, d := range definitions.All { if !d.InToc && len(d.OperationCategories) > 0 && !d.IsOldVersion && !d.IsInlined { missingFromToc = true } @@ -60,7 +60,7 @@ func PrintInfo(config *api.Config) { if missingFromToc { fmt.Printf("----------------------------------\n") fmt.Printf("Definitions with Operations Missing from Toc (Excluding old version):\n") - for name, d := range definitions.GetAllDefinitions() { + for name, d := range definitions.All { if !d.InToc && len(d.OperationCategories) > 0 && !d.IsOldVersion && !d.IsInlined { fmt.Printf("[%s]\n", name) for _, oc := range d.OperationCategories { @@ -73,7 +73,7 @@ func PrintInfo(config *api.Config) { } //fmt.Printf("Old definitions:\n") - //for name, d := range definitions.GetAllDefinitions() { + //for name, d := range definitions.All { // if !d.InToc && len(d.OperationCategories) > 0 && d.IsOldVersion && !d.IsInlined { // fmt.Printf("[%s]\n", name) // for _, oc := range d.OperationCategories { @@ -99,7 +99,7 @@ func PrintDebug(config *api.Config) { fmt.Printf("----------------------------------\n") fmt.Printf("\n\nDefinitions in Toc:\n") - for name, d := range definitions.GetAllDefinitions() { + for name, d := range definitions.All { if d.InToc { fmt.Printf("\n\n%s \n\tFields:\n", name) for _, f := range d.Fields { @@ -136,7 +136,7 @@ func PrintDebug(config *api.Config) { fmt.Printf("----------------------------------\n") fmt.Printf("\n\nOther Definitions:\n") - for name, d := range definitions.GetAllDefinitions() { + for name, d := range definitions.All { if !d.InToc && d.FoundInField { fmt.Printf("\n\n%s \n\tFields:\n", name) for _, f := range d.Fields { diff --git a/gen-apidocs/generators/writer.go b/gen-apidocs/generators/writer.go new file mode 100644 index 00000000..7c854108 --- /dev/null +++ b/gen-apidocs/generators/writer.go @@ -0,0 +1,173 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ +package generators + +import ( + "flag" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/kubernetes-incubator/reference-docs/gen-apidocs/generators/api" +) + +type Doc struct { + Filename string `json:"filename,omitempty"` +} + +type DocWriter interface { + Extension() string + DefaultStaticContent(title string) string + WriteOverview() + WriteResourceCategory(name, file string) + WriteResource(r *api.Resource) + WriteDefinitionsOverview() + WriteDefinition(d *api.Definition) + WriteOldVersionsOverview() + Finalize() +} + +var Backend = flag.String("backend", "go", + "Specify the backend to use for doc generation. Valid options are 'brodocs', 'go'.") + +func GenerateFiles() { + // Load the yaml config + config := api.NewConfig() + PrintInfo(config) + ensureIncludeDir() + + copyright := "Copyright 2016 The Kubernetes Authors." + var title string + if !*api.BuildOps { + title = "Kubernetes Resource Reference Docs" + } else { + title = "Kubernetes API Reference Docs" + } + + var writer DocWriter + if *Backend == "brodocs" { + writer = NewMarkdownWriter(config, copyright, title) + } else if *Backend == "go" { + writer = NewHTMLWriter(config, copyright, title) + } else { + panic(fmt.Sprintf("Unknown backend specified: %s", *Backend)) + } + + writer.WriteOverview() + + // Write resource definitions + for _, c := range config.ResourceCategories { + writer.WriteResourceCategory(c.Name, c.Include) + for _, r := range c.Resources { + if r.Definition == nil { + fmt.Printf("Warning: Missing definition for item in TOC %s\n", r.Name) + continue + } + writer.WriteResource(r) + } + } + + writer.WriteDefinitionsOverview() + // Add other definition imports + definitions := api.SortDefinitionsByName{} + for _, d := range config.Definitions.All { + // Don't add definitions for top level resources in the toc or inlined resources + if d.InToc || d.IsInlined || d.IsOldVersion { + continue + } + definitions = append(definitions, d) + } + sort.Sort(definitions) + for _, d := range definitions { + writer.WriteDefinition(d) + } + + writer.WriteOldVersionsOverview() + oldversions := api.SortDefinitionsByName{} + for _, d := range config.Definitions.All { + // Don't add definitions for top level resources in the toc or inlined resources + if d.IsOldVersion { + oldversions = append(oldversions, d) + } + } + sort.Sort(oldversions) + for _, d := range oldversions { + // Skip Inlined definitions + if d.IsInlined { + continue + } + r := &api.Resource{Definition: d, Name: d.Name} + writer.WriteResource(r) + } + + writer.Finalize() +} + +func ensureIncludeDir() { + if _, err := os.Stat(*api.ConfigDir + "/includes"); os.IsNotExist(err) { + os.Mkdir(*api.ConfigDir+"/includes", os.FileMode(0700)) + } +} + +func getStaticIncludesDir() string { + return filepath.Join(*api.ConfigDir, "static_includes") +} + +func definitionFileName(d *api.Definition) string { + name := "generated_" + strings.ToLower(strings.Replace(d.Name, ".", "_", 50)) + return fmt.Sprintf("%s_%s_%s_definition", name, d.Version, d.Group) +} + +func conceptFileName(d *api.Definition) string { + name := "generated_" + strings.ToLower(strings.Replace(d.Name, ".", "_", 50)) + return fmt.Sprintf("%s_%s_%s_concept", name, d.Version, d.Group) +} + +func getLink(s string) string { + tmp := strings.Replace(s, ".", "-", -1) + return strings.ToLower(strings.Replace(tmp, " ", "-", -1)) +} + +func writeStaticFile(title, location, defaultContent string) { + fn := filepath.Join(getStaticIncludesDir(), location) + to := filepath.Join(*api.ConfigDir, "includes", location) + _, err := os.Stat(fn) + if err == nil { + // copy the file if it exists + os.Link(fn, to) + return + } + + if !os.IsNotExist(err) { + panic(fmt.Sprintf("Could not stat file %s %v", fn, err)) + } + fmt.Printf("Creating file %s\n", to) + file, err := os.Create(to) + if err != nil { + panic(err) + } + file.Close() + + file, err = os.OpenFile(to, os.O_WRONLY, 0) + if err != nil { + fmt.Println(err) + return + } + fmt.Fprintf(file, defaultContent) + file.Close() +}