diff --git a/Dockerfile.dapper b/Dockerfile.dapper index e8baee89..a59903f3 100644 --- a/Dockerfile.dapper +++ b/Dockerfile.dapper @@ -1,15 +1,6 @@ FROM ubuntu:16.04 # FROM arm64=aarch64/ubuntu:16.04 arm=armhf/ubuntu:16.04 -ENV DAPPER_ENV VERSION DEV_BUILD -ENV DAPPER_DOCKER_SOCKET true -ENV DAPPER_SOURCE /go/src/github.com/rancher/os -ENV DAPPER_OUTPUT ./bin ./dist ./build/initrd -ENV DAPPER_RUN_ARGS --privileged -ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache -ENV SHELL /bin/bash -WORKDIR ${DAPPER_SOURCE} - RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential \ @@ -38,6 +29,17 @@ RUN apt-get update && \ wget \ xorriso +########## Dapper Configuration ##################### + +ENV DAPPER_ENV VERSION DEV_BUILD RUNTEST +ENV DAPPER_DOCKER_SOCKET true +ENV DAPPER_SOURCE /go/src/github.com/rancher/os +ENV DAPPER_OUTPUT ./bin ./dist ./build/initrd +ENV DAPPER_RUN_ARGS --privileged +ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache +ENV SHELL /bin/bash +WORKDIR ${DAPPER_SOURCE} + ########## General Configuration ##################### ARG DAPPER_HOST_ARCH=amd64 ARG HOST_ARCH=${DAPPER_HOST_ARCH} @@ -53,7 +55,7 @@ ARG DOCKER_BUILD_VERSION=1.10.3 ARG DOCKER_BUILD_PATCH_VERSION=v${DOCKER_BUILD_VERSION}-ros1 ARG SELINUX_POLICY_URL=https://github.com/rancher/refpolicy/releases/download/v0.0.3/policy.29 -ARG KERNEL_URL_amd64=https://github.com/rancher/os-kernel/releases/download/Ubuntu-4.4.0-42.62-rancher1-1/linux-4.4.21-rancher-x86.tar.gz +ARG KERNEL_URL_amd64=https://github.com/rancher/os-kernel/releases/download/v4.8.11/linux-4.8.11-rancher-x86.tar.gz ARG KERNEL_URL_arm64=https://github.com/imikushin/os-kernel/releases/download/Estuary-4.4.0-arm64.8/linux-4.4.0-rancher-arm64.tar.gz ARG DOCKER_URL_amd64=https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz @@ -70,9 +72,9 @@ ARG OS_SERVICES_REPO=https://raw.githubusercontent.com/${OS_REPO}/os-services ARG IMAGE_NAME=${OS_REPO}/os ARG DFS_IMAGE=${OS_REPO}/docker:v${DOCKER_VERSION}-2 -ARG OS_BASE_URL_amd64=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_amd64.tar.xz -ARG OS_BASE_URL_arm64=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_arm64.tar.xz -ARG OS_BASE_URL_arm=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_arm.tar.xz +ARG OS_BASE_URL_amd64=https://github.com/rancher/os-base/releases/download/v2016.08.1-2/os-base_amd64.tar.xz +ARG OS_BASE_URL_arm64=https://github.com/rancher/os-base/releases/download/v2016.08.1-2/os-base_arm64.tar.xz +ARG OS_BASE_URL_arm=https://github.com/rancher/os-base/releases/download/v2016.08.1-2/os-base_arm.tar.xz ###################################################### # Set up environment and export all ARGS as ENV @@ -140,6 +142,9 @@ RUN curl -fL ${!BUILD_DOCKER_URL} > /usr/bin/docker && \ # Install Trash RUN go get github.com/rancher/trash +# Install golint +RUN go get github.com/golang/lint/golint + RUN go get gopkg.in/check.v1 # Install dapper diff --git a/Makefile b/Makefile index dd96c5a9..9198eb34 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -TARGETS := $(shell ls scripts | grep -vE 'clean|run|help') +TARGETS := $(shell ls scripts | grep -vE 'clean|run|help|docs') .dapper: @echo Downloading dapper - @curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp + @curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m|sed 's/v7l//'` > .dapper.tmp @@chmod +x .dapper.tmp @./.dapper.tmp -v @mv .dapper.tmp .dapper @@ -25,6 +25,9 @@ run: build/initrd/.id .dapper ./.dapper -m bind build-target ./scripts/run +docs: + ./scripts/docs + shell-bind: .dapper ./.dapper -m bind -s diff --git a/README.md b/README.md index d043966f..88cfe68c 100644 --- a/README.md +++ b/README.md @@ -14,40 +14,48 @@ it would really be bad if somebody did `docker rm -f $(docker ps -qa)` and delet ## Latest Release -**v0.6.1 - Docker 1.12.1 - Linux 4.4.19** +**v0.7.1 - Docker 1.12.3 - Linux 4.4.24** ### ISO https://releases.rancher.com/os/latest/rancheros.iso -https://releases.rancher.com/os/v0.6.1/rancheros.iso +https://releases.rancher.com/os/v0.7.1/rancheros.iso ### Additional Downloads -#### Latest +#### Latest Links +##### v0.7.1 * https://releases.rancher.com/os/latest/initrd * https://releases.rancher.com/os/latest/iso-checksums.txt * https://releases.rancher.com/os/latest/rancheros-openstack.img -* https://releases.rancher.com/os/latest/rancheros-raspberry-pi.zip -* https://releases.rancher.com/os/latest/rancheros-v0.6.1.tar.gz * https://releases.rancher.com/os/latest/rancheros.iso -* https://releases.rancher.com/os/latest/rootfs_arm.tar.gz -* https://releases.rancher.com/os/latest/rootfs_arm64.tar.gz +* https://releases.rancher.com/os/latest/rancheros-v0.7.1.tar.gz * https://releases.rancher.com/os/latest/rootfs.tar.gz * https://releases.rancher.com/os/latest/vmlinuz -#### v0.6.1 +##### v0.7.0 -* https://releases.rancher.com/os/v0.6.1/initrd -* https://releases.rancher.com/os/v0.6.1/iso-checksums.txt -* https://releases.rancher.com/os/v0.6.1/rancheros-openstack.img -* https://releases.rancher.com/os/v0.6.1/rancheros-raspberry-pi.zip -* https://releases.rancher.com/os/v0.6.1/rancheros-v0.6.1.tar.gz -* https://releases.rancher.com/os/v0.6.1/rancheros.iso -* https://releases.rancher.com/os/v0.6.1/rootfs_arm.tar.gz -* https://releases.rancher.com/os/v0.6.1/rootfs_arm64.tar.gz -* https://releases.rancher.com/os/v0.6.1/rootfs.tar.gz -* https://releases.rancher.com/os/v0.6.1/vmlinuz + +* https://releases.rancher.com/os/latest/rancheros-raspberry-pi.zip +* https://releases.rancher.com/os/latest/rootfs_arm.tar.gz +* https://releases.rancher.com/os/latest/rootfs_arm64.tar.gz + +#### v0.7.1 Links + +* https://releases.rancher.com/os/v0.7.1/initrd +* https://releases.rancher.com/os/v0.7.1/iso-checksums.txt +* https://releases.rancher.com/os/v0.7.1/rancheros-openstack.img +* https://releases.rancher.com/os/v0.7.1/rancheros.iso +* https://releases.rancher.com/os/v0.7.1/rancheros-v0.7.1.tar.gz +* https://releases.rancher.com/os/v0.7.1/rootfs.tar.gz +* https://releases.rancher.com/os/v0.7.1/vmlinuz + +#### v0.7.0 Links + +* https://releases.rancher.com/os/v0.7.0/rancheros-raspberry-pi.zip +* https://releases.rancher.com/os/v0.7.0/rootfs_arm.tar.gz +* https://releases.rancher.com/os/v0.7.0/rootfs_arm64.tar.gz **Note**: you can use `http` instead of `https` in the above URLs, e.g. for iPXE. @@ -59,22 +67,24 @@ SSH keys are added to the **`rancher`** user, so you must log in using the **ran Region | Type | AMI | -------|------|------ -ap-northeast-1 | HVM | [ami-75954214](https://console.aws.amazon.com/ec2/home?region=ap-northeast-1#launchInstanceWizard:ami=ami-75954214) -ap-northeast-2 | HVM | [ami-690dd807](https://console.aws.amazon.com/ec2/home?region=ap-northeast-2#launchInstanceWizard:ami=ami-690dd807) -ap-south-1 | HVM | [ami-ed8cf982](https://console.aws.amazon.com/ec2/home?region=ap-south-1#launchInstanceWizard:ami=ami-ed8cf982) -ap-southeast-1 | HVM | [ami-27bc6644](https://console.aws.amazon.com/ec2/home?region=ap-southeast-1#launchInstanceWizard:ami=ami-27bc6644) -ap-southeast-2 | HVM | [ami-67172604](https://console.aws.amazon.com/ec2/home?region=ap-southeast-2#launchInstanceWizard:ami=ami-67172604) -eu-central-1 | HVM | [ami-e88d7f87](https://console.aws.amazon.com/ec2/home?region=eu-central-1#launchInstanceWizard:ami=ami-e88d7f87) -eu-west-1 | HVM | [ami-934837e0](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchInstanceWizard:ami=ami-934837e0) -sa-east-1 | HVM | [ami-6949d905](https://console.aws.amazon.com/ec2/home?region=sa-east-1#launchInstanceWizard:ami=ami-6949d905) -us-east-1 | HVM | [ami-a8d2a4bf](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchInstanceWizard:ami=ami-a8d2a4bf) -us-west-1 | HVM | [ami-fccb879c](https://console.aws.amazon.com/ec2/home?region=us-west-1#launchInstanceWizard:ami=ami-fccb879c) -us-west-2 | HVM | [ami-1ed3007e](https://console.aws.amazon.com/ec2/home?region=us-west-2#launchInstanceWizard:ami=ami-1ed3007e) +ap-northeast-1 | HVM | [ami-be5bf2df](https://console.aws.amazon.com/ec2/home?region=ap-northeast-1#launchInstanceWizard:ami=ami-be5bf2df) +ap-northeast-2 | HVM | [ami-247fab4a](https://console.aws.amazon.com/ec2/home?region=ap-northeast-2#launchInstanceWizard:ami=ami-247fab4a) +ap-south-1 | HVM | [ami-dbf682b4](https://console.aws.amazon.com/ec2/home?region=ap-south-1#launchInstanceWizard:ami=ami-dbf682b4) +ap-southeast-1 | HVM | [ami-c6d073a5](https://console.aws.amazon.com/ec2/home?region=ap-southeast-1#launchInstanceWizard:ami=ami-c6d073a5) +ap-southeast-2 | HVM | [ami-51132c32](https://console.aws.amazon.com/ec2/home?region=ap-southeast-2#launchInstanceWizard:ami=ami-51132c32) +eu-central-1 | HVM | [ami-2025df4f](https://console.aws.amazon.com/ec2/home?region=eu-central-1#launchInstanceWizard:ami=ami-2025df4f) +eu-west-1 | HVM | [ami-c62170b5](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchInstanceWizard:ami=ami-c62170b5) +sa-east-1 | HVM | [ami-52b8273e](https://console.aws.amazon.com/ec2/home?region=sa-east-1#launchInstanceWizard:ami=ami-52b8273e) +us-east-1 | HVM | [ami-dfdff3c8](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchInstanceWizard:ami=ami-dfdff3c8) +us-east-2 | HVM | [ami-674c1602](https://console.aws.amazon.com/ec2/home?region=us-east-2#launchInstanceWizard:ami=ami-674c1602) +us-west-1 | HVM | [ami-da2075ba](https://console.aws.amazon.com/ec2/home?region=us-west-1#launchInstanceWizard:ami=ami-da2075ba) +us-west-2 | HVM | [ami-ab3192cb](https://console.aws.amazon.com/ec2/home?region=us-west-2#launchInstanceWizard:ami=ami-ab3192cb) + ### Google Compute Engine We are providing a disk image that users can download and import for use in Google Compute Engine. The image can be obtained from the release artifacts for RancherOS. -[Download Image](https://github.com/rancher/os/releases/download/v0.6.1/rancheros-v0.6.1.tar.gz) +[Download Image](https://github.com/rancher/os/releases/download/v0.7.1/rancheros-v0.7.1.tar.gz) Please follow the directions at our [docs to launch in GCE](http://docs.rancher.com/os/running-rancheros/cloud/gce/). @@ -85,6 +95,8 @@ Please refer to our [RancherOS Documentation](http://docs.rancher.com/os/) websi ## Support, Discussion, and Community If you need any help with RancherOS or Rancher, please join us at either our [Rancher forums](http://forums.rancher.com) or [#rancher IRC channel](http://webchat.freenode.net/?channels=rancher) where most of our team hangs out at. +For issues relating to security, please email security@rancher.com instead of posting an open issue in Github. + Please submit any **RancherOS** bugs, issues, and feature requests to [rancher/os](//github.com/rancher/os/issues). Please submit any **Rancher** bugs, issues, and feature requests to [rancher/rancher](//github.com/rancher/rancher/issues). diff --git a/cmd/cloudinitexecute/authorize_ssh_keys.go b/cmd/cloudinitexecute/authorize_ssh_keys.go index 79016135..e0929889 100644 --- a/cmd/cloudinitexecute/authorize_ssh_keys.go +++ b/cmd/cloudinitexecute/authorize_ssh_keys.go @@ -1,20 +1,108 @@ package cloudinitexecute import ( + "io/ioutil" "os" - "os/exec" + "path" + "strconv" + "strings" - log "github.com/Sirupsen/logrus" + "github.com/rancher/os/log" + "github.com/rancher/os/util" ) -func authorizeSSHKeys(user string, authorizedKeys []string, name string) { - for _, authorizedKey := range authorizedKeys { - cmd := exec.Command("update-ssh-keys", user, authorizedKey) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err != nil { - log.WithFields(log.Fields{"err": err, "user": user, "auth_key": authorizedKey}).Error("Error updating SSH authorized_keys") +const ( + sshDirName = ".ssh" + authorizedKeysFileName = "authorized_keys" +) + +func authorizeSSHKeys(username string, authorizedKeys []string, name string) error { + var uid int + var gid int + var homeDir string + + bytes, err := ioutil.ReadFile("/etc/passwd") + if err != nil { + return err + } + + for _, line := range strings.Split(string(bytes), "\n") { + if strings.HasPrefix(line, username) { + split := strings.Split(line, ":") + if len(split) < 6 { + break + } + uid, err = strconv.Atoi(split[2]) + if err != nil { + return err + } + gid, err = strconv.Atoi(split[3]) + if err != nil { + return err + } + homeDir = split[5] } } + + sshDir := path.Join(homeDir, sshDirName) + authorizedKeysFile := path.Join(sshDir, authorizedKeysFileName) + + if _, err := os.Stat(sshDir); os.IsNotExist(err) { + if err = os.Mkdir(sshDir, 0700); err != nil { + return err + } + } else if err != nil { + return err + } + + if err = os.Chown(sshDir, uid, gid); err != nil { + return err + } + + for _, authorizedKey := range authorizedKeys { + if err = authorizeSSHKey(authorizedKey, authorizedKeysFile, uid, gid); err != nil { + log.Errorf("Failed to authorize SSH key %s: %v", authorizedKey, err) + } + } + + return nil +} + +func authorizeSSHKey(authorizedKey, authorizedKeysFile string, uid, gid int) error { + authorizedKeysFileInfo, err := os.Stat(authorizedKeysFile) + if os.IsNotExist(err) { + keysFile, err := os.Create(authorizedKeysFile) + if err != nil { + return err + } + if err = keysFile.Chmod(0600); err != nil { + return err + } + if err = keysFile.Close(); err != nil { + return err + } + authorizedKeysFileInfo, err = os.Stat(authorizedKeysFile) + if err != nil { + return err + } + } else if err != nil { + return err + } + + bytes, err := ioutil.ReadFile(authorizedKeysFile) + if err != nil { + return err + } + + if !strings.Contains(string(bytes), authorizedKey) { + bytes = append(bytes, []byte(authorizedKey)...) + bytes = append(bytes, '\n') + } + + perm := authorizedKeysFileInfo.Mode().Perm() + if err = util.WriteFileAtomic(authorizedKeysFile, bytes, perm); err != nil { + return err + } + + return os.Chown(authorizedKeysFile, uid, gid) } diff --git a/cmd/cloudinitexecute/cloudinitexecute.go b/cmd/cloudinitexecute/cloudinitexecute.go index fd924d84..37a8a7cd 100644 --- a/cmd/cloudinitexecute/cloudinitexecute.go +++ b/cmd/cloudinitexecute/cloudinitexecute.go @@ -9,10 +9,10 @@ import ( "path" "strings" - log "github.com/Sirupsen/logrus" "github.com/coreos/coreos-cloudinit/system" rancherConfig "github.com/rancher/os/config" "github.com/rancher/os/docker" + "github.com/rancher/os/log" "github.com/rancher/os/util" "golang.org/x/net/context" ) @@ -37,6 +37,7 @@ func init() { func Main() { flags.Parse(os.Args[1:]) + log.InitLogger() log.Infof("Running cloud-init-execute: pre-console=%v, console=%v", preConsole, console) cfg := rancherConfig.LoadConfig() @@ -56,8 +57,12 @@ func Main() { func ApplyConsole(cfg *rancherConfig.CloudConfig) { if len(cfg.SSHAuthorizedKeys) > 0 { - authorizeSSHKeys("rancher", cfg.SSHAuthorizedKeys, sshKeyName) - authorizeSSHKeys("docker", cfg.SSHAuthorizedKeys, sshKeyName) + if err := authorizeSSHKeys("rancher", cfg.SSHAuthorizedKeys, sshKeyName); err != nil { + log.Error(err) + } + if err := authorizeSSHKeys("docker", cfg.SSHAuthorizedKeys, sshKeyName); err != nil { + log.Error(err) + } } WriteFiles(cfg, "console") @@ -94,18 +99,7 @@ func ApplyConsole(cfg *rancherConfig.CloudConfig) { } } - for _, runcmd := range cfg.Runcmd { - if len(runcmd) == 0 { - continue - } - - cmd := exec.Command(runcmd[0], runcmd[1:]...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - log.Errorf("Failed to run %s: %v", runcmd, err) - } - } + util.RunCommandSequence(cfg.Runcmd) } func WriteFiles(cfg *rancherConfig.CloudConfig, container string) { diff --git a/cmd/cloudinitsave/cloudinitsave.go b/cmd/cloudinitsave/cloudinitsave.go index f1b0503a..8e75f02e 100644 --- a/cmd/cloudinitsave/cloudinitsave.go +++ b/cmd/cloudinitsave/cloudinitsave.go @@ -17,15 +17,14 @@ package cloudinitsave import ( "errors" - "flag" "os" "strings" "sync" + "syscall" "time" yaml "github.com/cloudfoundry-incubator/candiedyaml" - log "github.com/Sirupsen/logrus" "github.com/coreos/coreos-cloudinit/config" "github.com/coreos/coreos-cloudinit/datasource" "github.com/coreos/coreos-cloudinit/datasource/configdrive" @@ -36,9 +35,12 @@ import ( "github.com/coreos/coreos-cloudinit/datasource/proc_cmdline" "github.com/coreos/coreos-cloudinit/datasource/url" "github.com/coreos/coreos-cloudinit/pkg" - "github.com/rancher/netconf" + "github.com/docker/docker/pkg/mount" "github.com/rancher/os/cmd/cloudinitsave/gce" + "github.com/rancher/os/cmd/network" rancherConfig "github.com/rancher/os/config" + "github.com/rancher/os/log" + "github.com/rancher/os/netconf" "github.com/rancher/os/util" ) @@ -46,73 +48,43 @@ const ( datasourceInterval = 100 * time.Millisecond datasourceMaxInterval = 30 * time.Second datasourceTimeout = 5 * time.Minute + configDevName = "config-2" + configDev = "LABEL=" + configDevName + configDevMountPoint = "/media/config-2" ) -var ( - network bool - flags *flag.FlagSet -) - -func init() { - flags = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) - flags.BoolVar(&network, "network", true, "use network based datasources") -} - func Main() { - flags.Parse(os.Args[1:]) + log.InitLogger() + log.Info("Running cloud-init-save") - log.Infof("Running cloud-init-save: network=%v", network) + cfg := rancherConfig.LoadConfig() + network.ApplyNetworkConfig(cfg) - if err := saveCloudConfig(); err != nil { + if err := SaveCloudConfig(true); err != nil { log.Errorf("Failed to save cloud-config: %v", err) } } -func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error { - os.MkdirAll(rancherConfig.CloudConfigDir, os.ModeDir|0600) - - if len(scriptBytes) > 0 { - log.Infof("Writing to %s", rancherConfig.CloudConfigScriptFile) - if err := util.WriteFileAtomic(rancherConfig.CloudConfigScriptFile, scriptBytes, 500); err != nil { - log.Errorf("Error while writing file %s: %v", rancherConfig.CloudConfigScriptFile, err) - return err - } - } - - if len(cloudConfigBytes) > 0 { - if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil { - return err - } - log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes)) - } - - metaDataBytes, err := yaml.Marshal(metadata) - if err != nil { +func MountConfigDrive() error { + if err := os.MkdirAll(configDevMountPoint, 644); err != nil { return err } - if err = util.WriteFileAtomic(rancherConfig.MetaDataFile, metaDataBytes, 400); err != nil { - return err - } - log.Infof("Written to %s:\n%s", rancherConfig.MetaDataFile, string(metaDataBytes)) + configDev := util.ResolveDevice(configDev) - return nil -} - -func currentDatasource() (datasource.Datasource, error) { - cfg := rancherConfig.LoadConfig() - - dss := getDatasources(cfg) - if len(dss) == 0 { - return nil, nil + if configDev == "" { + return mount.Mount(configDevName, configDevMountPoint, "9p", "trans=virtio,version=9p2000.L") } - ds := selectDatasource(dss) - return ds, nil + return mount.Mount(configDev, configDevMountPoint, "iso9660,vfat", "") } -func saveCloudConfig() error { - userDataBytes, metadata, err := fetchUserData() +func UnmountConfigDrive() error { + return syscall.Unmount(configDevMountPoint, 0) +} + +func SaveCloudConfig(network bool) error { + userDataBytes, metadata, err := fetchUserData(network) if err != nil { return err } @@ -146,9 +118,67 @@ func saveCloudConfig() error { return saveFiles(userDataBytes, scriptBytes, metadata) } -func fetchUserData() ([]byte, datasource.Metadata, error) { +func RequiresNetwork(datasource string) bool { + parts := strings.SplitN(datasource, ":", 2) + requiresNetwork, ok := map[string]bool{ + "ec2": true, + "file": false, + "url": true, + "cmdline": true, + "configdrive": false, + "digitalocean": true, + "gce": true, + "packet": true, + }[parts[0]] + return ok && requiresNetwork +} + +func saveFiles(cloudConfigBytes, scriptBytes []byte, metadata datasource.Metadata) error { + os.MkdirAll(rancherConfig.CloudConfigDir, os.ModeDir|0600) + + if len(scriptBytes) > 0 { + log.Infof("Writing to %s", rancherConfig.CloudConfigScriptFile) + if err := util.WriteFileAtomic(rancherConfig.CloudConfigScriptFile, scriptBytes, 500); err != nil { + log.Errorf("Error while writing file %s: %v", rancherConfig.CloudConfigScriptFile, err) + return err + } + } + + if len(cloudConfigBytes) > 0 { + if err := util.WriteFileAtomic(rancherConfig.CloudConfigBootFile, cloudConfigBytes, 400); err != nil { + return err + } + log.Infof("Written to %s:\n%s", rancherConfig.CloudConfigBootFile, string(cloudConfigBytes)) + } + + metaDataBytes, err := yaml.Marshal(metadata) + if err != nil { + return err + } + + if err = util.WriteFileAtomic(rancherConfig.MetaDataFile, metaDataBytes, 400); err != nil { + return err + } + log.Infof("Written to %s:\n%s", rancherConfig.MetaDataFile, string(metaDataBytes)) + + return nil +} + +func currentDatasource(network bool) (datasource.Datasource, error) { + cfg := rancherConfig.LoadConfig() + + dss := getDatasources(cfg, network) + if len(dss) == 0 { + return nil, nil + } + + ds := selectDatasource(dss) + return ds, nil +} + +func fetchUserData(network bool) ([]byte, datasource.Metadata, error) { var metadata datasource.Metadata - ds, err := currentDatasource() + ds, err := currentDatasource(network) if err != nil || ds == nil { log.Errorf("Failed to select datasource: %v", err) return nil, metadata, err @@ -170,7 +200,7 @@ func fetchUserData() ([]byte, datasource.Metadata, error) { // getDatasources creates a slice of possible Datasources for cloudinit based // on the different source command-line flags. -func getDatasources(cfg *rancherConfig.CloudConfig) []datasource.Datasource { +func getDatasources(cfg *rancherConfig.CloudConfig, network bool) []datasource.Datasource { dss := make([]datasource.Datasource, 0, 5) for _, ds := range cfg.Rancher.CloudInit.Datasources { @@ -231,8 +261,8 @@ func getDatasources(cfg *rancherConfig.CloudConfig) []datasource.Datasource { } func enableDoLinkLocal() { - err := netconf.ApplyNetworkConfigs(&netconf.NetworkConfig{ - Interfaces: map[string]netconf.InterfaceConfig{ + err := netconf.ApplyNetworkConfigs(&rancherConfig.NetworkConfig{ + Interfaces: map[string]rancherConfig.InterfaceConfig{ "eth0": { IPV4LL: true, }, diff --git a/cmd/cloudinitsave/gce/metadata.go b/cmd/cloudinitsave/gce/metadata.go index 82c7ca58..c5200c16 100644 --- a/cmd/cloudinitsave/gce/metadata.go +++ b/cmd/cloudinitsave/gce/metadata.go @@ -31,15 +31,15 @@ const ( userdataPath = apiVersion + "instance/attributes/user-data" ) -type metadataService struct { +type MetadataService struct { metadata.MetadataService } -func NewDatasource(root string) *metadataService { - return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})} +func NewDatasource(root string) *MetadataService { + return &MetadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})} } -func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { +func (ms MetadataService) FetchMetadata() (datasource.Metadata, error) { public, err := ms.fetchIP("instance/network-interfaces/0/access-configs/0/external-ip") if err != nil { return datasource.Metadata{}, err @@ -53,16 +53,16 @@ func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { return datasource.Metadata{}, err } - projectSshKeys, err := ms.fetchString("project/attributes/sshKeys") + projectSSHKeys, err := ms.fetchString("project/attributes/sshKeys") if err != nil { return datasource.Metadata{}, err } - instanceSshKeys, err := ms.fetchString("instance/attributes/sshKeys") + instanceSSHKeys, err := ms.fetchString("instance/attributes/sshKeys") if err != nil { return datasource.Metadata{}, err } - keyStrings := strings.Split(projectSshKeys+"\n"+instanceSshKeys, "\n") + keyStrings := strings.Split(projectSSHKeys+"\n"+instanceSSHKeys, "\n") sshPublicKeys := map[string]string{} i := 0 @@ -85,11 +85,11 @@ func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { }, nil } -func (ms metadataService) Type() string { +func (ms MetadataService) Type() string { return "gce-metadata-service" } -func (ms metadataService) fetchString(key string) (string, error) { +func (ms MetadataService) fetchString(key string) (string, error) { data, err := ms.FetchData(ms.MetadataUrl() + key) if err != nil { return "", err @@ -98,7 +98,7 @@ func (ms metadataService) fetchString(key string) (string, error) { return string(data), nil } -func (ms metadataService) fetchIP(key string) (net.IP, error) { +func (ms MetadataService) fetchIP(key string) (net.IP, error) { str, err := ms.fetchString(key) if err != nil { return nil, err @@ -110,12 +110,11 @@ func (ms metadataService) fetchIP(key string) (net.IP, error) { if ip := net.ParseIP(str); ip != nil { return ip, nil - } else { - return nil, fmt.Errorf("couldn't parse %q as IP address", str) } + return nil, fmt.Errorf("couldn't parse %q as IP address", str) } -func (ms metadataService) FetchUserdata() ([]byte, error) { +func (ms MetadataService) FetchUserdata() ([]byte, error) { data, err := ms.FetchData(ms.UserdataUrl()) if err != nil { return nil, err diff --git a/cmd/cloudinitsave/packet.go b/cmd/cloudinitsave/packet.go index 6e093907..d93eaf33 100644 --- a/cmd/cloudinitsave/packet.go +++ b/cmd/cloudinitsave/packet.go @@ -8,20 +8,21 @@ import ( "path" "strings" + "github.com/rancher/os/log" + yaml "github.com/cloudfoundry-incubator/candiedyaml" - "github.com/Sirupsen/logrus" "github.com/packethost/packngo/metadata" - "github.com/rancher/netconf" - rancherConfig "github.com/rancher/os/config" + "github.com/rancher/os/config" + "github.com/rancher/os/netconf" ) -func enablePacketNetwork(cfg *rancherConfig.RancherConfig) { +func enablePacketNetwork(cfg *config.RancherConfig) { bootStrapped := false for _, v := range cfg.Network.Interfaces { if v.Address != "" { if err := netconf.ApplyNetworkConfigs(&cfg.Network); err != nil { - logrus.Errorf("Failed to bootstrap network: %v", err) + log.Errorf("Failed to bootstrap network: %v", err) return } bootStrapped = true @@ -36,11 +37,11 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) { c := metadata.NewClient(http.DefaultClient) m, err := c.Metadata.Get() if err != nil { - logrus.Errorf("Failed to get Packet metadata: %v", err) + log.Errorf("Failed to get Packet metadata: %v", err) return } - bondCfg := netconf.InterfaceConfig{ + bondCfg := config.InterfaceConfig{ Addresses: []string{}, BondOpts: map[string]string{ "lacp_rate": "1", @@ -51,11 +52,11 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) { "mode": "4", }, } - netCfg := netconf.NetworkConfig{ - Interfaces: map[string]netconf.InterfaceConfig{}, + netCfg := config.NetworkConfig{ + Interfaces: map[string]config.InterfaceConfig{}, } for _, iface := range m.Network.Interfaces { - netCfg.Interfaces["mac="+iface.Mac] = netconf.InterfaceConfig{ + netCfg.Interfaces["mac="+iface.Mac] = config.InterfaceConfig{ Bond: "bond0", } } @@ -78,26 +79,26 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) { netCfg.Interfaces["bond0"] = bondCfg b, _ := yaml.Marshal(netCfg) - logrus.Debugf("Generated network config: %s", string(b)) + log.Debugf("Generated network config: %s", string(b)) - cc := rancherConfig.CloudConfig{ - Rancher: rancherConfig.RancherConfig{ + cc := config.CloudConfig{ + Rancher: config.RancherConfig{ Network: netCfg, }, } // Post to phone home URL on first boot - if _, err = os.Stat(rancherConfig.CloudConfigNetworkFile); err != nil { + if _, err = os.Stat(config.CloudConfigNetworkFile); err != nil { if _, err = http.Post(m.PhoneHomeURL, "application/json", bytes.NewReader([]byte{})); err != nil { - logrus.Errorf("Failed to post to Packet phone home URL: %v", err) + log.Errorf("Failed to post to Packet phone home URL: %v", err) } } - if err := os.MkdirAll(path.Dir(rancherConfig.CloudConfigNetworkFile), 0700); err != nil { - logrus.Errorf("Failed to create directory for file %s: %v", rancherConfig.CloudConfigNetworkFile, err) + if err := os.MkdirAll(path.Dir(config.CloudConfigNetworkFile), 0700); err != nil { + log.Errorf("Failed to create directory for file %s: %v", config.CloudConfigNetworkFile, err) } - if err := rancherConfig.WriteToFile(cc, rancherConfig.CloudConfigNetworkFile); err != nil { - logrus.Errorf("Failed to save config file %s: %v", rancherConfig.CloudConfigNetworkFile, err) + if err := config.WriteToFile(cc, config.CloudConfigNetworkFile); err != nil { + log.Errorf("Failed to save config file %s: %v", config.CloudConfigNetworkFile, err) } } diff --git a/cmd/control/bootstrap.go b/cmd/control/bootstrap.go new file mode 100644 index 00000000..7d322567 --- /dev/null +++ b/cmd/control/bootstrap.go @@ -0,0 +1,109 @@ +package control + +import ( + "io/ioutil" + "os" + "os/exec" + "strings" + "time" + + "github.com/codegangsta/cli" + + "github.com/rancher/os/config" + "github.com/rancher/os/log" + "github.com/rancher/os/util" +) + +func bootstrapAction(c *cli.Context) error { + if err := UdevSettle(); err != nil { + log.Errorf("Failed to run udev settle: %v", err) + } + + cfg := config.LoadConfig() + + if cfg.Rancher.State.MdadmScan { + if err := mdadmScan(); err != nil { + log.Errorf("Failed to run mdadm scan: %v", err) + } + } + + stateScript := cfg.Rancher.State.Script + if stateScript != "" { + if err := runStateScript(stateScript); err != nil { + log.Errorf("Failed to run state script: %v", err) + } + } + + util.RunCommandSequence(cfg.Bootcmd) + + if cfg.Rancher.State.Dev != "" && cfg.Rancher.State.Wait { + waitForRoot(cfg) + } + + autoformatDevices := cfg.Rancher.State.Autoformat + if len(autoformatDevices) > 0 { + if err := autoformat(autoformatDevices); err != nil { + log.Errorf("Failed to run autoformat: %v", err) + } + } + + if err := UdevSettle(); err != nil { + log.Errorf("Failed to run udev settle: %v", err) + } + + return nil +} + +func mdadmScan() error { + cmd := exec.Command("mdadm", "--assemble", "--scan") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func runStateScript(script string) error { + f, err := ioutil.TempFile("", "") + if err != nil { + return err + } + if _, err := f.WriteString(script); err != nil { + return err + } + if err := f.Chmod(os.ModePerm); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + return util.RunScript(f.Name()) +} + +func waitForRoot(cfg *config.CloudConfig) { + var dev string + for i := 0; i < 30; i++ { + dev = util.ResolveDevice(cfg.Rancher.State.Dev) + if dev != "" { + break + } + time.Sleep(time.Millisecond * 1000) + } + if dev == "" { + return + } + for i := 0; i < 30; i++ { + if _, err := os.Stat(dev); err == nil { + break + } + time.Sleep(time.Millisecond * 1000) + } +} + +func autoformat(autoformatDevices []string) error { + cmd := exec.Command("/usr/sbin/auto-format.sh") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = []string{ + "AUTOFORMAT=" + strings.Join(autoformatDevices, " "), + } + return cmd.Run() +} diff --git a/cmd/control/cli.go b/cmd/control/cli.go index e09bb52f..048ba747 100644 --- a/cmd/control/cli.go +++ b/cmd/control/cli.go @@ -3,17 +3,19 @@ package control import ( "os" - log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/rancher/os/cmd/control/service" "github.com/rancher/os/config" + "github.com/rancher/os/log" ) func Main() { + log.InitLogger() app := cli.NewApp() app.Name = os.Args[0] app.Usage = "Control and configure RancherOS" - app.Version = config.VERSION + app.Version = config.Version app.Author = "Rancher Labs, Inc." app.EnableBashCompletion = true app.Before = func(c *cli.Context) error { @@ -24,6 +26,13 @@ func Main() { } app.Commands = []cli.Command{ + { + Name: "bootstrap", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: bootstrapAction, + }, { Name: "config", ShortName: "c", @@ -37,14 +46,27 @@ func Main() { HideHelp: true, Subcommands: consoleSubcommands(), }, + { + Name: "console-init", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: consoleInitAction, + }, { Name: "dev", - ShortName: "d", - Usage: "dev spec", + Hidden: true, HideHelp: true, SkipFlagParsing: true, Action: devAction, }, + { + Name: "docker-init", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: dockerInitAction, + }, { Name: "engine", Usage: "manage which Docker engine is used", @@ -53,31 +75,59 @@ func Main() { }, { Name: "entrypoint", + Hidden: true, HideHelp: true, SkipFlagParsing: true, Action: entrypointAction, }, { Name: "env", - ShortName: "e", - Usage: "env command", + Hidden: true, HideHelp: true, SkipFlagParsing: true, Action: envAction, }, - serviceCommand(), + service.Commands(), { Name: "os", Usage: "operating system upgrade/downgrade", HideHelp: true, Subcommands: osSubcommands(), }, + { + Name: "preload-images", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: preloadImagesAction, + }, + { + Name: "switch-console", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: switchConsoleAction, + }, { Name: "tls", Usage: "setup tls configuration", HideHelp: true, Subcommands: tlsConfCommands(), }, + { + Name: "udev-settle", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: udevSettleAction, + }, + { + Name: "user-docker", + Hidden: true, + HideHelp: true, + SkipFlagParsing: true, + Action: userDockerAction, + }, installCommand, selinuxCommand(), } diff --git a/cmd/control/config.go b/cmd/control/config.go index 01b45b69..334ae3ae 100644 --- a/cmd/control/config.go +++ b/cmd/control/config.go @@ -9,8 +9,8 @@ import ( "strings" "text/template" - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/rancher/os/log" "github.com/codegangsta/cli" "github.com/rancher/os/config" @@ -76,6 +76,17 @@ func configSubcommands() []cli.Command { }, }, }, + { + Name: "validate", + Usage: "validate configuration from stdin", + Action: validate, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "input, i", + Usage: "File from which to read", + }, + }, + }, } } @@ -85,9 +96,6 @@ func imagesFromConfig(cfg *config.CloudConfig) []string { for _, service := range cfg.Rancher.BootstrapContainers { imagesMap[service.Image] = 1 } - for _, service := range cfg.Rancher.Autoformat { - imagesMap[service.Image] = 1 - } for _, service := range cfg.Rancher.Services { imagesMap[service.Image] = 1 } @@ -96,7 +104,7 @@ func imagesFromConfig(cfg *config.CloudConfig) []string { i := 0 for image := range imagesMap { images[i] = image - i += 1 + i++ } sort.Strings(images) return images @@ -186,18 +194,7 @@ func configGet(c *cli.Context) error { } func merge(c *cli.Context) error { - input := os.Stdin - inputFile := c.String("input") - if inputFile != "" { - var err error - input, err = os.Open(inputFile) - if err != nil { - log.Fatal(err) - } - defer input.Close() - } - - bytes, err := ioutil.ReadAll(input) + bytes, err := inputBytes(c) if err != nil { log.Fatal(err) } @@ -227,3 +224,32 @@ func export(c *cli.Context) error { return nil } + +func validate(c *cli.Context) error { + bytes, err := inputBytes(c) + if err != nil { + log.Fatal(err) + } + validationErrors, err := config.Validate(bytes) + if err != nil { + log.Fatal(err) + } + for _, validationError := range validationErrors.Errors() { + log.Error(validationError) + } + return nil +} + +func inputBytes(c *cli.Context) ([]byte, error) { + input := os.Stdin + inputFile := c.String("input") + if inputFile != "" { + var err error + input, err = os.Open(inputFile) + if err != nil { + return nil, err + } + defer input.Close() + } + return ioutil.ReadAll(input) +} diff --git a/cmd/control/console.go b/cmd/control/console.go index 61eee2df..ac18bed5 100644 --- a/cmd/control/console.go +++ b/cmd/control/console.go @@ -1,21 +1,19 @@ package control import ( - "bufio" "fmt" "io/ioutil" - "os" "sort" "strings" "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" composeConfig "github.com/docker/libcompose/config" "github.com/docker/libcompose/project/options" "github.com/rancher/os/compose" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util/network" ) @@ -61,12 +59,11 @@ func consoleSwitch(c *cli.Context) error { } if !c.Bool("force") { - in := bufio.NewReader(os.Stdin) fmt.Println(`Switching consoles will 1. destroy the current console container 2. log you out 3. restart Docker`) - if !yes(in, "Continue") { + if !yes("Continue") { return nil } } @@ -82,11 +79,11 @@ func consoleSwitch(c *cli.Context) error { Privileged: true, Net: "host", Pid: "host", - Image: config.OS_BASE, + Image: config.OsBase, Labels: map[string]string{ - config.SCOPE: config.SYSTEM, + config.ScopeLabel: config.System, }, - Command: []string{"/usr/bin/switch-console", newConsole}, + Command: []string{"/usr/bin/ros", "switch-console", newConsole}, VolumesFrom: []string{"all-volumes"}, }) if err != nil { diff --git a/cmd/console/console.go b/cmd/control/console_init.go similarity index 79% rename from cmd/console/console.go rename to cmd/control/console_init.go index c8547286..759527e3 100644 --- a/cmd/console/console.go +++ b/cmd/control/console_init.go @@ -1,4 +1,4 @@ -package console +package control import ( "bytes" @@ -11,9 +11,10 @@ import ( "strings" "syscall" - log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" "github.com/rancher/os/cmd/cloudinitexecute" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util" ) @@ -29,7 +30,7 @@ type symlink struct { oldname, newname string } -func Main() { +func consoleInitAction(c *cli.Context) error { cfg := config.LoadConfig() if _, err := os.Stat(rancherHome); os.IsNotExist(err) { @@ -74,10 +75,6 @@ func Main() { log.Error(err) } - if err := writeOsRelease(); err != nil { - log.Error(err) - } - for _, link := range []symlink{ {"/var/lib/rancher/engine/docker", "/usr/bin/docker"}, {"/var/lib/rancher/engine/docker-containerd", "/usr/bin/docker-containerd"}, @@ -86,6 +83,8 @@ func Main() { {"/var/lib/rancher/engine/dockerd", "/usr/bin/dockerd"}, {"/var/lib/rancher/engine/docker-proxy", "/usr/bin/docker-proxy"}, {"/var/lib/rancher/engine/docker-runc", "/usr/bin/docker-runc"}, + {"/usr/share/rancher/os-release", "/usr/lib/os-release"}, + {"/usr/share/rancher/os-release", "/etc/os-release"}, } { syscall.Unlink(link.newname) if err := os.Symlink(link.oldname, link.newname); err != nil { @@ -105,10 +104,10 @@ func Main() { cloudinitexecute.ApplyConsole(cfg) - if err := runScript(config.CloudConfigScriptFile); err != nil { + if err := util.RunScript(config.CloudConfigScriptFile); err != nil { log.Error(err) } - if err := runScript(startScript); err != nil { + if err := util.RunScript(startScript); err != nil { log.Error(err) } @@ -116,7 +115,7 @@ func Main() { log.Error(err) } - if err := runScript("/etc/rc.local"); err != nil { + if err := util.RunScript("/etc/rc.local"); err != nil { log.Error(err) } @@ -124,10 +123,10 @@ func Main() { respawnBinPath, err := exec.LookPath("respawn") if err != nil { - log.Fatal(err) + return err } - log.Fatal(syscall.Exec(respawnBinPath, []string{"respawn", "-f", "/etc/respawn.conf"}, os.Environ())) + return syscall.Exec(respawnBinPath, []string{"respawn", "-f", "/etc/respawn.conf"}, os.Environ()) } func generateRespawnConf(cmdline string) string { @@ -211,33 +210,6 @@ func modifySshdConfig() error { return ioutil.WriteFile("/etc/ssh/sshd_config", []byte(sshdConfigString), 0644) } -func writeOsRelease() error { - idLike := "busybox" - if osRelease, err := ioutil.ReadFile("/etc/os-release"); err == nil { - for _, line := range strings.Split(string(osRelease), "\n") { - if strings.HasPrefix(line, "ID_LIKE") { - split := strings.Split(line, "ID_LIKE") - if len(split) > 1 { - idLike = split[1] - } - } - } - } - - return ioutil.WriteFile("/etc/os-release", []byte(fmt.Sprintf(` -NAME="RancherOS" -VERSION=%s -ID=rancheros -ID_LIKE=%s -VERSION_ID=%s -PRETTY_NAME="RancherOS %s" -HOME_URL= -SUPPORT_URL= -BUG_REPORT_URL= -BUILD_ID= -`, config.VERSION, idLike, config.VERSION, config.VERSION)), 0644) -} - func setupSSH(cfg *config.CloudConfig) error { for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} { outputFile := fmt.Sprintf("/etc/ssh/ssh_host_%s_key", keyType) @@ -247,8 +219,8 @@ func setupSSH(cfg *config.CloudConfig) error { continue } - saved, savedExists := cfg.Rancher.Ssh.Keys[keyType] - pub, pubExists := cfg.Rancher.Ssh.Keys[keyType+"-pub"] + saved, savedExists := cfg.Rancher.SSH.Keys[keyType] + pub, pubExists := cfg.Rancher.SSH.Keys[keyType+"-pub"] if savedExists && pubExists { // TODO check permissions @@ -282,29 +254,3 @@ func setupSSH(cfg *config.CloudConfig) error { return os.MkdirAll("/var/run/sshd", 0644) } - -func runScript(path string) error { - if !util.ExistsAndExecutable(path) { - return nil - } - - script, err := os.Open(path) - if err != nil { - return err - } - - magic := make([]byte, 2) - if _, err = script.Read(magic); err != nil { - return err - } - - cmd := exec.Command("/bin/sh", path) - if string(magic) == "#!" { - cmd = exec.Command(path) - } - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - return cmd.Run() -} diff --git a/cmd/dockerinit/main.go b/cmd/control/docker_init.go similarity index 80% rename from cmd/dockerinit/main.go rename to cmd/control/docker_init.go index 47ae56ac..44c48ec0 100644 --- a/cmd/dockerinit/main.go +++ b/cmd/control/docker_init.go @@ -1,4 +1,4 @@ -package dockerinit +package control import ( "fmt" @@ -9,19 +9,19 @@ import ( "syscall" "time" - log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util" ) const ( - consoleDone = "/run/console-done" - dockerConf = "/var/lib/rancher/conf/docker" - dockerDone = "/run/docker-done" - dockerLog = "/var/log/docker.log" + dockerConf = "/var/lib/rancher/conf/docker" + dockerDone = "/run/docker-done" + dockerLog = "/var/log/docker.log" ) -func Main() { +func dockerInitAction(c *cli.Context) error { for { if _, err := os.Stat(consoleDone); err == nil { break @@ -54,7 +54,7 @@ func Main() { mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo") if err != nil { - log.Fatal(err) + return err } for _, mount := range strings.Split(string(mountInfo), "\n") { @@ -66,7 +66,7 @@ func Main() { args := []string{ "bash", "-c", - fmt.Sprintf(`[ -e %s ] && source %s; exec /usr/bin/dockerlaunch %s %s $DOCKER_OPTS >> %s 2>&1`, dockerConf, dockerConf, dockerBin, strings.Join(os.Args[1:], " "), dockerLog), + fmt.Sprintf(`[ -e %s ] && source %s; exec /usr/bin/dockerlaunch %s %s $DOCKER_OPTS >> %s 2>&1`, dockerConf, dockerConf, dockerBin, strings.Join(c.Args(), " "), dockerLog), } cfg := config.LoadConfig() @@ -75,5 +75,5 @@ func Main() { log.Error(err) } - log.Fatal(syscall.Exec("/bin/bash", args, os.Environ())) + return syscall.Exec("/bin/bash", args, os.Environ()) } diff --git a/cmd/control/engine.go b/cmd/control/engine.go index 7e100afc..5ccdf916 100644 --- a/cmd/control/engine.go +++ b/cmd/control/engine.go @@ -8,18 +8,14 @@ import ( "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/libcompose/project/options" "github.com/rancher/os/compose" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util/network" ) -const ( - dockerDone = "/run/docker-done" -) - func engineSubcommands() []cli.Command { return []cli.Command{ { diff --git a/cmd/control/entrypoint.go b/cmd/control/entrypoint.go index d0cf05b2..32df1187 100644 --- a/cmd/control/entrypoint.go +++ b/cmd/control/entrypoint.go @@ -5,8 +5,8 @@ import ( "os/exec" "syscall" - log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/rancher/os/log" "golang.org/x/net/context" "github.com/rancher/os/cmd/cloudinitexecute" @@ -45,6 +45,8 @@ func entrypointAction(c *cli.Context) error { writeFiles(cfg) } + setupPowerOperations() + if len(os.Args) < 3 { return nil } @@ -58,7 +60,7 @@ func entrypointAction(c *cli.Context) error { } func writeFiles(cfg *config.CloudConfig) error { - id, err := util.GetCurrentContainerId() + id, err := util.GetCurrentContainerID() if err != nil { return err } @@ -74,3 +76,29 @@ func writeFiles(cfg *config.CloudConfig) error { cloudinitexecute.WriteFiles(cfg, info.Name[1:]) return nil } + +func setupPowerOperations() { + for _, powerOperation := range []string{ + "/sbin/poweroff", + "/sbin/shutdown", + "/sbin/reboot", + "/sbin/halt", + "/usr/sbin/poweroff", + "/usr/sbin/shutdown", + "/usr/sbin/reboot", + "/usr/sbin/halt", + } { + os.Remove(powerOperation) + } + + for _, link := range []symlink{ + {config.RosBin, "/sbin/poweroff"}, + {config.RosBin, "/sbin/reboot"}, + {config.RosBin, "/sbin/halt"}, + {config.RosBin, "/sbin/shutdown"}, + } { + if err := os.Symlink(link.oldname, link.newname); err != nil { + log.Error(err) + } + } +} diff --git a/cmd/control/install.go b/cmd/control/install.go index d26f8191..669c7be3 100644 --- a/cmd/control/install.go +++ b/cmd/control/install.go @@ -1,13 +1,12 @@ package control import ( - "bufio" "fmt" "os" "os/exec" "strings" - log "github.com/Sirupsen/logrus" + "github.com/rancher/os/log" "github.com/codegangsta/cli" "github.com/rancher/os/cmd/power" @@ -22,8 +21,10 @@ var installCommand = cli.Command{ Action: installAction, Flags: []cli.Flag{ cli.StringFlag{ - Name: "image, i", - Usage: "install from a certain image", + // TODO: need to validate ? -i rancher/os:v0.3.1 just sat there. + Name: "image, i", + Usage: `install from a certain image (e.g., 'rancher/os:v0.7.0') + use 'ros os list' to see what versions are available.`, }, cli.StringFlag{ Name: "install-type, t", @@ -65,7 +66,7 @@ func installAction(c *cli.Context) error { image := c.String("image") cfg := config.LoadConfig() if image == "" { - image = cfg.Rancher.Upgrade.Image + ":" + config.VERSION + config.SUFFIX + image = cfg.Rancher.Upgrade.Image + ":" + config.Version + config.Suffix } installType := c.String("install-type") @@ -97,12 +98,10 @@ func installAction(c *cli.Context) error { } func runInstall(image, installType, cloudConfig, device, append string, force, reboot bool) error { - in := bufio.NewReader(os.Stdin) - fmt.Printf("Installing from %s\n", image) if !force { - if !yes(in, "Continue") { + if !yes("Continue") { os.Exit(1) } } @@ -122,7 +121,7 @@ func runInstall(image, installType, cloudConfig, device, append string, force, r return err } - if reboot && (force || yes(in, "Continue with reboot")) { + if reboot && (force || yes("Continue with reboot")) { log.Info("Rebooting") power.Reboot() } diff --git a/cmd/control/os.go b/cmd/control/os.go index 992e5d9b..7086e19e 100644 --- a/cmd/control/os.go +++ b/cmd/control/os.go @@ -1,7 +1,6 @@ package control import ( - "bufio" "fmt" "io/ioutil" "net/http" @@ -11,8 +10,8 @@ import ( "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/rancher/os/log" "github.com/codegangsta/cli" dockerClient "github.com/docker/engine-api/client" @@ -79,31 +78,32 @@ func osSubcommands() []cli.Command { } } +// TODO: this and the getLatestImage should probably move to utils/network and be suitably cached. func getImages() (*Images, error) { - upgradeUrl, err := getUpgradeUrl() + upgradeURL, err := getUpgradeURL() if err != nil { return nil, err } var body []byte - if strings.HasPrefix(upgradeUrl, "/") { - body, err = ioutil.ReadFile(upgradeUrl) + if strings.HasPrefix(upgradeURL, "/") { + body, err = ioutil.ReadFile(upgradeURL) if err != nil { return nil, err } } else { - u, err := url.Parse(upgradeUrl) + u, err := url.Parse(upgradeURL) if err != nil { return nil, err } q := u.Query() - q.Set("current", config.VERSION) + q.Set("current", config.Version) u.RawQuery = q.Encode() - upgradeUrl = u.String() + upgradeURL = u.String() - resp, err := http.Get(upgradeUrl) + resp, err := http.Get(upgradeURL) if err != nil { return nil, err } @@ -128,13 +128,30 @@ func osMetaDataGet(c *cli.Context) error { log.Fatal(err) } - for _, image := range images.Available { + cfg := config.LoadConfig() + runningName := cfg.Rancher.Upgrade.Image + ":" + config.Version + + foundRunning := false + for i := len(images.Available) - 1; i >= 0; i-- { + image := images.Available[i] _, _, err := client.ImageInspectWithRaw(context.Background(), image, false) + local := "local" if dockerClient.IsErrImageNotFound(err) { - fmt.Println(image, "remote") - } else { - fmt.Println(image, "local") + local = "remote" } + available := "available" + if image == images.Current { + available = "latest" + } + var running string + if image == runningName { + foundRunning = true + running = "running" + } + fmt.Println(image, local, available, running) + } + if !foundRunning { + fmt.Println(config.Version, "running") } return nil @@ -173,16 +190,14 @@ func osUpgrade(c *cli.Context) error { } func osVersion(c *cli.Context) error { - fmt.Println(config.VERSION) + fmt.Println(config.Version) return nil } func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgradeConsole bool, kernelArgs string) error { - in := bufio.NewReader(os.Stdin) - command := []string{ "-t", "rancher-upgrade", - "-r", config.VERSION, + "-r", config.Version, } if kexec { @@ -203,10 +218,10 @@ func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgra fmt.Printf("Upgrading to %s\n", image) confirmation := "Continue" imageSplit := strings.Split(image, ":") - if len(imageSplit) > 1 && imageSplit[1] == config.VERSION+config.SUFFIX { + if len(imageSplit) > 1 && imageSplit[1] == config.Version+config.Suffix { confirmation = fmt.Sprintf("Already at version %s. Continue anyway", imageSplit[1]) } - if !force && !yes(in, confirmation) { + if !force && !yes(confirmation) { os.Exit(1) } @@ -217,7 +232,7 @@ func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgra Pid: "host", Image: image, Labels: map[string]string{ - config.SCOPE: config.SYSTEM, + config.ScopeLabel: config.System, }, Command: command, }) @@ -256,7 +271,7 @@ func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgra return err } - if reboot && (force || yes(in, "Continue with reboot")) { + if reboot && (force || yes("Continue with reboot")) { log.Info("Rebooting") power.Reboot() } @@ -275,7 +290,7 @@ func parseBody(body []byte) (*Images, error) { return update, nil } -func getUpgradeUrl() (string, error) { +func getUpgradeURL() (string, error) { cfg := config.LoadConfig() - return cfg.Rancher.Upgrade.Url, nil + return cfg.Rancher.Upgrade.URL, nil } diff --git a/cmd/control/preload.go b/cmd/control/preload.go new file mode 100644 index 00000000..609cf49b --- /dev/null +++ b/cmd/control/preload.go @@ -0,0 +1,106 @@ +package control + +import ( + "compress/gzip" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "regexp" + "strings" + + "github.com/codegangsta/cli" + + dockerClient "github.com/docker/engine-api/client" + "github.com/rancher/os/docker" + "github.com/rancher/os/log" +) + +const ( + userImagesPreloadDirectory = "/var/lib/rancher/preload/docker" +) + +func preloadImagesAction(c *cli.Context) error { + return PreloadImages(docker.NewDefaultClient, userImagesPreloadDirectory) +} + +func shouldLoad(file string) bool { + if strings.HasSuffix(file, ".done") { + return false + } + if _, err := os.Stat(fmt.Sprintf("%s.done", file)); err == nil { + return false + } + return true +} + +func PreloadImages(clientFactory func() (dockerClient.APIClient, error), imagesDir string) error { + var client dockerClient.APIClient + clientInitialized := false + + if _, err := os.Stat(imagesDir); os.IsNotExist(err) { + if err = os.MkdirAll(imagesDir, 0755); err != nil { + return err + } + } else if err != nil { + return err + } + + files, err := ioutil.ReadDir(imagesDir) + if err != nil { + return err + } + + for _, file := range files { + filename := path.Join(imagesDir, file.Name()) + if !shouldLoad(filename) { + continue + } + + image, err := os.Open(filename) + if err != nil { + return err + } + var imageReader io.Reader + imageReader = image + match, err := regexp.MatchString(".t?gz$", file.Name()) + if err != nil { + return err + } + if match { + imageReader, err = gzip.NewReader(image) + if err != nil { + return err + } + } + + if !clientInitialized { + client, err = clientFactory() + if err != nil { + return err + } + clientInitialized = true + } + + log.Infof("Loading image %s", filename) + if _, err = client.ImageLoad(context.Background(), imageReader, false); err != nil { + return err + } + + if err = image.Close(); err != nil { + return err + } + + doneStamp, err := os.Create(fmt.Sprintf("%s.done", filename)) + if err != nil { + return err + } + if err = doneStamp.Close(); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/control/selinux.go b/cmd/control/selinux.go index 8b3b3912..44bdfd1d 100644 --- a/cmd/control/selinux.go +++ b/cmd/control/selinux.go @@ -50,7 +50,7 @@ func selinuxCommand() cli.Command { "-v", "/etc/selinux:/etc/selinux", "-v", "/var/lib/selinux:/var/lib/selinux", "-v", "/usr/share/selinux:/usr/share/selinux", - fmt.Sprintf("%s/os-selinuxtools:%s%s", config.OS_REPO, config.VERSION, config.SUFFIX), "bash"} + fmt.Sprintf("%s/os-selinuxtools:%s%s", config.OsRepo, config.Version, config.Suffix), "bash"} syscall.Exec("/bin/system-docker", argv, []string{}) return nil } diff --git a/cmd/control/service/app/app.go b/cmd/control/service/app/app.go new file mode 100644 index 00000000..dc2e8414 --- /dev/null +++ b/cmd/control/service/app/app.go @@ -0,0 +1,180 @@ +package app + +import ( + "fmt" + "os" + "os/signal" + "strings" + "syscall" + + "github.com/rancher/os/log" + "golang.org/x/net/context" + + "github.com/codegangsta/cli" + "github.com/docker/libcompose/project" + "github.com/docker/libcompose/project/options" +) + +func ProjectPs(p project.APIProject, c *cli.Context) error { + qFlag := c.Bool("q") + allInfo, err := p.Ps(context.Background(), qFlag, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + os.Stdout.WriteString(allInfo.String(!qFlag)) + return nil +} + +func ProjectStop(p project.APIProject, c *cli.Context) error { + err := p.Stop(context.Background(), c.Int("timeout"), c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectDown(p project.APIProject, c *cli.Context) error { + options := options.Down{ + RemoveVolume: c.Bool("volumes"), + RemoveImages: options.ImageType(c.String("rmi")), + RemoveOrphans: c.Bool("remove-orphans"), + } + err := p.Down(context.Background(), options, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectBuild(p project.APIProject, c *cli.Context) error { + config := options.Build{ + NoCache: c.Bool("no-cache"), + ForceRemove: c.Bool("force-rm"), + Pull: c.Bool("pull"), + } + err := p.Build(context.Background(), config, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectCreate(p project.APIProject, c *cli.Context) error { + options := options.Create{ + NoRecreate: c.Bool("no-recreate"), + ForceRecreate: c.Bool("force-recreate"), + NoBuild: c.Bool("no-build"), + } + err := p.Create(context.Background(), options, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectUp(p project.APIProject, c *cli.Context) error { + options := options.Up{ + Create: options.Create{ + NoRecreate: c.Bool("no-recreate"), + ForceRecreate: c.Bool("force-recreate"), + NoBuild: c.Bool("no-build"), + }, + } + ctx, cancelFun := context.WithCancel(context.Background()) + err := p.Up(ctx, options, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + if c.Bool("foreground") { + signalChan := make(chan os.Signal, 1) + cleanupDone := make(chan bool) + signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) + errChan := make(chan error) + go func() { + errChan <- p.Log(ctx, true, c.Args()...) + }() + go func() { + select { + case <-signalChan: + fmt.Printf("\nGracefully stopping...\n") + cancelFun() + ProjectStop(p, c) + cleanupDone <- true + case err := <-errChan: + if err != nil { + log.Fatal(err) + } + cleanupDone <- true + } + }() + <-cleanupDone + return nil + } + return nil +} + +func ProjectStart(p project.APIProject, c *cli.Context) error { + err := p.Start(context.Background(), c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectRestart(p project.APIProject, c *cli.Context) error { + err := p.Restart(context.Background(), c.Int("timeout"), c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectLog(p project.APIProject, c *cli.Context) error { + err := p.Log(context.Background(), c.Bool("follow"), c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectPull(p project.APIProject, c *cli.Context) error { + err := p.Pull(context.Background(), c.Args()...) + if err != nil && !c.Bool("ignore-pull-failures") { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectDelete(p project.APIProject, c *cli.Context) error { + options := options.Delete{ + RemoveVolume: c.Bool("v"), + } + if !c.Bool("force") { + options.BeforeDeleteCallback = func(stoppedContainers []string) bool { + fmt.Printf("Going to remove %v\nAre you sure? [yN]\n", strings.Join(stoppedContainers, ", ")) + var answer string + _, err := fmt.Scanln(&answer) + if err != nil { + log.Error(err) + return false + } + if answer != "y" && answer != "Y" { + return false + } + return true + } + } + err := p.Delete(context.Background(), options, c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} + +func ProjectKill(p project.APIProject, c *cli.Context) error { + err := p.Kill(context.Background(), c.String("signal"), c.Args()...) + if err != nil { + return cli.NewExitError(err.Error(), 1) + } + return nil +} diff --git a/cmd/control/service/command/command.go b/cmd/control/service/command/command.go new file mode 100644 index 00000000..2db8d38d --- /dev/null +++ b/cmd/control/service/command/command.go @@ -0,0 +1,243 @@ +package command + +import ( + "errors" + + "github.com/codegangsta/cli" + composeApp "github.com/docker/libcompose/cli/app" + "github.com/rancher/os/cmd/control/service/app" +) + +func verifyOneOrMoreServices(c *cli.Context) error { + if len(c.Args()) == 0 { + return errors.New("Must specify one or more services") + } + return nil +} + +func CreateCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "create", + Usage: "Create services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectCreate), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "no-recreate", + Usage: "If containers already exist, don't recreate them. Incompatible with --force-recreate.", + }, + cli.BoolFlag{ + Name: "force-recreate", + Usage: "Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.", + }, + cli.BoolFlag{ + Name: "no-build", + Usage: "Don't build an image, even if it's missing.", + }, + }, + } +} + +func BuildCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "build", + Usage: "Build or rebuild services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectBuild), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "no-cache", + Usage: "Do not use cache when building the image", + }, + cli.BoolFlag{ + Name: "force-rm", + Usage: "Always remove intermediate containers", + }, + cli.BoolFlag{ + Name: "pull", + Usage: "Always attempt to pull a newer version of the image", + }, + }, + } +} + +func PsCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "ps", + Usage: "List containers", + Action: composeApp.WithProject(factory, app.ProjectPs), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "q", + Usage: "Only display IDs", + }, + }, + } +} + +func UpCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "up", + Usage: "Create and start containers", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectUp), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "foreground", + Usage: "Run in foreground and log", + }, + cli.BoolFlag{ + Name: "no-build", + Usage: "Don't build an image, even if it's missing.", + }, + cli.BoolFlag{ + Name: "no-recreate", + Usage: "If containers already exist, don't recreate them. Incompatible with --force-recreate.", + }, + cli.BoolFlag{ + Name: "force-recreate", + Usage: "Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.", + }, + }, + } +} + +func StartCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "start", + Usage: "Start services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectStart), + Flags: []cli.Flag{ + cli.BoolTFlag{ + Name: "foreground", + Usage: "Run in foreground and log", + }, + }, + } +} + +func PullCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "pull", + Usage: "Pulls service images", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectPull), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "ignore-pull-failures", + Usage: "Pull what it can and ignores images with pull failures.", + }, + }, + } +} + +func LogsCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "logs", + Usage: "View output from containers", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectLog), + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "lines", + Usage: "number of lines to tail", + Value: 100, + }, + cli.BoolFlag{ + Name: "follow", + Usage: "Follow log output.", + }, + }, + } +} + +func RestartCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "restart", + Usage: "Restart services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectRestart), + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "timeout,t", + Usage: "Specify a shutdown timeout in seconds.", + Value: 10, + }, + }, + } +} + +func StopCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "stop", + Usage: "Stop services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectStop), + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "timeout,t", + Usage: "Specify a shutdown timeout in seconds.", + Value: 10, + }, + }, + } +} + +func DownCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "down", + Usage: "Stop and remove containers, networks, images, and volumes", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectDown), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "volumes,v", + Usage: "Remove data volumes", + }, + cli.StringFlag{ + Name: "rmi", + Usage: "Remove images, type may be one of: 'all' to remove all images, or 'local' to remove only images that don't have an custom name set by the `image` field", + }, + cli.BoolFlag{ + Name: "remove-orphans", + Usage: "Remove containers for services not defined in the Compose file", + }, + }, + } +} + +func RmCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "rm", + Usage: "Delete services", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectDelete), + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "force,f", + Usage: "Allow deletion of all services", + }, + cli.BoolFlag{ + Name: "v", + Usage: "Remove volumes associated with containers", + }, + }, + } +} + +func KillCommand(factory composeApp.ProjectFactory) cli.Command { + return cli.Command{ + Name: "kill", + Usage: "Kill containers", + Before: verifyOneOrMoreServices, + Action: composeApp.WithProject(factory, app.ProjectKill), + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "signal,s", + Usage: "SIGNAL to send to the container", + Value: "SIGKILL", + }, + }, + } +} diff --git a/cmd/control/service.go b/cmd/control/service/service.go similarity index 87% rename from cmd/control/service.go rename to cmd/control/service/service.go index b681804c..da98e037 100644 --- a/cmd/control/service.go +++ b/cmd/control/service/service.go @@ -1,16 +1,16 @@ -package control +package service import ( "fmt" "strings" - "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - "github.com/docker/libcompose/cli/command" dockerApp "github.com/docker/libcompose/cli/docker/app" "github.com/docker/libcompose/project" + "github.com/rancher/os/cmd/control/service/command" "github.com/rancher/os/compose" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util/network" ) @@ -24,12 +24,12 @@ func (p *projectFactory) Create(c *cli.Context) (project.APIProject, error) { func beforeApp(c *cli.Context) error { if c.GlobalBool("verbose") { - logrus.SetLevel(logrus.DebugLevel) + log.SetLevel(log.DebugLevel) } return nil } -func serviceCommand() cli.Command { +func Commands() cli.Command { factory := &projectFactory{} app := cli.Command{} @@ -37,7 +37,9 @@ func serviceCommand() cli.Command { app.ShortName = "s" app.Usage = "Command line interface for services and compose." app.Before = beforeApp - app.Flags = append(command.CommonFlags(), dockerApp.DockerClientFlags()...) + app.Flags = append(dockerApp.DockerClientFlags(), cli.BoolFlag{ + Name: "verbose,debug", + }) app.Subcommands = append(serviceSubCommands(), command.BuildCommand(factory), command.CreateCommand(factory), @@ -46,11 +48,9 @@ func serviceCommand() cli.Command { command.LogsCommand(factory), command.RestartCommand(factory), command.StopCommand(factory), - command.ScaleCommand(factory), command.RmCommand(factory), command.PullCommand(factory), command.KillCommand(factory), - command.PortCommand(factory), command.PsCommand(factory), ) @@ -101,7 +101,7 @@ func disable(c *cli.Context) error { if changed { if err := updateIncludedServices(cfg); err != nil { - logrus.Fatal(err) + log.Fatal(err) } } @@ -122,7 +122,7 @@ func del(c *cli.Context) error { if changed { if err := updateIncludedServices(cfg); err != nil { - logrus.Fatal(err) + log.Fatal(err) } } @@ -137,7 +137,7 @@ func enable(c *cli.Context) error { for _, service := range c.Args() { if val, ok := cfg.Rancher.ServicesInclude[service]; !ok || !val { if strings.HasPrefix(service, "/") && !strings.HasPrefix(service, "/var/lib/rancher/conf") { - logrus.Fatalf("ERROR: Service should be in path /var/lib/rancher/conf") + log.Fatalf("ERROR: Service should be in path /var/lib/rancher/conf") } cfg.Rancher.ServicesInclude[service] = true @@ -147,11 +147,11 @@ func enable(c *cli.Context) error { if len(enabledServices) > 0 { if err := compose.StageServices(cfg, enabledServices...); err != nil { - logrus.Fatal(err) + log.Fatal(err) } if err := updateIncludedServices(cfg); err != nil { - logrus.Fatal(err) + log.Fatal(err) } } @@ -168,7 +168,7 @@ func list(c *cli.Context) error { services, err := network.GetServices(cfg.Rancher.Repositories.ToArray()) if err != nil { - logrus.Fatalf("Failed to get services: %v", err) + log.Fatalf("Failed to get services: %v", err) } for _, service := range services { diff --git a/cmd/switchconsole/switch_console.go b/cmd/control/switch_console.go similarity index 71% rename from cmd/switchconsole/switch_console.go rename to cmd/control/switch_console.go index 71a45f0c..b4e1b712 100644 --- a/cmd/switchconsole/switch_console.go +++ b/cmd/control/switch_console.go @@ -1,31 +1,32 @@ -package switchconsole +package control import ( - "os" + "errors" - log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" "github.com/docker/libcompose/project/options" "github.com/rancher/os/compose" "github.com/rancher/os/config" + "github.com/rancher/os/log" "golang.org/x/net/context" ) -func Main() { - if len(os.Args) != 2 { - log.Fatal("Must specify exactly one existing container") +func switchConsoleAction(c *cli.Context) error { + if len(c.Args()) != 1 { + return errors.New("Must specify exactly one existing container") } - newConsole := os.Args[1] + newConsole := c.Args()[0] cfg := config.LoadConfig() project, err := compose.GetProject(cfg, true, false) if err != nil { - log.Fatal(err) + return err } if newConsole != "default" { if err = compose.LoadSpecialService(project, cfg, "console", newConsole); err != nil { - log.Fatal(err) + return err } } @@ -36,10 +37,12 @@ func Main() { if err = project.Up(context.Background(), options.Up{ Log: true, }, "console"); err != nil { - log.Fatal(err) + return err } if err = project.Restart(context.Background(), 10, "docker"); err != nil { log.Errorf("Failed to restart Docker: %v", err) } + + return nil } diff --git a/cmd/control/tlsconf.go b/cmd/control/tlsconf.go index f6c25791..df8a64cb 100644 --- a/cmd/control/tlsconf.go +++ b/cmd/control/tlsconf.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - log "github.com/Sirupsen/logrus" + "github.com/rancher/os/log" "github.com/codegangsta/cli" machineUtil "github.com/docker/machine/utils" @@ -16,8 +16,8 @@ import ( const ( NAME string = "rancher" BITS int = 2048 - ServerTlsPath string = "/etc/docker/tls" - ClientTlsPath string = "/home/rancher/.docker" + ServerTLSPath string = "/etc/docker/tls" + ClientTLSPath string = "/home/rancher/.docker" Cert string = "cert.pem" Key string = "key.pem" ServerCert string = "server-cert.pem" @@ -141,9 +141,9 @@ func generate(c *cli.Context) error { func Generate(generateServer bool, outDir string, hostnames []string) error { if outDir == "" { if generateServer { - outDir = ServerTlsPath + outDir = ServerTLSPath } else { - outDir = ClientTlsPath + outDir = ClientTLSPath } log.Infof("Out directory (-d, --dir) not specified, using default: %s", outDir) } diff --git a/cmd/control/udevsettle.go b/cmd/control/udevsettle.go new file mode 100644 index 00000000..1f378140 --- /dev/null +++ b/cmd/control/udevsettle.go @@ -0,0 +1,36 @@ +package control + +import ( + "os" + "os/exec" + + "github.com/codegangsta/cli" + "github.com/rancher/os/log" +) + +func udevSettleAction(c *cli.Context) { + if err := UdevSettle(); err != nil { + log.Fatal(err) + } +} + +func UdevSettle() error { + cmd := exec.Command("udevd", "--daemon") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + + cmd = exec.Command("udevadm", "trigger", "--action=add") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + + cmd = exec.Command("udevadm", "settle") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/cmd/userdocker/main.go b/cmd/control/user_docker.go similarity index 82% rename from cmd/userdocker/main.go rename to cmd/control/user_docker.go index f97b128c..da3e616c 100644 --- a/cmd/userdocker/main.go +++ b/cmd/control/user_docker.go @@ -1,4 +1,4 @@ -package userdocker +package control import ( "io" @@ -12,37 +12,43 @@ import ( "path/filepath" - log "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" composeClient "github.com/docker/libcompose/docker/client" "github.com/docker/libcompose/project" - "github.com/rancher/os/cmd/control" "github.com/rancher/os/compose" "github.com/rancher/os/config" rosDocker "github.com/rancher/os/docker" + "github.com/rancher/os/log" "github.com/rancher/os/util" ) const ( - DEFAULT_STORAGE_CONTEXT = "console" - DOCKER_PID_FILE = "/var/run/docker.pid" - DOCKER_COMMAND = "docker-init" - userDocker = "user-docker" - sourceDirectory = "/engine" - destDirectory = "/var/lib/rancher/engine" + defaultStorageContext = "console" + dockerPidFile = "/var/run/docker.pid" + userDocker = "user-docker" + sourceDirectory = "/engine" + destDirectory = "/var/lib/rancher/engine" ) -func Main() { +var ( + dockerCommand = []string{ + "ros", + "docker-init", + } +) + +func userDockerAction(c *cli.Context) error { if err := copyBinaries(sourceDirectory, destDirectory); err != nil { - log.Fatal(err) + return err } if err := syscall.Mount("/host/sys", "/sys", "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { - log.Fatal(err) + return err } cfg := config.LoadConfig() - log.Fatal(startDocker(cfg)) + return startDocker(cfg) } func copyBinaries(source, dest string) error { @@ -98,15 +104,15 @@ func copyBinaries(source, dest string) error { return nil } -func writeCerts(cfg *config.CloudConfig) error { - outDir := control.ServerTlsPath +func writeConfigCerts(cfg *config.CloudConfig) error { + outDir := ServerTLSPath if err := os.MkdirAll(outDir, 0700); err != nil { return err } - caCertPath := filepath.Join(outDir, control.CaCert) - caKeyPath := filepath.Join(outDir, control.CaKey) - serverCertPath := filepath.Join(outDir, control.ServerCert) - serverKeyPath := filepath.Join(outDir, control.ServerKey) + caCertPath := filepath.Join(outDir, CaCert) + caKeyPath := filepath.Join(outDir, CaKey) + serverCertPath := filepath.Join(outDir, ServerCert) + serverKeyPath := filepath.Join(outDir, ServerKey) if cfg.Rancher.Docker.CACert != "" { if err := util.WriteFileAtomic(caCertPath, []byte(cfg.Rancher.Docker.CACert), 0400); err != nil { return err @@ -131,7 +137,7 @@ func writeCerts(cfg *config.CloudConfig) error { func startDocker(cfg *config.CloudConfig) error { storageContext := cfg.Rancher.Docker.StorageContext if storageContext == "" { - storageContext = DEFAULT_STORAGE_CONTEXT + storageContext = defaultStorageContext } log.Infof("Starting Docker in context: %s", storageContext) @@ -160,7 +166,7 @@ func startDocker(cfg *config.CloudConfig) error { log.Debugf("User Docker args: %v", args) if dockerCfg.TLS { - if err := writeCerts(cfg); err != nil { + if err := writeConfigCerts(cfg); err != nil { return err } } @@ -173,7 +179,7 @@ func startDocker(cfg *config.CloudConfig) error { cmd := []string{"docker-runc", "exec", "--", info.ID, "env"} log.Info(dockerCfg.AppendEnv()) cmd = append(cmd, dockerCfg.AppendEnv()...) - cmd = append(cmd, DOCKER_COMMAND) + cmd = append(cmd, dockerCommand...) cmd = append(cmd, args...) log.Infof("Running %v", cmd) @@ -208,7 +214,7 @@ func getPid(service string, project *project.Project) (int, error) { } client, err := composeClient.Create(composeClient.Options{ - Host: config.DOCKER_SYSTEM_HOST, + Host: config.SystemDockerHost, }) if err != nil { return 0, err diff --git a/cmd/control/util.go b/cmd/control/util.go index 6ab95b67..adced8b0 100644 --- a/cmd/control/util.go +++ b/cmd/control/util.go @@ -1,16 +1,16 @@ package control import ( - "bufio" "fmt" "strings" - log "github.com/Sirupsen/logrus" + "github.com/rancher/os/log" ) -func yes(in *bufio.Reader, question string) bool { +func yes(question string) bool { fmt.Printf("%s [y/N]: ", question) - line, err := in.ReadString('\n') + var line string + _, err := fmt.Scan(&line) if err != nil { log.Fatal(err) } diff --git a/cmd/network/network.go b/cmd/network/network.go index 87a8d3d6..34d6eeed 100644 --- a/cmd/network/network.go +++ b/cmd/network/network.go @@ -1,60 +1,31 @@ package network import ( - "flag" - "os" - - "golang.org/x/net/context" - - log "github.com/Sirupsen/logrus" + "github.com/rancher/os/log" "github.com/docker/libnetwork/resolvconf" - "github.com/rancher/netconf" "github.com/rancher/os/config" - "github.com/rancher/os/docker" "github.com/rancher/os/hostname" + "github.com/rancher/os/netconf" ) -var ( - stopNetworkPre bool - flags *flag.FlagSet -) - -func init() { - flags = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) - flags.BoolVar(&stopNetworkPre, "stop-network-pre", false, "") -} - func Main() { - flags.Parse(os.Args[1:]) - - log.Infof("Running network: stop-network-pre=%v", stopNetworkPre) - - if stopNetworkPre { - client, err := docker.NewSystemClient() - if err != nil { - log.Error(err) - } - - err = client.ContainerStop(context.Background(), "network-pre", 10) - if err != nil { - log.Error(err) - } - - _, err = client.ContainerWait(context.Background(), "network-pre") - if err != nil { - log.Error(err) - } - } + log.InitLogger() + log.Infof("Running network") cfg := config.LoadConfig() + ApplyNetworkConfig(cfg) - nameservers := cfg.Rancher.Network.Dns.Nameservers - search := cfg.Rancher.Network.Dns.Search - userSetDns := len(nameservers) > 0 || len(search) > 0 - if !userSetDns { - nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers - search = cfg.Rancher.Defaults.Network.Dns.Search + select {} +} + +func ApplyNetworkConfig(cfg *config.CloudConfig) { + nameservers := cfg.Rancher.Network.DNS.Nameservers + search := cfg.Rancher.Network.DNS.Search + userSetDNS := len(nameservers) > 0 || len(search) > 0 + if !userSetDNS { + nameservers = cfg.Rancher.Defaults.Network.DNS.Nameservers + search = cfg.Rancher.Defaults.Network.DNS.Search } if _, err := resolvconf.Build("/etc/resolv.conf", nameservers, search, nil); err != nil { @@ -70,13 +41,11 @@ func Main() { } userSetHostname := cfg.Hostname != "" - if err := netconf.RunDhcp(&cfg.Rancher.Network, !userSetHostname, !userSetDns); err != nil { + if err := netconf.RunDhcp(&cfg.Rancher.Network, !userSetHostname, !userSetDNS); err != nil { log.Error(err) } if err := hostname.SyncHostname(); err != nil { log.Error(err) } - - select {} } diff --git a/cmd/power/power.go b/cmd/power/power.go index 632e8aed..b473394b 100644 --- a/cmd/power/power.go +++ b/cmd/power/power.go @@ -10,10 +10,10 @@ import ( "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/filters" + "github.com/rancher/os/log" "github.com/rancher/os/docker" "github.com/rancher/os/util" @@ -47,12 +47,12 @@ func runDocker(name string) error { } } - currentContainerId, err := util.GetCurrentContainerId() + currentContainerID, err := util.GetCurrentContainerID() if err != nil { return err } - currentContainer, err := client.ContainerInspect(context.Background(), currentContainerId) + currentContainer, err := client.ContainerInspect(context.Background(), currentContainerID) if err != nil { return err } @@ -110,7 +110,7 @@ func common(name string) { } } -func PowerOff() { +func Off() { common("poweroff") reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF) } @@ -181,7 +181,7 @@ func shutDownContainers() error { return err } - currentContainerId, err := util.GetCurrentContainerId() + currentContainerID, err := util.GetCurrentContainerID() if err != nil { return err } @@ -189,7 +189,7 @@ func shutDownContainers() error { var stopErrorStrings []string for _, container := range containers { - if container.ID == currentContainerId { + if container.ID == currentContainerID { continue } @@ -203,7 +203,7 @@ func shutDownContainers() error { var waitErrorStrings []string for _, container := range containers { - if container.ID == currentContainerId { + if container.ID == currentContainerID { continue } _, waitErr := client.ContainerWait(context.Background(), container.ID) diff --git a/cmd/power/shutdown.go b/cmd/power/shutdown.go index 4993afb3..2bccc7df 100644 --- a/cmd/power/shutdown.go +++ b/cmd/power/shutdown.go @@ -5,14 +5,16 @@ import ( "github.com/codegangsta/cli" "github.com/rancher/os/config" + "github.com/rancher/os/log" ) func Main() { + log.InitLogger() app := cli.NewApp() app.Name = os.Args[0] app.Usage = "Control and configure RancherOS" - app.Version = config.VERSION + app.Version = config.Version app.Author = "Rancher Labs, Inc." app.Email = "sid@rancher.com" app.EnableBashCompletion = true @@ -39,7 +41,7 @@ func shutdown(c *cli.Context) error { if reboot == "now" { Reboot() } else if poweroff == "now" { - PowerOff() + Off() } return nil diff --git a/cmd/respawn/respawn.go b/cmd/respawn/respawn.go index 89149c0a..e8e34321 100644 --- a/cmd/respawn/respawn.go +++ b/cmd/respawn/respawn.go @@ -12,17 +12,18 @@ import ( "syscall" "time" - log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/rancher/os/log" ) var ( - running bool = true - processes map[int]*os.Process = map[int]*os.Process{} - processLock = sync.Mutex{} + running = true + processes = map[int]*os.Process{} + processLock = sync.Mutex{} ) func Main() { + log.InitLogger() runtime.GOMAXPROCS(1) runtime.LockOSThread() app := cli.NewApp() diff --git a/cmd/sysinit/sysinit.go b/cmd/sysinit/sysinit.go index 2e78d547..85733450 100644 --- a/cmd/sysinit/sysinit.go +++ b/cmd/sysinit/sysinit.go @@ -1,11 +1,12 @@ package sysinit import ( - log "github.com/Sirupsen/logrus" initPkg "github.com/rancher/os/init" + "github.com/rancher/os/log" ) func Main() { + log.InitLogger() if err := initPkg.SysInit(); err != nil { log.Fatal(err) } diff --git a/cmd/systemdocker/system-docker.go b/cmd/systemdocker/system-docker.go index 40683457..b9e9907a 100644 --- a/cmd/systemdocker/system-docker.go +++ b/cmd/systemdocker/system-docker.go @@ -1,20 +1,21 @@ package systemdocker import ( - "log" "os" "github.com/docker/docker/docker" "github.com/rancher/os/config" + "github.com/rancher/os/log" ) func Main() { + log.InitLogger() if os.Geteuid() != 0 { log.Fatalf("%s: Need to be root", os.Args[0]) } if os.Getenv("DOCKER_HOST") == "" { - os.Setenv("DOCKER_HOST", config.DOCKER_SYSTEM_HOST) + os.Setenv("DOCKER_HOST", config.SystemDockerHost) } docker.Main() diff --git a/cmd/wait/wait.go b/cmd/wait/wait.go index 0fcbde76..fd41c515 100644 --- a/cmd/wait/wait.go +++ b/cmd/wait/wait.go @@ -3,17 +3,18 @@ package wait import ( "os" - "github.com/Sirupsen/logrus" "github.com/rancher/os/config" "github.com/rancher/os/docker" + "github.com/rancher/os/log" ) func Main() { - _, err := docker.NewClient(config.DOCKER_HOST) + log.InitLogger() + _, err := docker.NewClient(config.DockerHost) if err != nil { - logrus.Errorf("Failed to conect to Docker") + log.Errorf("Failed to connect to Docker") os.Exit(1) } - logrus.Infof("Docker is ready") + log.Infof("Docker is ready") } diff --git a/compose/project.go b/compose/project.go index 37b4905e..fd1c8859 100644 --- a/compose/project.go +++ b/compose/project.go @@ -5,7 +5,6 @@ import ( "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" "github.com/docker/libcompose/cli/logger" composeConfig "github.com/docker/libcompose/config" @@ -16,6 +15,7 @@ import ( "github.com/docker/libcompose/project/options" "github.com/rancher/os/config" rosDocker "github.com/rancher/os/docker" + "github.com/rancher/os/log" "github.com/rancher/os/util" "github.com/rancher/os/util/network" ) @@ -201,7 +201,7 @@ func newCoreServiceProject(cfg *config.CloudConfig, useNetwork, loadConsole bool go func() { for event := range projectEvents { - if event.EventType == events.ContainerStarted && event.ServiceName == "ntp" { + if event.EventType == events.ContainerStarted && event.ServiceName == "network" { useNetwork = true } } diff --git a/compose/reload.go b/compose/reload.go index 492b3012..32b4ed8c 100644 --- a/compose/reload.go +++ b/compose/reload.go @@ -3,12 +3,12 @@ package compose import ( "fmt" - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" composeConfig "github.com/docker/libcompose/config" "github.com/docker/libcompose/project" "github.com/rancher/os/config" "github.com/rancher/os/docker" + "github.com/rancher/os/log" "github.com/rancher/os/util/network" ) diff --git a/config/config.go b/config/config.go index 108a24a4..259e7f0b 100644 --- a/config/config.go +++ b/config/config.go @@ -18,7 +18,7 @@ func Merge(bytes []byte) error { } func Export(private, full bool) (string, error) { - rawCfg := loadRawDiskConfig(full) + rawCfg := loadRawConfig("", full) if !private { rawCfg = filterPrivateKeys(rawCfg) } diff --git a/config/data_funcs.go b/config/data_funcs.go index 91a973a8..b036858f 100644 --- a/config/data_funcs.go +++ b/config/data_funcs.go @@ -1,8 +1,8 @@ package config import ( - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/rancher/os/log" "strings" diff --git a/config/disk.go b/config/disk.go index dbfd6d5d..c5a9ebf2 100644 --- a/config/disk.go +++ b/config/disk.go @@ -7,12 +7,12 @@ import ( "sort" "strings" - log "github.com/Sirupsen/logrus" yaml "github.com/cloudfoundry-incubator/candiedyaml" "github.com/coreos/coreos-cloudinit/datasource" "github.com/coreos/coreos-cloudinit/initialize" "github.com/docker/engine-api/types" composeConfig "github.com/docker/libcompose/config" + "github.com/rancher/os/log" "github.com/rancher/os/util" ) @@ -31,27 +31,32 @@ func ReadConfig(bytes []byte, substituteMetadataVars bool, files ...string) (*Cl return c, nil } -func loadRawDiskConfig(full bool) map[interface{}]interface{} { +func loadRawDiskConfig(dirPrefix string, full bool) map[interface{}]interface{} { var rawCfg map[interface{}]interface{} if full { rawCfg, _ = readConfigs(nil, true, false, OsConfigFile, OemConfigFile) } - files := append(CloudConfigDirFiles(), CloudConfigFile) + files := CloudConfigDirFiles(dirPrefix) + files = append(files, path.Join(dirPrefix, CloudConfigFile)) additionalCfgs, _ := readConfigs(nil, true, false, files...) return util.Merge(rawCfg, additionalCfgs) } -func loadRawConfig() map[interface{}]interface{} { - rawCfg := loadRawDiskConfig(true) +func loadRawConfig(dirPrefix string, full bool) map[interface{}]interface{} { + rawCfg := loadRawDiskConfig(dirPrefix, full) rawCfg = util.Merge(rawCfg, readCmdline()) rawCfg = applyDebugFlags(rawCfg) return mergeMetadata(rawCfg, readMetadata()) } func LoadConfig() *CloudConfig { - rawCfg := loadRawConfig() + return LoadConfigWithPrefix("") +} + +func LoadConfigWithPrefix(dirPrefix string) *CloudConfig { + rawCfg := loadRawConfig(dirPrefix, true) cfg := &CloudConfig{} if err := util.Convert(rawCfg, cfg); err != nil { @@ -63,8 +68,10 @@ func LoadConfig() *CloudConfig { return cfg } -func CloudConfigDirFiles() []string { - files, err := ioutil.ReadDir(CloudConfigDir) +func CloudConfigDirFiles(dirPrefix string) []string { + cloudConfigDir := path.Join(dirPrefix, CloudConfigDir) + + files, err := ioutil.ReadDir(cloudConfigDir) if err != nil { if os.IsNotExist(err) { // do nothing @@ -78,7 +85,7 @@ func CloudConfigDirFiles() []string { var finalFiles []string for _, file := range files { if !file.IsDir() && !strings.HasPrefix(file.Name(), ".") { - finalFiles = append(finalFiles, path.Join(CloudConfigDir, file.Name())) + finalFiles = append(finalFiles, path.Join(cloudConfigDir, file.Name())) } } @@ -176,9 +183,6 @@ func amendNils(c *CloudConfig) *CloudConfig { if t.Rancher.Environment == nil { t.Rancher.Environment = map[string]string{} } - if t.Rancher.Autoformat == nil { - t.Rancher.Autoformat = map[string]*composeConfig.ServiceConfigV1{} - } if t.Rancher.BootstrapContainers == nil { t.Rancher.BootstrapContainers = map[string]*composeConfig.ServiceConfigV1{} } @@ -199,7 +203,6 @@ func amendNils(c *CloudConfig) *CloudConfig { func amendContainerNames(c *CloudConfig) *CloudConfig { for _, scm := range []map[string]*composeConfig.ServiceConfigV1{ - c.Rancher.Autoformat, c.Rancher.BootstrapContainers, c.Rancher.Services, } { diff --git a/config/docker_config.go b/config/docker_config.go index 664aad80..92f2fe10 100644 --- a/config/docker_config.go +++ b/config/docker_config.go @@ -41,9 +41,17 @@ func generateEngineOptsSlice(opts EngineOpts) []string { optsSlice = append(optsSlice, fmt.Sprintf("--%s=false", optTag)) } } + case []string: + for _, elem := range value { + if elem != "" { + optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag), elem) + } + } case map[string]string: for k, v := range value { - optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag), fmt.Sprintf("%s=%s", k, v)) + if v != "" { + optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag), fmt.Sprintf("%s=%s", k, v)) + } } } } diff --git a/config/docker_config_test.go b/config/docker_config_test.go index 853669a3..750c57e4 100644 --- a/config/docker_config_test.go +++ b/config/docker_config_test.go @@ -18,6 +18,20 @@ func TestGenerateEngineOptsString(t *testing.T) { if len(generateEngineOptsSlice(EngineOpts{})) != 0 { t.Fail() } + if len(generateEngineOptsSlice(EngineOpts{ + Host: []string{ + "", + }, + })) != 0 { + t.Fail() + } + if len(generateEngineOptsSlice(EngineOpts{ + LogOpts: map[string]string{ + "max-file": "", + }, + })) != 0 { + t.Fail() + } testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{ Bridge: "bridge", @@ -30,6 +44,13 @@ func TestGenerateEngineOptsString(t *testing.T) { SelinuxEnabled: &[]bool{false}[0], })), "--selinux-enabled=false") + testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{ + Host: []string{ + "unix:///var/run/system-docker.sock", + "unix:///var/run/docker.sock", + }, + })), "--host unix:///var/run/system-docker.sock", "--host unix:///var/run/docker.sock") + testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{ LogOpts: map[string]string{ "max-size": "25m", diff --git a/config/schema.go b/config/schema.go new file mode 100644 index 00000000..0876f1e7 --- /dev/null +++ b/config/schema.go @@ -0,0 +1,200 @@ +package config + +var schema = `{ + "type": "object", + "additionalProperties": false, + + "properties": { + "ssh_authorized_keys": {"$ref": "#/definitions/list_of_strings"}, + "write_files": { + "type": "array", + "items": {"$ref": "#/definitions/file_config"} + }, + "hostname": {"type": "string"}, + "mounts": {"type": "array"}, + "rancher": {"$ref": "#/definitions/rancher_config"}, + "runcmd": {"type": "array"}, + "bootcmd": {"type": "array"} + }, + + "definitions": { + "rancher_config": { + "id": "#/definitions/rancher_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "console": {"type": "string"}, + "environment": {"type": "object"}, + "cloud_init_services": {"type": "object"}, + "services": {"type": "object"}, + "bootstrap": {"type": "object"}, + "autoformat": {"type": "object"}, + "bootstrap_docker": {"$ref": "#/definitions/docker_config"}, + "cloud_init": {"$ref": "#/definitions/cloud_init_config"}, + "debug": {"type": "boolean"}, + "rm_usr": {"type": "boolean"}, + "no_sharedroot": {"type": "boolean"}, + "log": {"type": "boolean"}, + "force_console_rebuild": {"type": "boolean"}, + "disable": {"$ref": "#/definitions/list_of_strings"}, + "services_include": {"type": "object"}, + "modules": {"$ref": "#/definitions/list_of_strings"}, + "network": {"$ref": "#/definitions/network_config"}, + "default_network": {"type": "object"}, + "repositories": {"type": "object"}, + "ssh": {"$ref": "#/definitions/ssh_config"}, + "state": {"$ref": "#/definitions/state_config"}, + "system_docker": {"$ref": "#/definitions/docker_config"}, + "upgrade": {"$ref": "#/definitions/upgrade_config"}, + "docker": {"$ref": "#/definitions/docker_config"}, + "registry_auths": {"type": "object"}, + "defaults": {"$ref": "#/definitions/defaults_config"}, + "resize_device": {"type": "string"}, + "sysctl": {"type": "object"}, + "restart_services": {"type": "array"} + } + }, + + "file_config": { + "id": "#/definitions/file_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "encoding": {"type": "string"}, + "container": {"type": "string"}, + "content": {"type": "string"}, + "owner": {"type": "string"}, + "path": {"type": "string"}, + "permissions": {"type": "string"} + } + }, + + "network_config": { + "id": "#/definitions/network_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "pre_cmds": {"$ref": "#/definitions/list_of_strings"}, + "dns": {"type": "object"}, + "interfaces": {"type": "object"}, + "post_cmds": {"$ref": "#/definitions/list_of_strings"}, + "http_proxy": {"type": "string"}, + "https_proxy": {"type": "string"}, + "no_proxy": {"type": "string"} + } + }, + + "upgrade_config": { + "id": "#/definitions/upgrade_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "url": {"type": "string"}, + "image": {"type": "string"}, + "rollback": {"type": "string"} + } + }, + + "docker_config": { + "id": "#/definitions/docker_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "engine": {"type": "string"}, + "tls": {"type": "boolean"}, + "tls_args": {"$ref": "#/definitions/list_of_strings"}, + "args": {"$ref": "#/definitions/list_of_strings"}, + "extra_args": {"$ref": "#/definitions/list_of_strings"}, + "server_cert": {"type": "string"}, + "server_key": {"type": "string"}, + "ca_cert": {"type": "string"}, + "ca_key": {"type": "string"}, + "environment": {"$ref": "#/definitions/list_of_strings"}, + "storage_context": {"type": "string"}, + "exec": {"type": ["boolean", "null"]}, + "bridge": {"type": "string"}, + "config_file": {"type": "string"}, + "containerd": {"type": "string"}, + "debug": {"type": ["boolean", "null"]}, + "exec_root": {"type": "string"}, + "group": {"type": "string"}, + "graph": {"type": "string"}, + "host": {"type": "array"}, + "live_restore": {"type": ["boolean", "null"]}, + "log_driver": {"type": "string"}, + "log_opts": {"type": "object"}, + "pid_file": {"type": "string"}, + "registry_mirror": {"type": "string"}, + "restart": {"type": ["boolean", "null"]}, + "selinux_enabled": {"type": ["boolean", "null"]}, + "storage_driver": {"type": "string"}, + "userland_proxy": {"type": ["boolean", "null"]}, + "insecure_registry": {"$ref": "#/definitions/list_of_strings"} + } + }, + + "ssh_config": { + "id": "#/definitions/ssh_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "keys": {"type": "object"} + } + }, + + "state_config": { + "id": "#/definitions/state_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "directory": {"type": "string"}, + "fstype": {"type": "string"}, + "dev": {"type": "string"}, + "wait": {"type": "boolean"}, + "required": {"type": "boolean"}, + "autoformat": {"$ref": "#/definitions/list_of_strings"}, + "mdadm_scan": {"type": "boolean"}, + "script": {"type": "string"}, + "oem_fstype": {"type": "string"}, + "oem_dev": {"type": "string"} + } + }, + + "cloud_init_config": { + "id": "#/definitions/cloud_init_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "datasources": {"$ref": "#/definitions/list_of_strings"} + } + }, + + "defaults_config": { + "id": "#/definitions/defaults_config", + "type": "object", + "additionalProperties": false, + + "properties": { + "hostname": {"type": "string"}, + "docker": {"type": "object"}, + "network": {"$ref": "#/definitions/network_config"} + } + }, + + "list_of_strings": { + "type": "array", + "items": {"type": "string"}, + "uniqueItems": true + } + } +} + +` diff --git a/config/types.go b/config/types.go index 12504af8..588578ae 100644 --- a/config/types.go +++ b/config/types.go @@ -7,35 +7,34 @@ import ( "github.com/coreos/coreos-cloudinit/config" "github.com/docker/engine-api/types" composeConfig "github.com/docker/libcompose/config" - "github.com/rancher/netconf" + "github.com/rancher/os/config/yaml" ) const ( - OEM = "/usr/share/ros/oem" - DOCKER_BIN = "/usr/bin/docker" - DOCKER_DIST_BIN = "/usr/bin/docker.dist" - ROS_BIN = "/usr/bin/ros" - SYSINIT_BIN = "/usr/bin/ros-sysinit" - DOCKER_SYSTEM_HOME = "/var/lib/system-docker" - DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock" - DOCKER_HOST = "unix:///var/run/docker.sock" - IMAGES_PATH = "/usr/share/ros" - IMAGES_PATTERN = "images*.tar" - MODULES_ARCHIVE = "/modules.tar" - DEBUG = false - SYSTEM_DOCKER_LOG = "/var/log/system-docker.log" - SYSTEM_DOCKER_BIN = "/usr/bin/system-docker" + OEM = "/usr/share/ros/oem" + DockerBin = "/usr/bin/docker" + DockerDistBin = "/usr/bin/docker.dist" + RosBin = "/usr/bin/ros" + SysInitBin = "/usr/bin/ros-sysinit" + SystemDockerHome = "/var/lib/system-docker" + SystemDockerHost = "unix:///var/run/system-docker.sock" + DockerHost = "unix:///var/run/docker.sock" + ImagesPath = "/usr/share/ros" + ImagesPattern = "images*.tar" + ModulesArchive = "/modules.tar" + Debug = false + SystemDockerLog = "/var/log/system-docker.log" + SystemDockerBin = "/usr/bin/system-docker" - LABEL = "label" - HASH = "io.rancher.os.hash" - ID = "io.rancher.os.id" - DETACH = "io.rancher.os.detach" - CREATE_ONLY = "io.rancher.os.createonly" - RELOAD_CONFIG = "io.rancher.os.reloadconfig" - CONSOLE = "io.rancher.os.console" - SCOPE = "io.rancher.os.scope" - REBUILD = "io.docker.compose.rebuild" - SYSTEM = "system" + HashLabel = "io.rancher.os.hash" + IDLabel = "io.rancher.os.id" + DetachLabel = "io.rancher.os.detach" + CreateOnlyLabel = "io.rancher.os.createonly" + ReloadConfigLabel = "io.rancher.os.reloadconfig" + ConsoleLabel = "io.rancher.os.console" + ScopeLabel = "io.rancher.os.scope" + RebuildLabel = "io.docker.compose.rebuild" + System = "system" OsConfigFile = "/usr/share/ros/os-config.yml" CloudConfigDir = "/var/lib/rancher/conf/cloud-config.d" @@ -48,11 +47,11 @@ const ( var ( OemConfigFile = OEM + "/oem-config.yml" - VERSION string - ARCH string - SUFFIX string - OS_REPO string - OS_BASE string + Version string + Arch string + Suffix string + OsRepo string + OsBase string PrivateKeys = []string{ "rancher.ssh", "rancher.docker.ca_key", @@ -63,33 +62,34 @@ var ( ) func init() { - if VERSION == "" { - VERSION = "v0.0.0-dev" + if Version == "" { + Version = "v0.0.0-dev" } - if ARCH == "" { - ARCH = runtime.GOARCH + if Arch == "" { + Arch = runtime.GOARCH } - if SUFFIX == "" && ARCH != "amd64" { - SUFFIX = "_" + ARCH + if Suffix == "" && Arch != "amd64" { + Suffix = "_" + Arch } - if OS_BASE == "" { - OS_BASE = fmt.Sprintf("%s/os-base:%s%s", OS_REPO, VERSION, SUFFIX) + if OsBase == "" { + OsBase = fmt.Sprintf("%s/os-base:%s%s", OsRepo, Version, Suffix) } } type Repository struct { - Url string `yaml:"url,omitempty"` + URL string `yaml:"url,omitempty"` } type Repositories map[string]Repository type CloudConfig struct { - SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"` - WriteFiles []File `yaml:"write_files"` - Hostname string `yaml:"hostname"` - Mounts [][]string `yaml:"mounts,omitempty"` - Rancher RancherConfig `yaml:"rancher,omitempty"` - Runcmd [][]string `yaml:"runcmd,omitempty"` + SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"` + WriteFiles []File `yaml:"write_files"` + Hostname string `yaml:"hostname"` + Mounts [][]string `yaml:"mounts,omitempty"` + Rancher RancherConfig `yaml:"rancher,omitempty"` + Runcmd []yaml.StringandSlice `yaml:"runcmd,omitempty"` + Bootcmd []yaml.StringandSlice `yaml:"bootcmd,omitempty"` } type File struct { @@ -102,7 +102,7 @@ type RancherConfig struct { Environment map[string]string `yaml:"environment,omitempty"` Services map[string]*composeConfig.ServiceConfigV1 `yaml:"services,omitempty"` BootstrapContainers map[string]*composeConfig.ServiceConfigV1 `yaml:"bootstrap,omitempty"` - Autoformat map[string]*composeConfig.ServiceConfigV1 `yaml:"autoformat,omitempty"` + CloudInitServices map[string]*composeConfig.ServiceConfigV1 `yaml:"cloud_init_services,omitempty"` BootstrapDocker DockerConfig `yaml:"bootstrap_docker,omitempty"` CloudInit CloudInit `yaml:"cloud_init,omitempty"` Debug bool `yaml:"debug,omitempty"` @@ -113,10 +113,10 @@ type RancherConfig struct { Disable []string `yaml:"disable,omitempty"` ServicesInclude map[string]bool `yaml:"services_include,omitempty"` Modules []string `yaml:"modules,omitempty"` - Network netconf.NetworkConfig `yaml:"network,omitempty"` - DefaultNetwork netconf.NetworkConfig `yaml:"default_network,omitempty"` + Network NetworkConfig `yaml:"network,omitempty"` + DefaultNetwork NetworkConfig `yaml:"default_network,omitempty"` Repositories Repositories `yaml:"repositories,omitempty"` - Ssh SshConfig `yaml:"ssh,omitempty"` + SSH SSHConfig `yaml:"ssh,omitempty"` State StateConfig `yaml:"state,omitempty"` SystemDocker DockerConfig `yaml:"system_docker,omitempty"` Upgrade UpgradeConfig `yaml:"upgrade,omitempty"` @@ -129,29 +129,30 @@ type RancherConfig struct { } type UpgradeConfig struct { - Url string `yaml:"url,omitempty"` + URL string `yaml:"url,omitempty"` Image string `yaml:"image,omitempty"` Rollback string `yaml:"rollback,omitempty"` } type EngineOpts struct { - Bridge string `yaml:"bridge,omitempty" opt:"bridge"` - ConfigFile string `yaml:"config_file,omitempty" opt:"config-file"` - Containerd string `yaml:"containerd,omitempty" opt:"containerd"` - Debug *bool `yaml:"debug,omitempty" opt:"debug"` - ExecRoot string `yaml:"exec_root,omitempty" opt:"exec-root"` - Group string `yaml:"group,omitempty" opt:"group"` - Graph string `yaml:"graph,omitempty" opt:"graph"` - Host string `yaml:"host,omitempty" opt:"host"` - LiveRestore *bool `yaml:"live_restore,omitempty" opt:"live-restore"` - LogDriver string `yaml:"log_driver,omitempty" opt:"log-driver"` - LogOpts map[string]string `yaml:"log_opts,omitempty" opt:"log-opt"` - PidFile string `yaml:"pid_file,omitempty" opt:"pidfile"` - RegistryMirror string `yaml:"registry_mirror,omitempty" opt:"registry-mirror"` - Restart *bool `yaml:"restart,omitempty" opt:"restart"` - SelinuxEnabled *bool `yaml:"selinux_enabled,omitempty" opt:"selinux-enabled"` - StorageDriver string `yaml:"storage_driver,omitempty" opt:"storage-driver"` - UserlandProxy *bool `yaml:"userland_proxy,omitempty" opt:"userland-proxy"` + Bridge string `yaml:"bridge,omitempty" opt:"bridge"` + ConfigFile string `yaml:"config_file,omitempty" opt:"config-file"` + Containerd string `yaml:"containerd,omitempty" opt:"containerd"` + Debug *bool `yaml:"debug,omitempty" opt:"debug"` + ExecRoot string `yaml:"exec_root,omitempty" opt:"exec-root"` + Group string `yaml:"group,omitempty" opt:"group"` + Graph string `yaml:"graph,omitempty" opt:"graph"` + Host []string `yaml:"host,omitempty" opt:"host"` + InsecureRegistry []string `yaml:"insecure_registry" opt:"insecure-registry"` + LiveRestore *bool `yaml:"live_restore,omitempty" opt:"live-restore"` + LogDriver string `yaml:"log_driver,omitempty" opt:"log-driver"` + LogOpts map[string]string `yaml:"log_opts,omitempty" opt:"log-opt"` + PidFile string `yaml:"pid_file,omitempty" opt:"pidfile"` + RegistryMirror string `yaml:"registry_mirror,omitempty" opt:"registry-mirror"` + Restart *bool `yaml:"restart,omitempty" opt:"restart"` + SelinuxEnabled *bool `yaml:"selinux_enabled,omitempty" opt:"selinux-enabled"` + StorageDriver string `yaml:"storage_driver,omitempty" opt:"storage-driver"` + UserlandProxy *bool `yaml:"userland_proxy,omitempty" opt:"userland-proxy"` } type DockerConfig struct { @@ -169,7 +170,40 @@ type DockerConfig struct { Exec bool `yaml:"exec,omitempty"` } -type SshConfig struct { +type NetworkConfig struct { + PreCmds []string `yaml:"pre_cmds,omitempty"` + DNS DNSConfig `yaml:"dns,omitempty"` + Interfaces map[string]InterfaceConfig `yaml:"interfaces,omitempty"` + PostCmds []string `yaml:"post_cmds,omitempty"` + HTTPProxy string `yaml:"http_proxy,omitempty"` + HTTPSProxy string `yaml:"https_proxy,omitempty"` + NoProxy string `yaml:"no_proxy,omitempty"` +} + +type InterfaceConfig struct { + Match string `yaml:"match,omitempty"` + DHCP bool `yaml:"dhcp,omitempty"` + DHCPArgs string `yaml:"dhcp_args,omitempty"` + Address string `yaml:"address,omitempty"` + Addresses []string `yaml:"addresses,omitempty"` + IPV4LL bool `yaml:"ipv4ll,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + GatewayIpv6 string `yaml:"gateway_ipv6,omitempty"` + MTU int `yaml:"mtu,omitempty"` + Bridge string `yaml:"bridge,omitempty"` + Bond string `yaml:"bond,omitempty"` + BondOpts map[string]string `yaml:"bond_opts,omitempty"` + PostUp []string `yaml:"post_up,omitempty"` + PreUp []string `yaml:"pre_up,omitempty"` + Vlans string `yaml:"vlans,omitempty"` +} + +type DNSConfig struct { + Nameservers []string `yaml:"nameservers,flow,omitempty"` + Search []string `yaml:"search,flow,omitempty"` +} + +type SSHConfig struct { Keys map[string]string `yaml:"keys,omitempty"` } @@ -191,16 +225,16 @@ type CloudInit struct { } type Defaults struct { - Hostname string `yaml:"hostname,omitempty"` - Docker DockerConfig `yaml:"docker,omitempty"` - Network netconf.NetworkConfig `yaml:"network,omitempty"` + Hostname string `yaml:"hostname,omitempty"` + Docker DockerConfig `yaml:"docker,omitempty"` + Network NetworkConfig `yaml:"network,omitempty"` } func (r Repositories) ToArray() []string { result := make([]string, 0, len(r)) for _, repo := range r { - if repo.Url != "" { - result = append(result, repo.Url) + if repo.URL != "" { + result = append(result, repo.URL) } } diff --git a/config/validate.go b/config/validate.go new file mode 100644 index 00000000..142ec923 --- /dev/null +++ b/config/validate.go @@ -0,0 +1,43 @@ +package config + +import ( + yaml "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/xeipuuv/gojsonschema" +) + +// ConvertKeysToStrings is temporarily copied from libcompose +// TODO: just import this in the future +func ConvertKeysToStrings(item interface{}) interface{} { + switch typedDatas := item.(type) { + case map[string]interface{}: + for key, value := range typedDatas { + typedDatas[key] = ConvertKeysToStrings(value) + } + return typedDatas + case map[interface{}]interface{}: + newMap := make(map[string]interface{}) + for key, value := range typedDatas { + stringKey := key.(string) + newMap[stringKey] = ConvertKeysToStrings(value) + } + return newMap + case []interface{}: + for i, value := range typedDatas { + typedDatas[i] = ConvertKeysToStrings(value) + } + return typedDatas + default: + return item + } +} + +func Validate(bytes []byte) (*gojsonschema.Result, error) { + var rawCfg map[string]interface{} + if err := yaml.Unmarshal([]byte(bytes), &rawCfg); err != nil { + return nil, err + } + rawCfg = ConvertKeysToStrings(rawCfg).(map[string]interface{}) + loader := gojsonschema.NewGoLoader(rawCfg) + schemaLoader := gojsonschema.NewStringLoader(schema) + return gojsonschema.Validate(schemaLoader, loader) +} diff --git a/config/validate_test.go b/config/validate_test.go new file mode 100644 index 00000000..ac82bde8 --- /dev/null +++ b/config/validate_test.go @@ -0,0 +1,53 @@ +package config + +import ( + "fmt" + "strings" + "testing" + + yaml "github.com/cloudfoundry-incubator/candiedyaml" + "github.com/rancher/os/util" +) + +func testValidate(t *testing.T, cfg []byte, contains string) { + validationErrors, err := Validate(cfg) + if err != nil { + t.Fatal(err) + } + if contains == "" && len(validationErrors.Errors()) != 0 { + t.Fail() + } + if !strings.Contains(fmt.Sprint(validationErrors.Errors()), contains) { + t.Fail() + } +} + +func TestValidate(t *testing.T) { + testValidate(t, []byte("{}"), "") + testValidate(t, []byte(`rancher: + log: true`), "") + testValidate(t, []byte(`write_files: +- container: console + path: /etc/rc.local + permissions: "0755" + owner: root + content: | + #!/bin/bash + wait-for-docker`), "") + testValidate(t, []byte(`rancher: + docker: + extra_args: ['--insecure-registry', 'my.registry.com']`), "") + + testValidate(t, []byte("bad_key: {}"), "Additional property bad_key is not allowed") + testValidate(t, []byte("rancher: []"), "rancher: Invalid type. Expected: object, given: array") + + var fullConfig map[string]interface{} + if err := util.ConvertIgnoreOmitEmpty(CloudConfig{}, &fullConfig); err != nil { + t.Fatal(err) + } + fullConfigBytes, err := yaml.Marshal(fullConfig) + if err != nil { + t.Fatal(err) + } + testValidate(t, fullConfigBytes, "") +} diff --git a/config/yaml/command.go b/config/yaml/command.go new file mode 100644 index 00000000..5d47abee --- /dev/null +++ b/config/yaml/command.go @@ -0,0 +1,44 @@ +package yaml + +import "fmt" + +// StringandSlice stores either a string or slice depending on original type +// Differs from libcompose Stringorslice by being able to determine original type +type StringandSlice struct { + StringValue string + SliceValue []string +} + +// UnmarshalYAML implements the Unmarshaller interface. +// TODO: this needs to be ported to go-yaml +func (s *StringandSlice) UnmarshalYAML(tag string, value interface{}) error { + switch value := value.(type) { + case []interface{}: + parts, err := toStrings(value) + if err != nil { + return err + } + s.SliceValue = parts + case string: + s.StringValue = value + default: + return fmt.Errorf("Failed to unmarshal StringandSlice: %#v", value) + } + return nil +} + +// TODO: use this function from libcompose +func toStrings(s []interface{}) ([]string, error) { + if len(s) == 0 { + return nil, nil + } + r := make([]string, len(s)) + for k, v := range s { + if sv, ok := v.(string); ok { + r[k] = sv + } else { + return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v) + } + } + return r, nil +} diff --git a/vendor/github.com/rancher/docker-from-scratch/one.go b/dfs/one.go similarity index 93% rename from vendor/github.com/rancher/docker-from-scratch/one.go rename to dfs/one.go index ef1a01f4..72e4ec58 100644 --- a/vendor/github.com/rancher/docker-from-scratch/one.go +++ b/dfs/one.go @@ -1,5 +1,6 @@ // +build linux -package dockerlaunch + +package dfs import ( "os" diff --git a/vendor/github.com/rancher/docker-from-scratch/scratch.go b/dfs/scratch.go similarity index 91% rename from vendor/github.com/rancher/docker-from-scratch/scratch.go rename to dfs/scratch.go index 74f3bb8e..354096f5 100644 --- a/vendor/github.com/rancher/docker-from-scratch/scratch.go +++ b/dfs/scratch.go @@ -1,4 +1,4 @@ -package dockerlaunch +package dfs import ( "bufio" @@ -11,11 +11,12 @@ import ( "strings" "syscall" - log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/resolvconf" - "github.com/rancher/docker-from-scratch/selinux" - "github.com/rancher/docker-from-scratch/util" - "github.com/rancher/netconf" + "github.com/rancher/os/config" + "github.com/rancher/os/log" + "github.com/rancher/os/netconf" + "github.com/rancher/os/selinux" + "github.com/rancher/os/util" ) const ( @@ -45,7 +46,7 @@ type Config struct { Fork bool PidOne bool CommandName string - DnsConfig netconf.DnsConfig + DNSConfig config.DNSConfig BridgeName string BridgeAddress string BridgeMtu int @@ -208,10 +209,9 @@ func execDocker(config *Config, docker, cmd string, args []string) (*exec.Cmd, e PidOne() } return cmd, err - } else { - err := syscall.Exec(expand(docker), append([]string{cmd}, args...), env) - return nil, err } + + return nil, syscall.Exec(expand(docker), append([]string{cmd}, args...), env) } func copyDefault(folder, name string) error { @@ -333,8 +333,8 @@ func createGroup() error { return tryCreateFile("/etc/group", "root:x:0:\n") } -func setupNetworking(config *Config) error { - if config == nil { +func setupNetworking(cfg *Config) error { + if cfg == nil { return nil } @@ -351,19 +351,19 @@ ff02::2 ip6-allrouters 127.0.1.1 `+hostname) - if len(config.DnsConfig.Nameservers) != 0 { - if _, err := resolvconf.Build("/etc/resolv.conf", config.DnsConfig.Nameservers, config.DnsConfig.Search, nil); err != nil { + if len(cfg.DNSConfig.Nameservers) != 0 { + if _, err := resolvconf.Build("/etc/resolv.conf", cfg.DNSConfig.Nameservers, cfg.DNSConfig.Search, nil); err != nil { return err } } - if config.BridgeName != "" && config.BridgeName != "none" { - log.Debugf("Creating bridge %s (%s)", config.BridgeName, config.BridgeAddress) - if err := netconf.ApplyNetworkConfigs(&netconf.NetworkConfig{ - Interfaces: map[string]netconf.InterfaceConfig{ - config.BridgeName: { - Address: config.BridgeAddress, - MTU: config.BridgeMtu, + if cfg.BridgeName != "" && cfg.BridgeName != "none" { + log.Debugf("Creating bridge %s (%s)", cfg.BridgeName, cfg.BridgeAddress) + if err := netconf.ApplyNetworkConfigs(&config.NetworkConfig{ + Interfaces: map[string]config.InterfaceConfig{ + cfg.BridgeName: { + Address: cfg.BridgeAddress, + MTU: cfg.BridgeMtu, Bridge: "true", }, }, @@ -375,23 +375,35 @@ ff02::2 ip6-allrouters return nil } +func GetValue(index int, args []string) string { + val := args[index] + parts := strings.SplitN(val, "=", 2) + if len(parts) == 1 { + if len(args) > index+1 { + return args[index+1] + } + return "" + } + return parts[1] +} + func ParseConfig(config *Config, args ...string) []string { for i, arg := range args { if strings.HasPrefix(arg, "--bip") { - config.BridgeAddress = util.GetValue(i, args) + config.BridgeAddress = GetValue(i, args) } else if strings.HasPrefix(arg, "--fixed-cidr") { - config.BridgeAddress = util.GetValue(i, args) + config.BridgeAddress = GetValue(i, args) } else if strings.HasPrefix(arg, "-b") || strings.HasPrefix(arg, "--bridge") { - config.BridgeName = util.GetValue(i, args) + config.BridgeName = GetValue(i, args) } else if strings.HasPrefix(arg, "--config-file") { - config.DaemonConfig = util.GetValue(i, args) + config.DaemonConfig = GetValue(i, args) } else if strings.HasPrefix(arg, "--mtu") { - mtu, err := strconv.Atoi(util.GetValue(i, args)) + mtu, err := strconv.Atoi(GetValue(i, args)) if err != nil { config.BridgeMtu = mtu } } else if strings.HasPrefix(arg, "-g") || strings.HasPrefix(arg, "--graph") { - config.GraphDirectory = util.GetValue(i, args) + config.GraphDirectory = GetValue(i, args) } } @@ -454,7 +466,7 @@ func touchSockets(args ...string) error { for i, arg := range args { if strings.HasPrefix(arg, "-H") { - val := util.GetValue(i, args) + val := GetValue(i, args) if strings.HasPrefix(val, "unix://") { val = val[len("unix://"):] log.Debugf("Creating temp file at %s", val) @@ -682,6 +694,7 @@ func LaunchDocker(config *Config, docker string, args ...string) (*exec.Cmd, err } func Main() { + log.InitLogger() if os.Getenv("DOCKER_LAUNCH_DEBUG") == "true" { log.SetLevel(log.DebugLevel) } diff --git a/docker/auth.go b/docker/auth.go index c4a086ad..bac015a6 100644 --- a/docker/auth.go +++ b/docker/auth.go @@ -5,11 +5,11 @@ import ( "fmt" "strings" - log "github.com/Sirupsen/logrus" "github.com/docker/docker/registry" "github.com/docker/engine-api/types" "github.com/docker/libcompose/docker" "github.com/rancher/os/config" + "github.com/rancher/os/log" ) // ConfigAuthLookup will lookup registry auth info from cloud config diff --git a/docker/client.go b/docker/client.go index b49f39e1..1ade19bb 100644 --- a/docker/client.go +++ b/docker/client.go @@ -7,11 +7,11 @@ import ( ) func NewSystemClient() (dockerClient.APIClient, error) { - return NewClient(config.DOCKER_SYSTEM_HOST) + return NewClient(config.SystemDockerHost) } func NewDefaultClient() (dockerClient.APIClient, error) { - return NewClient(config.DOCKER_HOST) + return NewClient(config.DockerHost) } func NewClient(endpoint string) (dockerClient.APIClient, error) { diff --git a/docker/client_factory.go b/docker/client_factory.go index cc12dfcd..78fc3cbe 100644 --- a/docker/client_factory.go +++ b/docker/client_factory.go @@ -6,11 +6,11 @@ import ( "golang.org/x/net/context" - log "github.com/Sirupsen/logrus" dockerclient "github.com/docker/engine-api/client" composeClient "github.com/docker/libcompose/docker/client" "github.com/docker/libcompose/project" "github.com/rancher/os/config" + "github.com/rancher/os/log" "github.com/rancher/os/util" ) @@ -25,8 +25,8 @@ func NewClientFactory(opts composeClient.Options) (project.ClientFactory, error) userOpts := opts systemOpts := opts - userOpts.Host = config.DOCKER_HOST - systemOpts.Host = config.DOCKER_SYSTEM_HOST + userOpts.Host = config.DockerHost + systemOpts.Host = config.SystemDockerHost userClient, err := composeClient.Create(userOpts) if err != nil { @@ -46,11 +46,11 @@ func NewClientFactory(opts composeClient.Options) (project.ClientFactory, error) func (c *ClientFactory) Create(service project.Service) dockerclient.APIClient { if IsSystemContainer(service.Config()) { - waitFor(&c.systemOnce, c.systemClient, config.DOCKER_SYSTEM_HOST) + waitFor(&c.systemOnce, c.systemClient, config.SystemDockerHost) return c.systemClient } - waitFor(&c.userOnce, c.userClient, config.DOCKER_HOST) + waitFor(&c.userOnce, c.userClient, config.DockerHost) return c.userClient } diff --git a/docker/env.go b/docker/env.go index db8d8f3a..2a4ce6fd 100644 --- a/docker/env.go +++ b/docker/env.go @@ -2,10 +2,13 @@ package docker import ( "fmt" + "io/ioutil" "strings" composeConfig "github.com/docker/libcompose/config" "github.com/rancher/os/config" + + log "github.com/Sirupsen/logrus" ) type ConfigEnvironment struct { @@ -29,18 +32,24 @@ func appendEnv(array []string, key, value string) []string { func environmentFromCloudConfig(cfg *config.CloudConfig) map[string]string { environment := cfg.Rancher.Environment - if cfg.Rancher.Network.HttpProxy != "" { - environment["http_proxy"] = cfg.Rancher.Network.HttpProxy - environment["HTTP_PROXY"] = cfg.Rancher.Network.HttpProxy + if cfg.Rancher.Network.HTTPProxy != "" { + environment["http_proxy"] = cfg.Rancher.Network.HTTPProxy + environment["HTTP_PROXY"] = cfg.Rancher.Network.HTTPProxy } - if cfg.Rancher.Network.HttpsProxy != "" { - environment["https_proxy"] = cfg.Rancher.Network.HttpsProxy - environment["HTTPS_PROXY"] = cfg.Rancher.Network.HttpsProxy + if cfg.Rancher.Network.HTTPSProxy != "" { + environment["https_proxy"] = cfg.Rancher.Network.HTTPSProxy + environment["HTTPS_PROXY"] = cfg.Rancher.Network.HTTPSProxy } if cfg.Rancher.Network.NoProxy != "" { environment["no_proxy"] = cfg.Rancher.Network.NoProxy environment["NO_PROXY"] = cfg.Rancher.Network.NoProxy } + b, err := ioutil.ReadFile("/proc/version") + if err == nil { + elem := strings.Split(string(b), " ") + environment["KERNEL_VERSION"] = elem[2] + log.Debugf("Using /proc/version to set rancher.environment.KERNEL_VERSION = %s", elem[2]) + } return environment } diff --git a/docker/service.go b/docker/service.go index 561d96b0..adb4ee30 100644 --- a/docker/service.go +++ b/docker/service.go @@ -3,7 +3,6 @@ package docker import ( "fmt" - "github.com/Sirupsen/logrus" dockerclient "github.com/docker/engine-api/client" "github.com/docker/engine-api/types" composeConfig "github.com/docker/libcompose/config" @@ -11,6 +10,7 @@ import ( "github.com/docker/libcompose/project" "github.com/docker/libcompose/project/options" "github.com/rancher/os/config" + "github.com/rancher/os/log" "golang.org/x/net/context" ) @@ -41,9 +41,7 @@ func (s *Service) DependentServices() []project.ServiceRelationship { } if s.requiresUserDocker() { - // Linking to cloud-init is a hack really. The problem is we need to link to something - // that will trigger a reload - rels = appendLink(rels, "cloud-init", false, s.project) + rels = appendLink(rels, "docker", false, s.project) } else if s.missingImage() { rels = appendLink(rels, "network", false, s.project) } @@ -65,7 +63,7 @@ func (s *Service) requiresSyslog() bool { } func (s *Service) requiresUserDocker() bool { - return s.Config().Labels[config.SCOPE] != config.SYSTEM + return s.Config().Labels[config.ScopeLabel] != config.System } func appendLink(deps []project.ServiceRelationship, name string, optional bool, p *project.Project) []project.ServiceRelationship { @@ -95,10 +93,10 @@ func (s *Service) shouldRebuild(ctx context.Context) (bool, error) { } name := containerInfo.Name[1:] - origRebuildLabel := containerInfo.Config.Labels[config.REBUILD] - newRebuildLabel := s.Config().Labels[config.REBUILD] + origRebuildLabel := containerInfo.Config.Labels[config.RebuildLabel] + newRebuildLabel := s.Config().Labels[config.RebuildLabel] rebuildLabelChanged := newRebuildLabel != origRebuildLabel - logrus.WithFields(logrus.Fields{ + log.WithFields(log.Fields{ "origRebuildLabel": origRebuildLabel, "newRebuildLabel": newRebuildLabel, "rebuildLabelChanged": rebuildLabelChanged, @@ -115,15 +113,15 @@ func (s *Service) shouldRebuild(ctx context.Context) (bool, error) { } if outOfSync { if s.Name() == "console" { - origConsoleLabel := containerInfo.Config.Labels[config.CONSOLE] - newConsoleLabel := s.Config().Labels[config.CONSOLE] + origConsoleLabel := containerInfo.Config.Labels[config.ConsoleLabel] + newConsoleLabel := s.Config().Labels[config.ConsoleLabel] if newConsoleLabel != origConsoleLabel { return true, nil } } else if rebuildLabelChanged || origRebuildLabel != "false" { return true, nil } else { - logrus.Warnf("%s needs rebuilding", name) + log.Warnf("%s needs rebuilding", name) } } } @@ -142,7 +140,7 @@ func (s *Service) Up(ctx context.Context, options options.Up) error { return err } if shouldRebuild { - logrus.Infof("Rebuilding %s", s.Name()) + log.Infof("Rebuilding %s", s.Name()) cs, err := s.Service.Containers(ctx) if err != nil { return err @@ -156,13 +154,13 @@ func (s *Service) Up(ctx context.Context, options options.Up) error { return err } } - if labels[config.CREATE_ONLY] == "true" { + if labels[config.CreateOnlyLabel] == "true" { return s.checkReload(labels) } if err := s.Service.Up(ctx, options); err != nil { return err } - if labels[config.DETACH] == "false" { + if labels[config.DetachLabel] == "false" { if err := s.wait(ctx); err != nil { return err } @@ -172,7 +170,7 @@ func (s *Service) Up(ctx context.Context, options options.Up) error { } func (s *Service) checkReload(labels map[string]string) error { - if labels[config.RELOAD_CONFIG] == "true" { + if labels[config.ReloadConfigLabel] == "true" { return project.ErrRestart } return nil @@ -223,9 +221,8 @@ func (s *Service) rename(ctx context.Context) error { } if len(info.Name) > 0 && info.Name[1:] != s.Name() { - logrus.Debugf("Renaming container %s => %s", info.Name[1:], s.Name()) + log.Debugf("Renaming container %s => %s", info.Name[1:], s.Name()) return client.ContainerRename(context.Background(), info.ID, s.Name()) - } else { - return nil } + return nil } diff --git a/docker/service_factory.go b/docker/service_factory.go index 6126aa0d..dae45361 100644 --- a/docker/service_factory.go +++ b/docker/service_factory.go @@ -15,11 +15,17 @@ type ServiceFactory struct { func (s *ServiceFactory) Create(project *project.Project, name string, serviceConfig *composeConfig.ServiceConfig) (project.Service, error) { if after := serviceConfig.Labels["io.rancher.os.after"]; after != "" { for _, dep := range util.TrimSplit(after, ",") { + if dep == "cloud-init" { + dep = "cloud-init-execute" + } s.Deps[name] = append(s.Deps[name], dep) } } if before := serviceConfig.Labels["io.rancher.os.before"]; before != "" { for _, dep := range util.TrimSplit(before, ",") { + if dep == "cloud-init" { + dep = "cloud-init-execute" + } s.Deps[dep] = append(s.Deps[dep], name) } } diff --git a/docker/util.go b/docker/util.go index 71622281..3bbf4c94 100644 --- a/docker/util.go +++ b/docker/util.go @@ -6,6 +6,5 @@ import ( ) func IsSystemContainer(serviceConfig *composeConfig.ServiceConfig) bool { - return serviceConfig.Labels[config.SCOPE] == config.SYSTEM - + return serviceConfig.Labels[config.ScopeLabel] == config.System } diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 00000000..b968ccab --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +require 'json' +require 'open-uri' +versions = JSON.parse(open('https://pages.github.com/versions.json').read) + +gem 'github-pages' diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 00000000..3ecbc351 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,131 @@ +GEM + remote: https://rubygems.org/ + specs: + RedCloth (4.2.9) + activesupport (4.2.5) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.3.8) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.10.0) + colorator (0.1) + ethon (0.8.0) + ffi (>= 1.3.0) + execjs (2.6.0) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + ffi (1.9.10) + gemoji (2.1.0) + github-pages (51) + RedCloth (= 4.2.9) + github-pages-health-check (= 1.0.1) + jekyll (= 3.0.3) + jekyll-coffeescript (= 1.0.1) + jekyll-feed (= 0.4.0) + jekyll-gist (= 1.4.0) + jekyll-mentions (= 1.0.1) + jekyll-paginate (= 1.1.0) + jekyll-redirect-from (= 0.9.1) + jekyll-sass-converter (= 1.3.0) + jekyll-seo-tag (= 1.2.0) + jekyll-sitemap (= 0.10.0) + jekyll-textile-converter (= 0.1.0) + jemoji (= 0.5.1) + kramdown (= 1.9.0) + liquid (= 3.0.6) + mercenary (~> 0.3) + rdiscount (= 2.1.8) + redcarpet (= 3.3.3) + rouge (= 1.10.1) + terminal-table (~> 1.4) + github-pages-health-check (1.0.1) + addressable (~> 2.3) + net-dns (~> 0.8) + octokit (~> 4.0) + public_suffix (~> 1.4) + typhoeus (~> 0.7) + html-pipeline (2.3.0) + activesupport (>= 2, < 5) + nokogiri (>= 1.4) + i18n (0.7.0) + jekyll (3.0.3) + colorator (~> 0.1) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 3.0) + mercenary (~> 0.3.3) + rouge (~> 1.7) + safe_yaml (~> 1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-feed (0.4.0) + jekyll-gist (1.4.0) + octokit (~> 4.2) + jekyll-mentions (1.0.1) + html-pipeline (~> 2.3) + jekyll (~> 3.0) + jekyll-paginate (1.1.0) + jekyll-redirect-from (0.9.1) + jekyll (>= 2.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-seo-tag (1.2.0) + jekyll (>= 2.0) + jekyll-sitemap (0.10.0) + jekyll-textile-converter (0.1.0) + RedCloth (~> 4.0) + jekyll-watch (1.3.0) + listen (~> 3.0) + jemoji (0.5.1) + gemoji (~> 2.0) + html-pipeline (~> 2.2) + jekyll (>= 2.0) + json (1.8.1) + kramdown (1.9.0) + liquid (3.0.6) + listen (3.0.4) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + mercenary (0.3.5) + mini_portile (0.6.2) + minitest (5.8.2) + multipart-post (2.0.0) + net-dns (0.8.0) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) + octokit (4.2.0) + sawyer (~> 0.6.0, >= 0.5.3) + public_suffix (1.5.2) + rb-fsevent (0.9.6) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + rdiscount (2.1.8) + redcarpet (3.3.3) + rouge (1.10.1) + safe_yaml (1.0.4) + sass (3.4.19) + sawyer (0.6.0) + addressable (~> 2.3.5) + faraday (~> 0.8, < 0.10) + terminal-table (1.5.2) + thread_safe (0.3.5) + typhoeus (0.8.0) + ethon (>= 0.8.0) + tzinfo (1.2.2) + thread_safe (~> 0.1) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + json + +BUNDLED WITH + 1.11.2 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..51258c6b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,20 @@ +# Documentation for the `master` version of `rancher/os` + +This dir is _not_ the documentation for any released version of RancherOS. +You can find that at the [Rancher Labs Documentation site](https://docs.rancher.com) and +specifically for [RancherOS](https://docs.rancher.com/os/). + +When there are Pull Requests to the `rancher/os` repository that affect the user (or developer), +then it should include changes to the documenation in this directory. + +When we make a new release of RancherOS, the `docs/os` dir will be copied into the `rancher/rancher.github.io` +repository to be accessible by users. + +## Previewing your changes + +You can either build and view your docs locally by running `make docs`, or you can +set your fork of the `rancher/os` repository to render your `master` using `GitHub Pages`. + +To set up `GitHub Pages`, browse to your fork, then to the `Settings` - under `GitHub Pages`, set the `Source` +to `master branch /docs folder` and hit the `Save` button. GitHub will tell you the URL at which the +documenation can be read. diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..6c883437 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,16 @@ +name: Rancher Documentation +description: Documentation for Rancher + + +#URL: http://rancher.github.io +baseurl: "" + +markdown: kramdown +highlighter: rouge +kramdown: + input: GFM + syntax_highlighter: rouge +permalink: pretty + +gems: + - jekyll-redirect-from diff --git a/docs/_includes/os-sidebar.html b/docs/_includes/os-sidebar.html new file mode 100644 index 00000000..e47851f9 --- /dev/null +++ b/docs/_includes/os-sidebar.html @@ -0,0 +1,142 @@ + diff --git a/docs/_includes/rancher-api-sidebar-v1.0.html b/docs/_includes/rancher-api-sidebar-v1.0.html new file mode 100644 index 00000000..b6a14d66 --- /dev/null +++ b/docs/_includes/rancher-api-sidebar-v1.0.html @@ -0,0 +1,615 @@ + diff --git a/docs/_includes/rancher-api-sidebar-v1.1.html b/docs/_includes/rancher-api-sidebar-v1.1.html new file mode 100644 index 00000000..a196ba7b --- /dev/null +++ b/docs/_includes/rancher-api-sidebar-v1.1.html @@ -0,0 +1,532 @@ + diff --git a/docs/_includes/rancher-api-sidebar-v1.2.html b/docs/_includes/rancher-api-sidebar-v1.2.html new file mode 100644 index 00000000..2ce0f7b2 --- /dev/null +++ b/docs/_includes/rancher-api-sidebar-v1.2.html @@ -0,0 +1,410 @@ + diff --git a/docs/_includes/rancher-api-sidebar.html b/docs/_includes/rancher-api-sidebar.html new file mode 100644 index 00000000..2697090d --- /dev/null +++ b/docs/_includes/rancher-api-sidebar.html @@ -0,0 +1,405 @@ + diff --git a/docs/_includes/rancher-api-v2-beta-sidebar-v1.2.html b/docs/_includes/rancher-api-v2-beta-sidebar-v1.2.html new file mode 100644 index 00000000..f3d4da57 --- /dev/null +++ b/docs/_includes/rancher-api-v2-beta-sidebar-v1.2.html @@ -0,0 +1,435 @@ + diff --git a/docs/_includes/rancher-sidebar-old.html b/docs/_includes/rancher-sidebar-old.html new file mode 100644 index 00000000..fbea6aa5 --- /dev/null +++ b/docs/_includes/rancher-sidebar-old.html @@ -0,0 +1,207 @@ + \ No newline at end of file diff --git a/docs/_includes/rancher-sidebar-v1.0.html b/docs/_includes/rancher-sidebar-v1.0.html new file mode 100644 index 00000000..dddbf24d --- /dev/null +++ b/docs/_includes/rancher-sidebar-v1.0.html @@ -0,0 +1,187 @@ + diff --git a/docs/_includes/rancher-sidebar-v1.1.html b/docs/_includes/rancher-sidebar-v1.1.html new file mode 100644 index 00000000..7491107b --- /dev/null +++ b/docs/_includes/rancher-sidebar-v1.1.html @@ -0,0 +1,182 @@ + diff --git a/docs/_includes/rancher-sidebar-v1.2.html b/docs/_includes/rancher-sidebar-v1.2.html new file mode 100644 index 00000000..7db60fdc --- /dev/null +++ b/docs/_includes/rancher-sidebar-v1.2.html @@ -0,0 +1,203 @@ + diff --git a/docs/_includes/rancher-sidebar.html b/docs/_includes/rancher-sidebar.html new file mode 100644 index 00000000..0a081507 --- /dev/null +++ b/docs/_includes/rancher-sidebar.html @@ -0,0 +1,203 @@ + diff --git a/docs/_includes/volume-sidebar.html b/docs/_includes/volume-sidebar.html new file mode 100644 index 00000000..c5970932 --- /dev/null +++ b/docs/_includes/volume-sidebar.html @@ -0,0 +1,28 @@ + diff --git a/docs/_layouts/os-default.html b/docs/_layouts/os-default.html new file mode 100644 index 00000000..5cf82523 --- /dev/null +++ b/docs/_layouts/os-default.html @@ -0,0 +1,44 @@ + + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include os-sidebar.html %} +
+
+
+ {{ content }} + +
+ +
+
+ +
+ + + + + + diff --git a/docs/_layouts/rancher-api-default-v1.0.html b/docs/_layouts/rancher-api-default-v1.0.html new file mode 100644 index 00000000..a2483c2c --- /dev/null +++ b/docs/_layouts/rancher-api-default-v1.0.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-api-sidebar-v1.0.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-api-default-v1.1.html b/docs/_layouts/rancher-api-default-v1.1.html new file mode 100644 index 00000000..374bbdbd --- /dev/null +++ b/docs/_layouts/rancher-api-default-v1.1.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-api-sidebar-v1.1.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-api-default-v1.2.html b/docs/_layouts/rancher-api-default-v1.2.html new file mode 100644 index 00000000..21ef1098 --- /dev/null +++ b/docs/_layouts/rancher-api-default-v1.2.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-api-sidebar-v1.2.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-api-v2-beta-default-v1.2.html b/docs/_layouts/rancher-api-v2-beta-default-v1.2.html new file mode 100644 index 00000000..03e5864f --- /dev/null +++ b/docs/_layouts/rancher-api-v2-beta-default-v1.2.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-api-v2-beta-sidebar-v1.2.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-default-v1.0.html b/docs/_layouts/rancher-default-v1.0.html new file mode 100644 index 00000000..d050525e --- /dev/null +++ b/docs/_layouts/rancher-default-v1.0.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-sidebar-v1.0.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-default-v1.1.html b/docs/_layouts/rancher-default-v1.1.html new file mode 100644 index 00000000..35b273d0 --- /dev/null +++ b/docs/_layouts/rancher-default-v1.1.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-sidebar-v1.1.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-default-v1.2.html b/docs/_layouts/rancher-default-v1.2.html new file mode 100644 index 00000000..b0044949 --- /dev/null +++ b/docs/_layouts/rancher-default-v1.2.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-sidebar-v1.2.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/rancher-default.html b/docs/_layouts/rancher-default.html new file mode 100644 index 00000000..8954c7a1 --- /dev/null +++ b/docs/_layouts/rancher-default.html @@ -0,0 +1,47 @@ + + + + + {{ page.title }} + + + + + + + + + + +
+
+
+ {% include rancher-sidebar.html %} +
+
+
+ {{ content }} + +
+ +
+
+
+ + + + + + + + diff --git a/docs/_layouts/volume-default.html b/docs/_layouts/volume-default.html new file mode 100644 index 00000000..1b0b82a4 --- /dev/null +++ b/docs/_layouts/volume-default.html @@ -0,0 +1,37 @@ + + + + + + {{ site.name }} + + + + + + + + + +
+
+
+ {% include volume-sidebar.html %} +
+
+
+ {{ content }} +
+
+
+
+ Copyright © 2016 Rancher Labs. All Rights Reserved. +
+
+
+
+ + + + + diff --git a/docs/css/bootstrap.css b/docs/css/bootstrap.css new file mode 100644 index 00000000..076cc515 --- /dev/null +++ b/docs/css/bootstrap.css @@ -0,0 +1,6585 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ +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: bold; +} +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 #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +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 { + *, + *:before, + *:after { + color: #000 !important; + text-shadow: none !important; + background: transparent !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^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .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 th, + .table-bordered td { + 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: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before, +.glyphicon-eur: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; +} +*:before, +*:after { + -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; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #337ab7; + text-decoration: none; +} +a:hover, +a:focus { + color: #23527c; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > 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; +} + +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, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #777; +} +h1, +.h1, +h2, +.h2, +h3, +.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, +.h4, +h5, +.h5, +h6, +.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:hover { + color: #286090; +} +.text-success { + color: #3c763d; +} +a.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #337ab7; +} +a.bg-primary:hover { + background-color: #286090; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + 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; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +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[title], +abbr[data-original-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 p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #777; +} +blockquote footer:before, +blockquote small: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 footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small: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: bold; + -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-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + 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-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + 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-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + 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-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + 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 > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + 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 > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #ddd; +} +.table .table { + background-color: #fff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + 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 > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + 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 > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + 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: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + 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="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + 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[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"], + input[type="time"], + input[type="datetime-local"], + input[type="month"] { + line-height: 34px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .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"] { + line-height: 30px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .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"] { + line-height: 46px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 4px \9; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox 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; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.form-group-sm .form-control { + height: 30px; + line-height: 30px; +} +textarea.form-group-sm .form-control, +select[multiple].form-group-sm .form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 30px; + min-height: 32px; + padding: 5px 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; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +select.form-group-lg .form-control { + height: 46px; + line-height: 46px; +} +textarea.form-group-lg .form-control, +select[multiple].form-group-lg .form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 46px; + min-height: 38px; + padding: 10px 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; +} +.input-lg + .form-control-feedback { + width: 46px; + height: 46px; + line-height: 46px; +} +.input-sm + .form-control-feedback { + width: 30px; + height: 30px; + line-height: 30px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-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 .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-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 .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-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 .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + 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: 14.333333px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + } +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + 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:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + 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 { + pointer-events: none; + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default.focus, +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + 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:hover, +.btn-primary:focus, +.btn-primary.focus, +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #fff; + background-color: #286090; + border-color: #204d74; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + 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:hover, +.btn-success:focus, +.btn-success.focus, +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + 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:hover, +.btn-info:focus, +.btn-info.focus, +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + 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:hover, +.btn-warning:focus, +.btn-warning.focus, +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + 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:hover, +.btn-danger:focus, +.btn-danger.focus, +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + 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:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #23527c; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #777; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 6px; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs, +.btn-group-xs > .btn { + 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="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].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-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + 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: normal; + line-height: 1.42857143; + color: #333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #337ab7; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #777; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + 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 solid; +} +.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 > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + 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-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-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-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="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + 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-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; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].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; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control: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: normal; + 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="radio"], +.input-group-addon input[type="checkbox"] { + 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:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + 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:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + 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:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + 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 { + 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:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #777; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #777; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + 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:hover, +.nav-tabs > li.active > a:focus { + 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:hover, +.nav-tabs.nav-justified > .active > a:focus { + 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:hover, + .nav-tabs.nav-justified > .active > a:focus { + 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:hover, +.nav-pills > li.active > a:focus { + 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:hover, +.nav-tabs-justified > .active > a:focus { + 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:hover, + .nav-tabs-justified > .active > a:focus { + 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-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + 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-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + 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: 12px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; + width: 170px; +} +@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 > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + 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 .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + 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:hover, +.navbar-default .navbar-brand:focus { + 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:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + 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:hover, +.navbar-default .navbar-nav > .open > a:focus { + 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:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + 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:hover, +.navbar-default .btn-link:focus { + color: #333; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #ccc; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #9d9d9d; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + 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:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + 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:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + 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:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + 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:hover, +.navbar-inverse .btn-link:focus { + color: #fff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + 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:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #23527c; + background-color: #eee; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + cursor: default; + background-color: #337ab7; + border-color: #337ab7; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + 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; +} +.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; +} +.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:hover, +.pager li > a:focus { + 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:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #777; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + 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]:hover, +.label-default[href]:focus { + background-color: #5e5e5e; +} +.label-primary { + background-color: #337ab7; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #286090; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #777; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + 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: 30px 15px; + 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 { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding: 48px 0; + } + .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 > img, +.thumbnail a > img { + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + 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: bold; +} +.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-striped .progress-bar, +.progress-bar-striped { + 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.active .progress-bar, +.progress-bar.active { + -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-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + 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 { + color: #555; +} +a.list-group-item .list-group-item-heading { + color: #333; +} +a.list-group-item:hover, +a.list-group-item:focus { + color: #555; + text-decoration: none; + background-color: #f5f5f5; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + color: #777; + cursor: not-allowed; + background-color: #eee; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #777; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #337ab7; + border-color: #337ab7; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #c7ddef; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + 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 > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.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-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-right: 15px; + padding-left: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead: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-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .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 td:first-child, +.panel > .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 td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th: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 th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .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 td:last-child, +.panel > .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 td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th: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 th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .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 td:first-child, +.panel > .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 td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .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 td:last-child, +.panel > .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 td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .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 th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.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 > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + 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 iframe, +.embed-responsive embed, +.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: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + 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 { + min-height: 16.42857143px; + 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-weight: normal; + line-height: 1.4; + filter: alpha(opacity=0); + opacity: 0; +} +.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; + text-decoration: none; + 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-weight: normal; + line-height: 1.42857143; + text-align: left; + 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); +} +.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 > img, +.carousel-inner > .item > a > 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: 1000; + perspective: 1000; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + left: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + left: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + 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); + 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:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: 0; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + 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-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -15px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -15px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer: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-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.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; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.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; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.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; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.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; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.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.css.map */ diff --git a/docs/css/bootstrap.min.css b/docs/css/bootstrap.min.css new file mode 100644 index 00000000..cd1c616a --- /dev/null +++ b/docs/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */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}select{background:#fff!important}.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:"\2a"}.glyphicon-plus:before{content:"\2b"}.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:thin dotted;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:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}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:thin dotted;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[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],input[type=time],input[type=datetime-local],input[type=month]{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}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 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}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 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}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.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:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.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:thin dotted;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{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,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.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,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.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,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.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,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.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,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.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,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-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 solid}.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-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-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-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-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{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{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:2;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}.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}.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:baseline;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:30px 15px;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{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.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-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{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.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{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.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{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.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{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.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{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.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{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-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{min-height:16.43px;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-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.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;text-decoration:none;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-weight:400;line-height:1.42857143;text-align:left;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)}.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:1000;perspective:1000}.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);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}.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;margin-top:-10px;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:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.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,.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,.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}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}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}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}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}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}} \ No newline at end of file diff --git a/docs/css/rancher.css b/docs/css/rancher.css new file mode 100644 index 00000000..daa41b21 --- /dev/null +++ b/docs/css/rancher.css @@ -0,0 +1,685 @@ +.sidebar-nav .btn-group { + margin: 15px 0 0 15px; +} + +BODY { + background-color: #f0f2f2; + font-family: 'Lato', sans-serif; + font-size: 14px; +} + +img { + max-width: 100%; + height: auto; +} + +/* make sidebar nav vertical */ +@media (min-width: 768px) { + .sidebar-nav .navbar .navbar-collapse { + padding: 0; + max-height: none; + } + .sidebar-nav .navbar ul { + float: none; + } + .sidebar-nav .navbar ul:not { + display: block; + } + .sidebar-nav .navbar li { + float: none; + display: block; + } + .sidebar-nav .navbar li a { + padding-top: 8px; + padding-bottom: 8px; + font-weight: 300; + } +} + + +pre { + padding: 0; + margin: 0; + background-color: transparent; + border: none; + border-radius: 0; +} + +pre code { + display: block; + padding: 9.5px; + font-size: 13px; + line-height: 1.42857143; + color: #ECF0F1; + word-break: break-all; + word-wrap: break-word; + background-color: #334851; + border: 1px solid #0A141A; + border-radius: 4px; +} + +.language-bash pre code{ + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + word-break: break-all; + word-wrap: break-word; + border-radius: 4px; + border: black; + background-color: #2B2B2B; + color: #ECF0F1; +} + +.language-sh pre code{ + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + word-break: break-all; + word-wrap: break-word; + border-radius: 4px; + border: black; + background-color: black; + color: white; +} + +/* Link Color in Content*/ +a { + color: #005f88; + text-decoration: none; +} + +a:hover, +a:focus { + color: #0077aa; + text-decoration: none; +} + +/* Heading in Markdown using # */ +h1, h2 { + font-weight: 300; +} + +/*h3 { + text-align: center; +} + +h3:before, h3:after { + content: ""; + width: 50px; + height: 3px; + background: #5c686f; + display: inline-block; + vertical-align: middle; + margin: 0 10px; +} +*/ +/*HEADERS*/ +h1, h2 { + font-weight: 300; +} + +h3, +h4, +h5, +h6 { + text-transform: uppercase; + color: #5c686f; + letter-spacing: .75px; +} +h3, +h4, +h5, +h6 { + text-transform: uppercase; + color: #5c686f; + font-weight: 900; +} +h3 { + color: #334851; +} +/* Line bar in markdown as --- */ +hr { + margin-top: 10px; +} + +/*Remove rounded corners on navigation*/ +@media (min-width: 768px) { + .navbar { + border-radius: 0px; + } +} + + +/* Remove right and left padding on column containers for */ +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + padding-right: 0px; + padding-left: 0px; +} +.container { + margin-right: 0; + margin-left: 0; + width: 100%; +} + +/*Provides padding around context*/ +.content-container { + padding-left: 5%; + max-width: 80%; +} + +.navbar-inverse { + background:#fff; + border: none; + color: #5c686f; +} + + +.navbar-inverse .navbar-nav > li > a { + color: #777; + font-weight: normal; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #0075a8; + background-color: transparent; + text-decoration: none; +} + +.navbar-inverse .navbar-nav > li > .no-list-group { + color: #788188; +} +.navbar-inverse .navbar-nav > li > .no-list-group:hover, +.navbar-inverse .navbar-nav > li > .no-list-group:focus { + background-color: #5c686f; + color:#0075a8; + text-decoration: none; +} + +.list-group-item { + position: relative; + display: block; + padding: 10px 10px; + margin-bottom: -1px; + background-color: transparent; + border: none; +} + +.list-group-submenu li { + list-style: none; + margin-left: 0; + margin-bottom:7px; + color:#788188; + padding:0; +} + +span.highlight { + background-color: yellow; +} + +blockquote { + font-size: inherit; +} + +code{ + padding:2px 5px; + display:inline-block; + background: #21364a; + color: #0075a8; +} + +.row{ + width:100%; + position:relative; + display:inline-block; +} + +.row .col-sm-3{ + background-color: #fff; +} +.copyright { + height: 34px; + line-height: 34px; +} +a i { + font-size: 16px; + margin-top: 3px; + padding-right:10px; +} +a.btn i { + margin: 0; + padding: 0; +} +a.collapsed i.fa-angle-down, a i.fa-angle-up{ + display:block; +} + +a.collapsed i.fa-angle-up, a i.fa-angle-down{ + display:none; +} + +/*ul li a[aria-expanded=true]{ + background-color: #ecf0f1; +}*/ + +/*NESTED SUBMENU*/ +ul.nav.navbar-nav li ul.list-group-submenu { + border-left: solid #0075a8 thick; + padding: 12px; +} +ul.nav.navbar-nav li ul.list-group-submenu li ul{ +border-left: solid rgba(0,0,0,.75) thick; + padding-left: 40px; + margin-left: -17px; +} +ul.nav.navbar-nav li ul.list-group-submenu li ul ul { + padding: 0; + margin: 0; + border: none; + margin-left: 27px; +} +ul.collapse { + padding: 0; +} + +.navbar-inverse .clearfix{ + background-color:#0075A8; +} + +.sidebar-nav{ + background-color: #5c686f; +} + +.navbar-inverse .navbar-nav > li > a.active { + background: #5c686f; + color: white; +} +ul.nav.navbar-nav li a.active:after { + content: ""; + border: solid transparent; + height: 0; + width: 0; + pointer-events: none; + border-color: transparent; + border-left-color: #5c686f; + border-width: 10px; + position: absolute; + right: -20px; + top: calc(50% - 10px); +} + +ul.nav.navbar-nav .list-group-submenu li a.active:after { +display: none; +} + +ul.collapse.in a.active { + color: #0075A8; +} +.panel { + margin-bottom: 0px; + border: 0px; + border-radius: 0px; + -webkit-box-shadow:none; + box-shadow:none; +} + +@media (max-width:768px){ + + .col-sm-9 .content-container{ + padding-left: 15px; + } + .row .col-sm-3 {f + height: auto; + min-height: 0px; + } + .container-fluid{ + padding:0; + } + + .row{ + width:100%; + padding:0; + margin:0; + } + + .row .col-sm-3{ + width:100%; + top:auto; + left:auto; + bottom:auto; + position:relative; + background-color: #5c686f; + } + + .row .col-sm-9{ + position:relative; + width:100%; + float:right; + } +} + +.header-anchor { + font-size: 14px; + visibility: hidden; + position: relative; + top: -3px; + left: 5px; +} + +H3:hover .header-anchor, +H4:hover .header-anchor, +H5:hover .header-anchor, +H6:hover .header-anchor { + visibility: visible; +} + + + + +/*ANCHORS*/ +a { + color: #0075a8; + text-decoration: none; +} +a:hover { + text-decoration: none; +} +hr { + margin: 2% 0; + border-top: 1px solid #BFBFBF; +} + +/*LISTS*/ +ol { + counter-reset: li; + margin: 20px 0; + padding-left: 0; +} + +ol > li { + position: relative; + margin: 0 0 25px 2em; + padding: 4px 8px 4px 20px; + list-style: none; + background: rgba(255,255,255,.75); +} + +ol > li::before { + content: counter(li); + counter-increment: li; + position: absolute; + top: 0; + left: -2em; + bottom: 0; + width: 2em; + margin-right: 8px; + padding: 4px; + font-weight: bold; + text-align: center; + background: #BDC3C7; + color: white; +} + +li ol, +li ul { + margin-top: 6px; +} + +ol ol li:last-child { + margin-bottom: 0; +} + +ol > li::before { + +} + +/*TABLES*/ +table { + background: white; + width: 100%; + border-collapse: collapse; + word-wrap:break-word; +} + +th { + background: #0075a8; + color: white; + font-weight: 400; +} + +th a { + color: #efefef; + border-bottom: solid 2px; +} +td, +th { + padding: 10px; + text-align: left; +} + +td { + border: 1px solid #ccd1d3; +} + +th { + border-right: 1px dotted rgba(255, 255, 255, 0.15); + border-bottom: 1px dotted rgba(255, 255, 255, 0.15); +} + +tr:nth-child(even) { + background: #efefef; +} +td code { + background: rgba(0,0,0,.05); +} + +.gsc-search-box td, .gsc-results-wrapper-overlay td { + border-color: transparent; +} + +.gsc-table-result td { + border-bottom: solid 2px #efefef; + padding-bottom: 30px; +} +.gsc-search-box td, .gsc-above-wrapper-area-container td { + padding: 0; + +} +.cse .gsc-search-button input.gsc-search-button-v2, input.gsc-search-button-v2 { + width: auto!important; + height: auto!important; +} + +.gsc-above-wrapper-area .gsc-selected-option-container { + min-width: 100px; +} + +.gsc-results-wrapper-overlay { + -webkit-box-shadow: 0 0 0 transparent!important; + -moz-box-shadow: 0 0 0 transparent!important; + -ms-box-shadow: 0 0 0 transparent!important; + -o-box-shadow: 0 0 0 transparent!important; + box-shadow: 0 0 0 transparent!important; +} +.gsc-modal-background-image { + background-color: rgba(153,163,168,.75)!important; +} +/*CODE SNIPPETS*/ +code { + word-wrap:break-word; + border-radius: 3px; + color: #444; + background-color: #ddd; +} + + +/*BLOCKQUOTES*/ +blockquote { + border-left: solid thick #0075a8; + padding: 1% 5%; + position: relative; + background: white; + margin-left: 0; + margin-right: 0; +} + +blockquote:before { + content: ""; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-color: transparent; + border-left-color: #0075a8; + border-width: 8px; + position: absolute; + left: 0; + top: calc(50% - 8px); +} + +blockquote strong:first-child{ + display: block; + text-transform: uppercase; + margin-bottom: 10px; + color: #5c686f; +} + +/*ACTIONS*/ +#other-actions p:first-child { + margin: 0; +} +.action > span { + display: block; +} +.action .header { + color: #0075a8; + font-weight: bold; + text-transform: uppercase; + background-color: #99c8dc; + float: left; + width: 100%; + line-height: 48px; + padding-left: 10px; +} +.action .header > *{ + display: inline-block; + vertical-align: middle; +} + +.action .header .headerright { + float: right; + background: #66accb; + color: white; + padding: 8px 10px; + text-transform: none; + line-height: normal; +} + +.action .header .headerright code { + color: white; + background: #3391b9; + margin-left: 10px; + padding: 8px; + font-weight: normal; + text-transform: none; +} + +.action{ + border: solid thin #efefef; + background: white; + display: block; + margin: 10px 0; +} +.action-contents{ + padding:20px; + border: solid thin #efefef; + background: white; + clear: both; +} +.action-contents th { + background: #66767c; + } +.input, .output{ + background-color: #e5f1f6; + padding: 10px 0; + display: block; + width: 100%; +} + +.input strong, .output strong { + padding: 10px; + background: #99c8dc; + position: relative; + margin-right: 15px; +} + +.input strong:before,.output strong:before { + content: ""; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-color: transparent; + border-left-color: #99c8dc; + border-width: 8px; + position: absolute; + right: -15px; + top: calc(50% - 8px); +} + +footer { + margin: 20px 0; + padding: 10px 0; + border-top: solid thin #BDC3C7; + height: 34px; + clear: both; +} +@media (max-width:768px){ + .navbar-inverse .navbar-toggle { + background: rgba(0,0,0,.25); + } + .navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { + background: rgba(0,0,0,.5); + } + .navbar-inverse .navbar-header{ + background: #0075a8; + } + + .col-sm-9 .content-container{ + padding: 0 2%; + max-width: 100%; + } + .row .col-sm-3 { + height: auto !important; + min-height: 0px !important; + } + .container-fluid{ + padding:0; + } + + .row{ + width:100%; + padding:0; + margin:0; + } + + .row .col-sm-3{ + width:100%; + top:auto; + left:auto; + bottom:auto; + position:relative; + background-color:#f2efef; + } + + .row .col-sm-9{ + position:relative; + width:100%; + float:right; + } +} diff --git a/docs/css/syntax.css b/docs/css/syntax.css new file mode 100644 index 00000000..3e539add --- /dev/null +++ b/docs/css/syntax.css @@ -0,0 +1,62 @@ +.highlight .c { color: #66767C; font-style: italic } /* Comment */ +.highlight .err { color: #ffffff } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #C0392B } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ +.highlight .gt { color: #C0392B } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #F15354; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #0075A8 } /* Literal.Number */ +.highlight .s { color: #EADF5A } /* Literal.String */ +.highlight .na { color: #A5C63B } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #0075A8 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #C0392B; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #78C9CF; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #F15354 } /* Name.Tag */ +.highlight .nv { color: #FFFFFF } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #0075A8 } /* Literal.Number.Float */ +.highlight .mh { color: #0075A8 } /* Literal.Number.Hex */ +.highlight .mi { color: #0075A8 } /* Literal.Number.Integer */ +.highlight .mo { color: #0075A8 } /* Literal.Number.Oct */ +.highlight .sb { color: #EADF5A } /* Literal.String.Backtick */ +.highlight .sc { color: #EADF5A } /* Literal.String.Char */ +.highlight .sd { color: #EADF5A } /* Literal.String.Doc */ +.highlight .s2 { color: #EADF5A } /* Literal.String.Double */ +.highlight .se { color: #EADF5A } /* Literal.String.Escape */ +.highlight .sh { color: #EADF5A } /* Literal.String.Heredoc */ +.highlight .si { color: #EADF5A } /* Literal.String.Interpol */ +.highlight .sx { color: #EADF5A } /* Literal.String.Other */ +.highlight .sr { color: #EADF5A } /* Literal.String.Regex */ +.highlight .s1 { color: #EADF5A } /* Literal.String.Single */ +.highlight .ss { color: #EADF5A } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #FFFFFF } /* Name.Variable.Class */ +.highlight .vg { color: #FFFFFF } /* Name.Variable.Global */ +.highlight .vi { color: #FFFFFF } /* Name.Variable.Instance */ +.highlight .il { color: #0075A8 } /* Literal.Number.Integer.Long */ + +.highlight .lineno { color: #ccc; display:inline-block; padding: 0 5px; border-right:1px solid #ccc; } +.highlight pre code { display: block; white-space: pre; overflow-x: auto; word-wrap: normal; } diff --git a/docs/favicon.png b/docs/favicon.png new file mode 100644 index 00000000..6128da5e Binary files /dev/null and b/docs/favicon.png differ diff --git a/docs/img/glyphicons-halflings-white.png b/docs/img/glyphicons-halflings-white.png new file mode 100644 index 00000000..3bf6484a Binary files /dev/null and b/docs/img/glyphicons-halflings-white.png differ diff --git a/docs/img/glyphicons-halflings.png b/docs/img/glyphicons-halflings.png new file mode 100644 index 00000000..a9969993 Binary files /dev/null and b/docs/img/glyphicons-halflings.png differ diff --git a/docs/img/os/Rancher_aws1.png b/docs/img/os/Rancher_aws1.png new file mode 100644 index 00000000..51714242 Binary files /dev/null and b/docs/img/os/Rancher_aws1.png differ diff --git a/docs/img/os/Rancher_aws2.png b/docs/img/os/Rancher_aws2.png new file mode 100644 index 00000000..44c1e734 Binary files /dev/null and b/docs/img/os/Rancher_aws2.png differ diff --git a/docs/img/os/Rancher_aws3.png b/docs/img/os/Rancher_aws3.png new file mode 100644 index 00000000..866bb3cb Binary files /dev/null and b/docs/img/os/Rancher_aws3.png differ diff --git a/docs/img/os/Rancher_aws4.png b/docs/img/os/Rancher_aws4.png new file mode 100644 index 00000000..a55c4c93 Binary files /dev/null and b/docs/img/os/Rancher_aws4.png differ diff --git a/docs/img/os/Rancher_aws5.png b/docs/img/os/Rancher_aws5.png new file mode 100644 index 00000000..6184541b Binary files /dev/null and b/docs/img/os/Rancher_aws5.png differ diff --git a/docs/img/os/Rancher_aws6.png b/docs/img/os/Rancher_aws6.png new file mode 100644 index 00000000..6f83bdd4 Binary files /dev/null and b/docs/img/os/Rancher_aws6.png differ diff --git a/docs/img/os/Rancher_aws7.png b/docs/img/os/Rancher_aws7.png new file mode 100644 index 00000000..1c5f5ae7 Binary files /dev/null and b/docs/img/os/Rancher_aws7.png differ diff --git a/docs/img/os/Rancher_aws8.png b/docs/img/os/Rancher_aws8.png new file mode 100644 index 00000000..71ea1a07 Binary files /dev/null and b/docs/img/os/Rancher_aws8.png differ diff --git a/docs/img/os/Rancher_aws9.png b/docs/img/os/Rancher_aws9.png new file mode 100644 index 00000000..83c6c49a Binary files /dev/null and b/docs/img/os/Rancher_aws9.png differ diff --git a/docs/img/os/Rancher_busydash.png b/docs/img/os/Rancher_busydash.png new file mode 100644 index 00000000..999e9b3a Binary files /dev/null and b/docs/img/os/Rancher_busydash.png differ diff --git a/docs/img/os/Rancher_disk1.png b/docs/img/os/Rancher_disk1.png new file mode 100644 index 00000000..4d7af226 Binary files /dev/null and b/docs/img/os/Rancher_disk1.png differ diff --git a/docs/img/os/Rancher_disk2.png b/docs/img/os/Rancher_disk2.png new file mode 100644 index 00000000..c0c4fbc9 Binary files /dev/null and b/docs/img/os/Rancher_disk2.png differ diff --git a/docs/img/os/Rancher_disk3.png b/docs/img/os/Rancher_disk3.png new file mode 100644 index 00000000..fca549b8 Binary files /dev/null and b/docs/img/os/Rancher_disk3.png differ diff --git a/docs/img/os/Rancher_gce1.png b/docs/img/os/Rancher_gce1.png new file mode 100644 index 00000000..8b0da400 Binary files /dev/null and b/docs/img/os/Rancher_gce1.png differ diff --git a/docs/img/os/Rancher_gce4.png b/docs/img/os/Rancher_gce4.png new file mode 100644 index 00000000..c480c118 Binary files /dev/null and b/docs/img/os/Rancher_gce4.png differ diff --git a/docs/img/os/Rancher_gce5.png b/docs/img/os/Rancher_gce5.png new file mode 100644 index 00000000..553cda60 Binary files /dev/null and b/docs/img/os/Rancher_gce5.png differ diff --git a/docs/img/os/Rancher_gce6.png b/docs/img/os/Rancher_gce6.png new file mode 100644 index 00000000..7d810106 Binary files /dev/null and b/docs/img/os/Rancher_gce6.png differ diff --git a/docs/img/os/Rancher_gce7.png b/docs/img/os/Rancher_gce7.png new file mode 100644 index 00000000..bb69e831 Binary files /dev/null and b/docs/img/os/Rancher_gce7.png differ diff --git a/docs/img/os/Rancher_gce8.png b/docs/img/os/Rancher_gce8.png new file mode 100644 index 00000000..16e6a1c0 Binary files /dev/null and b/docs/img/os/Rancher_gce8.png differ diff --git a/docs/img/os/Rancher_gce9.png b/docs/img/os/Rancher_gce9.png new file mode 100644 index 00000000..edb382d7 Binary files /dev/null and b/docs/img/os/Rancher_gce9.png differ diff --git a/docs/img/os/Rancher_iso1.png b/docs/img/os/Rancher_iso1.png new file mode 100644 index 00000000..f4a546e3 Binary files /dev/null and b/docs/img/os/Rancher_iso1.png differ diff --git a/docs/img/os/Rancher_iso2.png b/docs/img/os/Rancher_iso2.png new file mode 100644 index 00000000..c0a1a051 Binary files /dev/null and b/docs/img/os/Rancher_iso2.png differ diff --git a/docs/img/os/Rancher_iso3.png b/docs/img/os/Rancher_iso3.png new file mode 100644 index 00000000..988d750b Binary files /dev/null and b/docs/img/os/Rancher_iso3.png differ diff --git a/docs/img/os/Rancher_iso4.png b/docs/img/os/Rancher_iso4.png new file mode 100644 index 00000000..817f4119 Binary files /dev/null and b/docs/img/os/Rancher_iso4.png differ diff --git a/docs/img/os/Rancher_iso5.png b/docs/img/os/Rancher_iso5.png new file mode 100644 index 00000000..ac2e73ae Binary files /dev/null and b/docs/img/os/Rancher_iso5.png differ diff --git a/docs/img/os/Rancher_iso6.png b/docs/img/os/Rancher_iso6.png new file mode 100644 index 00000000..aa02e98b Binary files /dev/null and b/docs/img/os/Rancher_iso6.png differ diff --git a/docs/img/os/Rancher_iso7.png b/docs/img/os/Rancher_iso7.png new file mode 100644 index 00000000..7372ecc3 Binary files /dev/null and b/docs/img/os/Rancher_iso7.png differ diff --git a/docs/img/os/Rancher_iso8.png b/docs/img/os/Rancher_iso8.png new file mode 100644 index 00000000..cbbcd27b Binary files /dev/null and b/docs/img/os/Rancher_iso8.png differ diff --git a/docs/img/os/Rancher_platform1.png b/docs/img/os/Rancher_platform1.png new file mode 100644 index 00000000..7791f2fe Binary files /dev/null and b/docs/img/os/Rancher_platform1.png differ diff --git a/docs/img/os/Rancher_platform2.png b/docs/img/os/Rancher_platform2.png new file mode 100644 index 00000000..eb1d085f Binary files /dev/null and b/docs/img/os/Rancher_platform2.png differ diff --git a/docs/img/os/cloud-config.png b/docs/img/os/cloud-config.png new file mode 100644 index 00000000..98f7db89 Binary files /dev/null and b/docs/img/os/cloud-config.png differ diff --git a/docs/img/os/rancheroshowitworks.png b/docs/img/os/rancheroshowitworks.png new file mode 100644 index 00000000..c29a4779 Binary files /dev/null and b/docs/img/os/rancheroshowitworks.png differ diff --git a/docs/img/rancher-logo-nopadding-OLD.png b/docs/img/rancher-logo-nopadding-OLD.png new file mode 100644 index 00000000..b70b2785 Binary files /dev/null and b/docs/img/rancher-logo-nopadding-OLD.png differ diff --git a/docs/img/rancher-logo-nopadding.svg b/docs/img/rancher-logo-nopadding.svg new file mode 100644 index 00000000..b6492a28 --- /dev/null +++ b/docs/img/rancher-logo-nopadding.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/img/rancher/api_endpoint.png b/docs/img/rancher/api_endpoint.png new file mode 100644 index 00000000..90cac8b0 Binary files /dev/null and b/docs/img/rancher/api_endpoint.png differ diff --git a/docs/img/rancher/apikeys.png b/docs/img/rancher/apikeys.png new file mode 100644 index 00000000..3409b7a4 Binary files /dev/null and b/docs/img/rancher/apikeys.png differ diff --git a/docs/img/rancher/rancher_aws_1.png b/docs/img/rancher/rancher_aws_1.png new file mode 100644 index 00000000..b30804c2 Binary files /dev/null and b/docs/img/rancher/rancher_aws_1.png differ diff --git a/docs/img/rancher/rancher_aws_2.png b/docs/img/rancher/rancher_aws_2.png new file mode 100644 index 00000000..77382a4e Binary files /dev/null and b/docs/img/rancher/rancher_aws_2.png differ diff --git a/docs/img/rancher/rancher_aws_3.png b/docs/img/rancher/rancher_aws_3.png new file mode 100644 index 00000000..6d3f22d8 Binary files /dev/null and b/docs/img/rancher/rancher_aws_3.png differ diff --git a/docs/img/rancher/rancher_do_1.png b/docs/img/rancher/rancher_do_1.png new file mode 100644 index 00000000..80c13f4c Binary files /dev/null and b/docs/img/rancher/rancher_do_1.png differ diff --git a/docs/img/rancher/rancher_do_2.png b/docs/img/rancher/rancher_do_2.png new file mode 100644 index 00000000..ed37d526 Binary files /dev/null and b/docs/img/rancher/rancher_do_2.png differ diff --git a/docs/img/rancher/rancher_hosts_registration_1.png b/docs/img/rancher/rancher_hosts_registration_1.png new file mode 100644 index 00000000..fc7a335c Binary files /dev/null and b/docs/img/rancher/rancher_hosts_registration_1.png differ diff --git a/docs/img/rancher/rancher_overview.png b/docs/img/rancher/rancher_overview.png new file mode 100644 index 00000000..c445fec3 Binary files /dev/null and b/docs/img/rancher/rancher_overview.png differ diff --git a/docs/img/rancher/rancher_overview_2.png b/docs/img/rancher/rancher_overview_2.png new file mode 100644 index 00000000..00ce8eb2 Binary files /dev/null and b/docs/img/rancher/rancher_overview_2.png differ diff --git a/docs/img/rancher/rancher_packet_1.png b/docs/img/rancher/rancher_packet_1.png new file mode 100644 index 00000000..c6c53d63 Binary files /dev/null and b/docs/img/rancher/rancher_packet_1.png differ diff --git a/docs/img/rancher/rancher_packet_2.png b/docs/img/rancher/rancher_packet_2.png new file mode 100644 index 00000000..7073803a Binary files /dev/null and b/docs/img/rancher/rancher_packet_2.png differ diff --git a/docs/img/rancher/rancher_packet_3.png b/docs/img/rancher/rancher_packet_3.png new file mode 100644 index 00000000..1ec27f69 Binary files /dev/null and b/docs/img/rancher/rancher_packet_3.png differ diff --git a/docs/img/rancher/rancher_stacks_1.png b/docs/img/rancher/rancher_stacks_1.png new file mode 100644 index 00000000..0350bb11 Binary files /dev/null and b/docs/img/rancher/rancher_stacks_1.png differ diff --git a/docs/img/rancheros-logo-horiz-wht.svg b/docs/img/rancheros-logo-horiz-wht.svg new file mode 100644 index 00000000..1bf1e938 --- /dev/null +++ b/docs/img/rancheros-logo-horiz-wht.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/img/rancheros-logo-nopadding.png b/docs/img/rancheros-logo-nopadding.png new file mode 100644 index 00000000..a485f5c0 Binary files /dev/null and b/docs/img/rancheros-logo-nopadding.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..7948dc1b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,15 @@ + + + + + + + Page Redirection + + + + If you are not redirected automatically, follow the link to os + + diff --git a/docs/js/rancher.js b/docs/js/rancher.js new file mode 100644 index 00000000..201eecff --- /dev/null +++ b/docs/js/rancher.js @@ -0,0 +1,84 @@ +jQuery(document).ready(function () { + checkActiveState(); + + // Set height + var content_height = $(".col-sm-9").height(); + $(".col-sm-3").css("min-height", content_height + "px"); + + $("ul.nav li a").click(function (event) { + var link = $(this); + var local_destination = link.attr("href"); + + if ( link.data('toggle') ) + { + return; + } + + event.preventDefault(); + if ( window.location.protocol === 'file:' ) + { + if ( local_destination.substr(-1) === '/' ) + { + local_destination += 'index.html'; + } + + window.location.href = local_destination; + return false; + } + + $.get(local_destination, function (data) { + var title = $(data).find("title").text(); + var local_content = $(data).find(".col-sm-9").html(); + changeUrl(title, local_destination); + checkActiveState(); + $(".col-sm-9").html(local_content); + //If has a class hash (jump on the page) + if(link.hasClass('hash')){ + var local_destination_array = local_destination.split('#'); + var paragraph_id = local_destination_array[1]; + var paragraph_destination = $('.col-sm-9 #' + paragraph_id).offset().top; + $('body,html').animate({scrollTop: paragraph_destination + "px"}); + } + // Set height + var content_height = $(".col-sm-9").height(); + $(".col-sm-3").css("min-height", content_height + "px"); + }); + + setTimeout(function() { + linkAnchors(); + },250); + + }); + linkAnchors(); +}); + +function linkAnchors() { + $('.content-container H3[id], .content-container H4[id], .content-container H5[id], .content-container H6[id]').each(function(idx, el) { + $(el).append($('').addClass('header-anchor').attr('href', '#' + el.id).html('')); + }); +} + +function changeUrl(title, url) { + if (typeof (history.pushState) != "undefined") { + var obj = {Title: title, Url: url}; + history.pushState(obj, obj.Title, obj.Url); + } +} + +function checkActiveState() { + $('UL.nav UL').removeClass('in'); + $('UL A').each(function(idx, a) { + var $a = $(a); + if ( a.href === window.location.href ) + { + $a.addClass('active'); + $a.closest('.list-group-submenu-submenu').parent().children('a').addClass("active"); + $a.closest('.list-group-submenu').parent().children('a').addClass("active"); + $a.parents('UL').addClass('in'); + } + else + { + $a.removeClass('active'); + } + }); +} \ No newline at end of file diff --git a/docs/os/amazon-ecs/index.md b/docs/os/amazon-ecs/index.md new file mode 100644 index 00000000..86b0af4a --- /dev/null +++ b/docs/os/amazon-ecs/index.md @@ -0,0 +1,77 @@ +--- +title: Amazon ECS on RancherOS +layout: os-default + +--- + +## Amazon ECS (EC2 Container Service) +--- + +[Amazon ECS](https://aws.amazon.com/ecs/) is supported, which allows RancherOS EC2 instances to join your cluster. + +### Pre-Requisites + +Prior to launching RancherOS EC2 instances, the [ECS Container Instance IAM Role](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html) will need to have been created. This `ecsInstanceRole` will need to be used when launching EC2 instances. If you have been using ECS, you created this role if you followed the ECS "Get Started" interactive guide. + +### Launching an instance with ECS + +RancherOS makes it easy to join your ECS cluster. The ECS agent is a [system service]({{site.baseurl}}/os/system-services/adding-system-services/) that is enabled in the ECS enabled AMI. There may be other RancherOS AMIs that don't have the ECS agent enabled by default, but it can easily be added in the user data on any RancherOS AMI. + +When launching the RancherOS AMI, you'll need to specify the **IAM Role** and **Advanced Details** -> **User Data** in the **Configure Instance Details** step. + +For the **IAM Role**, you'll need to be sure to select the ECS Container Instance IAM role. + +For the **User Data**, you'll need to pass in the [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file. + +```yaml +#cloud-config +rancher: + environment: + ECS_CLUSTER: your-ecs-cluster-name +# If you have selected a RancherOS AMI that does not have ECS enabled by default, +# you'll need to enable the system service for the ECS agent. + services_include: + amazon-ecs-agent: true +``` + +#### Version + +By default, the ECS agent will be using the `latest` tag for the `amazon-ecs-agent` image. In v0.5.0, we introduced the ability to select which version of the `amazon-ecs-agent`. + +To select the version, you can update your [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file. + +```yaml +#cloud-config +rancher: + environment: + ECS_CLUSTER: your-ecs-cluster-name + # Note: You will need to make sure to include the colon in front of the version. + ECS_AGENT_VERSION: :v1.9.0 + # If you have selected a RancherOS AMI that does not have ECS enabled by default, + # you'll need to enable the system service for the ECS agent. + services_include: + amazon-ecs-agent: true +``` + +
+ +> **Note:** The `:` must be in front of the version tag in order for the ECS image to be tagged correctly. + +### Amazon ECS enabled AMIs + +Latest Release: [v0.7.1](https://github.com/rancher/os/releases/tag/v0.7.1) + +Region | Type | AMI +---|--- | --- +ap-northeast-1 | HVM - ECS Enabled | [ami-fb5af39a](https://console.aws.amazon.com/ec2/home?region=ap-northeast-1#launchInstanceWizard:ami=ami-fb5af39a) +ap-northeast-2 | HVM - ECS Enabled | [ami-9a78acf4](https://console.aws.amazon.com/ec2/home?region=ap-northeast-2#launchInstanceWizard:ami=ami-9a78acf4) +ap-south-1 | HVM - ECS Enabled | [ami-8bf581e4](https://console.aws.amazon.com/ec2/home?region=ap-south-1#launchInstanceWizard:ami=ami-8bf581e4) +ap-southeast-1 | HVM - ECS Enabled | [ami-c3d073a0](https://console.aws.amazon.com/ec2/home?region=ap-southeast-1#launchInstanceWizard:ami=ami-c3d073a0) +ap-southeast-2 | HVM - ECS Enabled | [ami-ec142b8f](https://console.aws.amazon.com/ec2/home?region=ap-southeast-2#launchInstanceWizard:ami=ami-ec142b8f) +eu-central-1 | HVM - ECS Enabled | [ami-a526dcca](https://console.aws.amazon.com/ec2/home?region=eu-central-1#launchInstanceWizard:ami=ami-a526dcca) +eu-west-1 | HVM - ECS Enabled | [ami-3d3d6c4e](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchInstanceWizard:ami=ami-3d3d6c4e) +sa-east-1 | HVM - ECS Enabled | [ami-03831c6f](https://console.aws.amazon.com/ec2/home?region=sa-east-1#launchInstanceWizard:ami=ami-03831c6f) +us-east-1 | HVM - ECS Enabled | [ami-afddf1b8](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchInstanceWizard:ami=ami-afddf1b8) +us-east-2 | HVM - ECS Enabled | [ami-f843199d](https://console.aws.amazon.com/ec2/home?region=us-east-2#launchInstanceWizard:ami=ami-f843199d) +us-west-1 | HVM - ECS Enabled | [ami-9e2174fe](https://console.aws.amazon.com/ec2/home?region=us-west-1#launchInstanceWizard:ami=ami-9e2174fe) +us-west-2 | HVM - ECS Enabled | [ami-e4319284](https://console.aws.amazon.com/ec2/home?region=us-west-2#launchInstanceWizard:ami=ami-e4319284) diff --git a/docs/os/boot-process/built-in-system-services/index.md b/docs/os/boot-process/built-in-system-services/index.md new file mode 100644 index 00000000..f8ef473b --- /dev/null +++ b/docs/os/boot-process/built-in-system-services/index.md @@ -0,0 +1,52 @@ +--- +title: Built-in System Services in RancherOS +layout: os-default +redirect_from: + - os/system-services/built-in-system-services/ +--- + +## Built-in System Services + +To launch RancherOS, we have built-in system services. They are defined in the [Docker Compose](https://docs.docker.com/compose/compose-file/) format, and can be found in the default system config file, `/usr/share/ros/os-config.yml`. You can [add your own system services]({{site.baseurl}}/os/system-services/) or override services in the cloud-config. + +### preload-user-images + +Read more about [image preloading]({{site.baseurl}}/os/boot-process/image-preloading/). + +### network + +During this service, networking is set up, e.g. hostname, interfaces, and DNS. + +It is configured by `hostname` and `rancher.network`[settings]({{site.baseurl}}/os/networking/) in [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). + +### ntp + +Runs `ntpd` in a System Docker container. + +### console + +This service provides the RancherOS user interface by running `sshd` and `getty`. It completes the RancherOS configuration on start up: + +1. If the `rancher.password=` kernel parameter exists, it sets `` as the password for the `rancher` user. + +2. If there are no host SSH keys, it generates host SSH keys and saves them under `rancher.ssh.keys` in [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). + +3. Runs `cloud-init -execute`, which does the following: + + * Updates `.ssh/authorized_keys` in `/home/rancher` and `/home/docker` from [cloud-config]({{site.baseurl}}/os/configuration/ssh-keys/) and metadata. + * Writes files specified by the `write_files` [cloud-config]({{site.baseurl}}/os/configuration/write-files/) setting. + * Resizes the device specified by the `rancher.resize_device` [cloud-config]({{site.baseurl}}/os/configuration/resizing-device-partition/) setting. + * Mount devices specified in the `mounts` [cloud-config]({{site.baseurl}}/os/configuration/additional-mounts/) setting. + * Set sysctl parameters specified in the`rancher.sysctl` [cloud-config]({{site.baseurl}}/os/configuration/sysctl/) setting. + +4. If user-data contained a file that started with `#!`, then a file would be saved at `/var/lib/rancher/conf/cloud-config-script` during cloud-init and then executed. Any errors are ignored. + +5. Runs `/opt/rancher/bin/start.sh` if it exists and is executable. Any errors are ignored. + +6. Runs `/etc/rc.local` if it exists and is executable. Any errors are ignored. + +### docker + +This system service runs the user docker daemon. Normally it runs inside the console system container by running `docker-init` script which, in turn, looks for docker binaries in `/opt/bin`, `/usr/local/bin` and `/usr/bin`, adds the first found directory with docker binaries to PATH and runs `dockerlaunch docker daemon` appending the passed arguments. + +Docker daemon args are read from `rancher.docker.args` cloud-config property (followed by `rancher.docker.extra_args`). diff --git a/docs/os/boot-process/cloud-init/index.md b/docs/os/boot-process/cloud-init/index.md new file mode 100644 index 00000000..7a14e2bd --- /dev/null +++ b/docs/os/boot-process/cloud-init/index.md @@ -0,0 +1,28 @@ +--- +title: Cloud-init +layout: os-default + +--- + +## Cloud-init + +Userdata and metadata can be fetched from a cloud provider, VM runtime, or management service during the RancherOS boot process. Since v0.8.0, this process occurs while RancherOS is still running from memory and before System Docker starts. It is configured by the `rancher.cloud_init.datasources` configuration parameter. For cloud-provider specific images, such as AWS and GCE, the datasource is pre-configured. + +### Userdata + +Userdata is a file given by users when launching RancherOS hosts. It is stored in different locations depending on its format. If the userdata is a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file, indicated by beginning with `#cloud-config` and being in YAML format, it is stored in `/var/lib/rancher/conf/cloud-config.d/boot.yml`. If the userdata is a script, indicated by beginning with `#!`, it is stored in `/var/lib/rancher/conf/cloud-config-script`. + +### Metadata + +Although the specifics vary based on provider, a metadata file will typically contain information about the RancherOS host and contain additional configuration. Its primary purpose within RancherOS is to provide an alternate source for SSH keys and hostname configuration. For example, AWS launches hosts with a set of authorized keys and RancherOS obtains these via metadata. Metadata is stored in `/var/lib/rancher/conf/metadata`. + +## Configuration Load Order + +[Cloud-config]({{site.baseurl}}/os/configuration/#cloud-config/) is read by system services when they need to get configuration. Each additional file overwrites and extends the previous configuration file. + +1. `/usr/share/ros/os-config.yml` - This is the system default configuration, which should **not** be modified by users. +2. `/usr/share/ros/oem/oem-config.yml` - This will typically exist by OEM, which should **not** be modified by users. +3. Files in `/var/lib/rancher/conf/cloud-config.d/` ordered by filename. If a file is passed in through user-data, it is written by cloud-init and saved as `/var/lib/rancher/conf/cloud-config.d/boot.yml`. +4. `/var/lib/rancher/conf/cloud-config.yml` - If you set anything with `ros config set`, the changes are saved in this file. +5. Kernel parameters with names starting with `rancher`. +6. `/var/lib/rancher/conf/metadata` - Metadata added by cloud-init. diff --git a/docs/os/boot-process/image-preloading/index.md b/docs/os/boot-process/image-preloading/index.md new file mode 100644 index 00000000..fc2ab41e --- /dev/null +++ b/docs/os/boot-process/image-preloading/index.md @@ -0,0 +1,24 @@ +--- +title: Image Preloading +layout: os-default +redirect_from: + - os/configuration/prepacking-docker-images/ + +--- + +## Image Preloading +--- + +On boot, RancherOS scans `/var/lib/rancher/preload/docker` and `/var/lib/rancher/preload/system-docker` directories and tries to load container image archives it finds there, with `docker load` and `system-docker load`. + +The archives are `.tar` files, optionally compressed with `xz` or `gzip`. These can be produced by `docker save` command, e.g.: + +``` +$ docker save my-image1 my-image2 some-other/image3 | xz > my-images.tar.xz +``` + +The resulting files should be placed into `/var/lib/rancher/preload/docker` or `/var/lib/rancher/preload/system-docker` (depending on whether you want it preloaded into Docker or System Docker). + +Pre-loading process only reads each new archive once, so it won't take time on subsequent boots (`.done` files are created to mark the read archives). If you update the archive (place a newer archive with the same name) it'll get read on the next boot as well. + +Pre-packing docker images is handy when you're customizing your RancherOS distribution (perhaps, building cloud VM images for your infrastructure). diff --git a/docs/os/configuration/custom-console/index.md b/docs/os/configuration/custom-console/index.md new file mode 100644 index 00000000..e79fb929 --- /dev/null +++ b/docs/os/configuration/custom-console/index.md @@ -0,0 +1,139 @@ +--- +title: Custom Console on RancherOS +layout: os-default + +--- + +## Custom Console +--- + +When [booting from the ISO]({{site.baseurl}}/os/running-rancheros/workstation/boot-from-iso/), RancherOS starts with the default console, which is based on busybox. + +You can select which console you want RancherOS to start with using the [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). + +### Enabling Consoles using Cloud-Config + +When launching RancherOS with a [cloud-config]({[site.baseurl}}/os/configuration/#cloud-config) file, you can select which console you want to use. + +Currently, the list of available consoles are: + +* default +* alpine +* centos +* debian +* fedora +* ubuntu + +Here is an example cloud-config file that can be used to enable the debian console. + +```yaml +#cloud-config +rancher: + console: debian +``` + +### Listing Available Consoles + +You can easily list the available consoles in RancherOS and what their status is with `sudo ros console list`. + +``` +$ sudo ros console list +disabled alpine +disabled centos +disabled debian +current default +disabled fedora +disabled ubuntu +``` + +### Changing Consoles after RancherOS has started + +You can view which console is being used by RancherOS by checking which console container is running in System Docker. If you wanted to switch consoles, you just need to run a simple command and select your new console. + +For our example, we'll switch to the Ubuntu console. + +``` +$ sudo ros console switch ubuntu +Switching consoles will +1. destroy the current console container +2. log you out +3. restart Docker +Continue [y/N]:y +Pulling console (rancher/os-ubuntuconsole:v0.5.0-3)... +v0.5.0-3: Pulling from rancher/os-ubuntuconsole +6d3a6d998241: Pull complete +606b08bdd0f3: Pull complete +1d99b95ffc1c: Pull complete +a3ed95caeb02: Pull complete +3fc2f42db623: Pull complete +2fb84911e8d2: Pull complete +fff5d987b31c: Pull complete +e7849ae8f782: Pull complete +de375d40ae05: Pull complete +8939c16614d1: Pull complete +Digest: sha256:37224c3964801d633ea8b9629137bc9d4a8db9d37f47901111b119d3e597d15b +Status: Downloaded newer image for rancher/os-ubuntuconsole:v0.5.0-3 +switch-console_1 | time="2016-07-02T01:47:14Z" level=info msg="Project [os]: Starting project " +switch-console_1 | time="2016-07-02T01:47:14Z" level=info msg="[0/18] [console]: Starting " +switch-console_1 | time="2016-07-02T01:47:14Z" level=info msg="Recreating console" +Connection to 127.0.0.1 closed by remote host. +``` + +
+ +After logging back, you'll be in the Ubuntu console. + +``` +$ sudo system-docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +6bf33541b2dc rancher/os-ubuntuconsole:v0.5.0-rc3 "/usr/sbin/entry.sh /" About a minute ago Up About a minute +``` + +
+ +> **Note:** When switching between consoles, the currently running console container is destroyed, Docker is restarted and you will be logged out. + +### Console persistence + +All consoles except the default (busybox) console are persistent. Persistent console means that the console container will remain the same and preserves changes made to its filesystem across reboots. If a container is deleted/rebuilt, state in the console will be lost except what is in the persisted directories. + +``` +/home +/opt +/var/lib/docker +/var/lib/rancher +``` + +
+ +> **Note:** When using a persistent console and in the current version's console, [rolling back]({{site.baseurl}}/os/upgrading/#rolling-back-an-upgrade) is not supported. For example, rolling back to v0.4.5 when using a v0.5.0 persistent console is not supported. + +### Enabling Consoles + +You can also enable a console that will be changed at the next reboot. + +For our example, we'll switch to the Debian console. + +``` +# Check the console running in System Docker +$ sudo system-docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +95d548689e82 rancher/os-docker:v0.5.0 "/usr/sbin/entry.sh /" About an hour ago Up About an hour docker +# Enable the Debian console +$ sudo ros console enable debian +Pulling console (rancher/os-debianconsole:v0.5.0-3)... +v0.5.0-3: Pulling from rancher/os-debianconsole +7268d8f794c4: Pull complete +a3ed95caeb02: Pull complete +21cb8a645d75: Pull complete +5ee1d288a088: Pull complete +c09f41c2bd29: Pull complete +02b48ce40553: Pull complete +38a4150e7e9c: Pull complete +Digest: sha256:5dbca5ba6c3b7ba6cd6ac75a1d054145db4b4ea140db732bfcbd06f17059c5d0 +Status: Downloaded newer image for rancher/os-debianconsole:v0.5.0-3 +``` + +
+ +At the next reboot, RancherOS will be using the Debian console. diff --git a/docs/os/configuration/dkms/index.md b/docs/os/configuration/dkms/index.md new file mode 100644 index 00000000..8e4a2b51 --- /dev/null +++ b/docs/os/configuration/dkms/index.md @@ -0,0 +1,29 @@ +--- +title: DKMS +layout: os-default + +--- + +## DKMS + +DKMS is supported by running the DKMS scripts inside a container. To compile any kernel modules, you first need to [install the kernel headers]({{site.baseurl}}/os/configuration/kernel-modules-kernel-headers/). After kernel headers are enabled, they are installed in `/lib/modules/$(uname -r)/build`. To deploy containers that runs DKMS, you will need to ensure that you bind mount in `/usr/src` and `/lib/modules`. + +### Docker Example + +``` +# Installing Kernel Headers for Docker +$ sudo ros service enable kernel-headers +$ sudo ros service up kernel-headers +# Run a container in Docker and bind mount specific directories to run DKMS +$ docker run -it -v /usr/src:/usr/src -v /lib/modules:/lib/modules ubuntu:15.10 sh -c 'apt-get update && apt-get install -y sysdig-dkms' +``` + +### System Docker Example + +``` +# Installing Kernel Headers for System Docker +$ sudo ros service enable kernel-headers-system-docker +$ sudo ros service up kernel-headers-system-docker +# Run a container in System Docker and bind mount specific directories to run DKMS +$ sudo system-docker run -it -v /usr/src:/usr/src -v /lib/modules:/lib/modules ubuntu:15.10 sh -c 'apt-get update && apt-get install -y sysdig-dkms' +``` diff --git a/docs/os/configuration/docker/index.md b/docs/os/configuration/docker/index.md new file mode 100644 index 00000000..b4cd348a --- /dev/null +++ b/docs/os/configuration/docker/index.md @@ -0,0 +1,86 @@ +--- +title: Configuring Docker in RancherOS +layout: os-default + +--- + +## Configuring Docker or System Docker + +In RancherOS, you can configure System Docker and Docker daemons by using [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). + +### Configuring Docker + +In your cloud-config, Docker configuration is located under the `rancher.docker` key. + +```yaml +#cloud-config +rancher: + docker: + tls: true + tls_args: [--tlsverify, --tlscacert=ca.pem, --tlscert=server-cert.pem, --tlskey=server-key.pem, '-H=0.0.0.0:2376'] + storage_driver: overlay +``` + +You can also customize Docker after it's been started using `ros config`. + +``` +$ sudo ros config set rancher.docker.storage_driver overlay +``` + +#### Valid Keys for Docker + +Many of the standard Docker daemon arguments can be placed under the `rancher.docker` key. The command needed to start the Docker daemon will be generated based on these arguments. The following arguments are currently supported. + +Key | Value +---|--- +`bridge` | String +`config_file` | String +`containerd` | String +`debug` | Boolean +`exec_root` | String +`group` | String +`graph` | String +`host` | List +`insecure_registry` | List +`live_restore` | Boolean +`log_driver` | String +`log_opts` | Map where keys and values are strings +`pid_file` | String +`registry_mirror` | String +`restart` | Boolean +`selinux_enabled` | Boolean +`storage_driver` | String +`userland_proxy` | Boolean + +In addition to the standard daemon arguments, there are a few fields specific to RancherOS. + +Key | Value | Default | Description +---|---|---| --- +`extra_args` | List of Strings | `[]` | Arbitrary daemon arguments, appended to the generated command +`environment` | List of Strings | `[]` | +`tls` | Boolean | `false` | When [setting up TLS]({{site.baseurl}}/os/configuration/setting-up-docker-tls/), this key needs to be set to true. +`tls_args` | List of Strings (used only if `tls: true`) | `[]` | +`server_key` | String (used only if `tls: true`)| `""` | PEM encoded server TLS key. +`server_cert` | String (used only if `tls: true`) | `""` | PEM encoded server TLS certificate. +`ca_key` | String (used only if `tls: true`) | `""` | PEM encoded CA TLS key. +`storage_context` | String | `console` | Specifies the name of the system container in whose context to run the Docker daemon process. + +### Configuring System Docker + +In your cloud-config, System Docker configuration is located under the `rancher.system_docker` key. + +```yaml +#cloud-config +rancher: + system_docker: + storage_driver: overlay +``` + +#### Valid Keys for System Docker + +All daemon arguments shown in the first table are also available to System Docker. The following are also supported. + +Key | Value | Default | Description +---|---|---| --- +`extra_args` | List of Strings | `[]` | Arbitrary daemon arguments, appended to the generated command +`environment` | List of Strings (optional) | `[]` | diff --git a/docs/os/configuration/hostname/index.md b/docs/os/configuration/hostname/index.md new file mode 100644 index 00000000..771fd294 --- /dev/null +++ b/docs/os/configuration/hostname/index.md @@ -0,0 +1,15 @@ +--- +title: Setting the Hostname in RancherOS +layout: os-default + +--- + +## Setting the Hostname +--- + +You can set the hostname of the host using [cloud-config]({[site.baseurl}}/os/configuration/#cloud-config). The example below shows how to configure it. + +```yaml +#cloud-config +hostname: myhost +``` diff --git a/docs/os/configuration/index.md b/docs/os/configuration/index.md new file mode 100644 index 00000000..488102ad --- /dev/null +++ b/docs/os/configuration/index.md @@ -0,0 +1,91 @@ +--- +title: Configuring RancherOS +layout: os-default +redirect_from: + - os/cloud-config/ +--- + +## Configuring RancherOS +--- +There are two ways that RancherOS can be configured. + +1. A cloud-config file can be used to provide configuration when first booting RancherOS. + +2. Manually changing configuration with the `ros config` command. + +Typically, when you first boot the server, you pass in a cloud-config file to configure the initialization of the server. After the first boot, if you have any changes for the configuration, it's recommended that you use `ros config` to set the necessary configuration properties. Any changes will be saved on disk and a reboot will be required for changes to be applied. + +### Cloud-Config + +Cloud-config is a declarative configuration file format supported by many Linux distributions and is the primary configuration mechanism for RancherOS. + +A Linux OS supporting cloud-config will invoke a cloud-init process during startup to parse the cloud-config file and configure the operating system. RancherOS runs its own cloud-init process in a system container. The cloud-init process will attempt to retrieve a cloud-config file from a variety of data sources. Once cloud-init obtains a cloud-config file, it configures the Linux OS according to the content of the cloud-config file. + +When you create a RancherOS instance on AWS, for example, you can optionally provide cloud-config passed in the `user-data` field. Inside the RancherOS instance, cloud-init process will retrieve the cloud-config content through its AWS cloud-config data source, which simply extracts the content of user-data received by the VM instance. If the file starts with "`#cloud-config`", cloud-init will interpret that file as a cloud-config file. If the file starts with `#!` (e.g., `#!/bin/sh`), cloud-init will simply execute that file. You can place any configuration commands in the file as scripts. + +A cloud-config file uses the YAML format. YAML is easy to understand and easy to parse. For more information on YAML, please read more at the [YAML site](http://www.yaml.org/start.html). The most important formatting principle is indentation or whitespace. This indentation indicates relationships of the items to one another. If something is indented more than the previous line, it is a sub-item of the top item that is less indented. + +Example: Notice how both are indented underneath `ssh-authorized-keys`. + +```yaml +#cloud-config +ssh_authorized_keys: + - ssh-rsa AAA...ZZZ example1@rancher + - ssh-rsa BBB...ZZZ example2@rancher +``` + +In our example above, we have our `#cloud-config` line to indicate it's a cloud-config file. We have 1 top-level property, `ssh_authorized_keys`. Its value is a list of public keys that are represented as a dashed list under `ssh_authorized_keys:`. + +### Manually Changing Configuration + +To update RancherOS configuration after booting, the `ros config` command can be used. + +#### Getting Values + +You can easily get any value that's been set in the `/var/lib/rancher/conf/cloud-config.yml` file. Let's see how easy it is to get the DNS configuration of the system. + +``` +$ sudo ros config get rancher.network.dns.nameservers +- 8.8.8.8 +- 8.8.4.4 +``` + +#### Setting Values + +You can set values in the `/var/lib/rancher/conf/cloud-config.yml` file. + +Setting a simple value in the `/var/lib/rancher/conf/cloud-config.yml` + +``` +$ sudo ros config set rancher.docker.tls true +``` + +Setting a list in the `/var/lib/rancher/conf/cloud-config.yml` + +``` +$ sudo ros config set rancher.network.dns.nameservers "['8.8.8.8','8.8.4.4']" +``` + +#### Exporting the Current Configuration + +To output and review the current configuration state you can use the `ros config export` command. + +``` +$ sudo ros config export +rancher: + docker: + tls: true + network: + dns: + nameservers: + - 8.8.8.8 + - 8.8.4.4 +``` + +#### Validating a Configuration File + +To validate a configuration file you can use the `ros config validate` command. + +``` +$ sudo ros config validate -i cloud-config.yml +``` diff --git a/docs/os/configuration/kernel-modules-kernel-headers/index.md b/docs/os/configuration/kernel-modules-kernel-headers/index.md new file mode 100644 index 00000000..7008f57e --- /dev/null +++ b/docs/os/configuration/kernel-modules-kernel-headers/index.md @@ -0,0 +1,41 @@ +--- +title: Installing Kernel Modules with Kernel Headers in RancherOS +layout: os-default + +--- + +## Installing Kernel Modules that require Kernel Headers + + +To compile any kernel modules, you will need to download the kernel headers. The kernel headers are available in the form of a system service. Since the kernel headers are a system service, they need to be enabled using the `ros service` command. + +### Installing Kernel Headers + +The following commands can be used to install kernel headers for usage by containers in Docker or System Docker. + +#### Docker + +``` +$ sudo ros service enable kernel-headers +$ sudo ros service up kernel-headers +``` + +#### System Docker + +``` +$ sudo ros service enable kernel-headers-system-docker +$ sudo ros service up kernel-headers-system-docker +``` + +The `ros service` commands will install the kernel headers in `/lib/modules/$(uname -r)/build`. Based on which service you install, the kernel headers will be available to containers, in Docker or System Docker, by bind mounting specific volumes. For any containers that compile a kernel module, the Docker command will need to bind mount in `/usr/src` and `/lib/modules`. + +> **Note:** Since both commands install kernel headers in the same location, the only reason for different services is due to the fact that the storage places for System Docker and Docker are different. Either one or both kernel headers can be installed in the same RancherOS services. + +### Example of Launching Containers to use Kernel Headers + +``` +# Run a container in Docker and bind mount specific directories +$ docker run -it -v /usr/src:/usr/src -v /lib/modules:/lib/modules ubuntu:15.10 +# Run a container in System Docker and bind mount specific directories +$ sudo system-docker run -it -v /usr/src:/usr/src -v /lib/modules:/lib/modules ubuntu:15.10 +``` diff --git a/docs/os/configuration/loading-kernel-modules/index.md b/docs/os/configuration/loading-kernel-modules/index.md new file mode 100644 index 00000000..2fb44490 --- /dev/null +++ b/docs/os/configuration/loading-kernel-modules/index.md @@ -0,0 +1,20 @@ +--- +title: Loading Kernel Modules in RancherOS +layout: os-default + +--- + +## Loading Kernel Modules +--- + +Privileged containers can load kernel modules. In RancherOS, the kernel modules are in the standard `/lib/modules/$(uname -r)` folder. If you want to be able to run `modprobe` from a container, you will need to bind mount the `/lib/modules` into your container. + +```yaml +myservice: + image: ... + privileged: true + volumes: + - /lib/modules:/lib/modules +``` + +By default, the `/lib/modules` folder is already available in the console. diff --git a/docs/os/configuration/private-registries/index.md b/docs/os/configuration/private-registries/index.md new file mode 100644 index 00000000..20ca4e8b --- /dev/null +++ b/docs/os/configuration/private-registries/index.md @@ -0,0 +1,96 @@ +--- +title: Private Registries in RancherOS +layout: os-default + +--- + +## Private Registries +--- + +When launching services through a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config), it is sometimes necessary to pull a private image from DockerHub or from a private registry. Authentication for these can be embedded in your cloud-config. + +For example, to add authentication for DockerHub: + +```yaml +#cloud-config +rancher: + registry_auths: + https://index.docker.io/v1/: + auth: dXNlcm5hbWU6cGFzc3dvcmQ= +``` + +The `auth` key is generated by base64 encoding a string of the form `username:password`. The `docker login` command can be be used to generate an `auth` key. After running the command and authenticating successfully, the key can be found in the `$HOME/.docker/config.json` file. + +```json +{ + "auths": { + "https://index.docker.io/v1/": { + "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=" + } + } +} +``` + +Alternatively, a username and password can be specified directly. + +```yaml +#cloud-config +rancher: + registry_auths: + https://index.docker.io/v1/: + username: username + password: password +``` + +### Docker Client Authentication + +Configuring authentication for the Docker client is not handled by the `registry_auth` key. Instead, the `write_files` directive can be used to write credentials to the standard Docker configuration location. + +``` +#cloud-config +write_files: + - path: /home/rancher/.docker/config.json + permissions: "0755" + owner: rancher + content: | + { + "auths": { + "https://index.docker.io/v1/": { + "auth": "asdf=", + "email": "not@val.id" + } + } + } +``` + +### Certificates for Private Registries + +Certificates can be stored in the standard locations (i.e. `/etc/docker/certs.d`) following the [Docker documentation](https://docs.docker.com/registry/insecure). By using the `write_files` directive of the [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config), the certificates can be written directly into `/etc/docker/certs.d`. + +```yaml +#cloud-config +write_files: + - path: /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt + permissions: "0644" + owner: root + content: | + -----BEGIN CERTIFICATE----- + MIIDJjCCAg4CCQDLCSjwGXM72TANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB + VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 + cyBQdHkgTHRkMQ4wDAYDVQQDEwVhbGVuYTAeFw0xNTA3MjMwMzUzMDdaFw0xNjA3 + MjIwMzUzMDdaMFUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw + HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDjAMBgNVBAMTBWFsZW5h + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxdVIDGlAySQmighbfNqb + TtqetENPXjNNq1JasIjGGZdOsmFvNciroNBgCps/HPJphICQwtHpNeKv4+ZuL0Yg + 1FECgW7oo6DOET74swUywtq/2IOeik+i+7skmpu1o9uNC+Fo+twpgHnGAaGk8IFm + fP5gDgthrWBWlEPTPY1tmPjI2Hepu2hJ28SzdXi1CpjfFYOiWL8cUlvFBdyNqzqT + uo6M2QCgSX3E1kXLnipRT6jUh0HokhFK4htAQ3hTBmzcxRkgTVZ/D0hA5lAocMKX + EVP1Tlw0y1ext2ppS1NR9Sg46GP4+ATgT1m3ae7rWjQGuBEB6DyDgyxdEAvmAEH4 + LQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA45V0bnGPhIIkb54Gzjt9jyPJxPVTW + mwTCP+0jtfLxAor5tFuCERVs8+cLw1wASfu4vH/yHJ/N/CW92yYmtqoGLuTsywJt + u1+amECJaLyq0pZ5EjHqLjeys9yW728IifDxbQDX0cj7bBjYYzzUXp0DB/dtWb/U + KdBmT1zYeKWmSxkXDFFSpL/SGKoqx3YLTdcIbgNHwKNMfTgD+wTZ/fvk0CLxye4P + n/1ZWdSeZPAgjkha5MTUw3o1hjo/0H0ekI4erZFrZnG2N3lDaqDPR8djR+x7Gv6E + vloANkUoc1pvzvxKoz2HIHUKf+xFT50xppx6wsQZ01pNMSNF0qgc1vvH + -----END CERTIFICATE----- +``` diff --git a/docs/os/configuration/resizing-device-partition/index.md b/docs/os/configuration/resizing-device-partition/index.md new file mode 100644 index 00000000..182a4f66 --- /dev/null +++ b/docs/os/configuration/resizing-device-partition/index.md @@ -0,0 +1,18 @@ +--- +title: Resizing a Device Partition in RancherOS +layout: os-default + +--- + +## Resizing a Device Partition +--- + +The `resize_device` cloud config option can be used to automatically extend the first partition to fill the size of it's device. + +```yaml +#cloud-config +rancher: + resize_device: /dev/sda +``` + +This behavior is the default when launching RancherOS on AWS. diff --git a/docs/os/configuration/running-commands/index.md b/docs/os/configuration/running-commands/index.md new file mode 100644 index 00000000..b5e46134 --- /dev/null +++ b/docs/os/configuration/running-commands/index.md @@ -0,0 +1,51 @@ +--- +title: Running Commands in RancherOS +layout: os-default + +--- + +## Running Commands +--- + +You can automate running commands on boot using the `runcmd` cloud-config directive. Commands can be specified as either a list or a string. In the latter case, the command is executed with `sh`. + +```yaml +#cloud-config +runcmd: +- [ touch, /home/rancher/test1 ] +- echo "test" > /home/rancher/test2 +``` + +Commands specified using `runcmd` will be executed within the context of the `console` container. More details on the ordering of commands run in the `console` container can be found [here]({{site.baseurl}}/os/system-services/built-in-system-services/#console). + +### Running Docker commands + +When using `runcmd`, RancherOS will wait for all commands to complete before starting Docker. As a result, any `docker run` command should not be placed under `runcmd`. Instead, the `/etc/rc.local` script can be used. RancherOS will not wait for commands in this script to complete, so you can use the `wait-for-docker` command to ensure that the Docker daemon is running before performing any `docker run` commands. + +```yaml +#cloud-config +rancher: +write_files: + - path: /etc/rc.local + permissions: "0755" + owner: root + content: | + #!/bin/bash + wait-for-docker + docker run -d nginx +``` + +Running Docker commands in this manner is useful when pieces of the `docker run` command are dynamically generated. For services whose configuration is static, [adding a system service]({{site.baseurl}}/os/system-services/adding-system-services/) is recommended. + +## Running Commands Early in the Boot Process +--- + +The `bootcmd` parameter can be used to run commands earlier in the boot process. In particular, `bootcmd` will be executed while RancherOS is still running from memory and before System Docker and any system services are started. + +The syntax for bootcmd is the same as `runcmd`. + +```yaml +#cloud-config +bootcmd: +- [ mdadm, --assemble, --scan ] +``` diff --git a/docs/os/configuration/setting-up-docker-tls/index.md b/docs/os/configuration/setting-up-docker-tls/index.md new file mode 100644 index 00000000..dba5d69c --- /dev/null +++ b/docs/os/configuration/setting-up-docker-tls/index.md @@ -0,0 +1,59 @@ +--- +title: Configuring TLS in RancherOS +layout: os-default + +--- + +## Setting up Docker TLS + +`ros tls generate` is used to generate both the client and server TLS certificates for Docker. + +Remember, all `ros` commands need to be used with `sudo` or as a `root` user. + +### End to end example + +#### Enable TLS for Docker and Generate Server Certificate + +To have docker secured by TLS you need to set `rancher.docker.tls` to `true`, and generate a set of server and client keys and certificates: + +``` +$ sudo ros config set rancher.docker.tls true +$ sudo ros tls gen --server -H localhost -H -H ... -H +$ sudo system-docker restart docker +``` + +Here, ``s are the hostnames that you will be able to use as your docker host names. A `` can be a wildcard pattern, e.g. "`*.*.*.*.*`". It is recommended to have `localhost` as one of the hostnames, so that you can test docker TLS connectivity locally. + +When you've done that, all the necessary server certificate and key files have been saved to `/etc/docker/tls` directory, and the `docker` service has been started with `--tlsverify` option. + +#### Generate Client Certificates + +You also need client cert and key to access Docker via a TCP socket now: + + +``` +$ sudo ros tls gen + INFO[0000] Out directory (-d, --dir) not specified, using default: /home/rancher/.docker +``` + +All the docker client TLS files are in `~/.docker` dir now. + +#### Test docker TLS connection + +Now you can use your client cert to check if you can access Docker via TCP: + +``` +$ docker --tlsverify version +``` + +Because all the necessary files are in the `~/.docker` dir, you don't need to specify them using `--tlscacert` `--tlscert` and `--tlskey` options. You also don't need `-H` to access Docker on localhost. + +Copy the files from `/home/rancher/.docker` to `$HOME/.docker` on your client machine if you need to access Docker on your RancherOS host from there. + +On your client machine, set the Docker host and test out if Docker commands work. + + +``` +$ export DOCKER_HOST=tcp://:2376 DOCKER_TLS_VERIFY=1 +$ docker ps +``` diff --git a/docs/os/configuration/ssh-keys/index.md b/docs/os/configuration/ssh-keys/index.md new file mode 100644 index 00000000..1b35f5c0 --- /dev/null +++ b/docs/os/configuration/ssh-keys/index.md @@ -0,0 +1,24 @@ +--- +title: SSH Keys in RancherOS +layout: os-default + +--- + +## SSH Keys +--- + +RancherOS supports adding SSH keys through the [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file. Within the cloud-config file, you simply add the ssh keys within the `ssh-authorized-keys` key. + +```yaml +#cloud-config +ssh_authorized_keys: + - ssh-rsa AAA...ZZZ example1@rancher + - ssh-rsa BBB...ZZZ example2@rancher +``` + +When we pass the cloud-config file during the `ros install` command, it will allow these ssh keys to be associated with the **rancher** user. You can ssh into RancherOS using the key. + +``` +$ ssh -i /path/to/private/key rancher@ +``` + diff --git a/docs/os/configuration/switching-docker-versions/index.md b/docs/os/configuration/switching-docker-versions/index.md new file mode 100644 index 00000000..29fe78b9 --- /dev/null +++ b/docs/os/configuration/switching-docker-versions/index.md @@ -0,0 +1,78 @@ +--- +title: Changing Docker Versions in RancherOS +layout: os-default +redirect_from: + - os/configuration/custom-docker/ + +--- + +## Changing Docker Versions + +The version of User Docker used in RancherOS can be configured using a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file or by using the `ros engine` command. + +> **Note:** There are known issues in Docker when switching between versions. For production systems, we recommend setting the Docker engine only once [using a cloud-config](#setting-the-docker-engine-using-cloud-config). + +### Available Docker engines + +The `ros engine list` command can be used to show which Docker engines are available to switch to. This command will also provide details of which Docker engine is currently being used. + +``` +$ sudo ros engine list +disabled docker-1.10.3 +disabled docker-1.11.2 +current docker-1.12.1 +``` + +### Setting the Docker engine using cloud-config + +RancherOS supports defining which Docker engine to use through the cloud-config file. To change the Docker version from the default packaged version, you can use the following cloud-config setting and select one of the available engines. In the following example, we'll use the cloud-config file to set RancherOS to use Docker 1.10.3 for User Docker. + +```yaml +#cloud-config +rancher: + docker: + engine: docker-1.10.3 +``` + +### Changing Docker engines after RancherOS has started + +If you've already started RancherOS and want to switch Docker engines, you can change the Docker engine by using the `ros engine switch` command. In our example, we'll switch to Docker 1.11.2. + +``` +$ sudo ros engine switch docker-1.11.2 +INFO[0000] Project [os]: Starting project +INFO[0000] [0/19] [docker]: Starting +Pulling docker (rancher/os-docker:1.11.2)... +1.11.2: Pulling from rancher/os-docker +2a6bbb293656: Pull complete +Digest: sha256:ec57fb24f6d4856d737e14c81a20f303afbeef11fc896d31b4e498829f5d18b2 +Status: Downloaded newer image for rancher/os-docker:1.11.2 +INFO[0007] Recreating docker +INFO[0007] [1/19] [docker]: Started +INFO[0007] Project [os]: Project started +$ docker version +Client: + Version: 1.11.2 + API version: 1.23 + Go version: go1.5.4 + Git commit: b9f10c9 + Built: Wed Jun 1 21:20:08 2016 + OS/Arch: linux/amd64 + +Server: + Version: 1.11.2 + API version: 1.23 + Go version: go1.5.4 + Git commit: b9f10c9 + Built: Wed Jun 1 21:20:08 2016 + OS/Arch: linux/amd64 + +``` + +### Enabling Docker engines + +If you don't want to automatically switch Docker engines, you can also set which version of Docker to use after the next reboot by enabling a Docker engine. + +``` +$ sudo ros engine enable docker-1.10.3 +``` diff --git a/docs/os/configuration/sysctl/index.md b/docs/os/configuration/sysctl/index.md new file mode 100644 index 00000000..6848065f --- /dev/null +++ b/docs/os/configuration/sysctl/index.md @@ -0,0 +1,17 @@ +--- +title: sysctl Settings in RancherOS +layout: os-default + +--- + +## sysctl Settings +--- + +The `rancher.sysctl` cloud-config key can be used to control sysctl parameters. This works in a manner similar to `/etc/sysctl.conf` for other Linux distros. + +``` +#cloud-config +rancher: + sysctl: + net.ipv4.conf.default.rp_filter: 1 +``` diff --git a/docs/os/configuration/users/index.md b/docs/os/configuration/users/index.md new file mode 100644 index 00000000..34abaec9 --- /dev/null +++ b/docs/os/configuration/users/index.md @@ -0,0 +1,15 @@ +--- +title: Users in RancherOS +layout: os-default + +--- + +## Configuring RancherOS Users +--- + +Currently, we don't support adding other users besides `rancher`. + +You _can_ add users in the console container, but these users will only exist as long as the console container exists. It only makes sense to add users in a [persistent consoles]({{site.baseurl}}/os/configuration/custom-console/#console-persistence). + +If you want the console user to be able to ssh into RancherOS, you need to add them +to the `docker` group. diff --git a/docs/os/configuration/write-files/index.md b/docs/os/configuration/write-files/index.md new file mode 100644 index 00000000..684bca53 --- /dev/null +++ b/docs/os/configuration/write-files/index.md @@ -0,0 +1,46 @@ +--- +title: Writing Files in RancherOS +layout: os-default + +--- + +## Writing Files +--- + +You can automate writing files to disk using the `write_files` cloud-config directive. + +```yaml +#cloud-config +write_files: + - path: /etc/rc.local + permissions: "0755" + owner: root + content: | + #!/bin/bash + echo "I'm doing things on start" +``` + +### Writing Files in Specific System Services + +By default, the `write_files` directive will create files in the console container. To write files in other system services, the `container` key can be used. For example, the `container` key could be used to write to `/etc/ntp.conf` in the NTP system service. + +```yaml +#cloud-config +write_files: + - container: ntp + path: /etc/ntp.conf + permissions: "0644" + owner: root + content: | + server 0.pool.ntp.org iburst + server 1.pool.ntp.org iburst + server 2.pool.ntp.org iburst + server 3.pool.ntp.org iburst + + # Allow only time queries, at a limited rate, sending KoD when in excess. + # Allow all local queries (IPv4, IPv6) + restrict default nomodify nopeer noquery limited kod + restrict 127.0.0.1 + restrict [::1] +``` + diff --git a/docs/os/contributing/index.md b/docs/os/contributing/index.md new file mode 100644 index 00000000..ffe60a9a --- /dev/null +++ b/docs/os/contributing/index.md @@ -0,0 +1,78 @@ +--- +title: Contributing to RancherOS +layout: os-default + +--- + +## Contributing to RancherOS +--- + +## Developing + +Development is easiest done with QEMU on Linux. OS X works too, although QEMU doesn't have KVM support. If you are running Linux in a virtual machine, then we recommend you run VMWare Fusion/Workstation and enable VT-x support. Then, QEMU will have KVM support and run sufficiently fast inside your Linux VM. + +### Building + +#### Requirements: + +* bash +* make +* Docker 1.10.3+ + +``` +$ make +``` + +The build will run in Docker containers, and when the build is done, the vmlinuz, initrd, and ISO should be in `dist/artifacts`. + +If you're building a version of RancherOS used for development and not for a release, you can instead run `make dev`. This will run faster than the standard build by avoiding building the `installer.tar` and `rootfs.tar.gz` artifacts which are not needed by QEMU. + +### Testing + +Run `make integration-tests` to run the all integration tests in a container, or `./scripts/integration-tests` to run them outside a container (they use QEMU to test the OS.) + +To run just one integration test, or a group of them (using regex's like `.*Console.*`, you can set the `RUNTEST` environment variable: + +``` +$ RUNTEST=TestPreload make integration-test +``` + +### Running + +Prerequisites: QEMU, coreutils, cdrtools/genisoimage/mkisofs. +On OS X, `brew` is recommended to install those. On Linux, use your distro package manager. + +To launch RancherOS in QEMU from your dev version, you can either use `make run`, or customise the vm using `./scripts/run` and its options. You can use `--append your.kernel=params here` and `--cloud-config your-cloud-config.yml` to configure the RancherOS instance you're launching. + +You can SSH in using `./scripts/ssh`. Your SSH keys should have been populated (if you didn't provide your own cloud-config) so you won't need a password. If you don't have SSH keys, or something is wrong with your cloud-config, then the password is "`rancher`". + +If you're on OS X, you can run RancherOS using [_xhyve_](https://github.com/mist64/xhyve) instead of QEMU: just pass `--xhyve` to `./scripts/run` and `./scripts/ssh`. + +### Debugging and logging. + +You can enable extra log information in the console by setting them using `sudo ros config set`, +or as kernel boot parameters. +Enable all logging by setting `rancher.debug` true +or you can set `rancher.docker.debug`, `racher.system_docker.debug`, `rancher.bootstrap_docker.debug`, or `rancher.log` individually. + +You will also be able to view the debug logging information by running `dmesg` as root. + +## Repositories + +All of repositories are located within our main GitHub [page](https://github.com/rancher). + +[RancherOS Repo](https://github.com/rancher/os): This repo contains the bulk of the RancherOS code. + +[RancherOS Services Repo](https://github.com/rancher/os-services): This repo is where any [system-services]({{site.baseurl}}/os/system-services/) can be contributed. + +[RancherOS Images Repo](https://github.com/rancher/os-images): This repo is for the corresponding service images. + + +## Bugs + +If you find any bugs or are having any trouble, please contact us by filing an [issue](https://github.com/rancher/os/issues/new). + +If you have any updates to our documentation, please make any PRs to our [docs repo](https://github.com/rancher/rancher.github.io). + +
+
diff --git a/docs/os/custom-builds/custom-kernels/index.md b/docs/os/custom-builds/custom-kernels/index.md new file mode 100644 index 00000000..7dc6f255 --- /dev/null +++ b/docs/os/custom-builds/custom-kernels/index.md @@ -0,0 +1,106 @@ +--- +title: Custom Kernels in RancherOS +layout: os-default +redirect_from: + - os/configuration/custom-kernels/ +--- + +## Custom Kernels + +### Building and Packaging a Kernel to be used in RancherOS + +We build the kernel for RancherOS at the [os-kernel repository](https://github.com/rancher/os-kernel). You can use this repository to help package your own custom kernel to be used in RancherOS. + + +1. Create a clone of the [os-kernel](https://github.com/rancher/os-kernel) repository to your local machine using `git clone`. + + ``` + $ git clone https://github.com/rancher/os-kernel.git + ``` + +2. In the `./Dockerfile.dapper` file, update the `KERNEL_TAG`, `KERNEL_VERSION`, `KERNEL_URL` and `KERNEL_SHA1`. `KERNEL_URL` points to Linux kernel sources archive, packaged as `.tar.gz` or `.tar.xz`. `KERNEL_SHA1` is the `SHA1` sum of the kernel sources archive. + + `./Dockerfile.dapper` file + + ```bash + ########## Kernel version Configuration ############################# + ENV KERNEL_TAG=v4.8.7 + ENV KERNEL_VERSION=4.8.7-rancher + ENV KERNEL_SHA1=5c10724a0e7e97b72046be841df0c69c6e2a03c2 + ENV KERNEL_URL=https://github.com/rancher/linux/archive/${KERNEL_TAG}.tar.gz + ``` + +3. After you've replaced the `KERNEL_*` values, run `make` in the root `os-kernel` directory. After the build is completed, a `./dist/kernel` directory will be created with the freshly built kernel tarball and headers. + + ``` + $ make + ...snip... + --- 4.8.7-rancher Kernel prepared for RancherOS + ./dist/kernel/extra-linux-4.8.7-rancher-x86.tar.gz + ./dist/kernel/build-linux-4.8.7-rancher-x86.tar.gz + ./dist/kernel/linux-4.8.7-rancher-x86.tar.gz + ./dist/kernel/config + + Images ready to push: + rancher/os-extras:4.8.7-rancher + rancher/os-headers:4.8.7-rancher + + ``` + +Now you need to either upload the `./dist/kernel/linux-4.8.7-rancher-x86.tar.gz` file to somewhere, or copy that file into your clone of the `rancher/os` repo, as `assets/kernel.tar.gz`. + +The `build-.tar.gz` and `extra-.tar.gz` files are used to build the `rancher/os-extras` and `rancher/os-headers` images for your RancherOS release - which you will need to tag them with a different organisation name, push them to a registry, and create custom service.yml files. + +### Building a RancherOS release using the Packaged kernel files. + +By default, RancherOS ships with the kernel provided by the [os-kernel repository](https://github.com/rancher/os-kernel). Swapping out the default kernel can by done by [building your own custom RancherOS ISO]({{site.baseurl}}/os/configuration/custom-rancheros-iso/). + + 1. Create a clone of the main [RancherOS repository](https://github.com/rancher/os) to your local machine with a `git clone`. + + ``` + $ git clone https://github.com/rancher/os.git + ``` + + 2. In the root of the repository, the "General Configuration" section of `Dockerfile.dapper` will need to be updated. Using your favorite editor, replace the appropriate `KERNEL_URL` value with a URL of your compiled custom kernel tarball. Ideally, the URL will use `HTTPS`. + + `Dockerfile.dapper` file + + ``` + # Update the URL to your own custom kernel tarball + ARG KERNEL_URL_amd64=https://github.com/rancher/os-kernel/releases/download/Ubuntu-4.4.0-23.41-rancher/linux-4.4.10-rancher-x86.tar.gz + ARG KERNEL_URL_arm64=https://github.com/imikushin/os-kernel/releases/download/Estuary-4.1.18-arm64-3/linux-4.1.18-arm64.tar.gz + ``` + +
+ + > **Note:** `KERNEL_URL` settings should point to a Linux kernel, compiled and packaged in a specific way. You can fork [os-kernel repository](https://github.com/rancher/os-kernel) to package your own kernel. + + Your kernel should be packaged and published as a set of files of the following format: + + `.tar.gz` is the one KERNEL_URL should point to. It contains the kernel binary, core modules and firmware: + + ``` + boot/ + vmlinuz- + lib/ + modules/ + / + ... + firmware/ + ... + ``` + + `build.tar.gz` contains build headers to build additional modules (e.g. using DKMS): it is a subset of the kernel sources tarball. These files will be installed into `/usr/src/` using the `kernel-headers-system-docker` and `kernel-headers` services. + + `extra.tar.gz` contains extra modules and firmware for your kernel and should be built into a `kernel-extras` service: + + ``` + lib/ + modules/ + / + ... + firmware/ + ... + ``` + + 3. After you've replaced the URL with your custom kernel, you can follow the steps in [building your own custom RancherOS ISO]({{site.baseurl}}/os/configuration/custom-rancheros-iso/). diff --git a/docs/os/custom-builds/custom-rancheros-iso/index.md b/docs/os/custom-builds/custom-rancheros-iso/index.md new file mode 100644 index 00000000..e790c120 --- /dev/null +++ b/docs/os/custom-builds/custom-rancheros-iso/index.md @@ -0,0 +1,92 @@ +--- +title: Custom RancherOS ISO +layout: os-default +redirect_from: + - os/configuration/custom-rancheros-iso/ +--- + +## Custom RancherOS ISO + +It's easy to build your own RancherOS ISO. + +1. Create a clone of the main [RancherOS repository](https://github.com/rancher/os) to your local machine with a `git clone`. + + ``` + $ git clone https://github.com/rancher/os.git + ``` + +2. In the root of the repository, the "General Configuration" section of `Dockerfile.dapper` can be updated to use [custom kernels]({{site.baseurl}}/os/configuration/custom-kernels), or [custom Docker]({{site.baseurl}}/os/configuration/custom-docker). + +3. After you've saved your edits, run `make` in the root directory. After the build has completed, a `./dist/artifacts` directory will be created with the custom built RancherOS release files. + + Build Requirements: `bash`, `make`, `docker` (Docker version >= 1.10.3) + + ``` + $ make + $ cd dist/artifacts + $ ls + initrd rancheros.iso + iso-checksums.txt vmlinuz + ``` + +The `rancheros.iso` is ready to be used to [boot RancherOS from ISO]({{site.baseurl}}/os/running-rancheros/workstation/boot-from-iso/) or [launch RancherOS using Docker Machine]({{site.baseurl}}/os/running-rancheros/workstation/docker-machine). + + +### Creating a GCE Image Archive + +You can build the [GCE image archive](https://cloud.google.com/compute/docs/tutorials/building-images) using [Packer](https://www.packer.io/). You will need Packer, QEMU and GNU tar installed. + +First, create `gce-qemu.json`: + +```json +{ + "builders": + [ + { + "type": "qemu", + "name": "qemu-googlecompute", + "iso_url": "https://github.com/rancherio/os/releases/download//rancheros.iso", + "iso_checksum": "", + "iso_checksum_type": "md5", + "ssh_wait_timeout": "360s", + "disk_size": 10000, + "format": "raw", + "headless": true, + "accelerator": "none", + "ssh_host_port_min": 2225, + "ssh_host_port_max": 2229, + "ssh_username": "rancher", + "ssh_password": "rancher", + "ssh_port": 22, + "net_device": "virtio-net", + "disk_interface": "scsi", + "qemuargs": [ + ["-m", "1024M"], ["-nographic"], ["-display", "none"] + ] + } + ], + "provisioners": [ + { + "type":"shell", + "script": "../scripts/install2disk" + } + ] +} +``` + +NOTE: For faster builds You can use `"kvm"` as the `accelerator` field value if you have KVM, but that's optional. + +Run: + +``` +$ packer build gce-qemu.json +``` + +Packer places its output into `output-qemu-googlecompute/packer-qemu-googlecompute` - it's a raw VM disk image. Now you just need to name it `disk.raw` and package it as sparse .tar.gz: + +``` +$ mv output-qemu-googlecompute/packer-qemu-googlecompute disk.raw +$ tar -czSf rancheros-.tar.gz disk.raw +``` + +NOTE: the last command should be using GNU tar. It might be named `gtar` on your system. diff --git a/docs/os/faqs/amazon/index.md b/docs/os/faqs/amazon/index.md new file mode 100644 index 00000000..c2e99112 --- /dev/null +++ b/docs/os/faqs/amazon/index.md @@ -0,0 +1,18 @@ +--- +title: Amazon FAQs +layout: os-default + +--- + +## Amazon Frequently Asked Questions +--- + +### How can I extend my disk size? + +Assuming your EC2 instance with RancherOS with more disk space than what's being read, run the following command to extend the disk size. This allows RancherOS to see the disk size. + +``` +$ docker run --privileged --rm --it debian:jessie resize2fs /dev/xvda1 +``` + +`xvda1` should be the right disk for your own setup. In the future, we will be trying to create a system service that would automatically do this on boot in AWS. diff --git a/docs/os/faqs/index.md b/docs/os/faqs/index.md new file mode 100644 index 00000000..86f74082 --- /dev/null +++ b/docs/os/faqs/index.md @@ -0,0 +1,23 @@ +--- +title: FAQs +layout: os-default + +--- + +## Frequently Asked Questions +--- + +###What is required to run RancherOS? + +RancherOS runs on any laptop, physical, or virtual servers. + +###What are some commands? + +Command | Description +--------|------------ +`docker`| Good old Docker, use that to run stuff. +`system-docker` | The Docker instance running the system containers. Must run as root or using `sudo` +`ros` | Control and configure RancherOS + + + diff --git a/docs/os/index.md b/docs/os/index.md new file mode 100644 index 00000000..5a734051 --- /dev/null +++ b/docs/os/index.md @@ -0,0 +1,45 @@ +--- +title: Overview of RancherOS +layout: os-default +--- + +## Overview of RancherOS +--- +RancherOS is the smallest, easiest way to run Docker in production. Everything in RancherOS is a container managed by Docker. This includes system services such as `udev` and `syslog`. RancherOS is dramatically smaller than most traditional operating systems, because it only includes the services necessary to run Docker. By removing unnecessary libraries and services, requirements for security patches and other maintenance are dramatically reduced. This is possible because with Docker, users typically package all necessary libraries into their containers. + +Another way in which RancherOS is designed specifically for running Docker is that it always runs the latest version of Docker. This allows users to take advantage of the latest Docker capabilities and bug fixes. + +Like other minimalist Linux distributions, RancherOS boots incredibly quickly, generally in 5-10 seconds. Starting Docker containers is nearly instant, similar to starting any other process. This quickness is ideal for organizations adopting microservices and autoscaling. + +Docker is an open-source platform designed for developers, system admins, and DevOps, it is used to build, ship, and run containers, using simple yet powerful CLI (Command Line Interface), you can get started with Docker from [Docker user guide](https://docs.docker.com/userguide/). + +### Hardware Requirements +--- + +* x86_64 server with at least 512MB of RAM. + +> **Note:** If you are planning on [installing to disk]({{site.baseurl}}/os/running-rancheros/server/install-to-disk/), you will need at least 1024MB of RAM. + + +### How this works +--- + +Everything in RancherOS is a Docker container. We accomplish this by launching two instances of Docker. One is what we call **System Docker**, the first process on the system. All other system services, like `ntpd`, `syslog`, and `console`, are running in Docker containers. System Docker replaces traditional init systems like `systemd`, and can be used to launch [additional system services]({{site.baseurl}}/os/system-services/adding-system-services/). + +System Docker runs a special container called **Docker**, which is another Docker daemon responsible for managing all of the user’s containers. Any containers that you launch as a user from the console will run inside this Docker. This creates isolation from the System Docker containers, and ensures normal user commands don’t impact system services. + + We created this separation because it seemed logical and also it would really be bad if somebody did +`docker rm -f $(docker ps -qa)` and deleted the entire OS. + +![How it works]({{site.baseurl}}/img/os/rancheroshowitworks.png "How it works") + +### Running RancherOS +--- +To find out more about installing RancherOS, jump to our [Quick Start Guide]({{site.baseurl}}/os/quick-start-guide/). + +### Latest Release +--- +Please check our repository for the latest release in our [README](https://github.com/rancher/os/blob/master/README.md). + +
+
diff --git a/docs/os/networking/dns/index.md b/docs/os/networking/dns/index.md new file mode 100644 index 00000000..e4351035 --- /dev/null +++ b/docs/os/networking/dns/index.md @@ -0,0 +1,31 @@ +--- +title: Configuring DNS in RancherOS +layout: os-default +redirect_from: + - os/configuration/networking/#dns +--- + +## DNS + +If you wanted to configure the DNS through the cloud config file, you'll need to place DNS configurations within the `rancher` key. + +```yaml +#cloud-config + +#Remember, any changes for rancher will be within the rancher key +rancher: + network: + dns: + search: + - mydomain.com + - example.com +``` + +Using `ros config`, you can set the `nameservers`, and `search`, which directly map to the fields of the same name in `/etc/resolv.conf`. + +``` +$ sudo ros config set rancher.network.dns.search "['mydomain.com','example.com']" +$ sudo ros config get rancher.network.dns.search +- mydomain.com +- example.com +``` diff --git a/docs/os/networking/interfaces/index.md b/docs/os/networking/interfaces/index.md new file mode 100644 index 00000000..f7465221 --- /dev/null +++ b/docs/os/networking/interfaces/index.md @@ -0,0 +1,96 @@ +--- +title: Configuring Network Interfaces in RancherOS +layout: os-default +redirect_from: + - os/configuration/networking/ +--- + +## Interfaces + +Using `ros config`, you can configure specific interfaces. Wildcard globbing is supported so `eth*` will match `eth1` and `eth2`. The available options you can configure are `address`, `gateway`, `mtu`, and `dhcp`. + +``` +$ sudo ros config set rancher.network.interfaces.eth1.address 172.68.1.100/24 +$ sudo ros config set rancher.network.interfaces.eth1.gateway 172.68.1.1 +$ sudo ros config set rancher.network.interfaces.eth1.mtu 1500 +$ sudo ros config set rancher.network.interfaces.eth1.dhcp false +``` + +If you wanted to configure the interfaces through the cloud config file, you'll need to place interface configurations within the `rancher` key. + +```yaml +#cloud-config +rancher: + network: + interfaces: + eth1: + address: 172.68.1.100/24 + gateway: 172.68.1.1 + mtu: 1500 + dhcp: false +``` + +### Multiple NICs + +If you want to configure one of multiple network interfaces, you can specify the MAC address of the interface you want to configure. + +Using `ros config`, you can specify the MAC address of the NIC you want to configure as follows: + +``` +$ sudo ros config set rancher.network.interfaces.”mac=ea:34:71:66:90:12:01”.dhcp true +``` + +Alternatively, you can place the MAC address selection in your cloud config file as follows: + +```yaml +#cloud-config +rancher: + network: + interfaces: + "mac=ea:34:71:66:90:12:01": + dhcp: true +``` + +### NIC bonding + +You can aggregate several network links into one virtual link for redundancy and increased throughput. For example: + +```yaml +#cloud-config +rancher: + network: + interfaces: + bond0: + addresses: + - 192.168.101.33/31 + - 10.88.23.129/31 + gateway: 192.168.101.32 + bond_opts: + downdelay: "200" + lacp_rate: "1" + miimon: "100" + mode: "4" + updelay: "200" + xmit_hash_policy: layer3+4 + post_up: + - ip route add 10.0.0.0/8 via 10.88.23.128 + mac=0c:c4:d7:b2:14:d2: + bond: bond0 + mac=0c:c4:d7:b2:14:d3: + bond: bond0 +``` + +In this example two physical NICs (with MACs `0c:c4:d7:b2:14:d2` and `0c:c4:d7:b2:14:d3`) are aggregated into a virtual one `bond0`. + +### VLANS + +In this example, you can create an interface `eth0.100` which is tied to VLAN 100 and an interface `foobar` that will be tied to VLAN 200. + +``` +#cloud-config +rancher: + network: + interfaces: + eth0: + vlans: 100,200:foobar +``` diff --git a/docs/os/networking/proxy-settings/index.md b/docs/os/networking/proxy-settings/index.md new file mode 100644 index 00000000..d57fb7ab --- /dev/null +++ b/docs/os/networking/proxy-settings/index.md @@ -0,0 +1,36 @@ +--- +title: Configuring Proxy Settings in RancherOS +layout: os-default + +--- + +## Proxy settings + +HTTP proxy settings can be set directly under the `network` key. This will automatically configure proxy settings for both Docker and System Docker. + +```yaml +#cloud-config +rancher: + network: + http_proxy: https://myproxy.example.com + https_proxy: https://myproxy.example.com + no_proxy: localhost,127.0.0.1 +``` + +
+ +> **Note:** System Docker proxy settings will not be applied until after a reboot. + +To add the `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables to a system service, specify each under the `environment` key for the service. + +```yaml +#cloud-config +rancher: + services: + myservice: + ... + environment: + - HTTP_PROXY + - HTTPS_PROXY + - NO_PROXY +``` diff --git a/docs/os/quick-start-guide/index.md b/docs/os/quick-start-guide/index.md new file mode 100644 index 00000000..4dbed716 --- /dev/null +++ b/docs/os/quick-start-guide/index.md @@ -0,0 +1,134 @@ +--- +title: Quick Start Guide for RancherOS +layout: os-default + +--- + +## Quick Start Guide +--- + +If you have a specific RanchersOS machine requirements, please check out our [guides on running RancherOS]({{site.baseurl}}/os/running-rancheros/). With the rest of this guide, we'll start up a RancherOS using [Docker machine]({{site.baseurl}}/os/running-rancheros/workstation/docker-machine/) and show you some of what RancherOS can do. + +### Launching RancherOS using Docker Machine + +Before moving forward, you'll need to have [Docker Machine](https://docs.docker.com/machine/) and [VirtualBox](https://www.virtualbox.org/wiki/Downloads) installed. Once you have VirtualBox and Docker Machine installed, it's just one command to get RancherOS running. + +``` +$ docker-machine create -d virtualbox --virtualbox-boot2docker-url https://releases.rancher.com/os/latest/rancheros.iso +``` + +That's it! You're up and running a RancherOS instance. + +To log into the instance, just use the `docker-machine` command. + +``` +$ docker-machine ssh +``` + +### A First Look At RancherOS + +There are two Docker daemons running in RancherOS. The first is called **System Docker**, which is where RancherOS runs system services like ntpd and syslog. You can use the `system-docker` command to control the **System Docker** daemon. + +The other Docker daemon running on the system is **Docker**, which can be accessed by using the normal `docker` command. + +When you first launch RancherOS, there are no containers running in the Docker daemon. However, if you run the same command against the System Docker, you’ll see a number of system services that are shipped with RancherOS. + +> **Note:** `system-docker` can only be used by root, so it is necessary to use the `sudo` command whenever you want to interact with System Docker. + +``` +$ sudo system-docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +6f56057cf5ba rancher/os-base:v0.5.0 "/usr/sbin/entry.sh /" 16 seconds ago Up 15 seconds docker +bd5376830237 rancher/os-console:v0.5.0 "/usr/sbin/entry.sh /" 16 seconds ago Up 15 seconds console +ede8ce39fff5 rancher/os-base:v0.5.0 "/usr/sbin/entry.sh n" 16 seconds ago Up 15 seconds network +9e5d18bca391 rancher/os-base:v0.5.0 "/usr/sbin/entry.sh n" 17 seconds ago Up 16 seconds ntp +393b9fb7e30a rancher/os-udev:v0.5.0 "/usr/sbin/entry.sh /" 18 seconds ago Up 16 seconds udev +dc2cafca3c69 rancher/os-syslog:v0.5.0 "/usr/sbin/entry.sh /" 18 seconds ago Up 17 seconds syslog +439d5535fbfa rancher/os-base:v0.5.0 "/usr/sbin/entry.sh /" 18 seconds ago Up 17 seconds acpid +``` + +Some containers are run at boot time, and others, such as the `console`, `docker`, etc. containers are always running. + +## Using RancherOS +--- + +### Deploying a Docker Container + +Let's try to deploy a normal Docker container on the Docker daemon. The RancherOS Docker daemon is identical to any other Docker environment, so all normal Docker commands work. + +``` +$ docker run -d nginx +``` + +You can see that the nginx container is up and running: + +``` +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +e99c2c4b8b30 nginx "nginx -g 'daemon off" 12 seconds ago Up 11 seconds 80/tcp, 443/tcp drunk_ptolemy +``` + +### Deploying A System Service Container + +The following is a simple Docker container to set up Linux-dash, which is a minimal low-overhead web dashboard for monitoring Linux servers. The Dockerfile will be like this: + +``` +FROM hwestphal/nodebox +MAINTAINER hussein.galal.ahmed.11@gmail.com + +RUN opkg-install unzip +RUN curl -k -L -o master.zip https://github.com/afaqurk/linux-dash/archive/master.zip +RUN unzip master.zip +WORKDIR linux-dash-master +RUN npm install + +ENTRYPOINT ["node","server"] +``` + +Using the `hwestphal/nodebox` image, which uses a Busybox image and installs `node.js` and `npm`. We downloaded the source code of Linux-dash, and then ran the server. Linux-dash will run on port 80 by default. + +To run this container in System Docker use the following command: + +``` +$ sudo system-docker run -d --net=host --name busydash husseingalal/busydash +``` +In the commad, we used `--net=host` to tell System Docker not to containerize the container's networking, and use the host’s networking instead. After running the container, you can see the monitoring server by accessing `http:// **Hosts** -> **Custom** page. + +```bash +$ sudo docker run --d --privileged -v /var/run/docker.sock:/var/run/docker.sock \ + rancher/agent:v0.8.2 http://:8080/v1/projects/1a5/scripts/ +``` + +
+ +> **Note:** The `rancher/agent` version is correlated to the Rancher server version. You will need to check the custom command to get the appropriate tag for the version to use. + +_Cloud-Config Example_ + +Here's using the command above and converting it into a cloud-config file to launch the rancher/agent in docker when RancherOS boots up. + +```yaml +#cloud-config +rancher: + services: + rancher-agent1: + image: rancher/agent:v0.8.2 + command: http://:8080/v1/projects/1a5/scripts/ + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock +``` +
+ +> **Note:** You can not name the service `rancher-agent` as this will not allow the rancher/agent container to be launched correctly. Please read more about why [you can't name your container as `rancher-agent`]({{site.baseurl}}/rancher/faqs/agents/#adding-in-name-rancher-agent). + +### Adding in Host Labels + +With each host, you have the ability to add labels to help you organize your hosts. The labels are added as an environment variable when launching the rancher/agent container. The host label in the UI will be a key/value pair and the keys must be unique identifiers. If you added two keys with different values, we'll take the last inputted value to use as the key/value pair. + +By adding labels to hosts, you can use these labels when [schedule services/load balancers/services]({{site.baseurl}}/rancher/rancher-ui/scheduling/) and create a whitelist or blacklist of hosts for your [services]({{site.baseurl}}/rancher/rancher-ui/applications/stacks/adding-services/) to run on. + +When adding a custom host, you can add the labels using the UI and it will automatically add the environment variable (`CATTLE_HOST_LABELS`) with the key/value pair into the command on the UI screen. + +#### Native Docker Commands Example + +```bash +# Adding one host label to the rancher/agent command +$ sudo docker run -e CATTLE_HOST_LABELS='foo=bar' -d --privileged \ + -v /var/run/docker.sock:/var/run/docker.sock rancher/agent:v0.8.2 \ + http://:8080/v1/projects/1a5/scripts/ + +# Adding more than one host label requires joining the additional host labels with an `&` +$ sudo docker run -e CATTLE_HOST_LABELS='foo=bar&hello=world' -d --privileged \ + -v /var/run/docker.sock:/var/run/docker.sock rancher/agent:v0.8.2 \ + http://:8080/v1/projects/1a5/scripts/ +``` + +#### Cloud-Config Example + +Adding one host label + +```yaml +#cloud-config +rancher: + services: + rancher-agent1: + image: rancher/agent:v0.8.2 + command: http://:8080/v1/projects/1a5/scripts/ + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + CATTLE_HOST_LABELS: foo=bar +``` +
+ +Adding more than one host label requires joining the additional host labels with an `&` + +```yaml +#cloud-config +rancher: + services: + rancher-agent1: + image: rancher/agent:v0.8.2 + command: http://:8080/v1/projects/1a5/scripts/ + privileged: true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + CATTLE_HOST_LABELS: foo=bar&hello=world +``` + diff --git a/docs/os/running-rancheros/cloud/aws/index.md b/docs/os/running-rancheros/cloud/aws/index.md new file mode 100644 index 00000000..8826e638 --- /dev/null +++ b/docs/os/running-rancheros/cloud/aws/index.md @@ -0,0 +1,76 @@ +--- +title: Getting Started on Amazon EC2 +layout: os-default + +--- +## Running RancherOS on AWS +---- +RancherOS is available as an Amazon Web Services AMI, and can be easily run on EC2. You can launch RancherOS either using the AWS Command Line Interface (CLI) or using the AWS console. + +### Launching RancherOS through the AWS CLI + +If you haven't installed the AWS CLI, follow the instructions on the [AWS CLI page](http://aws.amazon.com/cli/) to install the CLI and configure access key and secret keys. + +Once you've installed your AWS CLI, use this command to launch an EC2 instance with the RancherOS AMI. You will need to know your SSH key name and security group name for the _region_ that you are configured for. These can be found from the AWS console. + +> **Note:** Check the RancherOS [README](https://github.com/rancher/os/blob/master/README.md) for AMI names for each region. We support PV and HVM types of AMIs. + +``` +$ aws ec2 run-instances --image-id ami-ID# --count 1 --instance-type t2.micro --key-name MySSHKeyName --security-groups sg-name +``` + +Your EC2 instance is now running RancherOS! + +### Launching RancherOS through the AWS Console + +Let’s walk through how to import and create a RancherOS on EC2 machine using the AWS console. + + +1. First login to your AWS console, and go to the EC2 dashboard, click on **Launch Instance**: + + ![RancherOS on AWS 1]({{site.baseurl}}/img/os/Rancher_aws1.png) + +2. Select the **Community AMIs** on the sidebar and search for **RancherOS**. Pick the latest version and click **Select**. + + ![RancherOS on AWS 2]({{site.baseurl}}/img/os/Rancher_aws2.png) + +3. Go through the steps of creating the instance type through the AWS console. If you want to pass in a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file during boot of RancherOS, you'd pass in the file as **User data** by expanding the **Advanced Details** in **Step 3: Configure Instance Details**. You can pass in the data as text or as a file. + + ![RancherOS on AWS 6]({{site.baseurl}}/img/os/Rancher_aws6.png) + + After going through all the steps, you finally click on **Launch**, and either create a new key pair or choose an existing key pair to be used with the EC2 instance. If you have created a new key pair, download the key pair. If you have chosen an existing key pair, make sure you have the key pair accessible. Click on **Launch Instances**. + + ![RancherOS on AWS 3]({{site.baseurl}}/img/os/Rancher_aws3.png) + +4. Your instance will be launching and you can click on **View Instances** to see it's status. + + ![RancherOS on AWS 4]({{site.baseurl}}/img/os/Rancher_aws4.png) + + Your instance is now running! + + ![RancherOS on AWS 5]({{site.baseurl}}/img/os/Rancher_aws5.png) + +## Logging into RancherOS +---- + +From a command line, log into the EC2 Instance. If you added ssh keys using a cloud-config, +both those keys, and the one you selected in the AWS UI will be installed. + +``` +$ ssh -i /Directory/of/MySSHKeyName.pem rancher@ +``` + +If you have issues logging into RancherOS, try using this command to help debug the issue. + +``` +$ ssh -v -i /Directory/of/MySSHKeyName.pem rancher@ +``` + +## Latest AMI Releases +---- + +Please check the [README](https://github.com/rancher/os/blob/master/README.md) in our RancherOS repository for our latest AMIs. + + + + diff --git a/docs/os/running-rancheros/cloud/azure/index.md b/docs/os/running-rancheros/cloud/azure/index.md new file mode 100644 index 00000000..4e08576e --- /dev/null +++ b/docs/os/running-rancheros/cloud/azure/index.md @@ -0,0 +1,32 @@ +--- +title: Running RancherOS on Azure +layout: os-default + +--- + +## Running RancherOS on Azure +--- + +RancherOS is available as an image with Azure Resource Management. Please note that RancherOS is only offered in Azure Resource Management and not available in the Azure Service Management. + +> **Note:** Currently, we only have v0.3.1 available as an image in Azure and it does not support passing in cloud config files. We are working on adding a new version that has cloud config enabled. Also, only certain regions are supported with RancherOS on Azure. + +### Launching Rancheros through the Azure Portal + +Using the new Azure Resource Management portal, click on **Marketplace**. Search for **RancherOS**. Click on **Create**. + +Follow the steps to create a virtual machine. + +In the _Basics_ step, provide a **name** for the VM, use _rancher_ as the **user name** and select the **SSH public key** option of authenticating. Add your ssh public key into the appropriate field. Select the **Resource group** that you want to add the VM to or create a new one. Select the **location** for your VM. + +In the _Size_ step, select a virtual machine that has at least **1GB** of memory. + +In the _Settings_ step, you can use all the default settings to get RancherOS running. + +Review your VM and buy it so that you can **Create** your VM. + +After the VM has been provisioned, click on the VM to find the public IP address. SSH into your VM using the _rancher_ username. + +``` +$ ssh rancher@ -p 22 +``` diff --git a/docs/os/running-rancheros/cloud/do/index.md b/docs/os/running-rancheros/cloud/do/index.md new file mode 100644 index 00000000..be1a72d9 --- /dev/null +++ b/docs/os/running-rancheros/cloud/do/index.md @@ -0,0 +1,10 @@ +--- +title: Running RancherOS on Digital Ocean +layout: os-default + +--- + +## Running RancherOS on DigitalOcean +--- + +Running RancherOS on DigitalOcean is not yet supported. diff --git a/docs/os/running-rancheros/cloud/gce/index.md b/docs/os/running-rancheros/cloud/gce/index.md new file mode 100644 index 00000000..b9778d03 --- /dev/null +++ b/docs/os/running-rancheros/cloud/gce/index.md @@ -0,0 +1,148 @@ +--- +title: Running RancherOS on GCE +layout: os-default + +--- +## Running RancherOS on Google Compute Engine (GCE) +---- + +Note: The Google Compute Engine image is still experimental. There are known issues with the image, so please do not use it in production! + +### Adding the RancherOS Image into GCE + +RancherOS is available as an image in GCE, and can be easily run in Google Compute Engine (GCE). Let’s walk through how to upload GCE image. + +1. Download the most recent RancherOS image. The image can be found in the [release artifacts](https://github.com/rancher/os/releases). It is a `.tar.gz` file. + +2. Follow Google's instructions on how to [upload the image](https://cloud.google.com/compute/docs/tutorials/building-images#publishingimage). The image must be uploaded into a Google Cloud Storage bucket before it can be added to a project. + +3. Follow Google's instructions on how to [import a RAW image](https://cloud.google.com/compute/docs/images/import-existing-image#use_saved_image). + +4. Once the image is added to your Google Compute Engine, we can start creating new instances! + +### Launching RancherOS using `gcloud compute` + +After the image is uploaded, we can use the `gcloud compute` [command-line tool](https://cloud.google.com/compute/docs/gcloud-compute/) to start a new instance. It automatically merges the SSH keys from the project and adds the keys to the **rancher** user. If you don't have any project level SSH keys, go to the _Adding SSH Keys_ section to learn more about adding SSH keys. + +Since the image is private, we need to follow Google's [instructions](https://cloud.google.com/compute/docs/creating-custom-image#start_an_instance_from_a_custom_image). + +``` +$ gcloud compute instances create --project --zone --image +``` + +### Using a Cloud Config File with GCE + +If you want to pass in your own cloud config file that will be processed by [cloud init]({{site.baseurl}}/os/configuration/#cloud-config), you can pass it as metadata upon creation of the instance during the `gcloud compute` command. The file will need to be stored locally before running the command. The key of the metadata will be `user-data` and the value is the location of the file. If any SSH keys are added in the cloud config file, it will also be added to the **rancher** user. + +``` +$ gcloud compute instances create --project --zone --image --metadata-from-file user-data=/Directory/of/Cloud_Config.yml +``` + +**Adding your Cloud Config to Existing Instance** + +If you have already created the instance, you can still add the cloud config file after the instance is created. You will just need to reset the machine after you've added the metadata. + +``` +$ gcloud compute instances add-metadata --metadata-from-file user-data=/Directory/of/File --project --zone +Updated [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE_OF_INSTANCE/instances/INSTANCE_NAME]. +$ gcloud compute instances reset --project --zone +Updated [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE_OF_INSTANCE/instances/INSTANCE_NAME]. +``` + +**Reviewing your Cloud Config** + +If you want to review the cloud config file for your instance, review the **metadata** section: + +``` +$ gcloud compute instances describe --project --zone +``` + +**Removing your Cloud Config** + +If you want to remove your cloud config file, use the following command to remove the metadata. + +``` +$ gcloud compute instances remove-metadata --project --zone --keys user-data +Updated [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE_OF_INSTANCE/instances/INSTANCE_NAME]. +``` + +**Resetting your Instance** + +After any changes to the cloud config file, you'll need to reset the machine. You can reset either using the console or using this command: + +``` +$ gcloud compute instances reset --project --zone +Updated [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE_OF_INSTANCE/instances/INSTANCE_NAME]. +``` + +### Launching RancherOS using the Google Console + +After the image is uploaded, it's easy to use the console to create new instances. You will **not** be able to upload your own cloud config file when creating instances through the console. You can add it after the instance is created using `gcloud compute` commands and resetting the instance. + +1. Make sure you are in the project that the image was created in. + + ![RancherOS on GCE 4]({{site.baseurl}}/img/os/Rancher_gce4.png) + +2. In the navigation bar, click on the **VM instances**, which is located at Compute -> Compute Engine -> Metadata. Click on **Create instance**. + + ![RancherOS on GCE 5]({{site.baseurl}}/img/os/Rancher_gce5.png) + +2. Fill out the information for your instance. In the **Image** dropdown, your private image will be listed among the public images provided by Google. Select the private image for RancherOS. Click **Create**. + + ![RancherOS on GCE 6]({{site.baseurl}}/img/os/Rancher_gce6.png) + +3. Your instance is being created and will be up and running shortly! + +#### Adding SSH keys + +In order to SSH into the GCE instance, you will need to have SSH keys set up in either the project instance, add them to the instance after the instance is created, or add them using the `gcloud compute` commands to add meta-data to an instance. + +**Option 1: Project Level SSH Keys** + +In your project, click on **Metadata**, which is located within Compute -> Compute Engine -> Metadata. Click on **SSH Keys**. + +![RancherOS on GCE 7]({{site.baseurl}}/img/os/Rancher_gce7.png) + +Add the SSH keys that you want to have access to any instances within your project. + +Note: If you do this after any RancherOS instance is created, you will need to reset the instance so that the SSH keys are added to the **rancher** user. + +**Option 2: Instance Level SSH Keys** + +After your instance is created, click on the instance name. Scroll down to the **SSH Keys** section and click on **Add SSH key**. This key will only be applicable to the instance. + +![RancherOS on GCE 8]({{site.baseurl}}/img/os/Rancher_gce8.png) + +After the SSH keys have been added, you'll need to reset the machine, by clicking **Reset**. + +![RancherOS on GCE 9]({{site.baseurl}}/img/os/Rancher_gce9.png) + +After a little bit, you will be able to SSH into the box using the **rancher** user. + +**Option 3: Using the Cloud Config file** + +You can add SSH keys by adding them into the cloud config file. Follow the directions above that walk through how to pass the cloud config file to an instance. + +Example of cloud config file that has only SSH keys: + +```yaml +#cloud-config + +ssh_authorized_keys: + - ssh-rsa AAA... user@host +``` + +## Logging into RancherOS +---- + +Remember, the SSH keys are passed to the **rancher** user. The SSH keys can be passed from the project level, the instance level or through the cloud config file. If you add any of these SSH keys after the instance has been created, the instance will need to be reset before the SSH keys are passed through. + +``` +$ gcloud compute ssh rancher@ --project --zone +``` + +If you have issues logging into RancherOS, try using this command to help debug the instance. + +``` +$ gcloud compute instances get-serial-port-output --zone --project +``` diff --git a/docs/os/running-rancheros/cloud/openstack/index.md b/docs/os/running-rancheros/cloud/openstack/index.md new file mode 100644 index 00000000..854ad008 --- /dev/null +++ b/docs/os/running-rancheros/cloud/openstack/index.md @@ -0,0 +1,11 @@ +--- +title: Rancher RancherOS in Openstack +layout: os-default +--- + +## Openstack +--- + +As of v0.5.0, RancherOS releases include an Openstack image that can be found on our [releases page](https://github.com/rancher/os/releases). The image format is QCOW2. + +When launching an instance using the image, you must enable **Advanced Options** -> **Configuration Drive** and in order to use a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config) file. diff --git a/docs/os/running-rancheros/index.md b/docs/os/running-rancheros/index.md new file mode 100644 index 00000000..89771c34 --- /dev/null +++ b/docs/os/running-rancheros/index.md @@ -0,0 +1,39 @@ +--- +title: Running RancherOS +layout: os-default + +--- + +## Running RancherOS +--- + +RancherOS runs on virtualization platforms, cloud providers and bare metal servers. We also support running a local VM on your laptop. To start running RancherOS as quickly as possible, follow our [Quick Start Guide]({{site.baseurl}}/os/quick-start-guide/). + +### Platforms + +#### Workstation + +[Docker Machine]({{site.baseurl}}/os/running-rancheros/workstation/docker-machine) + +[Boot from ISO]({{site.baseurl}}/os/running-rancheros/workstation/boot-from-iso) + + +#### Cloud + +[Amazon EC2]({{site.baseurl}}/os/running-rancheros/cloud/aws) + +[Google Compute Engine]({{site.baseurl}}/os/running-rancheros/cloud/gce) + +[DigitalOcean]({{site.baseurl}}/os/running-rancheros/cloud/do) + +[Azure]({{site.baseurl}}/os/running-rancheros/cloud/azure) + +#### Bare Metal & Virtual Servers + +[iPXE]({{site.baseurl}}/os/running-rancheros/server/ipxe) + +[PXE]({{site.baseurl}}/os/running-rancheros/server/pxe) + +[Install to Hard Disk]({{site.baseurl}}/os/running-rancheros/server/install-to-disk) + +
diff --git a/docs/os/running-rancheros/server/install-to-disk/index.md b/docs/os/running-rancheros/server/install-to-disk/index.md new file mode 100644 index 00000000..4168c1f0 --- /dev/null +++ b/docs/os/running-rancheros/server/install-to-disk/index.md @@ -0,0 +1,100 @@ +--- +title: Installing RancherOS to Disk +layout: os-default +--- + +## Installing RancherOS to Disk +--- +RancherOS comes with a simple installer that will install RancherOS on a given target disk. To install RancherOS on a new disk, you can use the `ros install` command. Before installing, you'll need to have already [booted RancherOS from ISO]({{site.baseurl}}/os/running-rancheros/workstation/boot-from-iso). Please be sure to pick the `rancheros.iso` from our release [page](https://github.com/rancher/os/releases). + +### Using `ros install` to Install RancherOS + +The `ros install` command orchestrates the installation from the `rancher/os` container. You will need to have already created a cloud-config file and found the target disk. + +#### Cloud-Config + +The easiest way to log in is to pass a `cloud-config.yml` file containing your public SSH keys. To learn more about what's supported in our cloud-config, please read our [documentation]({{site.baseurl}}/os/configuration/#cloud-config). + +The `ros install` command will process your `cloud-config.yml` file specified with the `-c` flag. This file will also be placed onto the disk and installed to `/var/lib/rancher/conf/`. It will be evaluated on every boot. + +Create a cloud-config file with a SSH key, this allows you to SSH into the box as the rancher user. The yml file would look like this: + +```yaml +#cloud-config +ssh_authorized_keys: + - ssh-rsa AAA... +``` + +
+ +You can generate a new SSH key for `cloud-config.yml` file by following this [article](https://help.github.com/articles/generating-ssh-keys/). + +Copy the public SSH key into RancherOS before installing to disk. + +Now that our `cloud-config.yml` contains our public SSH key, we can move on to installing RancherOS to disk! + +``` +$ sudo ros install -c cloud-config.yml -d /dev/sda +INFO[0000] No install type specified...defaulting to generic +Installing from rancher/os:v0.5.0 +Continue [y/N]: +``` + +You will be prompted to see if you want to continue. Type **y**. + +``` +Unable to find image 'rancher/os:v0.5.0' locally +v0.5.0: Pulling from rancher/os +... +... +... +Status: Downloaded newer image for rancher/os:v0.5.0 ++ DEVICE=/dev/sda +... +... +... ++ umount /mnt/new_img +Continue with reboot [y/N]: +``` + +After installing RancherOS to disk, you will no longer be automatically logged in as the `rancher` user. You'll need to have added in SSH keys within your [cloud-config file]({{site.baseurl}}/os/configuration/#cloud-config). + +#### Installing a Different Version + +By default, `ros install` uses the same installer image version as the ISO it is run from. The `-i` option specifies the particular image to install from. To keep the ISO as small as possible, the installer image is downloaded from DockerHub and used in System Docker. For example for RancherOS v0.5.0 the default installer image would be `rancher/os:v0.5.0`. + +You can use `ros os list` command to find the list of available RancherOS images/versions. + +``` +$ sudo ros os list +rancher/os:v0.4.0 remote +rancher/os:v0.4.1 remote +rancher/os:v0.4.2 remote +rancher/os:v0.4.3 remote +rancher/os:v0.4.4 remote +rancher/os:v0.4.5 remote +rancher/os:v0.5.0 remote +``` + +Alternatively, you can set the installer image to any image in System Docker to install RancherOS. This is particularily useful for machines that will not have direct access to the internet. + +### SSH into RancherOS + +After installing RancherOS, you can ssh into RancherOS using your private key and the **rancher** user. + +``` +$ ssh -i /path/to/private/key rancher@ +``` + +### Installing with no Internet Access + +If you'd like to install RancherOS onto a machine that has no internet access, it is assumed you either have your own private registry or other means of distributing docker images to System Docker of the machine. If you need help with creating a private registry, please refer to the [Docker documentation for private registries](https://docs.docker.com/registry/). + +In the installation command (i.e. `sudo ros install`), there is an option to pass in a specific image to install. As long as this image is available in System Docker, then RancherOS will use that image to install RancherOS. + +``` +$ sudo ros install -c cloud-config.yml -d /dev/sda -i +INFO[0000] No install type specified...defaulting to generic +Installing from +Continue [y/N]: +``` diff --git a/docs/os/running-rancheros/server/pxe/index.md b/docs/os/running-rancheros/server/pxe/index.md new file mode 100644 index 00000000..c773968d --- /dev/null +++ b/docs/os/running-rancheros/server/pxe/index.md @@ -0,0 +1,37 @@ +--- +title: Booting RancherOS with iPXE +layout: os-default + +--- +## Booting RancherOS via iPXE +---- + +``` +#!ipxe +# Boot a persistent RancherOS to RAM + +# Location of Kernel/Initrd images +set base-url http://releases.rancher.com/os/latest + +kernel ${base-url}/vmlinuz rancher.state.dev=LABEL=RANCHER_STATE rancher.state.autoformat=[/dev/sda] rancher.cloud_init.datasources=[url:http://example.com/cloud-config] +initrd ${base-url}/initrd +boot +``` + +### Datasources + +Valid [datasources](https://github.com/rancher/os/blob/3338c4ac63597940bcde7e6005f1cc09287062a2/cmd/cloudinit/cloudinit.go#L378) for RancherOS. + +| type | default | +|---|---| +| ec2 | DefaultAddress | +| file | path | +| url | url | +| cmdline | | +| configdrive | | +| digitalocean | DefaultAddress | +| gce | | + +### Cloud-Config + +When booting via iPXE, RancherOS can be configured using a [cloud-config file]({{site.baseurl}}/os/configuration/#cloud-config). diff --git a/docs/os/running-rancheros/server/raspberry-pi/index.md b/docs/os/running-rancheros/server/raspberry-pi/index.md new file mode 100644 index 00000000..ff8ccdc6 --- /dev/null +++ b/docs/os/running-rancheros/server/raspberry-pi/index.md @@ -0,0 +1,34 @@ +--- +title: Running RancherOS on Raspberry Pi +layout: os-default +--- + +## Raspberry Pi +--- + +As of v0.5.0, RancherOS releases include a Raspberry Pi image that can be found on our [releases page](https://github.com/rancher/os/releases). The official Raspberry Pi documentation contains instructions on how to [install operating system images](https://www.raspberrypi.org/documentation/installation/installing-images/). + +When installing, there is no ability to pass in a [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). You will need to boot up, change the configuration and then reboot to apply those changes. + +Currently, only Raspberry Pi 2 and 3 are tested and known to work. + +### Using the entire SD Card + +RancherOS does not currently expand the root partition to fill the remainder of the SD card automatically. Instead, the following workaround can be used to store Docker containers on a larger partition that fills the remainder. + +1. `sudo fdisk /dev/mmcblk0` +2. Create a `n`ew partition +3. Press `[Enter]` four (4x) times to accept the defaults +4. Then `w`rite the table and exit +5. `sudo reboot` to reboot and reload the new partition table +6. `sudo mkdir /mnt/docker` to create the directory to be used as the new Docker root +7. `sudo ros config set rancher.docker.extra_args [-g,/mnt/docker]` to configure Docker to use the new root +8. `sudo mkfs.ext4 /dev/mmcblk0p3` to format the disk +9. `sudo ros config set mounts "[['/dev/mmcblk0p3','/mnt/docker','ext4','']]"` to preserve this mount after reboots +10. `sudo mount /dev/mmcblk0p3 /mnt/docker` to mount the Docker root +11. `sudo system-docker restart docker` to restart Docker using the new root + +If this is not a new installation, you'll have to copy over your existing Docker root (`/var/lib/docker`) to the new root (`/mnt/docker`). + +1. `sudo cp -R /var/lib/docker/* /mnt/docker` to recursively copy all files +2. `sudo system-docker restart docker` to restart Docker using the new root diff --git a/docs/os/running-rancheros/workstation/boot-from-iso/index.md b/docs/os/running-rancheros/workstation/boot-from-iso/index.md new file mode 100644 index 00000000..d2965e8c --- /dev/null +++ b/docs/os/running-rancheros/workstation/boot-from-iso/index.md @@ -0,0 +1,86 @@ +--- +title: Booting from ISO +layout: os-default +--- + +## Boot from ISO +--- +The RancherOS ISO file can be used to create a fresh RancherOS install on KVM, VMware, VirtualBox, or bare metal servers. You can download the `rancheros.iso` file from our [releases page](https://github.com/rancher/os/releases/). + +You must boot with at least **512MB** of memory. If you boot with the ISO, you will automatically be logged in as the `rancher` user. Only the ISO is set to use autologin by default. If you run from a cloud or install to disk, SSH keys or a password of your choice is expected to be used. + +> **Note:** If you are planning on [installing to disk]({{site.baseurl}}/os/running-rancheros/server/install-to-disk/), you will need at least 1.5GB of RAM. + +### Install to Disk +--- +After you boot RancherOS from ISO, you can follow the instructions [here]({{site.baseurl}}/os/running-rancheros/server/install-to-disk/) to install RancherOS to a hard disk. + +### Persisting State +--- +If you are running from the ISO, RancherOS will be running from memory. All downloaded Docker images, for example, will be stored in a ramdisk and will be lost after the server is rebooted. You can +create a file system with the label `RANCHER_STATE` to instruct RancherOS to use that partition to store state. Suppose you have a disk partition on the server called `/dev/sda`, the following command formats that partition and labels it `RANCHER_STATE` + +``` +$ sudo mkfs.ext4 -L RANCHER_STATE /dev/sda +# Reboot afterwards in order for the changes to start being saved. +$ sudo reboot +``` + +After you reboot, the server RancherOS will use `/dev/sda` as the state partition. + +> **Note:** If you are installing RancherOS to disk, you do not need to run this command. + + + diff --git a/docs/os/running-rancheros/workstation/docker-machine/index.md b/docs/os/running-rancheros/workstation/docker-machine/index.md new file mode 100644 index 00000000..0c3df330 --- /dev/null +++ b/docs/os/running-rancheros/workstation/docker-machine/index.md @@ -0,0 +1,84 @@ +--- +title: Using Docker Machine to run RancherOS +layout: os-default + +--- + +## Docker Machine +--- + +Before we get started, you'll need to make sure that you have docker machine installed. Download it directly from the docker machine [releases](https://github.com/docker/machine/releases). + +> **Note:** If you create a RancherOS instance using Docker Machine, you will not be able to upgrade your version of RancherOS. + +### Downloading RancherOS + +Get the latest `rancheros.iso` artifact from the RancherOS [releases](https://github.com/rancher/os/releases). + +### Using Docker Machine + +You can use Docker Machine to launch VMs for various providers. Currently only VirtualBox and AWS are supported. + +#### Using Docker Machine with VirtualBox + +Before moving forward, you'll need to have VirtualBox installed. Download it directly from [VirtualBox](https://www.virtualbox.org/wiki/Downloads). Once you have VirtualBox and Docker Machine installed, it's just one command to get RancherOS running. + +``` +$ docker-machine create -d virtualbox --virtualbox-boot2docker-url +``` + +
+ +> **Note:** Instead of downloading the ISO, you can directly use the URL for the `rancheros.iso`. + +Example using the RancherOS latest link: + +``` +$ docker-machine create -d virtualbox --virtualbox-boot2docker-url https://releases.rancher.com/os/latest/rancheros.iso +``` + +That's it! You should now have a RancherOS host running on VirtualBox. You can verify that you have a VirtualBox VM running on your host. + +> **Note:** After the machine is created, Docker Machine may display some errors regarding creation, but if the VirtualBox VM is running, you should be able to [log in](#logging-into-rancheros). + +``` +$ VBoxManage list runningvms | grep +``` + +This command will print out the newly created machine. If not, something went wrong with the provisioning step. + +### Logging into RancherOS + +Logging into RancherOS follows the standard Docker Machine commands. To login into your newly provisioned RancherOS VM. + +``` +$ docker-machine ssh +``` + +You'll be logged into RancherOS and can start exploring the OS, This will log you into the RancherOS VM. You'll then be able to explore the OS by [adding system services]({{site.baseurl}}/os/system-services/adding-system-services/), [customizing the configuration]({{site.baseurl}}/os/configuration/), and launching containers. + +If you want to exit out of RancherOS, you can exit by pressing `Ctrl+D`. + +### Docker Machine Benefits + +With Docker Machine, you can point the docker client on your host to the docker daemon running inside of the VM. This allows you to run your docker commands as if you had installed docker on your host. + +To point your docker client to the docker daemon inside the VM, use the following command: + +``` +$ eval $(docker-machine env ) +``` + +After setting this up, you can run any docker command in your host, and it will execute the command in your RancherOS VM. + +``` +$ docker run -p 80:80 -p 443:443 -d nginx +``` + +In your VM, a nginx container will start on your VM. To access the container, you will need the IP address of the VM. + +``` +$ docker-machine ip +``` + +Once you obtain the IP address, paste it in a browser and a _Welcome Page_ for nginx will be displayed. diff --git a/docs/os/storage/additional-mounts/index.md b/docs/os/storage/additional-mounts/index.md new file mode 100644 index 00000000..369a25e2 --- /dev/null +++ b/docs/os/storage/additional-mounts/index.md @@ -0,0 +1,28 @@ +--- +title: Additional Mounts in RancherOS +layout: os-default +redirect_from: + - os/configuration/additional-mounts/ +--- + +## Additional Mounts + +Additional mounts can be specified as part of your [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config). These mounts are applied within the console container. Here's a simple example that mounts `/dev/vdb` to `/mnt/s`. + +```yaml +#cloud-config +mounts: +- ["/dev/vdb", "/mnt/s", "ext4", ""] +``` + +
+ +The four arguments for each mount are the same as those given for [cloud-init](https://cloudinit.readthedocs.io/en/latest/topics/examples.html#adjust-mount-points-mounted). Only the first four arguments are currently supported. The `mount_default_fields` key is not yet implemented. + +RancherOS uses the mount syscall rather than the `mount` command behind the scenes. This means that `auto` cannot be used as the filesystem type (third argument) and `defaults` cannot be used for the options (forth argument). + +### Shared Mounts + +By default, `/media` and `/mnt` are mounted as shared in the console container. This means that mounts within these directories will propogate to the host as well as other system services that mount these folders as shared. + +See [here](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) for a more detailed overview of shared mounts and their properties. diff --git a/docs/os/storage/state-partition/index.md b/docs/os/storage/state-partition/index.md new file mode 100644 index 00000000..f56b47d5 --- /dev/null +++ b/docs/os/storage/state-partition/index.md @@ -0,0 +1,28 @@ +--- +title: Persistent State Partition in RancherOS +layout: os-default +--- + +## Persistent State Partition + +RancherOS will store its state in a single partition specified by the `dev` field. The field can be a device such as `/dev/sda1` or a logical name such `LABEL=state` or `UUID=123124`. The default value is `LABEL=RANCHER_STATE`. The file system type of that partition can be set to `auto` or a specific file system type such as `ext4`. + +```yaml +#cloud-config +rancher: + state: + fstype: auto + dev: LABEL=RANCHER_STATE + autoformat: + - /dev/sda + - /dev/vda +``` + +### Autoformat + +You can specify a list of devices to check to format on boot. If the state partition is already found, RancherOS will not try to auto format a partition. By default, auto-formatting is off. + +RancherOS will autoformat the partition to ext4 if the device specified in `autoformat`: + +* Contains a boot2docker magic string +* Starts with 1 megabyte of zeros and `rancher.state.formatzero` is true diff --git a/docs/os/storage/using-zfs/index.md b/docs/os/storage/using-zfs/index.md new file mode 100644 index 00000000..af7d8fdd --- /dev/null +++ b/docs/os/storage/using-zfs/index.md @@ -0,0 +1,148 @@ +--- +title: Using ZFS in RancherOS +layout: os-default +redirect_from: + - os/configuration/storage/ +--- + +## Using ZFS + +In order to start using ZFS, you'll need to first enable one of the [persistent consoles]({{site.baseurl}}/os/configuration/custom-console/#console-persistence) and enable [kernel headers]({{site.baseurl}}/os/configuration/kernel-modules-kernel-headers/). + +``` +$ sudo ros console switch ubuntu +$ sudo ros service enable kernel-headers +$ sudo ros service up kernel-headers +$ sudo ros service logs kernel-headers +``` + +When RancherOS console has reloaded, you will have logged into the persistent console. The current kernel headers will need to be downloaded using the `ros service enable` and the service will be started with `ros service up kernel-headers`. + +You can make sure that the headers are in the right place by looking at the kernel-headers service logs. + +#### Installing ZFS on Ubuntu Console + +Based on the [Ubuntu ZFS docs](https://wiki.ubuntu.com/Kernel/Reference/ZFS), you only need to install `zfs` package into the Ubuntu console to enable ZFS. All the other necessary packages will be installed as its dependencies. + +``` +$ sudo apt update +$ sudo apt install zfs +``` + +Then have a look at the zfs dmks build log file - which is likely to be a file similar to `/var/lib/dkms/zfs/0.6.5.6/build/make.log`. + +#### Mounting ZFS filesystems on boot + +In order for ZFS to load on boot, it needs to be added to `modules` list in the config. Prior to adding it to the list of modules, you'll need to check to see if there are other modules that are currently enabled. + +``` +# Check to see what modules currently exist +$ sudo ros config get rancher.modules +# Make sure to include any modules that were already enabled +$ sudo ros config set rancher.modules [zfs] +``` + +
+ +You will also need to have the zpool cache imported on boot: + +``` +[ -f /etc/zfs/zpool.cache ] && zpool import -c /etc/zfs/zpool.cache -a +``` + +
+ +A cloud-config `runcmd` instruction will do it for you: + +``` +# check current 'runcmd' list +$ sudo ros config get runcmd +[] +# add the command we need to run on boot +$ sudo ros config set runcmd "[[sh, -c, '[ -f /etc/zfs/zpool.cache ] && zpool import -c /etc/zfs/zpool.cache -a']]" +``` + +#### Using ZFS + +After it's installed, it should be ready to use! + +``` +$ sudo modprobe zfs +$ sudo zpool list +$ sudo zpool create zpool1 /dev/ +``` + +
+ +To experiment with ZFS, you can create zpool backed by just ordinary files, not necessarily real block devices. In fact, you can mix storage devices in your ZFS pools; it's perfectly fine to create a zpool backed by real devices **and** ordinary files. + +## ZFS storage for Docker on RancherOS + +First, you need to stop the`docker` system service and wipe out `/var/lib/docker` folder: + +``` +$ sudo system-docker stop docker +$ sudo rm -rf /var/lib/docker/* +``` + +To enable ZFS as the storage driver for Docker, you'll need to create a ZFS filesystem for Docker and make sure it's mounted. + +``` +$ sudo zfs create zpool1/docker +$ sudo zfs list -o name,mountpoint,mounted +``` + +At this point you'll have a ZFS filesystem created and mounted at `/zpool1/docker`. According to [Docker ZFS storage docs](https://docs.docker.com/engine/userguide/storagedriver/zfs-driver/), if the Docker root dir is a ZFS filesystem, the Docker daemon will automatically use `zfs` as its storage driver. + +Now you'll need to remove `-s overlay` (or any other storage driver) from the Docker daemon args to allow docker to automatically detect `zfs`. + +``` +$ sudo ros config set rancher.docker.storage_driver '' +$ sudo ros config set rancher.docker.graph /zpool1/docker +# After editing Docker daemon args, you'll need to start Docker +$ sudo system-docker stop docker +$ sudo system-docker start docker +``` + +After customizing the Docker daemon arguments and restarting `docker` system service, ZFS will be used as Docker storage driver: + +``` +$ docker info +Containers: 1 + Running: 0 + Paused: 0 + Stopped: 1 +Images: 1 +Server Version: 1.12.1 +Storage Driver: zfs + Zpool: zpool1 + Zpool Health: ONLINE + Parent Dataset: zpool1/docker + Space Used By Parent: 27761152 + Space Available: 4100088320 + Parent Quota: no + Compression: off +Logging Driver: json-file +Cgroup Driver: cgroupfs +Plugins: + Volume: local + Network: host null bridge overlay +Swarm: inactive +Runtimes: runc +Default Runtime: runc +Security Options: seccomp +Kernel Version: 4.4.16-rancher +Operating System: RancherOS v0.6.0-rc8 +OSType: linux +Architecture: x86_64 +CPUs: 2 +Total Memory: 1.938 GiB +Name: rancher +ID: EK7Q:WTBH:33KR:UCRY:YAPI:N7RX:D25K:S7ZH:DRNY:ZJ3J:25XE:P3RF +Docker Root Dir: /zpool1/docker +Debug Mode (client): false +Debug Mode (server): false +Registry: https://index.docker.io/v1/ +Insecure Registries: + 127.0.0.0/8 +``` diff --git a/docs/os/system-services/adding-system-services/index.md b/docs/os/system-services/adding-system-services/index.md new file mode 100644 index 00000000..9a484ebe --- /dev/null +++ b/docs/os/system-services/adding-system-services/index.md @@ -0,0 +1,56 @@ +--- +title: System Services in RancherOS +layout: os-default +redirect_from: + - os/system-services/ + - os/configuration/system-services/ +--- + +## System Services + +A system service is a container that can be run in either System Docker or Docker. Rancher provides services that are already available in RancherOS by adding them to the [os-services repo](https://github.com/rancher/os-services). Anything in the `index.yml` file from the repository for the tagged release will be an available system service when using the `ros service list` command. + +### Enabling and Starting System Services + +For any services that are listed from the `ros service list`, they can be enabled by running a single command. After enabling a service, you will need to run start the service. + +``` +# List out available system services +$ sudo ros service list +disabled amazon-ecs-agent +disabled kernel-headers +disabled kernel-headers-system-docker +disabled open-vm-tools +# Enable a system service +$ sudo ros service enable kernel-headers +# Start a system service +$ sudo ros service up kernel-headers +``` + +### Disabling and Removing System Services + +In order to stop a system service from running, you will need to stop and disable the system service. + +``` +# List out available system services +$ sudo ros service list +disabled amazon-ecs-agent +enabled kernel-headers +disabled kernel-headers-system-docker +disabled open-vm-tools +# Disable a system service +$ sudo ros service disable kernel-headers +# Stop a system service +$ sudo ros service stop kernel-headers +# Remove the containers associated with the system service +$ sudo ros service down kernel-headers +``` + +
+If you want to remove a system service from the list of service, just delete the service. + +``` +$ sudo ros service delete +``` + + diff --git a/docs/os/system-services/custom-system-services/index.md b/docs/os/system-services/custom-system-services/index.md new file mode 100644 index 00000000..26191fe2 --- /dev/null +++ b/docs/os/system-services/custom-system-services/index.md @@ -0,0 +1,107 @@ +--- +title: Custom System Services in RancherOS +layout: os-default +--- + +## Custom System Services + +You can also create your own system service in [Docker Compose](https://docs.docker.com/compose/) format. After creating your own custom service, you can launch it in RancherOS in a couple of methods. The service could be directly added to the [cloud-config]({{site.baseurl}}/os/configuration/#cloud-config), or a `docker-compose.yml` file could be saved at a http(s) url location or in a specific directory of RancherOS. + +### Launching Services through Cloud-Config + +If you want to boot RancherOS with a system service running, you can add the service to the cloud-config that is passed to RancherOS. When RancherOS starts, this service will automatically be started. + +```yaml +#cloud-config +rancher: + services: + nginxapp: + image: nginx + restart: always +``` + +### Launching Services using local files + +If you already have RancherOS running, you can start a system service by saving a `docker-compose.yml` file at `/var/lib/rancher/conf/`. + +```yaml +nginxapp: + image: nginx + restart: always +``` + +To enable a custom system service from the file location, the command must indicate the file location if saved in RancherOS. If the file is saved at a http(s) url, just use the http(s) url when enabling/disabling. + +``` +# Enable the system service saved in /var/lib/rancher/conf +$ sudo ros service enable /var/lib/rancher/conf/example.yml +# Enable a system service saved at a http(s) url +$ sudo ros service enable https://mydomain.com/example.yml +``` + +
+ +After the custom system service is enabled, you can start the service using `sudo ros service up `. The `` will be the names of the services inside the `docker-compose.yml`. + +``` +$ sudo ros service up nginxapp +# If you have more than 1 service in your docker-compose.yml, add all service names to the command +$ sudo ros service up service1 service2 service3 +``` + +### Launching Services from a web repository + +The https://github.com/rancher/os-services repository is used for the built-in services, but you can create your own, and configure RancherOS to use it in addition (or to replace) it. + +The config settings to set the url in which `ros` should look for an `index.yml` file is: `rancher.repositories..url`. The `core` repository url is set when a release is made, and any other `` url you add will be listed together when running `ros console list`, `ros servce list` or `ros engine list` + +For example, in RancherOS v0.7.0, the `core` repository is set to `https://raw.githubusercontent.com/rancher/os-services/v0.7.0`. + +### Creating your own Console + +Once you have your own Services repository, you can add a new service to its index.yml, and then add a `.yml` file to the directory starting with the first letter. + +To create your own console images, you need to: + +1 install some basic tools, including an ssh daemon, sudo, and kernel module tools +2 create `rancher` and `docker` users and groups with UID and GID's of `1100` and `1101` respectively +3 add both users to the `docker` and `sudo` groups +4 add both groups into the `/etc/sudoers` file to allow password-less sudo +5 configure sshd to accept logins from users in the `docker` group, and deny `root`. +6 set `ENTRYPOINT ["/usr/bin/ros", "entrypoint"]` + +the `ros` binary, and other host specific configuration files will be bind mounted into the running console container when its launched. + +For examples of existing images, see https://github.com/rancher/os-images. + +## Labels + +We use labels to determine how to handle the service containers. + +Key | Value |Description +----|-----|--- +`io.rancher.os.detach` | Default: `true` | Equivalent of `docker run -d`. If set to `false`, equivalent of `docker run --detach=false` +`io.rancher.os.scope` | `system` | Use this label to have the container deployed in System Docker instead of Docker. +`io.rancher.os.before`/`io.rancher.os.after` | Service Names (Comma separated list is accepted) | Used to determine order of when containers should be started. +`io.rancher.os.createonly` | Default: `false` | When set to `true`, only a `docker create` will be performed and not a `docker start`. +`io.rancher.os.reloadconfig` | Default: `false`| When set to `true`, it reloads the configuration. + + +RancherOS uses labels to determine if the container should be deployed in System Docker. By default without the label, the container will be deployed in User Docker. + +```yaml +labels: + - io.rancher.os.scope=system +``` + + +### Example of how to order container deployment + +```yaml +foo: + labels: + # Start foo before bar is launched + io.rancher.os.before: bar + # Start foo after baz has been launched + io.rancher.os.after: baz +``` diff --git a/docs/os/system-services/environment/index.md b/docs/os/system-services/environment/index.md new file mode 100644 index 00000000..ce8cf141 --- /dev/null +++ b/docs/os/system-services/environment/index.md @@ -0,0 +1,36 @@ +--- +title: Environment +layout: os-default + +--- + +## Environment +--- + +The [environment key](https://docs.docker.com/compose/yml/#environment) can be used to customize system services. When a value is not assigned, RancherOS looks up the value from the `rancher.environment` key. + +In the example below, `ETCD_DISCOVERY` will be set to `https://discovery.etcd.io/d1cd18f5ee1c1e2223aed6a1734719f7` for the `etcd` service. + +```yaml +rancher: + environment: + ETCD_DISCOVERY: https://discovery.etcd.io/d1cd18f5ee1c1e2223aed6a1734719f7 + services: + etcd: + ... + environment: + - ETCD_DISCOVERY +``` + +Wildcard globbing is also supported. In the example below, `ETCD_DISCOVERY` will be set as in the previous example, along with any other environment variables beginning with `ETCD_`. + +```yaml +rancher: + environment: + ETCD_DISCOVERY: https://discovery.etcd.io/d1cd18f5ee1c1e2223aed6a1734719f7 + services: + etcd: + ... + environment: + - ETCD_* +``` diff --git a/docs/os/system-services/system-docker-volumes/index.md b/docs/os/system-services/system-docker-volumes/index.md new file mode 100644 index 00000000..a2b9dc31 --- /dev/null +++ b/docs/os/system-services/system-docker-volumes/index.md @@ -0,0 +1,79 @@ +--- +title: System Docker Volumes +layout: os-default + +--- + +## System Docker Volumes +--- + +A few services are containers in `created` state. Their purpose is to provide volumes for other services. + +### user-volumes + +Provides user accessible persistent storage directories, used by console service: + +``` +/home +/opt +``` + +### container-data-volumes + +Provides docker storage directory, used by console service (and, indirectly, by docker) + +``` +/var/lib/docker +``` + +### command-volumes + +Provides necessary command binaries (read-only), used by system services: + +``` +/usr/bin/docker-containerd.dist +/usr/bin/docker-containerd-shim.dist +/usr/bin/docker-runc.dist +/usr/bin/docker.dist +/usr/bin/dockerlaunch +/usr/bin/user-docker +/usr/bin/system-docker +/sbin/poweroff +/sbin/reboot +/sbin/halt +/sbin/shutdown +/usr/bin/respawn +/usr/bin/ros +/usr/bin/cloud-init +/usr/sbin/netconf +/usr/sbin/wait-for-docker +/usr/bin/switch-console +``` + +### system-volumes + +Provides necessary persistent directories, used by system services: + +``` +/host/dev +/etc/docker +/etc/hosts +/etc/resolv.conf +/etc/ssl/certs/ca-certificates.crt.rancher +/etc/selinux +/lib/firmware +/lib/modules +/run +/usr/share/ros +/var/lib/rancher/cache +/var/lib/rancher/conf +/var/lib/rancher +/var/log +/var/run +``` + +### all-volumes + +Combines all of the above, used by the console service. + + diff --git a/docs/os/under-the-hood/device-plug-and-unplug/index.md b/docs/os/under-the-hood/device-plug-and-unplug/index.md new file mode 100644 index 00000000..1cf1428f --- /dev/null +++ b/docs/os/under-the-hood/device-plug-and-unplug/index.md @@ -0,0 +1,10 @@ +--- +title: Device Plug and Unplug +layout: os-default + +--- + +## Device Plug and Unplug +--- + +More information coming soon! \ No newline at end of file diff --git a/docs/os/under-the-hood/directories/index.md b/docs/os/under-the-hood/directories/index.md new file mode 100644 index 00000000..e13292e4 --- /dev/null +++ b/docs/os/under-the-hood/directories/index.md @@ -0,0 +1,19 @@ +--- +title: Directories +layout: os-default +--- + +## How directories are mounted, Ram disk, etc. +--- + +### Persistent Directories Across Reboot + +With v0.4.0, ubuntu and debian consoles are [persistent consoles]({{site.baseurl}}/os/configuration/custom-console/#console-persistence). Therefore, the only difference is what is persisted inside a containers as opposed to on the host. If a container is deleted/rebuilt, state in the console will be lost except what is in the persisted directories. + +``` +/home +/opt +/var/lib/docker +/var/lib/rancher +``` + diff --git a/docs/os/under-the-hood/porting/index.md b/docs/os/under-the-hood/porting/index.md new file mode 100644 index 00000000..787aaff8 --- /dev/null +++ b/docs/os/under-the-hood/porting/index.md @@ -0,0 +1,8 @@ +--- +title: Porting +layout: os-default + +--- + +## Porting + diff --git a/docs/os/under-the-hood/startup-sequence/index.md b/docs/os/under-the-hood/startup-sequence/index.md new file mode 100644 index 00000000..82c4332c --- /dev/null +++ b/docs/os/under-the-hood/startup-sequence/index.md @@ -0,0 +1,10 @@ +--- +title: Startup Sequence +layout: os-default + +--- + +## RancherOS Startup Sequence +--- + +More information coming soon! \ No newline at end of file diff --git a/docs/os/under-the-hood/zombie-process-management/index.md b/docs/os/under-the-hood/zombie-process-management/index.md new file mode 100644 index 00000000..63dc02c5 --- /dev/null +++ b/docs/os/under-the-hood/zombie-process-management/index.md @@ -0,0 +1,10 @@ +--- +title: Zombie process management +layout: os-default + +--- + +## Zombie Process Management (Our hack on Docker Daemon) +--- + +More information coming soon! \ No newline at end of file diff --git a/docs/os/upgrading/index.md b/docs/os/upgrading/index.md new file mode 100644 index 00000000..ca43b9b3 --- /dev/null +++ b/docs/os/upgrading/index.md @@ -0,0 +1,138 @@ +--- +title: Upgrading RancherOS +layout: os-default + +--- + +## Upgrading +--- + +If RancherOS has released a new version and you want to learn how to upgrade your OS, we make it easy using the `ros os` command. + +Since RancherOS is a kernel and initrd, the upgrade process is downloading a new kernel and initrd, and updating the boot loader to point to it. The old kernel and initrd are not removed. If there is a problem with your upgrade, you can select the old kernel from the bootloader, which is grub2 by default. + +To see all of our releases, please visit our [releases page](https://github.com/rancher/os/releases) in GitHub. + +### Version Control + +First, let's check what version you have running on your system. + +``` +$ sudo ros os version +v0.4.5 +``` + +If you just want to find out the available releases from the command line, it's a simple command. + +``` +# List all available releases +$ sudo ros os list +rancher/os:v0.4.0 remote +rancher/os:v0.4.1 remote +rancher/os:v0.4.2 remote +rancher/os:v0.4.3 remote +rancher/os:v0.4.4 remote +rancher/os:v0.4.5 remote +rancher/os:v0.5.0 local +``` + +The `local`/`remote` label shows which images are available to System Docker locally versus which need to be pulled from Docker Hub. If you choose to upgrade to a version that is remote, we will automatically pull that image during the upgrade. + +### Upgrading + +Let's walk through upgrading! The `ros os upgrade` command will automatically upgrade to the current release of RancherOS. The current release is designated as the most recent release of RancherOS. + +``` +$ sudo ros os upgrade +Upgrading to rancher/os:v0.5.0 +``` + +Confirm that you want to continue and the final step will be to confirm that you want to reboot. + +``` +Continue [y/N]: y +... +... +... +Continue with reboot [y/N]: y +INFO[0037] Rebooting +``` + +After rebooting, you can check that your version has been updated. + +``` +$ sudo ros -v +ros version v0.5.0 +``` + +> **Note:** If you are booting from ISO and have not installed to disk, your upgrade will not be saved. You can view our guide to [installing to disk]({{site.baseurl}}/os/running-rancheros/server/install-to-disk/). + +#### Upgrading to a Specific Version + +If you are a couple of versions behind the current version, use the `-i` option to pick the version that you want to upgrade to. + +``` +$ sudo ros os upgrade -i rancher/os:v0.5.0 +Upgrading to rancher/os:v0.5.0 +Continue [y/N]: y +... +... +... +Continue with reboot [y/N]: y +INFO[0082] Rebooting +``` + +#### Bypassing The Prompts + +We have added the ability to bypass the prompts. Use the `-f` or `--force` option when upgrading. Your machine will automatically be rebooted and you'll just need to log back in when it's done. + +If you want to bypass the prompts, but you don't want to immediately reboot, you can add `--no-reboot` to avoid rebooting immediately. + +### Rolling back an Upgrade + +If you've upgraded your RancherOS and something's not working anymore, you can easily rollback your upgrade. + +The `ros os upgrade` command works for rolling back. We'll use the `-i` option to "upgrade" to a specific version. All you need to do is pick the previous version! Same as before, you will be prompted to confirm your upgrade version as well as confirm your reboot. + +``` +$ sudo ros -v +ros version v0.4.5 +$ sudo ros os upgrade -i rancher/os:v0.4.4 +Upgrading to rancher/os:v0.4.4 +Continue [y/N]: y +... +... +... +Continue with reboot [y/N]: y +INFO[0082] Rebooting +``` +After rebooting, the rollback will be complete. + +``` +$ sudo ros -v +ros version 0.4.4 +``` + +
+ +> **Note:** If you are using a [persistent console]({{site.baseurl}}/os/configuration/custom-console/#console-persistence) and in the current version's console, rolling back is not supported. For example, rolling back to v0.4.5 when using a v0.5.0 persistent console is not supported. + +### Staging an Upgrade + +During an upgrade, the template of the upgrade is downloaded from the rancher/os repository. You can download this template ahead of time so that it's saved locally. This will decrease the time it takes to upgrade. We'll use the `-s` option to stage the specific template. You will need to specify the image name with the `-i` option, otherwise it will automatically stage the current version. + +``` +$ sudo ros os upgrade -s -i rancher/os:v0.5.0 +``` + +### Custom Upgrade Sources + +In the `upgrade` key, the `url` is used to find the list of available and current versions of RancherOS. This can be modified to track custom builds and releases. + +```yaml +#cloud-config +rancher: + upgrade: + url: https://releases.rancher.com/os/releases.yml + image: rancher/os +``` diff --git a/docs/vendor/bootstrap.js b/docs/vendor/bootstrap.js new file mode 100644 index 00000000..1c88b71e --- /dev/null +++ b/docs/vendor/bootstrap.js @@ -0,0 +1,2317 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery') +} + ++function ($) { + 'use strict'; + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') + } +}(jQuery); + +/* ======================================================================== + * Bootstrap: transition.js v3.3.4 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one('bsTransitionEnd', function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) + } + } + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.3.4 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.VERSION = '3.3.4' + + Alert.TRANSITION_DURATION = 150 + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.closest('.alert') + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one('bsTransitionEnd', removeElement) + .emulateTransitionEnd(Alert.TRANSITION_DURATION) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.alert + + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.3.4 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.4' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.3.4 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = null + this.sliding = null + this.interval = null + this.$active = null + this.$items = null + + this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + + this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } + + Carousel.VERSION = '3.3.4' + + Carousel.TRANSITION_DURATION = 600 + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true, + keyboard: true + } + + Carousel.prototype.keydown = function (e) { + if (/input|textarea/i.test(e.target.tagName)) return + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + + e.preventDefault() + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } + + Carousel.prototype.getItemForDirection = function (direction, active) { + var activeIndex = this.getItemIndex(active) + var willWrap = (direction == 'prev' && activeIndex === 0) + || (direction == 'next' && activeIndex == (this.$items.length - 1)) + if (willWrap && !this.options.wrap) return active + var delta = direction == 'prev' ? -1 : 1 + var itemIndex = (activeIndex + delta) % this.$items.length + return this.$items.eq(itemIndex) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || this.getItemForDirection(type, $active) + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var that = this + + if ($next.hasClass('active')) return (this.sliding = false) + + var relatedTarget = $next[0] + var slideEvent = $.Event('slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + }) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one('bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { + that.$element.trigger(slidEvent) + }, 0) + }) + .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + var old = $.fn.carousel + + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + var clickHandler = function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + Plugin.call($target, options) + + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + } + + $(document) + .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) + .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.3.4 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + + '[data-toggle="collapse"][data-target="#' + element.id + '"]') + this.transitioning = null + + if (this.options.parent) { + this.$parent = this.getParent() + } else { + this.addAriaAndCollapsedClass(this.$element, this.$trigger) + } + + if (this.options.toggle) this.toggle() + } + + Collapse.VERSION = '3.3.4' + + Collapse.TRANSITION_DURATION = 350 + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var activesData + var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') + + if (actives && actives.length) { + activesData = actives.data('bs.collapse') + if (activesData && activesData.transitioning) return + } + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + if (actives && actives.length) { + Plugin.call(actives, 'hide') + activesData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + .attr('aria-expanded', true) + + this.$trigger + .removeClass('collapsed') + .attr('aria-expanded', true) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element[dimension](this.$element[dimension]())[0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse in') + .attr('aria-expanded', false) + + this.$trigger + .addClass('collapsed') + .attr('aria-expanded', false) + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .removeClass('collapsing') + .addClass('collapse') + .trigger('hidden.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + Collapse.prototype.getParent = function () { + return $(this.options.parent) + .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') + .each($.proxy(function (i, element) { + var $element = $(element) + this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) + }, this)) + .end() + } + + Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { + var isOpen = $element.hasClass('in') + + $element.attr('aria-expanded', isOpen) + $trigger + .toggleClass('collapsed', !isOpen) + .attr('aria-expanded', isOpen) + } + + function getTargetFromTrigger($trigger) { + var href + var target = $trigger.attr('data-target') + || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + + return $(target) + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.collapse + + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var $this = $(this) + + if (!$this.attr('data-target')) e.preventDefault() + + var $target = getTargetFromTrigger($this) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + + Plugin.call($target, option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.3.4 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.VERSION = '3.3.4' + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('