website: initial commit

This commit is contained in:
Jack Pearkes 2014-07-16 17:51:48 -04:00
parent 1e81b13943
commit 7b72a9defb
117 changed files with 5690 additions and 0 deletions

2
website/.buildpacks Normal file
View File

@ -0,0 +1,2 @@
https://github.com/heroku/heroku-buildpack-ruby.git
https://github.com/hashicorp/heroku-buildpack-middleman.git

14
website/Gemfile Normal file
View File

@ -0,0 +1,14 @@
source 'https://rubygems.org'
gem "less", "~> 2.5.0"
gem "middleman", "~> 3.3.2"
gem "middleman-minify-html", "~> 3.1.1"
gem "rack-contrib", "~> 1.1.0"
gem "redcarpet", "~> 3.0.0"
gem "therubyracer", "~> 0.12.0"
gem "thin", "~> 1.5.0"
group :development do
gem "highline", "~> 1.6.15"
end

132
website/Gemfile.lock Normal file
View File

@ -0,0 +1,132 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.0.4)
i18n (~> 0.6, >= 0.6.9)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
chunky_png (1.3.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.7.0)
commonjs (0.2.7)
compass (0.12.5)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.2.19)
compass-import-once (1.0.4)
sass (>= 3.2, < 3.5)
daemons (1.1.9)
erubis (2.7.0)
eventmachine (1.0.3)
execjs (2.0.2)
ffi (1.9.3)
fssm (0.2.10)
haml (4.0.5)
tilt
highline (1.6.21)
hike (1.2.3)
hooks (0.4.0)
uber (~> 0.0.4)
i18n (0.6.9)
json (1.8.1)
kramdown (1.3.3)
less (2.5.0)
commonjs (~> 0.2.7)
libv8 (3.16.14.3)
listen (1.3.1)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
rb-kqueue (>= 0.2)
middleman (3.3.2)
coffee-script (~> 2.2.0)
compass (>= 0.12.4)
compass-import-once (~> 1.0.4)
execjs (~> 2.0)
haml (>= 4.0.5)
kramdown (~> 1.2)
middleman-core (= 3.3.2)
middleman-sprockets (>= 3.1.2)
sass (>= 3.2.17, < 4.0)
uglifier (~> 2.5)
middleman-core (3.3.2)
activesupport (~> 4.0.1)
bundler (~> 1.1)
erubis
hooks (~> 0.3)
i18n (~> 0.6.9)
listen (~> 1.1)
padrino-helpers (~> 0.12.1)
rack (>= 1.4.5, < 2.0)
rack-test (~> 0.6.2)
thor (>= 0.15.2, < 2.0)
tilt (~> 1.4.1, < 2.0)
middleman-minify-html (3.1.1)
middleman-core (~> 3.0)
middleman-sprockets (3.3.2)
middleman-core (>= 3.2)
sprockets (~> 2.2)
sprockets-helpers (~> 1.1.0)
sprockets-sass (~> 1.0.0)
minitest (4.7.5)
multi_json (1.9.2)
padrino-helpers (0.12.1)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.12.1)
tilt (~> 1.4.1)
padrino-support (0.12.1)
activesupport (>= 3.1)
rack (1.5.2)
rack-contrib (1.1.0)
rack (>= 0.9.1)
rack-test (0.6.2)
rack (>= 1.0)
rb-fsevent (0.9.4)
rb-inotify (0.9.3)
ffi (>= 0.5.0)
rb-kqueue (0.2.2)
ffi (>= 0.5.0)
redcarpet (3.0.0)
ref (1.0.5)
sass (3.2.19)
sprockets (2.12.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-helpers (1.1.0)
sprockets (~> 2.0)
sprockets-sass (1.0.3)
sprockets (~> 2.0)
tilt (~> 1.1)
therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
thin (1.5.1)
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
thor (0.19.1)
thread_safe (0.3.3)
tilt (1.4.1)
tzinfo (0.3.39)
uber (0.0.4)
uglifier (2.5.0)
execjs (>= 0.3.0)
json (>= 1.8.0)
PLATFORMS
ruby
DEPENDENCIES
highline (~> 1.6.15)
less (~> 2.5.0)
middleman (~> 3.3.2)
middleman-minify-html (~> 3.1.1)
rack-contrib (~> 1.1.0)
redcarpet (~> 3.0.0)
therubyracer (~> 0.12.0)
thin (~> 1.5.0)

10
website/LICENSE.md Normal file
View File

@ -0,0 +1,10 @@
# Proprietary License
This license is temporary while a more official one is drafted. However,
this should make it clear:
* The text contents of this website are MPL 2.0 licensed.
* The design contents of this website are proprietary and may not be reproduced
or reused in any way other than to run the Terraform website locally. The license
for the design is owned solely by HashiCorp, Inc.

1
website/Procfile Normal file
View File

@ -0,0 +1 @@
web: bundle exec thin start -p $PORT

24
website/README.md Normal file
View File

@ -0,0 +1,24 @@
# Terraform Website
This subdirectory contains the entire source for the [Terraform Website](http://www.terraform.io).
This is a [Middleman](http://middlemanapp.com) project, which builds a static
site from these source files.
## Contributions Welcome!
If you find a typo or you feel like you can improve the HTML, CSS, or
JavaScript, we welcome contributions. Feel free to open issues or pull
requests like any normal GitHub project, and we'll merge it in.
## Running the Site Locally
Running the site locally is simple. Clone this repo and run the following
commands:
```
$ bundle
$ bundle exec middleman server
```
Then open up `localhost:4567`. Note that some URLs you may need to append
".html" to make them work (in the navigation and such).

24
website/Vagrantfile vendored Normal file
View File

@ -0,0 +1,24 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
$script = <<SCRIPT
sudo apt-get -y update
sudo apt-get -y install curl
curl -sSL https://get.rvm.io | bash -s stable
. ~/.bashrc
. ~/.bash_profile
rvm install 2.0.0
rvm --default use 2.0.0
cd /vagrant
bundle
SCRIPT
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "chef/ubuntu-12.04"
config.vm.network "private_network", ip: "33.33.30.10"
config.vm.provision "shell", inline: $script, privileged: false
config.vm.synced_folder ".", "/vagrant", type: "rsync"
end

20
website/config.rb Normal file
View File

@ -0,0 +1,20 @@
#-------------------------------------------------------------------------
# Configure Middleman
#-------------------------------------------------------------------------
set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
# Use the RedCarpet Markdown engine
set :markdown_engine, :redcarpet
set :markdown,
:fenced_code_blocks => true,
:with_toc_data => true
# Build-specific configuration
configure :build do
activate :asset_hash
activate :minify_html
activate :minify_javascript
end

27
website/config.ru Normal file
View File

@ -0,0 +1,27 @@
require "rack"
require "rack/contrib/not_found"
require "rack/contrib/response_headers"
require "rack/contrib/static_cache"
require "rack/contrib/try_static"
# Properly compress the output if the client can handle it.
use Rack::Deflater
# Set the "forever expire" cache headers for these static assets. Since
# we hash the contents of the assets to determine filenames, this is safe
# to do.
use Rack::StaticCache,
:root => "build",
:urls => ["/images", "/javascripts", "/stylesheets"],
:duration => 2,
:versioning => false
# Try to find a static file that matches our request, since Middleman
# statically generates everything.
use Rack::TryStatic,
:root => "build",
:urls => ["/"],
:try => [".html", "index.html", "/index.html"]
# 404 if we reached this point. Sad times.
run Rack::NotFound.new(File.expand_path("../build/404.html", __FILE__))

4
website/dummy.txt Normal file
View File

@ -0,0 +1,4 @@
This file doesn't do anything, but we periodically update the number
below just to force being able to deploy the website again.
1

View File

@ -0,0 +1,67 @@
require "net/http"
$terraform_files = {}
$terraform_os = []
if ENV["CONSUL_VERSION"]
raise "BINTRAY_API_KEY must be set." if !ENV["BINTRAY_API_KEY"]
http = Net::HTTP.new("dl.bintray.com", 80)
req = Net::HTTP::Get.new("/mitchellh/terraform/")
req.basic_auth "mitchellh", ENV["BINTRAY_API_KEY"]
response = http.request(req)
response.body.split("\n").each do |line|
next if line !~ /\/mitchellh\/terraform\/(#{Regexp.quote(ENV["CONSUL_VERSION"])}.+?)'/
filename = $1.to_s
os = filename.split("_")[1]
next if os == "SHA256SUMS"
next if os == "web"
$terraform_files[os] ||= []
$terraform_files[os] << filename
end
$terraform_os = ["darwin", "linux", "windows"] & $consul_files.keys
$terraform_os += $consul_files.keys
$terraform_os.uniq!
$terraform_files.each do |key, value|
value.sort!
end
end
module DownloadHelpers
def download_arch(file)
parts = file.split("_")
return "" if parts.length != 3
parts[2].split(".")[0]
end
def download_os_human(os)
if os == "darwin"
return "Mac OS X"
elsif os == "freebsd"
return "FreeBSD"
elsif os == "openbsd"
return "OpenBSD"
elsif os == "Linux"
return "Linux"
elsif os == "windows"
return "Windows"
else
return os
end
end
def download_url(file)
"https://dl.bintray.com/mitchellh/terraform/#{file}"
end
def ui_download_url
download_url("#{latest_version}_web_ui.zip")
end
def latest_version
ENV["CONSUL_VERSION"]
end
end

View File

@ -0,0 +1,12 @@
module SidebarHelpers
# This helps by setting the "active" class for sidebar nav elements
# if the YAML frontmatter matches the expected value.
def sidebar_current(expected)
current = current_page.data.sidebar_current || ""
if current.start_with?(expected)
return " class=\"active\""
else
return ""
end
end
end

2
website/source/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Source folder
node_modules/

View File

@ -0,0 +1 @@
<h2>Page Not Found</h2>

View File

@ -0,0 +1,69 @@
module.exports = function(grunt) {
// Configuration goes here
grunt.initConfig({
less: {
development:{
files: {
"stylesheets/main.css": "stylesheets/main.less"
}
}
},
concat: {
options: {
separator: ';'
},
site: {
src: [
'javascripts/app/app.js',
'javascripts/app/util.js',
'javascripts/app/homepage.js'
],
dest: 'javascripts/app/deploy/site.js'
},
},
uglify: {
app: {
files: {
'javascripts/app/deploy/site.min.js': ['javascripts/app/deploy/site.js']
}
}
},
watch: {
less: {
files: 'stylesheets/*.less',
tasks: ['less']
},
js: {
files: 'javascripts/app/*.js',
tasks: ['concat', 'uglify']
}
}
});
// Load plugins here
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-recess');
// JS distribution task.
grunt.registerTask('dist-js', ['concat', 'uglify']);
// Full distribution task.
grunt.registerTask('dist', ['dist-js']);
grunt.registerTask('default', ['watch']);
};

View File

@ -0,0 +1,93 @@
---
page_title: "Community"
---
<div class="container">
<div class="col-md-8 col-md-offset-2">
<div class="bs-docs-section">
<h1>Community</h1>
<p>
Terraform is a new project with a growing community. Despite this,
there are active, dedicated users willing to help you through various
mediums.
</p>
<p>
<strong>IRC:</strong> <code>#terraform</code> on Freenode
</p>
<p>
<strong>Mailing list:</strong>
<a href="https://groups.google.com/group/terraform-tool">Terraform Google Group</a>
</p>
<p>
<strong>Bug Tracker:</strong>
<a href="https://github.com/hashicorp/terraform/issues">Issue tracker
on GitHub</a>. Please only use this for reporting bugs. Do not ask
for general help here. Use IRC or the mailing list for that.
<h1>People</h1>
<p>
The following people are some of the faces behind Terraform. They each
contribute to Terraform in some core way. Over time, faces may appear and
disappear from this list as contributors come and go.
</p>
<div class="people">
<div class="person">
<img class="pull-left" src="http://www.gravatar.com/avatar/11ba9630c9136eef9a70d26473d355d5.png?s=125">
<div class="bio">
<h3>Armon Dadgar (<a href="https://github.com/armon">@armon</a>)</h3>
<p>
Armon Dadgar is the creator of Terraform. He researched and developed
most of the internals of how Terraform works, including the
gossip layer, leader election, etc. Armon is also the creator of
<a href="https://github.com/hashicorp/serf">Serf</a>,
<a href="https://github.com/armon/statsite">Statsite</a>, and
<a href="https://github.com/armon/bloomd">Bloomd</a>.
</div>
</div>
<div class="person">
<img class="pull-left" src="http://www.gravatar.com/avatar/54079122b67de9677c1f93933ce8b63a.png?s=125">
<div class="bio">
<h3>Mitchell Hashimoto (<a href="https://github.com/mitchellh">@mitchellh</a>)</h3>
<p>
Mitchell Hashimoto is a co-creator of Terraform. He primarily took
a management role in the creation of Terraform, guiding product
and user experience decisions on top of Armon's technical decisions.
Mitchell Hashimoto is also the creator of
<a href="http://www.vagrantup.com">Vagrant</a>,
<a href="http://www.packer.io">Packer</a>, and
<a href="http://www.serfdom.io">Serf</a>.
</p>
</div>
</div>
<div class="person">
<img class="pull-left" src="http://www.gravatar.com/avatar/2acc31dd6370a54b18f6755cd0710ce6.png?s=125">
<div class="bio">
<h3>Jack Pearkes (<a href="https://github.com/pearkes">@pearkes</a>)</h3>
<p>
Jack Pearkes created and maintains the Terraform web UI.
He is also a core committer to
<a href="http://www.packer.io">Packer</a> and maintains
many successful
<a href="https://github.com/pearkes">open source projects</a>
while also being an employee of
<a href="http://www.hashicorp.com">HashiCorp</a>.
</p>
</div>
</div>
<div class="person">
<img class="pull-left" src="//www.gravatar.com/avatar/1e87e6016a7c4f4ecbd2517d84058467.png?s=125">
<div class="bio">
<h3>William Tisäter (<a href="https://github.com/tiwilliam">@tiwilliam</a>)</h3>
<p>William Tisäter is a Terraform core committer. He is also maintainer of <a href="https://pypi.python.org/pypi/pygeoip">pygeoip</a> and build things daily at <a href="https://tictail.com">Tictail</a>.</p>
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,98 @@
---
layout: "docs"
page_title: "Agent"
sidebar_current: "docs-agent-running"
---
# Terraform Agent
The Terraform agent is the core process of Terraform. The agent maintains membership
information, registers services, runs checks, responds to queries
and more. The agent must run on every node that is part of a Terraform cluster.
Any Agent may run in one of two modes: client or server. A server
node takes on the additional responsibility of being part of the [consensus quorum](#).
These nodes take part in Raft, and provide strong consistency and availability in
the case of failure. The higher burden on the server nodes means that usually they
should be run on dedicated instances, as they are more resource intensive than a client
node. Client nodes make up the majority of the cluster, and they are very lightweight
as they maintain very little state and interface with the server nodes for most operations.
## Running an Agent
The agent is started with the `terraform agent` command. This command blocks,
running forever or until told to quit. The agent command takes a variety
of configuration options but the defaults are usually good enough. When
running `terraform agent`, you should see output similar to that below:
```
$ terraform agent -data-dir=/tmp/terraform
==> Starting Terraform agent...
==> Starting Terraform agent RPC...
==> Terraform agent running!
Node name: 'Armons-MacBook-Air'
Datacenter: 'dc1'
Server: false (bootstrap: false)
Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, RPC: 8400)
Cluster Addr: 192.168.1.43 (LAN: 8301, WAN: 8302)
==> Log data will now stream in as it occurs:
[INFO] serf: EventMemberJoin: Armons-MacBook-Air.local 192.168.1.43
...
```
There are several important components that `terraform agent` outputs:
* **Node name**: This is a unique name for the agent. By default this
is the hostname of the machine, but you may customize it to whatever
you'd like using the `-node` flag.
* **Datacenter**: This is the datacenter the agent is configured to run
in. Terraform has first-class support for multiple datacenters, but to work efficiently
each node must be configured to correctly report its datacenter. The `-dc` flag
can be used to set the datacenter. For single-DC configurations, the agent
will default to "dc1".
* **Server**: This shows if the agent is running in the server or client mode.
Server nodes have the extra burden of participating in the consensus quorum,
storing cluster state, and handling queries. Additionally, a server may be
in "bootstrap" mode. The first server must be in this mode to allow additional
servers to join the cluster. Multiple servers cannot be in bootstrap mode,
otherwise the cluster state will be inconsistent.
* **Client Addr**: This is the address used for client interfaces to the agent.
This includes the ports for the HTTP, DNS, and RPC interfaces. The RPC
address is used for other `terraform` commands. Other Terraform commands such
as `terraform members` connect to a running agent and use RPC to query and
control the agent. By default, this binds only to localhost. If you
change this address or port, you'll have to specify an `-rpc-addr` to commands
such as `terraform members` so they know how to talk to the agent. This is also
the address other applications can use over [RPC to control Terraform](/docs/agent/rpc.html).
* **Cluster Addr**: This is the address and ports used for communication between
Terraform agents in a cluster. Every Terraform agent in a cluster does not have to
use the same port, but this address **MUST** be reachable by all other nodes.
## Stopping an Agent
An agent can be stopped in two ways: gracefully or forcefully. To gracefully
halt an agent, send the process an interrupt signal, which is usually
`Ctrl-C` from a terminal. When gracefully exiting, the agent first notifies
the cluster it intends to leave the cluster. This way, other cluster members
notify the cluster that the node has _left_.
Alternatively, you can force kill the agent by sending it a kill signal.
When force killed, the agent ends immediately. The rest of the cluster will
eventually (usually within seconds) detect that the node has died and will
notify the cluster that the node has _failed_.
It is especially important that a server node be allowed to gracefully leave,
so that there will be a minimal impact on availability as the server leaves
the consensus quorum.
For client agents, the difference between a node _failing_ and a node _leaving_
may not be important for your use case. For example, for a web server and load
balancer setup, both result in the same action: remove the web node
from the load balancer pool. But for other situations, you may handle
each scenario differently.

View File

@ -0,0 +1,16 @@
---
layout: "docs"
page_title: "Commands: Agent"
sidebar_current: "docs-commands-agent"
---
# Terraform Agent
The `terraform agent` command is the heart of Terraform: it runs the agent that
performs the important task of maintaining membership information,
running checks, announcing services, handling queries, etc.
Due to the power and flexibility of this command, the Terraform agent
is documented in its own section. See the [Terraform Agent](/docs/agent/basics.html)
section for more information on how to use this command and the
options it has.

View File

@ -0,0 +1,119 @@
---
layout: "docs"
page_title: "Adding/Removing Servers"
sidebar_current: "docs-guides-servers"
---
# Adding/Removing Servers
Terraform is designed to require minimal operator involvement, however any changes
to the set of Terraform servers must be handled carefully. To better understand
why, reading about the [consensus protocol](/docs/internals/consensus.html) will
be useful. In short, the Terraform servers perform leader election and replication.
For changes to be processed, a minimum quorum of servers (N/2)+1 must be available.
That means if there are 3 server nodes, at least 2 must be available.
In general, if you are ever adding and removing nodes simultaneously, it is better
to first add the new nodes and then remove the old nodes.
## Adding New Servers
Adding new servers is generally straightforward. After the initial server, no further
servers should ever be started with the `-bootstrap` flag. Instead, simply start the new
server with the `-server` flag. At this point, the server will not be a member of
any cluster, and should emit something like:
[WARN] raft: EnableSingleNode disabled, and no known peers. Aborting election.
This means that it does not know about any peers and is not configured to elect itself.
This is expected, and we can now add this node to the existing cluster using `join`.
From the new server, we can join any member of the existing cluster:
$ terraform join <Node Address>
Successfully joined cluster by contacting 1 nodes.
It is important to note that any node, including a non-server may be specified for
join. The gossip protocol is used to properly discover all the nodes in the cluster.
Once the node has joined, the existing cluster leader should log something like:
[INFO] raft: Added peer 127.0.0.2:8300, starting replication
This means that raft, the underlying consensus protocol, has added the peer and begun
replicating state. Since the existing cluster may be very far ahead, it can take some
time for the new node to catch up. To check on this, run `info` on the leader:
```
$ terraform info
...
raft:
applied_index = 47244
commit_index = 47244
fsm_pending = 0
last_log_index = 47244
last_log_term = 21
last_snapshot_index = 40966
last_snapshot_term = 20
num_peers = 2
state = Leader
term = 21
...
```
This will provide various information about the state of Raft. In particular
the `last_log_index` shows the last log that is on disk. The same `info` command
can be run on the new server to see how far behind it is. Eventually the server
will be caught up, and the values should match.
It is best to add servers one at a time, allowing them to catch up. This avoids
the possibility of data loss in case the existing servers fail while bringing
the new servers up-to-date.
## Removing Servers
Removing servers must be done carefully to avoid causing an availability outage.
For a cluster of N servers, at least (N/2)+1 must be available for the cluster
to functions. See this [deployment table](/docs/internals/consensus.html#toc_3).
If you have 3 servers, and 1 of them is currently failed, removing any servers
will cause the cluster to become unavailable.
To avoid this, it may be necessary to first add new servers to the cluster,
increasing the failure tolerance of the cluster, and then to remove old servers.
Even if all 3 nodes are functioning, removing one leaves the cluster in a state
that cannot tolerate the failure of any node.
Once you have verified the existing servers are healthy, and that the cluster
can handle a node leaving, the actual process is simple. You simply issue a
`leave` command to the server.
The server leaving should contain logs like:
...
[INFO] terraform: server starting leave
...
[INFO] raft: Removed ourself, transitioning to follower
...
The leader should also emit various logs including:
...
[INFO] terraform: member 'node-10-0-1-8' left, deregistering
[INFO] raft: Removed peer 10.0.1.8:8300, stopping replication
...
At this point the node has been gracefully removed from the cluster, and
will shut down.
## Forced Removal
In some cases, it may not be possible to gracefully remove a server. For example,
if the server simply fails, then there is no ability to issue a leave. Instead,
the cluster will detect the failure and replication will continuously retry.
If the server can be recovered, it is best to bring it back online and then gracefully
leave the cluster. However, if this is not a possibility, then the `force-leave` command
can be used to force removal of a server.
This is done by invoking that command with the name of the failed node. At this point,
the cluster leader will mark the node as having left the cluster and it will stop attempting
to replicate.

View File

@ -0,0 +1,12 @@
---
layout: "docs"
page_title: "Documentation"
sidebar_current: "docs-home"
---
# Terraform Documentation
Welcome to the Terraform documentation! This documentation is more of a reference
guide for all available features and options of Terraform. If you're just getting
started with Terraform, please start with the
[introduction and getting started guide](/intro/index.html) instead.

View File

@ -0,0 +1,117 @@
---
layout: "docs"
page_title: "Terraform Architecture"
sidebar_current: "docs-internals-architecture"
---
# Terraform Architecture
Terraform is a complex system that has many different moving parts. To help
users and developers of Terraform form a mental model of how it works, this
page documents the system architecture.
<div class="alert alert-block alert-warning">
<strong>Advanced Topic!</strong> This page covers technical details of
the internals of Terraform. You don't need to know these details to effectively
operate and use Terraform. These details are documented here for those who wish
to learn about them without having to go spelunking through the source code.
</div>
## Glossary
Before describing the architecture, we provide a glossary of terms to help
clarify what is being discussed:
* Agent - An agent is the long running daemon on every member of the Terraform cluster.
It is started by running `terraform agent`. The agent is able to run in either *client*,
or *server* mode. Since all nodes must be running an agent, it is simpler to refer to
the node as either being a client or server, but there are other instances of the agent. All
agents can run the DNS or HTTP interfaces, and are responsible for running checks and
keeping services in sync.
* Client - A client is an agent that forwards all RPCs to a server. The client is relatively
stateless. The only background activity a client performs is taking part of LAN gossip pool.
This has a minimal resource overhead and consumes only a small amount of network bandwidth.
* Server - An agent that is server mode. When in server mode, there is an expanded set
of responsibilities including participating in the Raft quorum, maintaining cluster state,
responding to RPC queries, WAN gossip to other datacenters, and forwarding queries to leaders
or remote datacenters.
* Datacenter - A datacenter seems obvious, but there are subtle details such as multiple
availability zones in EC2. We define a datacenter to be a networking environment that is
private, low latency, and high bandwidth. This excludes communication that would traverse
the public internet.
* Consensus - When used in our documentation we use consensus to mean agreement upon
the elected leader as well as agreement on the ordering of transactions. Since these
transactions are applied to a FSM, we implicitly include the consistency of a replicated
state machine. Consensus is described in more detail on [Wikipedia](http://en.wikipedia.org/wiki/Consensus_(computer_science)),
as well as our [implementation here](/docs/internals/consensus.html).
* Gossip - Terraform is built on top of [Serf](http://www.serfdom.io/), which provides a full
[gossip protocol](http://en.wikipedia.org/wiki/Gossip_protocol) that is used for multiple purposes.
Serf provides membership, failure detection, and event broadcast mechanisms. Our use of these
is described more in the [gossip documentation](/docs/internals/gossip.html). It is enough to know
gossip involves random node-to-node communication, primarily over UDP.
* LAN Gossip - This is used to mean that there is a gossip pool, containing nodes that
are all located on the same local area network or datacenter.
* WAN Gossip - This is used to mean that there is a gossip pool, containing servers that
are primary located in different datacenters and must communicate over the internet or
wide area network.
* RPC - RPC is short for a Remote Procedure Call. This is a request / response mechanism
allowing a client to make a request from a server.
## 10,000 foot view
From a 10,000 foot altitude the architecture of Terraform looks like this:
![Terraform Architecture](/images/terraform-arch.png)
Lets break down this image and describe each piece. First of all we can see
that there are two datacenters, one and two respectively. Terraform has first
class support for multiple datacenters and expects this to be the common case.
Within each datacenter we have a mixture of clients and servers. It is expected
that there be between three to five servers. This strikes a balance between
availability in the case of failure and performance, as consensus gets progressively
slower as more machines are added. However, there is no limit to the number of clients,
and they can easily scale into the thousands or tens of thousands.
All the nodes that are in a datacenter participate in a [gossip protocol](/docs/internals/gossip.html).
This means there is a gossip pool that contains all the nodes for a given datacenter. This serves
a few purposes: first, there is no need to configure clients with the addresses of servers,
discovery is done automatically. Second, the work of detecting node failures
is not placed on the servers but is distributed. This makes the failure detection much more
scalable than naive heartbeating schemes. Thirdly, it is used as a messaging layer to notify
when important events such as leader election take place.
The servers in each datacenter are all part of a single Raft peer set. This means that
they work together to elect a leader, which has extra duties. The leader is responsible for
processing all queries and transactions. Transactions must also be replicated to all peers
as part of the [consensus protocol](/docs/internals/consensus.html). Because of this requirement,
when a non-leader server receives an RPC request it forwards it to the cluster leader.
The server nodes also operate as part of a WAN gossip. This pool is different from the LAN pool,
as it is optimized for the higher latency of the internet, and is expected to only contain
other Terraform server nodes. The purpose of this pool is to allow datacenters to discover each
other in a low touch manner. Bringing a new datacenter online is as easy as joining the existing
WAN gossip. Because the servers are all operating in this pool, it also enables cross-datacenter requests.
When a server receives a request for a different datacenter, it forwards it to a random server
in the correct datacenter. That server may then forward to the local leader.
This results in a very low coupling between datacenters, but because of failure detection,
connection caching and multiplexing, cross-datacenter requests are relatively fast and reliable.
## Getting in depth
At this point we've covered the high level architecture of Terraform, but there are much
more details to each of the sub-systems. The [consensus protocol](/docs/internals/consensus.html) is
documented in detail, as is the [gossip protocol](/docs/internals/gossip.html). The [documentation](/docs/internals/security.html)
for the security model and protocols used are also available.
For other details, either terraformt the code, ask in IRC or reach out to the mailing list.

View File

@ -0,0 +1,46 @@
---
layout: "downloads"
page_title: "Download Terraform"
sidebar_current: "downloads-terraform"
---
<h1>Download Terraform</h1>
<section class="downloads">
<div class="description row">
<div class="col-md-12">
<p>
Below are all available downloads for the latest version of Terraform
(<%= latest_version %>). Please download the proper package for your
operating system and architecture. You can find SHA256 checksums
for packages <a href="https://dl.bintray.com/mitchellh/terraform/<%= latest_version %>_SHA256SUMS?direct">here</a>.
</p>
</div>
</div>
<% $terraform_os.each do |os| %>
<div class="row">
<div class="col-md-12 download">
<div class="icon pull-left"><%= image_tag "/images/icons/icon_#{os}.png" %>
</div>
<div class="details">
<h2 class="os-name"><%= download_os_human(os) %></h2>
<ul>
<% $terraform_files[os].each do |file| %>
<li><a href="<%= download_url(file) %>"><%= download_arch(file) %></a></li>
<% end %>
</ul>
<div class="clearfix">
</div>
</div>
</div>
</div>
<% end %>
<div class="row">
<div class="col-md-12 poweredby">
<a href='http://www.bintray.com'>
<img src='http://www.bintray.com/docs/images/poweredByBintray_ColorTransparent.png'>
</a>
</div>
</div>
</section>

View File

@ -0,0 +1,33 @@
---
layout: "downloads"
page_title: "Download Terraform Web UI"
sidebar_current: "downloads-ui"
---
<h1>Download Terraform Web UI</h1>
<section class="downloads">
<div class="description row">
<div class="col-md-12">
<p>
From this page you can download the web UI for Terraform. This is
distributed as a separate ZIP package. You can view a
<a href="http://demo.terraform.io">demo of the web UI here</a> or
you can
<a href="/intro/getting-started/ui.html">read the docs on how to set up the UI here</a>.
</p>
<p class="center">
<a class="btn btn-default btn-lg" href="<%= ui_download_url %>">
Download Terraform Web UI <%= latest_version %></a>
</p>
</div>
</div>
<div class="row">
<div class="col-md-12 poweredby">
<a href='http://www.bintray.com'>
<img src='http://www.bintray.com/docs/images/poweredByBintray_ColorTransparent.png'>
</a>
</div>
</div>
</section>

Binary file not shown.

View File

@ -0,0 +1,230 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="LeagueGothicRegular" horiz-adv-x="724" >
<font-face units-per-em="2048" ascent="1505" descent="-543" />
<missing-glyph horiz-adv-x="315" />
<glyph horiz-adv-x="0" />
<glyph horiz-adv-x="2048" />
<glyph unicode="&#xd;" horiz-adv-x="682" />
<glyph unicode=" " horiz-adv-x="315" />
<glyph unicode="&#x09;" horiz-adv-x="315" />
<glyph unicode="&#xa0;" horiz-adv-x="315" />
<glyph unicode="!" horiz-adv-x="387" d="M74 1505h239l-55 -1099h-129zM86 0v227h215v-227h-215z" />
<glyph unicode="&#x22;" horiz-adv-x="329" d="M57 1505h215l-30 -551h-154z" />
<glyph unicode="#" horiz-adv-x="1232" d="M49 438l27 195h198l37 258h-196l26 194h197l57 420h197l-57 -420h260l57 420h197l-58 -420h193l-27 -194h-192l-37 -258h190l-26 -195h-191l-59 -438h-197l60 438h-261l-59 -438h-197l60 438h-199zM471 633h260l37 258h-260z" />
<glyph unicode="$" horiz-adv-x="692" d="M37 358l192 13q12 -186 129 -187q88 0 93 185q0 74 -61 175q-21 36 -34 53l-40 55q-28 38 -65.5 90t-70.5 101.5t-70.5 141.5t-37.5 170q4 293 215 342v131h123v-125q201 -23 235 -282l-192 -25q-14 129 -93 125q-80 -2 -84 -162q0 -102 94 -227l41 -59q30 -42 37 -52 t33 -48l37 -52q41 -57 68 -109l26 -55q43 -94 43 -186q-4 -338 -245 -369v-217h-123v221q-236 41 -250 352z" />
<glyph unicode="%" horiz-adv-x="1001" d="M55 911v437q0 110 82 156q33 18 90.5 18t97.5 -44t44 -87l4 -43v-437q0 -107 -81 -157q-32 -19 -77 -19q-129 0 -156 135zM158 0l553 1505h131l-547 -1505h-137zM178 911q-4 -55 37 -55q16 0 25.5 14.5t9.5 26.5v451q2 55 -35 55q-18 0 -27.5 -13.5t-9.5 -27.5v-451z M631 158v436q0 108 81 156q33 20 79 20q125 0 153 -135l4 -41v-436q0 -110 -80 -156q-32 -18 -90.5 -18t-98.5 43t-44 88zM754 158q-4 -57 37 -58q37 0 34 58v436q2 55 -34 55q-18 0 -27.5 -13t-9.5 -28v-450z" />
<glyph unicode="&#x26;" horiz-adv-x="854" d="M49 304q0 126 44 225.5t126 222.5q-106 225 -106 442v18q0 94 47 180q70 130 223 130q203 0 252 -215q14 -61 12 -113q0 -162 -205 -434q76 -174 148 -285q33 96 47 211l176 -33q-16 -213 -92 -358q55 -63 92 -76v-235q-23 0 -86 37.5t-123 101.5q-123 -139 -252 -139 t-216 97t-87 223zM263 325.5q1 -65.5 28.5 -107.5t78.5 -42t117 86q-88 139 -174 295q-18 -30 -34.5 -98t-15.5 -133.5zM305 1194q0 -111 55 -246q101 156 101 252q-2 2 0 15.5t-2 36t-11 42.5q-19 52 -61.5 52t-62 -38t-19.5 -75v-39z" />
<glyph unicode="'" horiz-adv-x="309" d="M45 1012l72 266h-72v227h215v-227l-113 -266h-102z" />
<glyph unicode="(" horiz-adv-x="561" d="M66 645q0 143 29.5 292.5t73.5 261.5q92 235 159 343l30 47l162 -84q-38 -53 -86.5 -148t-82.5 -189.5t-61.5 -238t-27.5 -284.5t26.5 -282.5t64.5 -240.5q80 -207 141 -296l26 -39l-162 -84q-41 61 -96 173t-94 217.5t-70.5 257t-31.5 294.5z" />
<glyph unicode=")" horiz-adv-x="561" d="M41 -213q36 50 85.5 147t83.5 190t61.5 236.5t27.5 284.5t-26.5 282.5t-64.5 240.5q-78 205 -140 298l-27 39l162 84q41 -61 96 -173.5t94 -217t71 -257.5t32 -296t-30 -292.5t-74 -260.5q-92 -233 -159 -342l-30 -47z" />
<glyph unicode="*" horiz-adv-x="677" d="M74 1251l43 148l164 -70l-19 176h154l-19 -176l164 70l43 -148l-172 -34l115 -138l-131 -80l-78 152l-76 -152l-131 80l115 138z" />
<glyph unicode="+" horiz-adv-x="1060" d="M74 649v172h370v346h172v-346h371v-172h-371v-346h-172v346h-370z" />
<glyph unicode="," horiz-adv-x="309" d="M45 0v227h215v-227l-113 -266h-102l72 266h-72z" />
<glyph unicode="-" horiz-adv-x="444" d="M74 455v194h297v-194h-297z" />
<glyph unicode="." horiz-adv-x="321" d="M53 0v227h215v-227h-215z" />
<glyph unicode="/" horiz-adv-x="720" d="M8 -147l543 1652h162l-537 -1652h-168z" />
<glyph unicode="0" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5l2 26v887q0 46 -19.5 78.5 t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="1" horiz-adv-x="475" d="M25 1180v141q129 25 205 130q16 21 30 54h133v-1505h-221v1180h-147z" />
<glyph unicode="2" horiz-adv-x="731" d="M55 0v219l39 62q25 39 88.5 152.5t112.5 220t91 241.5t44 238q0 184 -73.5 184t-73.5 -184v-105h-222v105q0 389 295 389t295 -375q0 -336 -346 -928h350v-219h-600z" />
<glyph unicode="3" horiz-adv-x="686" d="M45 1071q0 249 63 343q29 42 84.5 75t134.5 33t136 -31t84.5 -71t44.5 -92q22 -71 22 -130q0 -291 -108 -399q127 -100 127 -414q0 -68 -19.5 -145.5t-47 -128t-85 -89t-136.5 -38.5t-135 31.5t-86 75.5t-48 113q-23 91 -23 230h217q2 -150 17.5 -203t59.5 -53t56.5 50.5 t12.5 104.5t1 102t0 63q-6 82 -14 95l-18 33q-12 22 -29 29q-55 22 -108 25h-19v184q133 7 156 73q12 34 12 91v105q0 146 -29 177q-16 17 -40 17q-41 0 -52.5 -49t-13.5 -207h-217z" />
<glyph unicode="4" horiz-adv-x="684" d="M25 328v194l323 983h221v-983h103v-194h-103v-328h-202v328h-342zM213 522h154v516h-13z" />
<glyph unicode="5" horiz-adv-x="704" d="M74 438h221v-59q0 -115 14.5 -159t52 -44t53 45t15.5 156v336q0 111 -70 110q-33 0 -59.5 -40t-26.5 -70h-186v792h535v-219h-344v-313q74 55 127 51q78 0 133 -40t77 -100q35 -98 35 -171v-336q0 -393 -289 -393q-78 0 -133 29.5t-84.5 71.5t-46.5 109q-24 98 -24 244z " />
<glyph unicode="6" horiz-adv-x="700" d="M66 309v856q0 356 288.5 356.5t288.5 -356.5v-94h-221q0 162 -11.5 210t-53.5 48t-56 -37t-14 -127v-268q59 37 124.5 37t119 -36t75.5 -93q37 -92 37 -189v-307q0 -90 -42 -187q-26 -61 -89 -99.5t-157.5 -38.5t-158 38.5t-88.5 99.5q-42 98 -42 187zM287 244 q0 -20 17.5 -44t49 -24t50 24.5t18.5 43.5v450q0 18 -18.5 43t-49 25t-48 -20.5t-19.5 -41.5v-456z" />
<glyph unicode="7" horiz-adv-x="589" d="M8 1286v219h557v-221l-221 -1284h-229l225 1286h-332z" />
<glyph unicode="8" horiz-adv-x="696" d="M53 322v176q0 188 115 297q-102 102 -102 276v127q0 213 147 293q57 31 135 31t135.5 -31t84 -71t42.5 -93q21 -66 21 -129v-127q0 -174 -103 -276q115 -109 115 -297v-176q0 -222 -153 -306q-60 -32 -142 -32t-141.5 32.5t-88 73.5t-44.5 96q-21 69 -21 136zM269 422 q1 -139 16.5 -187.5t57.5 -48.5t59.5 30t21.5 71t4 158t-13.5 174t-66.5 57t-66.5 -57.5t-12.5 -196.5zM284 1116q-1 -123 11 -173t53 -50t53.5 50t12.5 170t-12.5 167t-51.5 47t-52 -44t-14 -167z" />
<glyph unicode="9" horiz-adv-x="700" d="M57 340v94h222q0 -162 11 -210t53 -48t56.5 37t14.5 127v283q-59 -37 -125 -37t-119 35.5t-76 92.5q-37 96 -37 189v293q0 87 43 188q25 60 88.5 99t157.5 39t157.5 -39t88.5 -99q43 -101 43 -188v-856q0 -356 -289 -356t-289 356zM279 825q0 -18 18 -42.5t49 -24.5 t48.5 20.5t19.5 40.5v443q0 20 -17.5 43.5t-49.5 23.5t-50 -24.5t-18 -42.5v-437z" />
<glyph unicode=":" horiz-adv-x="362" d="M74 0v227h215v-227h-215zM74 893v227h215v-227h-215z" />
<glyph unicode=";" horiz-adv-x="362" d="M74 0v227h215v-227l-113 -266h-102l71 266h-71zM74 893v227h215v-227h-215z" />
<glyph unicode="&#x3c;" horiz-adv-x="1058" d="M74 649v160l911 475v-199l-698 -356l698 -356v-199z" />
<glyph unicode="=" horiz-adv-x="1058" d="M74 477v172h911v-172h-911zM74 864v172h911v-172h-911z" />
<glyph unicode="&#x3e;" horiz-adv-x="1058" d="M74 174v199l698 356l-698 356v199l911 -475v-160z" />
<glyph unicode="?" horiz-adv-x="645" d="M25 1260q24 67 78 131q105 128 235 122q82 -2 138 -33.5t82 -81.5q46 -88 46 -170.5t-80 -219.5l-57 -96q-18 -32 -42 -106.5t-24 -143.5v-256h-190v256q0 102 24.5 195t48 140t65.5 118t50 105t-9 67.5t-60 34.5t-78 -48t-49 -98zM199 0h215v227h-215v-227z" />
<glyph unicode="@" horiz-adv-x="872" d="M66 303v889q0 97 73 200q39 56 117 93t184.5 37t184 -37t116.5 -93q74 -105 74 -200v-793h-164l-20 56q-14 -28 -46 -48t-67 -20q-145 0 -145 172v485q0 170 145 170q71 0 113 -67v45q0 51 -45 104.5t-145.5 53.5t-145.5 -53.5t-45 -104.5v-889q0 -53 44 -103t153.5 -50 t160.5 63l152 -86q-109 -143 -320 -143q-106 0 -184 35.5t-117 90.5q-73 102 -73 193zM535 573q0 -53 48 -53t48 53v455q0 53 -48 53t-48 -53v-455z" />
<glyph unicode="A" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM307 541h152l-64 475l-6 39h-12z" />
<glyph unicode="B" horiz-adv-x="745" d="M82 0v1505h194q205 0 304.5 -91t99.5 -308q0 -106 -29.5 -175t-107.5 -136q14 -5 47 -38.5t54 -71.5q52 -97 52 -259q0 -414 -342 -426h-272zM303 219q74 0 109 31q55 56 55 211t-63 195q-42 26 -93 26h-8v-463zM303 885q87 0 119 39q45 55 45 138t-14.5 124t-30.5 60.5 t-45 28.5q-35 11 -74 11v-401z" />
<glyph unicode="C" horiz-adv-x="708" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-207h-206v207q-2 0 0 11.5t-3.5 27.5t-12.5 33q-17 39 -68 39q-70 -10 -78 -111v-887q0 -43 21.5 -76.5t59.5 -33.5t59.5 27.5t21.5 56.5v233h206v-207q0 -42 -17 -106t-45 -107 t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175z" />
<glyph unicode="D" horiz-adv-x="761" d="M82 0v1505h174q270 0 346 -113q31 -46 50.5 -95.5t28.5 -139.5t12 -177t3 -228.5t-3 -228.5t-12 -176t-28.5 -138t-50.5 -95t-80 -68q-106 -46 -266 -46h-174zM303 221q117 0 140.5 78t23.5 399v111q0 322 -23.5 398.5t-140.5 76.5v-1063z" />
<glyph unicode="E" horiz-adv-x="628" d="M82 0v1505h506v-227h-285v-395h205v-242h-205v-414h285v-227h-506z" />
<glyph unicode="F" horiz-adv-x="616" d="M82 0v1505h526v-227h-305v-395h205v-228h-205v-655h-221z" />
<glyph unicode="G" horiz-adv-x="737" d="M67 271.5q0 26.5 1 37.5v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-231h-221v231q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-905q0 -46 19.5 -78.5t54 -32.5t53 28t18.5 54l2 29v272h-88v187h309v-750h-131l-26 72 q-70 -88 -172 -88q-203 0 -250 213q-11 48 -11 74.5z" />
<glyph unicode="H" horiz-adv-x="778" d="M82 0v1505h221v-622h172v622h221v-1505h-221v655h-172v-655h-221z" />
<glyph unicode="I" horiz-adv-x="385" d="M82 0v1505h221v-1505h-221z" />
<glyph unicode="J" horiz-adv-x="423" d="M12 -14v217q4 0 12.5 -1t29 2t35.5 12t28.5 34.5t13.5 62.5v1192h221v-1226q0 -137 -74 -216q-74 -78 -223 -78h-4q-19 0 -39 1z" />
<glyph unicode="K" horiz-adv-x="768" d="M82 0v1505h221v-526h8l195 526h215l-203 -495l230 -1010h-216l-153 655l-6 31h-6l-64 -154v-532h-221z" />
<glyph unicode="L" horiz-adv-x="604" d="M82 0v1505h221v-1300h293v-205h-514z" />
<glyph unicode="M" horiz-adv-x="991" d="M82 0v1505h270l131 -688l11 -80h4l10 80l131 688h270v-1505h-204v1010h-13l-149 -1010h-94l-142 946l-8 64h-12v-1010h-205z" />
<glyph unicode="N" horiz-adv-x="808" d="M82 0v1505h197l215 -784l18 -70h12v854h203v-1505h-197l-215 784l-18 70h-12v-854h-203z" />
<glyph unicode="O" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5l2 26v887q0 46 -19.5 78.5 t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="P" horiz-adv-x="720" d="M82 0v1505h221q166 0 277.5 -105.5t111.5 -345t-111.5 -346t-277.5 -106.5v-602h-221zM303 827q102 0 134 45.5t32 175.5t-33 181t-133 51v-453z" />
<glyph unicode="Q" horiz-adv-x="729" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -94 -45 -182q33 -43 88 -53v-189q-160 0 -227 117q-55 -18 -125 -18t-130 33.5t-88 81.5q-55 94 -60 175zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5l2 26v887 q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="R" horiz-adv-x="739" d="M82 0v1505h221q377 0 377 -434q0 -258 -123 -342l141 -729h-221l-115 635h-59v-635h-221zM303 840q117 0 149 98q15 49 15 125t-15.5 125t-45.5 68q-44 30 -103 30v-446z" />
<glyph unicode="S" horiz-adv-x="702" d="M37 422l217 20q0 -256 104 -256q90 0 91 166q0 59 -32 117.5t-45 79.5l-54 79q-40 58 -77 113t-73.5 117t-68 148.5t-31.5 162.5q0 139 71.5 245t216.5 108h10q88 0 152 -36t94 -100q54 -120 54 -264l-217 -20q0 217 -89 217q-75 -2 -75 -146q0 -59 23 -105 q32 -66 58 -104l197 -296q31 -49 67 -139.5t36 -166.5q0 -378 -306 -378h-2q-229 0 -290 188q-31 99 -31 250z" />
<glyph unicode="T" horiz-adv-x="647" d="M4 1278v227h639v-227h-209v-1278h-221v1278h-209z" />
<glyph unicode="U" horiz-adv-x="749" d="M80 309v1196h221v-1196q0 -46 19.5 -78t54.5 -32t53 27.5t18 56.5l3 26v1196h221v-1196q0 -42 -17.5 -106t-45 -107t-88 -77.5t-144.5 -34.5t-144.5 33.5t-88.5 81.5q-55 97 -60 175z" />
<glyph unicode="V" horiz-adv-x="716" d="M18 1505h215l111 -827l8 -64h13l118 891h215l-229 -1505h-221z" />
<glyph unicode="W" horiz-adv-x="1036" d="M25 1505h204l88 -782l5 -49h16l100 831h160l100 -831h17l92 831h205l-203 -1505h-172l-115 801h-8l-115 -801h-172z" />
<glyph unicode="X" horiz-adv-x="737" d="M16 0l244 791l-240 714h218l120 -381l7 -18h8l127 399h217l-240 -714l244 -791h-217l-127 449l-4 18h-8l-132 -467h-217z" />
<glyph unicode="Y" horiz-adv-x="700" d="M14 1505h217l111 -481l6 -14h4l6 14l111 481h217l-225 -864v-641h-221v641z" />
<glyph unicode="Z" horiz-adv-x="626" d="M20 0v238l347 1048h-297v219h536v-219l-352 -1067h352v-219h-586z" />
<glyph unicode="[" horiz-adv-x="538" d="M82 -213v1718h399v-196h-202v-1325h202v-197h-399z" />
<glyph unicode="\" horiz-adv-x="792" d="M8 1692h162l614 -1872h-168z" />
<glyph unicode="]" horiz-adv-x="538" d="M57 -16h203v1325h-203v196h400v-1718h-400v197z" />
<glyph unicode="^" horiz-adv-x="1101" d="M53 809l381 696h234l381 -696h-199l-299 543l-299 -543h-199z" />
<glyph unicode="_" horiz-adv-x="1210" d="M74 -154h1063v-172h-1063v172z" />
<glyph unicode="`" horiz-adv-x="1024" d="M293 1489h215l106 -184h-159z" />
<glyph unicode="a" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM252 291 q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250z" />
<glyph unicode="b" horiz-adv-x="686" d="M82 0v1505h207v-458q88 90 165 90t117.5 -69t40.5 -150v-715q0 -82 -41 -150.5t-118 -68.5q-33 0 -74 22.5t-66 44.5l-24 23v-74h-207zM289 246q0 -29 19.5 -48.5t42 -19.5t39 19.5t16.5 48.5v628q0 29 -16.5 48.5t-39 19.5t-42 -21.5t-19.5 -46.5v-628z" />
<glyph unicode="c" horiz-adv-x="645" d="M66 315v490q0 332 264 332q137 0 201.5 -71t64.5 -251v-88h-207v135q0 51 -12 70.5t-47 19.5q-58 0 -58 -90v-604q0 -90 58 -90q35 0 47 19.5t12 70.5v156h207v-109q0 -180 -64.5 -250.5t-201.5 -70.5q-264 0 -264 331z" />
<glyph unicode="d" horiz-adv-x="686" d="M74 203v715q0 82 41 150.5t118 68.5q33 0 74 -22.5t66 -45.5l24 -22v458h207v-1505h-207v74q-88 -90 -165 -90t-117.5 68.5t-40.5 150.5zM281 246q0 -29 16 -48.5t38.5 -19.5t42 19.5t19.5 48.5v628q0 25 -19.5 46.5t-42 21.5t-38.5 -19.5t-16 -48.5v-628z" />
<glyph unicode="e" horiz-adv-x="659" d="M66 279v563q0 36 16 94.5t42 97.5t81 71t129 32q199 0 252 -197q14 -51 14 -92v-326h-342v-256q0 -59 39 -88q16 -12 37 -12q70 10 74 113v122h192v-129q0 -37 -16.5 -93t-41 -95t-79.5 -69.5t-130 -30.5t-130.5 30.5t-80.5 73.5q-49 87 -54 160zM258 684h150v158 q0 48 -19.5 81t-53.5 33t-53.5 -28.5t-21.5 -57.5l-2 -28v-158z" />
<glyph unicode="f" horiz-adv-x="475" d="M20 934v186h105v31q0 190 51 270q23 35 71 63.5t115 28.5l97 -14v-178q-27 8 -62 8q-65 0 -65 -175v-5v-29h104v-186h-104v-934h-207v934h-105z" />
<glyph unicode="g" horiz-adv-x="700" d="M12 -184q0 94 162 170q-125 35 -125 149q0 45 40 93t89 75q-51 35 -80.5 95.5t-34.5 105.5l-4 43v305q0 35 16.5 91t41 94t79 69t126.5 31q135 0 206 -103q102 102 170 103v-185q-72 0 -120 -24l10 -70v-317q0 -37 -17.5 -90.5t-42 -90t-79 -66.5t-104.5 -30t-62 2 q-29 -25 -29 -46t11 -33.5t42 -20.5t45.5 -10t65.5 -10.5t95 -21.5t89 -41q96 -60 96 -205t-103 -212q-100 -65 -250 -65h-9q-156 2 -240 50t-84 165zM213 -150q0 -77 132 -77h3q59 0 108.5 19t49.5 54t-20.5 52.5t-90.5 29.5l-106 21q-76 -43 -76 -99zM262 509 q0 -17 15.5 -45t44.5 -28q63 6 63 101v307q-2 0 0 10q1 3 1 7q0 8 -3 19q-4 15 -9 30q-11 36 -46 36t-50.5 -25.5t-15.5 -52.5v-359z" />
<glyph unicode="h" horiz-adv-x="690" d="M82 0v1505h207v-479l32 32q79 79 145.5 79t106 -69t39.5 -150v-918h-206v887q-1 49 -50 49q-41 0 -67 -53v-883h-207z" />
<glyph unicode="i" horiz-adv-x="370" d="M82 0v1120h207v-1120h-207zM82 1298v207h207v-207h-207z" />
<glyph unicode="j" horiz-adv-x="364" d="M-45 -182q29 -8 57 -8q64 0 64 142v1168h207v-1149q0 -186 -51 -266q-23 -35 -71 -62.5t-115 -27.5t-91 12v191zM76 1298v207h207v-207h-207z" />
<glyph unicode="k" horiz-adv-x="641" d="M82 0v1505h207v-714h10l113 329h186l-149 -364l188 -756h-199l-102 453l-4 16h-10l-33 -82v-387h-207z" />
<glyph unicode="l" horiz-adv-x="370" d="M82 0v1505h207v-1505h-207z" />
<glyph unicode="m" horiz-adv-x="1021" d="M82 0v1120h207v-94q2 0 33 30q80 81 139 81q100 0 139 -125q125 125 194.5 125t109.5 -69t40 -150v-918h-194v887q-1 49 -56 49q-41 0 -78 -53v-883h-194v887q0 49 -55 49q-41 0 -78 -53v-883h-207z" />
<glyph unicode="n" horiz-adv-x="690" d="M82 0v1120h207v-94l32 32q79 79 145.5 79t106 -69t39.5 -150v-918h-206v887q-1 49 -50 49q-41 0 -67 -53v-883h-207z" />
<glyph unicode="o" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM257 259q0 -17 9 -44q18 -49 62 -49q70 10 71 113v563l1 19q0 19 -10 45q-18 50 -62 50 q-68 -10 -70 -114v-563q1 -1 1 -4z" />
<glyph unicode="p" horiz-adv-x="686" d="M82 -385v1505h207v-73q88 90 165 90t117.5 -69t40.5 -150v-715q0 -82 -41 -150.5t-118 -68.5q-33 0 -74 22.5t-66 44.5l-24 23v-459h-207zM289 246q0 -25 19.5 -46.5t42 -21.5t39 19.5t16.5 48.5v628q0 29 -16.5 48.5t-39 19.5t-42 -19.5t-19.5 -48.5v-628z" />
<glyph unicode="q" horiz-adv-x="686" d="M74 203v715q0 82 41 150.5t118 68.5q33 0 74 -22.5t66 -45.5l24 -22v73h207v-1505h-207v459q-88 -90 -165 -90t-117.5 68.5t-40.5 150.5zM281 246q0 -29 16 -48.5t38.5 -19.5t42 21.5t19.5 46.5v628q0 29 -19.5 48.5t-42 19.5t-38.5 -19.5t-16 -48.5v-628z" />
<glyph unicode="r" horiz-adv-x="503" d="M82 0v1120h207v-125q8 41 58.5 91.5t148.5 50.5v-230q-34 11 -77 11t-86.5 -39t-43.5 -101v-778h-207z" />
<glyph unicode="s" horiz-adv-x="630" d="M37 326h192q0 -170 97 -170q71 0 71 131q0 78 -129 202q-68 66 -98.5 99t-64 101.5t-33.5 134t12 114.5t39 95q59 100 201 104h11q161 0 211 -105q42 -86 42 -198h-193q0 131 -67 131q-63 -2 -64 -131q0 -33 23.5 -73t45 -62.5t66.5 -65.5q190 -182 191 -342 q0 -123 -64.5 -215t-199.5 -92q-197 0 -260 170q-29 76 -29 172z" />
<glyph unicode="t" horiz-adv-x="501" d="M20 934v186h105v277h207v-277h141v-186h-141v-557q0 -184 65 -184l76 8v-203q-45 -14 -112 -14t-114.5 28.5t-70 64.5t-34.5 96q-17 79 -17 187v574h-105z" />
<glyph unicode="u" horiz-adv-x="690" d="M78 203v917h207v-887q0 -49 49 -49q41 0 67 54v882h207v-1120h-207v94l-31 -32q-78 -78 -145.5 -78t-107 68.5t-39.5 150.5z" />
<glyph unicode="v" horiz-adv-x="602" d="M16 1120h201l68 -649l8 -72h16l76 721h201l-183 -1120h-204z" />
<glyph unicode="w" horiz-adv-x="905" d="M20 1120h189l65 -585l9 -64h12l96 649h123l86 -585l10 -64h13l73 649h189l-166 -1120h-172l-80 535l-10 63h-8l-91 -598h-172z" />
<glyph unicode="x" horiz-adv-x="618" d="M16 0l193 578l-176 542h194l74 -262l6 -31h4l6 31l74 262h195l-176 -542l192 -578h-201l-84 283l-6 30h-4l-6 -30l-84 -283h-201z" />
<glyph unicode="y" horiz-adv-x="634" d="M25 1120h202l82 -688l4 -57h9l4 57l82 688h202l-198 -1204q-16 -127 -94 -222t-193 -95l-92 4v184q16 -4 49 -4q61 6 97 61.5t36 122.5z" />
<glyph unicode="z" horiz-adv-x="532" d="M12 0v168l285 764h-240v188h459v-168l-285 -764h285v-188h-504z" />
<glyph unicode="{" horiz-adv-x="688" d="M61 453v163q72 0 102 49.5t30 90.5v397q0 223 96 298t342 71v-172q-135 2 -188.5 -38t-53.5 -159v-397q0 -143 -127 -221q127 -82 127 -222v-397q0 -119 53.5 -159t188.5 -38v-172q-246 -4 -342 71t-96 298v397q0 57 -41 97.5t-91 42.5z" />
<glyph unicode="|" horiz-adv-x="356" d="M82 -512v2204h192v-2204h-192z" />
<glyph unicode="}" horiz-adv-x="688" d="M57 -281q135 -2 188.5 38t53.5 159v397q0 139 127 222q-127 78 -127 221v397q0 119 -53 159t-189 38v172q246 4 342.5 -71t96.5 -298v-397q0 -63 41 -101.5t90 -38.5v-163q-72 -4 -101.5 -52.5t-29.5 -87.5v-397q0 -223 -96.5 -298t-342.5 -71v172z" />
<glyph unicode="~" horiz-adv-x="1280" d="M113 1352q35 106 115 200q34 41 94.5 74t121 33t116.5 -18.5t82 -33t83 -51.5q106 -72 174 -71q109 0 178 153l13 29l135 -57q-63 -189 -206 -276q-56 -34 -120 -34q-121 0 -272 101q-115 74 -178.5 74t-113.5 -45.5t-69 -90.5l-18 -45z" />
<glyph unicode="&#xa1;" horiz-adv-x="387" d="M74 -385l55 1100h129l55 -1100h-239zM86 893v227h215v-227h-215z" />
<glyph unicode="&#xa2;" horiz-adv-x="636" d="M66 508v489q0 297 208 328v242h123v-244q98 -16 144.5 -88t46.5 -227v-88h-189v135q0 90 -72.5 90t-72.5 -90v-604q0 -90 72 -91q74 0 73 91v155h189v-108q0 -156 -46 -228.5t-145 -89.5v-303h-123v301q-209 31 -208 330z" />
<glyph unicode="&#xa3;" horiz-adv-x="817" d="M4 63q8 20 23.5 53.5t70 91.5t117.5 68q37 111 37 189t-31 184h-188v137h147l-6 21q-78 254 -78 333t15.5 140t48.5 116q72 122 231 126q190 4 267 -126q65 -108 65 -276h-213q0 201 -115 197q-47 -2 -68.5 -51t-21.5 -139.5t70 -315.5l6 -25h211v-137h-174 q25 -100 24.5 -189t-57.5 -204q16 -8 44 -24q59 -35 89 -35q74 4 82 190l188 -22q-12 -182 -81.5 -281.5t-169.5 -99.5q-51 0 -143.5 51t-127.5 51t-63.5 -25.5t-40.5 -52.5l-12 -24z" />
<glyph unicode="&#xa5;" horiz-adv-x="720" d="M25 1505h217l110 -481l6 -14h4l7 14l110 481h217l-196 -753h147v-138h-176v-137h176v-137h-176v-340h-221v340h-176v137h176v137h-176v138h147z" />
<glyph unicode="&#xa8;" horiz-adv-x="1024" d="M272 1305v200h191v-200h-191zM561 1305v200h191v-200h-191z" />
<glyph unicode="&#xa9;" horiz-adv-x="1644" d="M53 751.5q0 317.5 225.5 544t543 226.5t543.5 -226.5t226 -544t-226 -542.5t-543.5 -225t-543 225t-225.5 542.5zM172 751.5q0 -266.5 191.5 -458t457.5 -191.5t459 191.5t193 459t-191.5 459t-459 191.5t-459 -192.5t-191.5 -459zM627 487v531q0 122 97 174q40 22 95 22 q147 0 182 -147l7 -49v-125h-138v142q0 11 -12 28.5t-37 17.5q-47 -2 -49 -63v-531q0 -63 49 -63q53 2 49 63v125h138v-125q0 -68 -40 -127q-18 -26 -57 -47.5t-108.5 -21.5t-117.5 49t-54 98z" />
<glyph unicode="&#xaa;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM252 291 q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250z" />
<glyph unicode="&#xad;" horiz-adv-x="444" d="M74 455v194h297v-194h-297z" />
<glyph unicode="&#xae;" horiz-adv-x="1644" d="M53 751.5q0 317.5 225.5 544t543 226.5t543.5 -226.5t226 -544t-226 -542.5t-543.5 -225t-543 225t-225.5 542.5zM172 751.5q0 -266.5 191.5 -458t457.5 -191.5t459 191.5t193 459t-191.5 459t-459 191.5t-459 -192.5t-191.5 -459zM625 313v879h196q231 0 232 -258 q0 -76 -16.5 -125t-71.5 -96l106 -400h-151l-95 365h-55v-365h-145zM770 805h45q43 0 65.5 21.5t27.5 45t5 61.5t-5 62.5t-27.5 46t-65.5 21.5h-45v-258z" />
<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M313 1315v162h398v-162h-398z" />
<glyph unicode="&#xb2;" horiz-adv-x="731" d="M55 0v219l39 62q25 39 88.5 152.5t112.5 220t91 241.5t44 238q0 184 -73.5 184t-73.5 -184v-105h-222v105q0 389 295 389t295 -375q0 -336 -346 -928h350v-219h-600z" />
<glyph unicode="&#xb3;" horiz-adv-x="686" d="M45 1071q0 249 63 343q29 42 84.5 75t134.5 33t136 -31t84.5 -71t44.5 -92q22 -71 22 -130q0 -291 -108 -399q127 -100 127 -414q0 -68 -19.5 -145.5t-47 -128t-85 -89t-136.5 -38.5t-135 31.5t-86 75.5t-48 113q-23 91 -23 230h217q2 -150 17.5 -203t59.5 -53t56.5 50.5 t12.5 104.5t1 102t0 63q-6 82 -14 95l-18 33q-12 22 -29 29q-55 22 -108 25h-19v184q133 7 156 73q12 34 12 91v105q0 146 -29 177q-16 17 -40 17q-41 0 -52.5 -49t-13.5 -207h-217z" />
<glyph unicode="&#xb4;" horiz-adv-x="1024" d="M410 1305l106 184h215l-162 -184h-159z" />
<glyph unicode="&#xb7;" horiz-adv-x="215" d="M0 649v228h215v-228h-215z" />
<glyph unicode="&#xb8;" horiz-adv-x="1024" d="M426 -111h172v-141l-45 -133h-104l40 133h-63v141z" />
<glyph unicode="&#xb9;" horiz-adv-x="475" d="M25 1180v141q129 25 205 130q16 21 30 54h133v-1505h-221v1180h-147z" />
<glyph unicode="&#xba;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM257 259q0 -17 9 -44q18 -49 62 -49q70 10 71 113v563l1 19q0 19 -10 45q-18 50 -62 50 q-68 -10 -70 -114v-563q1 -1 1 -4z" />
<glyph unicode="&#xbf;" horiz-adv-x="645" d="M41 -106q0 82 80 219l57 95q18 32 42 106.5t24 144.5v256h190v-256q0 -102 -24.5 -195.5t-48 -140.5t-65.5 -118t-50 -104.5t9 -67.5t60 -35t78 48.5t49 98.5l179 -84q-24 -66 -78 -132q-104 -126 -236 -122q-163 4 -220 115q-46 90 -46 172zM231 893v227h215v-227h-215z " />
<glyph unicode="&#xc0;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM141 1823h215l107 -185h-160zM307 541h152l-64 475l-6 39h-12z" />
<glyph unicode="&#xc1;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM293 1638l106 185h215l-161 -185h-160zM307 541h152l-64 475l-6 39h-12z" />
<glyph unicode="&#xc2;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM133 1638l141 185h220l141 -185h-189l-63 72l-61 -72h-189zM307 541h152l-64 475l-6 39h-12z" />
<glyph unicode="&#xc3;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM184 1632v152q49 39 95.5 39t104.5 -18.5t100.5 -19.5t97.5 32v-152q-51 -39 -95.5 -39t-102.5 19.5t-98 19.5t-102 -33zM307 541h152l-64 475l-6 39h-12z" />
<glyph unicode="&#xc4;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM143 1638v201h191v-201h-191zM307 541h152l-64 475l-6 39h-12zM432 1638v201h191v-201h-191z" />
<glyph unicode="&#xc5;" horiz-adv-x="765" d="M20 0l228 1505h270l227 -1505h-215l-41 307h-213l-40 -307h-216zM231 1761.5q0 61.5 45.5 102.5t109 41t107.5 -41t44 -102.5t-44 -102.5t-107.5 -41t-109 41t-45.5 102.5zM307 541h152l-64 475l-6 39h-12zM309 1761.5q0 -28.5 23.5 -50t52.5 -21.5t52.5 21.5t23.5 50 t-23.5 50t-52.5 21.5t-52.5 -21.5t-23.5 -50z" />
<glyph unicode="&#xc6;" horiz-adv-x="1099" d="M16 0l420 1505h623v-227h-285v-395h205v-242h-205v-414h285v-227h-506v307h-227l-90 -307h-220zM393 541h160v514h-10z" />
<glyph unicode="&#xc7;" horiz-adv-x="708" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-207h-206v207q-2 0 0 11.5t-3.5 27.5t-12.5 33q-17 39 -68 39q-70 -10 -78 -111v-887q0 -43 21.5 -76.5t59.5 -33.5t59.5 27.5t21.5 56.5v233h206v-207q0 -42 -17 -106t-45 -107 t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM268 -111v-141h64l-41 -133h104l45 133v141h-172z" />
<glyph unicode="&#xc8;" horiz-adv-x="628" d="M82 0v1505h506v-227h-285v-395h205v-242h-205v-414h285v-227h-506zM111 1823h215l106 -185h-160z" />
<glyph unicode="&#xc9;" horiz-adv-x="628" d="M82 0v1505h506v-227h-285v-395h205v-242h-205v-414h285v-227h-506zM236 1638l106 185h215l-162 -185h-159z" />
<glyph unicode="&#xca;" horiz-adv-x="628" d="M82 0v1505h506v-227h-285v-395h205v-242h-205v-414h285v-227h-506zM84 1638l141 185h219l142 -185h-189l-63 72l-62 -72h-188z" />
<glyph unicode="&#xcb;" horiz-adv-x="628" d="M82 0v1505h506v-227h-285v-395h205v-242h-205v-414h285v-227h-506zM94 1638v201h191v-201h-191zM383 1638v201h190v-201h-190z" />
<glyph unicode="&#xcc;" horiz-adv-x="401" d="M-6 1823h215l106 -185h-159zM98 0v1505h221v-1505h-221z" />
<glyph unicode="&#xcd;" horiz-adv-x="401" d="M82 0v1505h221v-1505h-221zM86 1638l107 185h215l-162 -185h-160z" />
<glyph unicode="&#xce;" horiz-adv-x="370" d="M-66 1638l142 185h219l141 -185h-188l-64 72l-61 -72h-189zM74 0v1505h221v-1505h-221z" />
<glyph unicode="&#xcf;" horiz-adv-x="372" d="M-53 1638v201h190v-201h-190zM76 0v1505h221v-1505h-221zM236 1638v201h190v-201h-190z" />
<glyph unicode="&#xd0;" horiz-adv-x="761" d="M20 655v228h62v622h174q270 0 346 -113q31 -46 50.5 -95.5t28.5 -139.5t12 -177t3 -228.5t-3 -228.5t-12 -176t-28.5 -138t-50.5 -95t-80 -68q-106 -46 -266 -46h-174v655h-62zM303 221q117 0 141.5 81t22.5 452q2 371 -22.5 450.5t-141.5 79.5v-401h84v-228h-84v-434z " />
<glyph unicode="&#xd1;" horiz-adv-x="808" d="M82 0v1505h197l215 -784l18 -70h12v854h203v-1505h-197l-215 784l-18 70h-12v-854h-203zM207 1632v152q49 39 95 39t104.5 -18.5t102.5 -19.5t95 32v-152q-51 -39 -95 -39t-102.5 19.5t-100 19.5t-99.5 -33z" />
<glyph unicode="&#xd2;" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM121 1823h215l106 -185h-159zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5 l2 26v887q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="&#xd3;" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM285 1638l106 185h215l-162 -185h-159zM289 309q0 -46 19.5 -78t54 -32t53 27.5 t18.5 56.5l2 26v887q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="&#xd4;" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM113 1638l141 185h219l141 -185h-188l-64 72l-61 -72h-188zM289 309q0 -46 19.5 -78 t54 -32t53 27.5t18.5 56.5l2 26v887q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="&#xd5;" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM164 1632v152q49 39 95 39t104.5 -18.5t102.5 -19.5t95 32v-152q-51 -39 -95 -39 t-102.5 19.5t-100 19.5t-99.5 -33zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5l2 26v887q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887z" />
<glyph unicode="&#xd6;" d="M68 309v887q0 42 17 106t45 107t88.5 78t144 35t144 -34t88.5 -81q55 -93 60 -178l2 -33v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-144 -34.5t-144 33.5t-88.5 81.5q-55 94 -60 175zM123 1638v201h190v-201h-190zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5 l2 26v887q0 46 -19.5 78.5t-54 32.5t-53 -28t-18.5 -54l-2 -29v-887zM412 1638v201h190v-201h-190z" />
<glyph unicode="&#xd8;" d="M59 -20l47 157q-36 74 -36 148l-2 24v887q0 42 17 106t45 107t88.5 78t148 35t153.5 -43l15 47h122l-45 -150q43 -84 43 -155l2 -25v-887q0 -42 -17 -106t-45 -107t-88.5 -77.5t-150.5 -34.5t-153 43l-15 -47h-129zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5 l2 26v488zM289 727l147 479q-8 100 -74 101q-35 0 -53 -28t-18 -54l-2 -29v-469z" />
<glyph unicode="&#xd9;" horiz-adv-x="749" d="M80 309q0 -42 17.5 -106t45 -107t88 -77.5t144.5 -34.5t144.5 33.5t88.5 81.5q55 97 60 175l2 35v1196h-221v-1196q0 -44 -19.5 -77t-54.5 -33t-53.5 27.5t-18.5 56.5l-2 26v1196h-221v-1196zM145 1823h215l107 -185h-160z" />
<glyph unicode="&#xda;" horiz-adv-x="749" d="M80 309q0 -42 17.5 -106t45 -107t88 -77.5t144.5 -34.5t144.5 33.5t88.5 81.5q55 97 60 175l2 35v1196h-221v-1196q0 -44 -19.5 -77t-54.5 -33t-53.5 27.5t-18.5 56.5l-2 26v1196h-221v-1196zM307 1638l107 185h215l-162 -185h-160z" />
<glyph unicode="&#xdb;" horiz-adv-x="749" d="M80 309q0 -42 17.5 -106t45 -107t88 -77.5t144.5 -34.5t144.5 33.5t88.5 81.5q55 97 60 175l2 35v1196h-221v-1196q0 -44 -19.5 -77t-54.5 -33t-53.5 27.5t-18.5 56.5l-2 26v1196h-221v-1196zM125 1638l141 185h219l142 -185h-189l-63 72l-62 -72h-188z" />
<glyph unicode="&#xdc;" horiz-adv-x="749" d="M80 309v1196h221v-1196q0 -46 19.5 -78t54.5 -32t53 27.5t18 56.5l3 26v1196h221v-1196q0 -42 -17.5 -106t-45 -107t-88 -77.5t-144.5 -34.5t-144.5 33.5t-88.5 81.5q-55 97 -60 175zM135 1638v201h191v-201h-191zM424 1638v201h190v-201h-190z" />
<glyph unicode="&#xdd;" horiz-adv-x="704" d="M16 1505l226 -864v-641h221v641l225 864h-217l-111 -481l-6 -14h-4l-6 14l-111 481h-217zM254 1638l106 185h215l-161 -185h-160z" />
<glyph unicode="&#xde;" d="M82 0v1505h219v-241h2q166 0 277.5 -105.5t111.5 -345.5t-111.5 -346.5t-277.5 -106.5v-360h-221zM303 586q102 0 134 45t32 175t-33 181t-133 51v-452z" />
<glyph unicode="&#xdf;" horiz-adv-x="733" d="M66 0v1235q0 123 70.5 205t206.5 82t204.5 -81t68.5 -197t-88 -181q152 -88 152 -488q0 -362 -87 -475q-46 -59 -102.5 -79.5t-144.5 -20.5v193q45 0 70 25q57 57 57 357q0 316 -57 377q-25 27 -70 27v141q35 0 60.5 33t25.5 84q0 100 -86 100q-74 0 -74 -102v-1235h-206 z" />
<glyph unicode="&#xe0;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM102 1489h215 l107 -184h-160zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250z" />
<glyph unicode="&#xe1;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM252 291 q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250zM264 1305l107 184h215l-162 -184h-160z" />
<glyph unicode="&#xe2;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM90 1305 l141 184h220l141 -184h-189l-63 71l-61 -71h-189zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250z" />
<glyph unicode="&#xe3;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM143 1305v151 q49 39 95.5 39t104.5 -18.5t97 -19.5t101 32v-152q-51 -39 -95.5 -39t-102.5 19.5t-99 19.5t-101 -32zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250z" />
<glyph unicode="&#xe4;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM102 1305v200 h191v-200h-191zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250zM391 1305v200h191v-200h-191z" />
<glyph unicode="&#xe5;" horiz-adv-x="681" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t190 88t184.5 -74t75 -180v-688q0 -109 14 -195h-202q-18 20 -19 90h-14q-20 -37 -65.5 -71.5t-102.5 -34.5t-110.5 60t-53.5 191zM188 1421.5 q0 61.5 45.5 102.5t109 41t107.5 -41t44 -102.5t-44 -102.5t-107.5 -41t-109 41t-45.5 102.5zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250zM266 1421.5q0 -28.5 23.5 -50t52.5 -21.5t52.5 21.5t23.5 50t-23.5 50t-52.5 21.5t-52.5 -21.5 t-23.5 -50z" />
<glyph unicode="&#xe6;" horiz-adv-x="989" d="M49 235q0 131 34 212t83 124t98 73t88 50.5t43 36.5v123q0 102 -57 102q-41 0 -50 -42t-9 -84v-39h-207v47q0 123 80.5 211t197.5 88q84 0 152 -52q66 51 162 52q199 0 251 -197q14 -51 15 -92v-326h-342v-256q0 -60 38 -88q17 -12 38 -12q70 10 73 113v122h193v-129 q0 -37 -16.5 -93t-41 -95t-80 -69.5t-130.5 -30.5q-158 0 -226 131q-102 -131 -221 -131q-59 0 -112.5 60t-53.5 191zM252 291q0 -104 57 -105q35 0 60.5 19.5t25.5 48.5v287q-143 -62 -143 -250zM588 684h149v158q0 48 -19.5 81t-53 33t-53 -28.5t-21.5 -57.5l-2 -28v-158z " />
<glyph unicode="&#xe7;" horiz-adv-x="645" d="M66 315v490q0 332 264 332q137 0 201.5 -71t64.5 -251v-88h-207v135q0 51 -12 70.5t-47 19.5q-58 0 -58 -90v-604q0 -90 58 -90q35 0 47 19.5t12 70.5v156h207v-109q0 -180 -64.5 -250.5t-201.5 -70.5q-264 0 -264 331zM238 -111v-141h63l-41 -133h105l45 133v141h-172z " />
<glyph unicode="&#xe8;" horiz-adv-x="659" d="M66 279v563q0 36 16 94.5t42 97.5t81 71t129 32q199 0 252 -197q14 -51 14 -92v-326h-342v-256q0 -59 39 -88q16 -12 37 -12q70 10 74 113v122h192v-129q0 -37 -16.5 -93t-41 -95t-79.5 -69.5t-130 -30.5t-130.5 30.5t-80.5 73.5q-49 87 -54 160zM102 1489h215l107 -184 h-160zM258 684h150v158q0 48 -19.5 81t-53.5 33t-53.5 -28.5t-21.5 -57.5l-2 -28v-158z" />
<glyph unicode="&#xe9;" horiz-adv-x="659" d="M66 279v563q0 36 16 94.5t42 97.5t81 71t129 32q199 0 252 -197q14 -51 14 -92v-326h-342v-256q0 -59 39 -88q16 -12 37 -12q70 10 74 113v122h192v-129q0 -37 -16.5 -93t-41 -95t-79.5 -69.5t-130 -30.5t-130.5 30.5t-80.5 73.5q-49 87 -54 160zM258 684h150v158 q0 48 -19.5 81t-53.5 33t-53.5 -28.5t-21.5 -57.5l-2 -28v-158zM264 1305l107 184h215l-162 -184h-160z" />
<glyph unicode="&#xea;" horiz-adv-x="659" d="M66 279v563q0 36 16 94.5t42 97.5t81 71t129 32q199 0 252 -197q14 -51 14 -92v-326h-342v-256q0 -59 39 -88q16 -12 37 -12q70 10 74 113v122h192v-129q0 -37 -16.5 -93t-41 -95t-79.5 -69.5t-130 -30.5t-130.5 30.5t-80.5 73.5q-49 87 -54 160zM80 1305l141 184h219 l142 -184h-189l-63 71l-62 -71h-188zM258 684h150v158q0 48 -19.5 81t-53.5 33t-53.5 -28.5t-21.5 -57.5l-2 -28v-158z" />
<glyph unicode="&#xeb;" horiz-adv-x="659" d="M66 279v563q0 36 16 94.5t42 97.5t81 71t129 32q199 0 252 -197q14 -51 14 -92v-326h-342v-256q0 -59 39 -88q16 -12 37 -12q70 10 74 113v122h192v-129q0 -37 -16.5 -93t-41 -95t-79.5 -69.5t-130 -30.5t-130.5 30.5t-80.5 73.5q-49 87 -54 160zM90 1305v200h191v-200 h-191zM258 684h150v158q0 48 -19.5 81t-53.5 33t-53.5 -28.5t-21.5 -57.5l-2 -28v-158zM379 1305v200h190v-200h-190z" />
<glyph unicode="&#xec;" horiz-adv-x="370" d="M-33 1489h215l107 -184h-160zM82 0h207v1120h-207v-1120z" />
<glyph unicode="&#xed;" horiz-adv-x="370" d="M82 0h207v1120h-207v-1120zM82 1305l106 184h215l-161 -184h-160z" />
<glyph unicode="&#xee;" horiz-adv-x="370" d="M-66 1305l142 184h219l141 -184h-188l-64 71l-61 -71h-189zM82 0h207v1120h-207v-1120z" />
<glyph unicode="&#xef;" horiz-adv-x="372" d="M-53 1305v200h190v-200h-190zM82 0v1120h207v-1120h-207zM236 1305v200h190v-200h-190z" />
<glyph unicode="&#xf0;" horiz-adv-x="673" d="M76 279v579q0 279 172 279q63 0 155 -78q-12 109 -51 203l-82 -72l-55 63l100 88l-45 66l109 100q25 -27 53 -61l94 82l56 -66l-101 -88q125 -201 125 -446v-656q0 -102 -56 -188q-26 -39 -80 -69.5t-129 -30.5t-130 30.5t-80 73.5q-53 91 -53 160zM270 267.5 q-2 -11.5 2 -29t10 -34.5q16 -38 58 -38q70 10 72 113v563q-2 0 0 11t-2 28.5t-10 34.5q-16 40 -60 40q-68 -10 -70 -114v-563q2 0 0 -11.5z" />
<glyph unicode="&#xf1;" horiz-adv-x="690" d="M82 0v1120h207v-94l32 32q79 79 145.5 79t106 -69t39.5 -150v-918h-206v887q-1 49 -50 49q-41 0 -67 -53v-883h-207zM147 1305v151q49 39 95.5 39t105 -18.5t97 -19.5t100.5 32v-152q-51 -39 -95.5 -39t-102.5 19.5t-99 19.5t-101 -32z" />
<glyph unicode="&#xf2;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM98 1489h215l107 -184h-160zM258 267.5q-2 -11.5 2 -29t10 -34.5q14 -38 58 -38 q70 10 71 113v563q-2 0 0 11t-2 28.5t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5z" />
<glyph unicode="&#xf3;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM258 267.5q-2 -11.5 2 -29t10 -34.5q14 -38 58 -38q70 10 71 113v563q-2 0 0 11t-2 28.5 t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5zM260 1305l107 184h215l-162 -184h-160z" />
<glyph unicode="&#xf4;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM78 1305l141 184h219l142 -184h-189l-63 71l-62 -71h-188zM258 267.5q-2 -11.5 2 -29 t10 -34.5q14 -38 58 -38q70 10 71 113v563q-2 0 0 11t-2 28.5t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5z" />
<glyph unicode="&#xf5;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM131 1305v151q49 39 95.5 39t104.5 -18.5t98.5 -19.5t98.5 32v-152q-51 -39 -95 -39 t-102 19.5t-101 19.5t-99 -32zM258 267.5q-2 -11.5 2 -29t10 -34.5q14 -38 58 -38q70 10 71 113v563q-2 0 0 11t-2 28.5t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5z" />
<glyph unicode="&#xf6;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t129.5 32q199 0 252 -197q14 -51 14 -92v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-129 -30.5t-130 30.5t-80.5 73.5q-52 92 -52 160zM90 1305v200h191v-200h-191zM258 267.5q-2 -11.5 2 -29t10 -34.5q14 -38 58 -38 q70 10 71 113v563q-2 0 0 11t-2 28.5t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5zM379 1305v200h190v-200h-190z" />
<glyph unicode="&#xf8;" horiz-adv-x="657" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t118 32t117.5 -19l21 80h75l-30 -121q88 -84 94 -229v-576q0 -102 -56 -188q-26 -39 -80.5 -69.5t-120.5 -30.5t-112 16l-20 -78h-80l31 121q-41 39 -64.5 97.5t-25.5 97.5zM258 436l125 486q-18 35 -55 34q-68 -10 -70 -114 v-406zM274 197q17 -31 54 -31q70 10 71 113v403z" />
<glyph unicode="&#xf9;" horiz-adv-x="690" d="M78 203v917h207v-887q0 -49 49 -49q41 0 67 54v882h207v-1120h-207v94l-31 -32q-78 -78 -145.5 -78t-107 68.5t-39.5 150.5zM113 1489h215l106 -184h-160z" />
<glyph unicode="&#xfa;" horiz-adv-x="690" d="M78 203v917h207v-887q0 -49 49 -49q41 0 67 54v882h207v-1120h-207v94l-31 -32q-78 -78 -145.5 -78t-107 68.5t-39.5 150.5zM274 1305l107 184h215l-162 -184h-160z" />
<glyph unicode="&#xfb;" horiz-adv-x="690" d="M78 203v917h207v-887q0 -49 49 -49q41 0 67 54v882h207v-1120h-207v94l-31 -32q-78 -78 -145.5 -78t-107 68.5t-39.5 150.5zM94 1305l142 184h219l141 -184h-188l-64 71l-61 -71h-189z" />
<glyph unicode="&#xfc;" horiz-adv-x="690" d="M78 203v917h207v-887q0 -49 49 -49q41 0 67 54v882h207v-1120h-207v94l-31 -32q-78 -78 -145.5 -78t-107 68.5t-39.5 150.5zM106 1305v200h191v-200h-191zM395 1305v200h191v-200h-191z" />
<glyph unicode="&#xfd;" horiz-adv-x="634" d="M25 1120l190 -1153q0 -68 -36 -123t-97 -61l-49 4v-184q70 -4 92 -4q115 0 192.5 95t94.5 222l198 1204h-202l-82 -688l-4 -57h-9l-4 57l-82 688h-202zM231 1305l107 184h215l-162 -184h-160z" />
<glyph unicode="&#xfe;" horiz-adv-x="686" d="M82 -385v1890h207v-458q88 90 165 90t117.5 -69t40.5 -150v-715q0 -82 -41 -150.5t-118 -68.5q-33 0 -74 22.5t-66 44.5l-24 23v-459h-207zM289 246q0 -25 19.5 -46.5t42 -21.5t39 19.5t16.5 48.5v628q0 29 -16.5 48.5t-39 19.5t-42 -19.5t-19.5 -48.5v-628z" />
<glyph unicode="&#xff;" horiz-adv-x="634" d="M25 1120h202l82 -688l4 -57h9l4 57l82 688h202l-198 -1204q-16 -127 -94 -222t-193 -95l-92 4v184q16 -4 49 -4q61 6 97 61.5t36 122.5zM78 1305v200h190v-200h-190zM367 1305v200h190v-200h-190z" />
<glyph unicode="&#x152;" horiz-adv-x="983" d="M68 309v887q0 41 17 101.5t45 100.5t88.5 73.5t143.5 33.5h580v-227h-285v-395h205v-242h-205v-414h285v-227h-580q-84 0 -144 31.5t-88 78.5q-55 91 -60 169zM289 309q0 -46 19.5 -78t54 -32t53 27.5t18.5 56.5l2 26v901q-6 96 -74 97q-35 0 -53 -28t-18 -54l-2 -29 v-887z" />
<glyph unicode="&#x153;" horiz-adv-x="995" d="M63 279v563q0 40 15.5 96.5t40 95.5t80 71t145.5 32t156 -60q66 59 170 60q199 0 252 -197q14 -51 14 -92v-326h-342v-250q0 -46 22.5 -76t53.5 -30q70 10 73 113v122h193v-129q0 -37 -16.5 -93t-41 -95t-80 -69.5t-146 -30.5t-154.5 57q-68 -57 -156 -57t-143.5 30.5 t-80.5 73.5q-52 92 -52 160zM258 267.5q-2 -11.5 2 -29t10 -34.5q14 -38 58 -38q70 10 71 113v563q-2 0 0 11t-2 28.5t-10 34.5q-15 40 -59 40q-68 -10 -70 -114v-563q2 0 0 -11.5zM594 684h149v158q0 48 -19 81t-58 33t-55.5 -37.5t-16.5 -70.5v-164z" />
<glyph unicode="&#x178;" horiz-adv-x="704" d="M16 1505h217l111 -481l6 -14h4l6 14l111 481h217l-225 -864v-641h-221v641zM113 1638v201h190v-201h-190zM401 1638v201h191v-201h-191z" />
<glyph unicode="&#x2c6;" horiz-adv-x="1021" d="M260 1305l141 184h220l141 -184h-189l-63 71l-61 -71h-189z" />
<glyph unicode="&#x2dc;" horiz-adv-x="1024" d="M313 1305v151q49 39 95.5 39t104.5 -18.5t97 -19.5t101 32v-152q-51 -39 -95.5 -39t-102.5 19.5t-99 19.5t-101 -32z" />
<glyph unicode="&#x2000;" horiz-adv-x="952" />
<glyph unicode="&#x2001;" horiz-adv-x="1905" />
<glyph unicode="&#x2002;" horiz-adv-x="952" />
<glyph unicode="&#x2003;" horiz-adv-x="1905" />
<glyph unicode="&#x2004;" horiz-adv-x="635" />
<glyph unicode="&#x2005;" horiz-adv-x="476" />
<glyph unicode="&#x2006;" horiz-adv-x="317" />
<glyph unicode="&#x2007;" horiz-adv-x="317" />
<glyph unicode="&#x2008;" horiz-adv-x="238" />
<glyph unicode="&#x2009;" horiz-adv-x="381" />
<glyph unicode="&#x200a;" horiz-adv-x="105" />
<glyph unicode="&#x2010;" horiz-adv-x="444" d="M74 455v194h297v-194h-297z" />
<glyph unicode="&#x2011;" horiz-adv-x="444" d="M74 455v194h297v-194h-297z" />
<glyph unicode="&#x2012;" horiz-adv-x="444" d="M74 455v194h297v-194h-297z" />
<glyph unicode="&#x2013;" horiz-adv-x="806" d="M74 649v195h659v-195h-659z" />
<glyph unicode="&#x2014;" horiz-adv-x="972" d="M74 649v195h825v-195h-825z" />
<glyph unicode="&#x2018;" horiz-adv-x="309" d="M49 1012v227l113 266h102l-71 -266h71v-227h-215z" />
<glyph unicode="&#x2019;" horiz-adv-x="309" d="M45 1012l72 266h-72v227h215v-227l-113 -266h-102z" />
<glyph unicode="&#x201a;" horiz-adv-x="309" d="M45 0v227h215v-227l-113 -266h-102l72 266h-72z" />
<glyph unicode="&#x201c;" horiz-adv-x="624" d="M53 1012v227l113 266h102l-71 -266h71v-227h-215zM356 1012v227l113 266h102l-71 -266h71v-227h-215z" />
<glyph unicode="&#x201d;" horiz-adv-x="624" d="M53 1012l72 266h-72v227h215v-227l-112 -266h-103zM356 1012l72 266h-72v227h215v-227l-112 -266h-103z" />
<glyph unicode="&#x201e;" horiz-adv-x="624" d="M53 0v227h215v-227l-112 -266h-103l72 266h-72zM356 0v227h215v-227l-112 -266h-103l72 266h-72z" />
<glyph unicode="&#x2022;" horiz-adv-x="663" d="M82 815q0 104 72.5 177t177 73t177.5 -72.5t73 -177t-73 -177.5t-177 -73t-177 73t-73 177z" />
<glyph unicode="&#x2026;" horiz-adv-x="964" d="M53 0v227h215v-227h-215zM375 0v227h215v-227h-215zM696 0v227h215v-227h-215z" />
<glyph unicode="&#x202f;" horiz-adv-x="381" />
<glyph unicode="&#x2039;" horiz-adv-x="1058" d="M74 649v160l911 475v-199l-698 -356l698 -356v-199z" />
<glyph unicode="&#x203a;" horiz-adv-x="1058" d="M74 174v199l698 356l-698 356v199l911 -475v-160z" />
<glyph unicode="&#x205f;" horiz-adv-x="476" />
<glyph unicode="&#x20ac;" horiz-adv-x="813" d="M53 547v137h107v137h-107v137h107v238q0 42 17.5 106t45 107t88 78t144.5 35t144 -34t88 -81q53 -90 61 -178l2 -33v-84h-207v84q-2 0 0 11.5t-3 27.5t-12 33q-18 39 -69 39q-70 -10 -78 -111v-238h233v-137h-233v-137h233v-137h-233v-238q0 -43 21.5 -76.5t59.5 -33.5 t58.5 27.5t20.5 56.5l2 26v84h207v-84q0 -38 -17.5 -104t-45.5 -109t-88 -77.5t-144 -34.5t-144.5 33.5t-88.5 81.5q-55 97 -60 175l-2 35v238h-107z" />
<glyph unicode="&#x2122;" horiz-adv-x="937" d="M74 1401v104h321v-104h-104v-580h-113v580h-104zM440 821v684h138l67 -319h6l68 319h137v-684h-104v449l-78 -449h-51l-80 449v-449h-103z" />
<glyph unicode="&#xe000;" horiz-adv-x="1120" d="M0 0v1120h1120v-1120h-1120z" />
<glyph unicode="&#xfb01;" horiz-adv-x="772" d="M20 934v186h105v31q0 172 31 231q16 31 42 67q53 71 181 71q59 0 127 -13l20 -2v-184q-41 12 -91 12t-69.5 -18.5t-25.5 -58.5q-8 -52 -8 -107v-29h358v-1120h-207v934h-151v-934h-207v934h-105z" />
<glyph unicode="&#xfb02;" horiz-adv-x="772" d="M20 934v186h105v31q0 172 31 231q16 31 42 67q53 71 181 71q59 0 127 -13l20 -2h164v-1505h-207v1329q-37 4 -67.5 4t-50 -18.5t-25.5 -58.5q-8 -52 -8 -107v-29h104v-186h-104v-934h-207v934h-105z" />
<glyph unicode="&#xfb03;" horiz-adv-x="1320" d="M20 934v186h105v31q0 190 51 270q23 35 71 63.5t115 28.5l97 -14v-178q-27 8 -62 8q-66 0 -65 -180v-29h104v-186h-104v-934h-207v934h-105zM495 934v186h105v31q0 190 51 270q23 35 71 63.5t115 28.5l97 -14v-178q-27 8 -62 8q-66 0 -65 -180v-29h104v-186h-104v-934 h-207v934h-105zM1032 0v1120h207v-1120h-207zM1032 1298v207h207v-207h-207z" />
<glyph unicode="&#xfb04;" horiz-adv-x="1320" d="M20 934v186h105v31q0 190 51 270q23 35 71 63.5t115 28.5l97 -14v-178q-27 8 -62 8q-66 0 -65 -180v-29h104v-186h-104v-934h-207v934h-105zM495 934v186h105v31q0 190 51 270q23 35 71 63.5t115 28.5l97 -14v-178q-27 8 -62 8q-66 0 -65 -180v-29h104v-186h-104v-934 h-207v934h-105zM1032 0v1505h207v-1505h-207z" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,182 @@
<!-- Main jumbotron for a primary marketing message or call to action -->
<div id="jumbotron-mask">
<div id="jumbotron">
<div class="container">
<div class="col-lg-6 col-md-6">
<h2 class="rls-l">
Service discovery and configuration made easy.
Distributed, highly available, and
datacenter-aware.
</h2>
</div>
<div class="jumbo-logo-wrap col-lg-offset-1 col-lg-5 col-md-6 hidden-xs hidden-sm">
<div class="jumbo-logo"></div>
</div>
<!-- <p><a class="btn btn-primary btn-lg">Learn more &raquo;</a></p> -->
</div>
<div class="jumbotron-dots"></div>
</div>
</div>
<div id="features">
<div class="container">
<div class="row double-row">
<div class="col-lg-6 col-md-6">
<div class="row">
<div class="col-lg-5 col-md-5">
<span class="icn discovery"></span>
</div>
<div class="col-lg-7 col-md-7">
<h2>Service Discovery</h2>
<p>
Terraform makes it simple for services to register themselves
and to discover other services via a DNS or HTTP interface.
Register external services such as SaaS providers as well.</p>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="row">
<div class="col-lg-5 col-md-5">
<span class="icn health"></span>
</div>
<div class="col-lg-7 col-md-7">
<h2>Failure Detection</h2>
<p>Pairing service discovery with health checking prevents routing requests to unhealthy hosts and enables services to easily provide circuit breakers.</p>
</div>
</div>
</div>
</div>
<div class="row double-row">
<div class="col-lg-6 col-md-6">
<div class="row">
<div class="col-lg-5 col-md-5">
<span class="icn multi"></span>
</div>
<div class="col-lg-7 col-md-7">
<h2>Multi Datacenter</h2>
<p>Terraform scales to multiple datacenters out of the box with no complicated configuration. Look up services in other datacenters, or keep the request local.</p>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6">
<div class="row">
<div class="col-lg-5 col-md-5">
<span class="icn config"></span>
</div>
<div class="col-lg-7 col-md-7">
<h2>Key/Value Storage</h2>
<p>Flexible key/value store for dynamic configuration, feature flagging, coordination, leader election and more. Long poll for near-instant notification of configuration changes.</p>
</div>
</div>
</div>
</div>
</div> <!-- /container -->
</div> <!-- /features -->
<div id="demos">
<div class="container">
<div class="terminals row">
<div class="col-xs-12 col-lg-12 explantion">
<h2>DNS Query Interface</h2>
<p>
Look up services using Terraform's built-in DNS server. Support
existing infrastructure without any code change.
</p>
</div>
<div class="terminal-item col-xs-12 col-lg-12">
<div class="terminal">
<header>
<h4>Terminal</h4>
<ul class='shell-dots'>
<li></li>
<li></li>
<li></li>
</ul>
</header>
<div class="terminal-window">
<div class="terminal">
<div class="display">
<p class="command"><span class="txt-r">admin@hashicorp</span>: dig web-frontend.service.terraform. ANY</p>
<p>; &lt;&lt;&gt;&gt; DiG 9.8.3-P1 &lt;&lt;&gt;&gt; web-frontend.service.terraform. ANY</p>
<p>;; global options: +cmd</p>
<p> </p>
<p>;; Got answer:</p>
<p>;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 29981</p>
<p>;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0</p>
<p> </p>
<p>;; QUESTION SECTION:</p>
<p>;web-frontend.service.terraform. IN ANY</p>
<p> </p>
<p>;; ANSWER SECTION:</p>
<p>web-frontend.service.terraform. 0 IN A <span class="txt-p">10.0.3.83</span></p>
<p>web-frontend.service.terraform. 0 IN A <span class="txt-p">10.0.1.109</span></p>
<p class="command"><span class="txt-r">admin@hashicorp</span>: <span class="cursor">&nbsp;</span></p>
</div>
</div>
</div>
</div>
</div> <!-- /.terminal-item -->
<div class="col-xs-12 col-lg-12 explantion">
<h2>Key Value Storage</h2>
<p>
Terraform provides a hierarchical key/value store with a simple HTTP API.
Managing configuration has never been simpler.
</p>
</div>
<div class="terminal-item col-xs-12 col-lg-12">
<div class="terminal">
<header>
<h4>Terminal</h4>
<ul class='shell-dots'>
<li></li>
<li></li>
<li></li>
</ul>
</header>
<div class="terminal-window">
<div class="terminal">
<div class="display">
<p class="command"><span class="txt-r">admin@hashicorp</span>: curl -X PUT -d 'bar' http://localhost:8500/v1/kv/foo</p>
<p>true</p>
<p class="command"><span class="txt-r">admin@hashicorp</span>: curl http://localhost:8500/v1/kv/foo</p>
<p>[</p>
<p> {</p>
<p> "CreateIndex": 100,</p>
<p> "ModifyIndex": 200,</p>
<p> "Key": "foo",</p>
<p> "Flags": 0,</p>
<p> "Value": <span class="txt-p">"YmFy"</span></p>
<p> }</p>
<p>]</p>
<p class="command"><span class="txt-r">admin@hashicorp</span>: <span class="cursor">&nbsp;</span></p>
</div>
</div>
</div>
</div>
</div> <!-- /.terminal-item -->
</div>
</div>
</div><!-- /#demos -->
<div id="cta">
<div class="container">
<div class="row">
<div class="intro">
<div class="left col-xs-12 col-sm-offset-2 col-sm-4">
<p>The intro and getting started guide contain
a simple and approachable walkthrough for running Terraform locally.</p>
</div>
<div class="col-xs-offset-5 col-xs-12 col-sm-6 col-sm-offset-0 right">
<a class="outline-btn purple" href="/intro/index.html">Read the intro &#187;</a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,125 @@
---
layout: "intro"
page_title: "Run the Agent"
sidebar_current: "gettingstarted-agent"
---
# Run the Terraform Agent
After Terraform is installed, the agent must be run. The agent can either run
in a server or client mode. Each datacenter must have at least one server,
although 3 or 5 is recommended. A single server deployment is _**highly**_ discouraged
as data loss is inevitable in a failure scenario. [This guide](/docs/guides/bootstrapping.html)
covers bootstrapping a new datacenter. All other agents run in client mode, which
is a very lightweight process that registers services, runs health checks,
and forwards queries to servers. The agent must be run for every node that
will be part of the cluster.
## Starting the Agent
For simplicity, we'll run a single Terraform agent in server mode right now:
```
$ terraform agent -server -bootstrap -data-dir /tmp/consul
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting Terraform agent...
==> Starting Terraform agent RPC...
==> Terraform agent running!
Node name: 'Armons-MacBook-Air'
Datacenter: 'dc1'
Server: true (bootstrap: true)
Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, RPC: 8400)
Cluster Addr: 10.1.10.38 (LAN: 8301, WAN: 8302)
==> Log data will now stream in as it occurs:
[INFO] serf: EventMemberJoin: Armons-MacBook-Air.local 10.1.10.38
[INFO] raft: Node at 10.1.10.38:8300 [Follower] entering Follower state
[INFO] terraform: adding server for datacenter: dc1, addr: 10.1.10.38:8300
[ERR] agent: failed to sync remote state: rpc error: No cluster leader
[WARN] raft: Heartbeat timeout reached, starting election
[INFO] raft: Node at 10.1.10.38:8300 [Candidate] entering Candidate state
[INFO] raft: Election won. Tally: 1
[INFO] raft: Node at 10.1.10.38:8300 [Leader] entering Leader state
[INFO] terraform: cluster leadership acquired
[INFO] terraform: New leader elected: Armons-MacBook-Air
[INFO] terraform: member 'Armons-MacBook-Air' joined, marking health alive
```
As you can see, the Terraform agent has started and has output some log
data. From the log data, you can see that our agent is running in server mode,
and has claimed leadership of the cluster. Additionally, the local member has
been marked as a healthy member of the cluster.
<div class="alert alert-block alert-warning">
<strong>Note for OS X Users:</strong> Terraform uses your hostname as the
default node name. If your hostname contains periods, DNS queries to
that node will not work with Terraform. To avoid this, explicitly set
the name of your node with the <code>-node</code> flag.
</div>
## Cluster Members
If you run `terraform members` in another terminal, you can see the members of
the Terraform cluster. You should only see one member (yourself). We'll cover
joining clusters in the next section.
```
$ terraform members
Armons-MacBook-Air 10.1.10.38:8301 alive role=terraform,dc=dc1,vsn=1,vsn_min=1,vsn_max=1,port=8300,bootstrap=1
```
The output shows our own node, the address it is running on, its
health state, and some metadata associated with the node. Some important
metadata keys to recognize are the `role` and `dc` keys. These tell you
the service name and the datacenter that member is within. These can be
used to lookup nodes and services using the DNS interface, which is covered
shortly.
The output from the `members` command is generated based on the
[gossip protocol](/docs/internals/gossip.html) and is eventually consistent.
For a strongly consistent view of the world, use the
[HTTP API](/docs/agent/http.html), which forwards the request to the
Terraform servers:
```
$ curl localhost:8500/v1/catalog/nodes
[{"Node":"Armons-MacBook-Air","Address":"10.1.10.38"}]
```
In addition to the HTTP API, the
[DNS interface](/docs/agent/dns.html) can be used to query the node. Note
that you have to make sure to point your DNS lookups to the Terraform agent's
DNS server, which runs on port 8600 by default. The format of the DNS
entries (such as "Armons-MacBook-Air.node.terraform") will be covered later.
```
$ dig @127.0.0.1 -p 8600 Armons-MacBook-Air.node.terraform
...
;; QUESTION SECTION:
;Armons-MacBook-Air.node.terraform. IN A
;; ANSWER SECTION:
Armons-MacBook-Air.node.terraform. 0 IN A 10.1.10.38
```
## Stopping the Agent
You can use `Ctrl-C` (the interrupt signal) to gracefully halt the agent.
After interrupting the agent, you should see it leave the cluster gracefully
and shut down.
By gracefully leaving, Terraform notifies other cluster members that the
node _left_. If you had forcibly killed the agent process, other members
of the cluster would have detected that the node _failed_. When a member leaves,
its services and checks are removed from the catalog. When a member fails,
its health is simply marked as critical, but is not removed from the catalog.
Terraform will automatically try to reconnect to _failed_ nodes, which allows it
to recover from certain network conditions, while _left_ nodes are no longer contacted.
Additionally, if an agent is operating as a server, a graceful leave is important
to avoid causing a potential availability outage affecting the [consensus protocol](/docs/internals/consensus.html).
See the [guides section](/docs/guides/index.html) to safely add and remove servers.

View File

@ -0,0 +1,94 @@
---
layout: "intro"
page_title: "Registering Health Checks"
sidebar_current: "gettingstarted-checks"
---
# Health Checks
We've now seen how simple it is to run Terraform, add nodes and services, and
query those nodes and services. In this section we will continue by adding
health checks to both nodes and services, a critical component of service
discovery that prevents using services that are unhealthy.
This page will build upon the previous page and assumes you have a
two node cluster running.
## Defining Checks
Similarly to a service, a check can be registered either by providing a
[check definition](/docs/agent/checks.html)
, or by making the appropriate calls to the
[HTTP API](/docs/agent/http.html).
We will use the check definition, because just like services, definitions
are the most common way to setup checks.
Create two definition files in the Terraform configuration directory of
the second node.
The first file will add a host-level check, and the second will modify the web
service definition to add a service-level check.
```
$ echo '{"check": {"name": "ping", "script": "ping -c1 google.com >/dev/null", "interval": "30s"}}' >/etc/terraform.d/ping.json
$ echo '{"service": {"name": "web", "tags": ["rails"], "port": 80,
"check": {"script": "curl localhost:80 >/dev/null 2>&1", "interval": "10s"}}}' >/etc/terraform.d/web.json
```
The first definition adds a host-level check named "ping". This check runs
on a 30 second interval, invoking `ping -c1 google.com`. If the command
exits with a non-zero exit code, then the node will be flagged unhealthy.
The second command modifies the web service and adds a check that uses
curl every 10 seconds to verify that the web server is running.
Restart the second agent, or send a `SIGHUP` to it. We should now see the
following log lines:
```
==> Starting Terraform agent...
...
[INFO] agent: Synced service 'web'
[INFO] agent: Synced check 'service:web'
[INFO] agent: Synced check 'ping'
[WARN] Check 'service:web' is now critical
```
The first few log lines indicate that the agent has synced the new
definitions. The last line indicates that the check we added for
the `web` service is critical. This is because we're not actually running
a web server and the curl test is failing!
## Checking Health Status
Now that we've added some simple checks, we can use the HTTP API to check
them. First, we can look for any failing checks. You can run this curl
on either node:
```
$ curl http://localhost:8500/v1/health/state/critical
[{"Node":"agent-two","CheckID":"service:web","Name":"Service 'web' check","Status":"critical","Notes":"","ServiceID":"web","ServiceName":"web"}]
```
We can see that there is only a single check in the `critical` state, which is
our `web` service check.
Additionally, we can attempt to query the web service using DNS. Terraform
will not return any results, since the service is unhealthy:
```
dig @127.0.0.1 -p 8600 web.service.terraform
...
;; QUESTION SECTION:
;web.service.terraform. IN A
```
This section should have shown that checks can be easily added. Check definitions
can be updated by changing configuration files and sending a `SIGHUP` to the agent.
Alternatively the HTTP API can be used to add, remove and modify checks dynamically.
The API allows for a "dead man's switch" or [TTL based check](/docs/agent/checks.html).
TTL checks can be used to integrate an application more tightly with Terraform, enabling
business logic to be evaluated as part of passing a check.

View File

@ -0,0 +1,66 @@
---
layout: "intro"
page_title: "Installing Terraform"
sidebar_current: "gettingstarted-install"
---
# Install Terraform
Terraform must first be installed on every node that will be a member of a
Terraform cluster. To make installation easy, Terraform is distributed as a
[binary package](/downloads.html) for all supported platforms and
architectures. This page will not cover how to compile Terraform from
source.
## Installing Terraform
To install Terraform, find the [appropriate package](/downloads.html) for
your system and download it. Terraform is packaged as a "zip" archive.
After downloading Terraform, unzip the package. Copy the `terraform` binary to
somewhere on the PATH so that it can be executed. On Unix systems,
`~/bin` and `/usr/local/bin` are common installation directories,
depending on if you want to restrict the install to a single user or
expose it to the entire system. On Windows systems, you can put it wherever
you would like.
### OS X
If you are using [homebrew](http://brew.sh/#install) as a package manager,
than you can install terraform as simple as:
```
brew cask install terraform
```
if you are missing the [cask plugin](http://caskroom.io/) you can install it with:
```
brew install caskroom/cask/brew-cask
```
## Verifying the Installation
After installing Terraform, verify the installation worked by opening a new
terminal session and checking that `terraform` is available. By executing
`terraform` you should see help output similar to that below:
```
$ terraform
usage: terraform [--version] [--help] <command> [<args>]
Available commands are:
agent Runs a Terraform agent
force-leave Forces a member of the cluster to enter the "left" state
info Provides debugging information for operators
join Tell Terraform agent to join cluster
keygen Generates a new encryption key
leave Gracefully leaves the Terraform cluster and shuts down
members Lists the members of a Terraform cluster
monitor Stream logs from a Terraform agent
version Prints the Terraform version
```
If you get an error that `terraform` could not be found, then your PATH
environment variable was not setup properly. Please go back and ensure
that your PATH variable contains the directory where Terraform was installed.
Otherwise, Terraform is installed and ready to go!

View File

@ -0,0 +1,121 @@
---
layout: "intro"
page_title: "Terraform Cluster"
sidebar_current: "gettingstarted-join"
---
# Terraform Cluster
By this point, we've started our first agent and registered and queried
one or more services on that agent. This showed how easy it is to use
Terraform, but didn't show how this could be extended to a scalable production
service discovery infrastructure. On this page, we'll create our first
real cluster with multiple members.
When starting a Terraform agent, it begins without knowledge of any other node, and is
an isolated cluster of one. To learn about other cluster members, the agent must
_join_ an existing cluster. To join an existing cluster, only needs to know
about a _single_ existing member. After it joins, the agent will gossip with this
member and quickly discover the other members in the cluster. A Terraform
agent can join any other agent, it doesn't have to be an agent in server mode.
## Starting the Agents
To simulate a more realistic cluster, we are using a two node cluster in
Vagrant. The Vagrantfile can be found in the demo section of the repo
[here](https://github.com/hashicorp/terraform/tree/master/demo/vagrant-cluster).
We start the first agent on our first node and also specify a node name.
The node name must be unique and is how a machine is uniquely identified.
By default it is the hostname of the machine, but we'll manually override it.
We are also providing a bind address. This is the address that Terraform listens on,
and it *must* be accessible by all other nodes in the cluster. The first node
will act as our server in this cluster. We're still not making a cluster
of servers.
```
$ terraform agent -server -bootstrap -data-dir /tmp/consul \
-node=agent-one -bind=172.20.20.10
...
```
Then, in another terminal, start the second agent on the new node.
This time, we set the bind address to match the IP of the second node
as specified in the Vagrantfile. In production, you will generally want
to provide a bind address or interface as well.
```
$ terraform agent -data-dir /tmp/consul -node=agent-two -bind=172.20.20.11
...
```
At this point, you have two Terraform agents running, one server and one client.
The two Terraform agents still don't know anything about each other, and are each part of their own
clusters (of one member). You can verify this by running `terraform members`
against each agent and noting that only one member is a part of each.
## Joining a Cluster
Now, let's tell the first agent to join the second agent by running
the following command in a new terminal:
```
$ terraform join 172.20.20.11
Successfully joined cluster by contacting 1 nodes.
```
You should see some log output in each of the agent logs. If you read
carefully, you'll see that they received join information. If you
run `terraform members` against each agent, you'll see that both agents now
know about each other:
```
$ terraform members
agent-one 172.20.20.10:8301 alive role=terraform,dc=dc1,vsn=1,vsn_min=1,vsn_max=1,port=8300,bootstrap=1
agent-two 172.20.20.11:8301 alive role=node,dc=dc1,vsn=1,vsn_min=1,vsn_max=1
```
<div class="alert alert-block alert-info">
<p><strong>Remember:</strong> To join a cluster, a Terraform agent needs to only
learn about <em>one existing member</em>. After joining the cluster, the
agents gossip with each other to propagate full membership information.
</p>
</div>
In addition to using `terraform join` you can use the `-join` flag on
`terraform agent` to join a cluster as part of starting up the agent.
## Querying Nodes
Just like querying services, Terraform has an API for querying the
nodes themselves. You can do this via the DNS or HTTP API.
For the DNS API, the structure of the names is `NAME.node.terraform` or
`NAME.DATACENTER.node.terraform`. If the datacenter is omitted, Terraform
will only search the local datacenter.
From "agent-one", query "agent-two":
```
$ dig @127.0.0.1 -p 8600 agent-two.node.terraform
...
;; QUESTION SECTION:
;agent-two.node.terraform. IN A
;; ANSWER SECTION:
agent-two.node.terraform. 0 IN A 172.20.20.11
```
The ability to look up nodes in addition to services is incredibly
useful for system administration tasks. For example, knowing the address
of the node to SSH into is as easy as making it part of the Terraform cluster
and querying it.
## Leaving a Cluster
To leave the cluster, you can either gracefully quit an agent (using
`Ctrl-C`) or force kill one of the agents. Gracefully leaving allows
the node to transition into the _left_ state, otherwise other nodes
will detect it as having _failed_. The difference is covered
in more detail [here](/intro/getting-started/agent.html#toc_3).

View File

@ -0,0 +1,118 @@
---
layout: "intro"
page_title: "Key/Value Data"
sidebar_current: "gettingstarted-kv"
---
# Key/Value Data
In addition to providing service discovery and integrated health checking,
Terraform provides an easy to use Key/Value store. This can be used to hold
dynamic configuration, assist in service coordination, build leader election,
and anything else a developer can think to build. The
[HTTP API](/docs/agent/http.html) fully documents the features of the K/V store.
This page assumes you have at least one Terraform agent already running.
## Simple Usage
To demonstrate how simple it is to get started, we will manipulate a few keys
in the K/V store.
Querying the agent we started in a prior page, we can first verify that
there are no existing keys in the k/v store:
```
$ curl -v http://localhost:8500/v1/kv/?recurse
* About to connect() to localhost port 8500 (#0)
* Trying 127.0.0.1... connected
> GET /v1/kv/?recurse HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8500
> Accept: */*
>
< HTTP/1.1 404 Not Found
< X-Terraform-Index: 1
< Date: Fri, 11 Apr 2014 02:10:28 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
* Closing connection #0
```
Since there are no keys, we get a 404 response back.
Now, we can put a few example keys:
```
$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1
true
$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key2?flags=42
true
$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/sub/key3
true
$ curl http://localhost:8500/v1/kv/?recurse
[{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="},
{"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="},
{"CreateIndex":99,"ModifyIndex":99,"Key":"web/sub/key3","Flags":0,"Value":"dGVzdA=="}]
```
Here we have created 3 keys, each with the value of "test". Note that the
`Value` field returned is base64 encoded to allow non-UTF8
characters. For the "web/key2" key, we set a `flag` value of 42. All keys
support setting a 64bit integer flag value. This is opaque to Terraform but can
be used by clients for any purpose.
After setting the values, we then issued a GET request to retrieve multiple
keys using the `?recurse` parameter.
You can also fetch a single key just as easily:
```
$ curl http://localhost:8500/v1/kv/web/key1
[{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="}]
```
Deleting keys is simple as well. We can delete a single key by specifying the
full path, or we can recursively delete all keys under a root using "?recurse":
```
$ curl -X DELETE http://localhost:8500/v1/kv/web/sub?recurse
$ curl http://localhost:8500/v1/kv/web?recurse
[{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="},
{"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="}]
```
A key can be updated by setting a new value by issuing the same PUT request.
Additionally, Terraform provides a Check-And-Set operation, enabling atomic
key updates. This is done by providing the `?cas=` paramter with the last
`ModifyIndex` value from the GET request. For example, suppose we wanted
to update "web/key1":
```
$ curl -X PUT -d 'newval' http://localhost:8500/v1/kv/web/key1?cas=97
true
$ curl -X PUT -d 'newval' http://localhost:8500/v1/kv/web/key1?cas=97
false
```
In this case, the first CAS update succeeds because the last modify time is 97.
However the second operation fails because the `ModifyIndex` is no longer 97.
We can also make use of the `ModifyIndex` to wait for a key's value to change.
For example, suppose we wanted to wait for key2 to be modified:
```
$ curl "http://localhost:8500/v1/kv/web/key2?index=101&wait=5s"
[{"CreateIndex":98,"ModifyIndex":101,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="}]
```
By providing "?index=" we are asking to wait until the key has a `ModifyIndex` greater
than 101. However the "?wait=5s" parameter restricts the query to at most 5 seconds,
returning the current, unchanged value. This can be used to efficiently wait for
key modifications. Additionally, this same technique can be used to wait for a list
of keys, waiting only until any of the keys has a newer modification time.
This is only a few example of what the API supports. For full documentation, please
reference the [HTTP API](/docs/agent/http.html).

View File

@ -0,0 +1,29 @@
---
layout: "intro"
page_title: "Next Steps"
sidebar_current: "gettingstarted-nextsteps"
---
# Next Steps
That concludes the getting started guide for Terraform. Hopefully you're able to
see that while Terraform is simple to use, it has a powerful set of features.
We've covered the basics for all of these features in this guide.
Terraform is designed to be friendly to both the DevOps community and
application developers, making it perfect for modern, elastic infrastructures.
As a next step, the following resources are available:
* [Documentation](/docs/index.html) - The documentation is an in-depth reference
guide to all the features of Terraform, including technical details about the
internals of how Terraform operates.
* [Guides](/docs/guides/index.html) - This section provides various getting
started guides with Terraform, including how to bootstrap a new datacenter.
* [Examples](https://github.com/hashicorp/terraform/tree/master/demo) -
The work-in-progress examples folder within the GitHub
repository for Terraform contains functional examples of various use cases
of Terraform to help you get started with exactly what you need.

View File

@ -0,0 +1,139 @@
---
layout: "intro"
page_title: "Registering Services"
sidebar_current: "gettingstarted-services"
---
# Registering Services
In the previous page, we ran our first agent, saw the cluster members, and
queried that node. On this page, we'll register our first service and query
that service. We're not yet running a cluster of Terraform agents.
## Defining a Service
A service can be registered either by providing a
[service definition](/docs/agent/services.html),
or by making the appropriate calls to the
[HTTP API](/docs/agent/http.html).
We're going to start by registering a service using a service definition,
since this is the most common way that services are registered. We'll be
building on what we covered in the
[previous page](/intro/getting-started/agent.html).
First, create a directory for Terraform configurations. A good directory
is typically `/etc/terraform.d`. Terraform loads all configuration files in the
configuration directory.
```
$ sudo mkdir /etc/terraform.d
```
Next, we'll write a service definition configuration file. We'll
pretend we have a service named "web" running on port 80. Additionally,
we'll give it some tags, which we can use as additional ways to query
it later.
```
$ echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' \
>/etc/terraform.d/web.json
```
Now, restart the agent we're running, providing the configuration directory:
```
$ terraform agent -server -bootstrap -data-dir /tmp/consul -config-dir /etc/consul.d
==> Starting Terraform agent...
...
[INFO] agent: Synced service 'web'
...
```
You'll notice in the output that it "synced" the web service. This means
that it loaded the information from the configuration.
If you wanted to register multiple services, you create multiple service
definition files in the Terraform configuration directory.
## Querying Services
Once the agent is started and the service is synced, we can query that
service using either the DNS or HTTP API.
### DNS API
Let's first query it using the DNS API. For the DNS API, the DNS name
for services is `NAME.service.terraform`. All DNS names are always in the
`terraform` namespace. The `service` subdomain on that tells Terraform we're
querying services, and the `NAME` is the name of the service. For the
web service we registered, that would be `web.service.terraform`:
```
$ dig @127.0.0.1 -p 8600 web.service.terraform
...
;; QUESTION SECTION:
;web.service.terraform. IN A
;; ANSWER SECTION:
web.service.terraform. 0 IN A 172.20.20.11
```
As you can see, an A record was returned with the IP address of the node that
the service is available on. A records can only hold IP addresses. You can
also use the DNS API to retrieve the entire address/port pair using SRV
records:
```
$ dig @127.0.0.1 -p 8600 web.service.terraform SRV
...
;; QUESTION SECTION:
;web.service.terraform. IN SRV
;; ANSWER SECTION:
web.service.terraform. 0 IN SRV 1 1 80 agent-one.node.dc1.consul.
;; ADDITIONAL SECTION:
agent-one.node.dc1.terraform. 0 IN A 172.20.20.11
```
The SRV record returned says that the web service is running on port 80
and exists on the node `agent-one.node.dc1.terraform.`. An additional section
is returned by the DNS with the A record for that node.
Finally, we can also use the DNS API to filter services by tags. The
format for tag-based service queries is `TAG.NAME.service.terraform`. In
the example below, we ask Terraform for all web services with the "rails"
tag. We get a response since we registered our service with that tag.
```
$ dig @127.0.0.1 -p 8600 rails.web.service.terraform
...
;; QUESTION SECTION:
;rails.web.service.terraform. IN A
;; ANSWER SECTION:
rails.web.service.terraform. 0 IN A 172.20.20.11
```
### HTTP API
In addition to the DNS API, the HTTP API can be used to query services:
```
$ curl http://localhost:8500/v1/catalog/service/web
[{"Node":"agent-one","Address":"172.20.20.11","ServiceID":"web","ServiceName":"web","ServiceTags":["rails"],"ServicePort":80}]
```
## Updating Services
Service definitions can be updated by changing configuration files and
sending a `SIGHUP` to the agent. This lets you update services without
any downtime or unavailability to service queries.
Alternatively the HTTP API can be used to add, remove, and modify services
dynamically.

View File

@ -0,0 +1,56 @@
---
layout: "intro"
page_title: "Web UI"
sidebar_current: "gettingstarted-ui"
---
# Terraform Web UI
Terraform comes with support for a
[beautiful, functional web UI](http://demo.terraform.io) out of the box.
This UI can be used for viewing all services and nodes, viewing all
health checks and their current status, and for reading and setting
key/value data. The UI automatically supports multi-datacenter.
For ease of deployment, the UI is
[distributed](/downloads_web_ui.html)
as static HTML and JavaScript.
You don't need a separate web server to run the web UI. The Terraform
agent itself can be configured to serve the UI.
## Screenshot and Demo
You can view a live demo of the Terraform Web UI
[here](http://demo.terraform.io).
While the live demo is able to access data from all datacenters,
we've also setup demo endpoints in the specific datacenters:
[AMS2](http://ams2.demo.terraform.io) (Amsterdam),
[SFO1](http://sfo1.demo.terraform.io) (San Francisco),
and [NYC1](http://nyc1.demo.terraform.io) (New York).
A screenshot of one page of the demo is shown below so you can get an
idea of what the web UI is like. Click the screenshot for the full size.
<div class="center">
<a href="/images/terraform_web_ui.png">
<img src="/images/terraform_web_ui.png">
</a>
</div>
## Set Up
To set up the web UI,
[download the web UI package](/downloads_web_ui.html)
and unzip it to a directory somewhere on the server where the Terraform agent
is also being run. Then, just append the `-ui-dir` to the `terraform agent`
command pointing to the directory where you unzipped the UI (the
directory with the `index.html` file):
```
$ terraform agent -ui-dir /path/to/ui
...
```
The UI is available at the `/ui` path on the same port as the HTTP API.
By default this is `http://localhost:8500/ui`.

View File

@ -0,0 +1,75 @@
---
layout: "intro"
page_title: "Introduction"
sidebar_current: "what"
---
# Introduction to Terraform
Welcome to the intro guide to Terraform! This guide is the best place to start
with Terraform. We cover what Terraform is, what problems it can solve, how it compares
to existing software, and a quick start for using Terraform. If you are already familiar
with the basics of Terraform, the [documentation](/docs/index.html) provides more
of a reference for all available features.
## What is Terraform?
Terraform has multiple components, but as a whole, it is a tool for discovering
and configuring services in your infrastructure. It provides several
key features:
* **Service Discovery**: Clients of Terraform can _provide_ a service, such as
`api` or `mysql`, and other clients can use Terraform to _discover_ providers
of a given service. Using either DNS or HTTP, applications can easily find
the services they depend upon.
* **Health Checking**: Terraform clients can provide any number of health checks,
either associated with a given service ("is the webserver returning 200 OK"), or
with the local node ("is memory utilization below 90%"). This information can be
used by an operator to monitor cluster health, and it is used by the service
discovery components to route traffic away from unhealthy hosts.
* **Key/Value Store**: Applications can make use of Terraform's hierarchical key/value
store for any number of purposes including: dynamic configuration, feature flagging,
coordination, leader election, etc. The simple HTTP API makes it easy to use.
* **Multi Datacenter**: Terraform supports multiple datacenters out of the box. This
means users of Terraform do not have to worry about building additional layers of
abstraction to grow to multiple regions.
Terraform is designed to be friendly to both the DevOps community and
application developers, making it perfect for modern, elastic infrastructures.
## Basic Architecture of Terraform
Terraform is a distributed, highly available system. There is an
[in-depth architecture overview](/docs/internals/architecture.html) available,
but this section will cover the basics so you can get an understanding
of how Terraform works. This section will purposely omit details to quickly
provide an overview of the architecture.
Every node that provides services to Terraform runs a _Terraform agent_. Running
an agent is not required for discovering other services or getting/setting
key/value data. The agent is responsible for health checking the services
on the node as well as the node itself.
The agents talk to one or more _Terraform servers_. The Terraform servers are
where data is stored and replicated. The servers themselves elect a leader.
While Terraform can function with one server, 3 to 5 is recommended to avoid
data loss scenarios. A cluster of Terraform servers is recommended for each
datacenter.
Components of your infrastructure that need to discover other services
or nodes can query any of the Terraform servers _or_ any of the Terraform agents.
The agents forward queries to the servers automatically.
Each datacenter runs a cluster of Terraform servers. When a cross-datacenter
service discovery or configuration request is made, the local Terraform servers
forward the request to the remote datacenter and return the result.
## Next Steps
See the page on [how Terraform compares to other software](/intro/vs/index.html)
to see how it fits into your existing infrastructure. Or continue onwards with
the [getting started guide](/intro/getting-started/install.html) to get
Terraform up and running and see how it works.

View File

@ -0,0 +1,42 @@
---
layout: "intro"
page_title: "Terraform vs. Chef, Puppet, etc."
sidebar_current: "vs-other-chef"
---
# Terraform vs. Chef, Puppet, etc.
It is not uncommon to find people using Chef, Puppet, and other configuration
management tools to build service discovery mechanisms. This is usually
done by querying global state to construct configuration files on each
node during a periodic convergence run.
Unfortunately, this approach has
a number of pitfalls. The configuration information is static,
and cannot update any more frequently than convergence runs. Generally this
is on the interval of many minutes or hours. Additionally, there is no
mechanism to incorporate the system state in the configuration. Nodes which
are unhealthy may receive traffic exacerbating issues further. Using this
approach also makes supporting multiple datacenters challenging as a central
group of servers must manage all datacenters.
Terraform is designed specifically as a service discovery tool. As such,
it is much more dynamic and responsive to the state of the cluster. Nodes
can register and deregister the services they provide, enabling dependent
applications and services to rapidly discover all providers. By using the
integrated health checking, Terraform can route traffic away from unhealthy
nodes, allowing systems and services to gracefully recover. Static configuration
that may be provided by configuration management tools can be moved into the
dynamic key/value store. This allows application configuration to be updated
without a slow convergence run. Lastly, because each datacenter runs indepedently,
supporting multiple datacenters is no different than a single datacenter.
That said, Terraform is not a replacement for configuration management tools.
These tools are still critical to setup applications and even to
configure Terraform itself. Static provisioning is best managed
by existing tools, while dynamic state and discovery is better managed by
Terraform. The separation of configuration management and cluster management
also has a number of advantageous side effects: Chef recipes and Puppet manifests
become simpler without global state, periodic runs are no longer required for service
or configuration changes, and the infrastructure can become immutable since config management
runs require no global state.

View File

@ -0,0 +1,25 @@
---
layout: "intro"
page_title: "Terraform vs. Custom Solutions"
sidebar_current: "vs-other-custom"
---
# Terraform vs. Custom Solutions
As a code base grows, a monolithic app usually evolves into a Service Oriented Architecture (SOA).
A universal pain point for SOA is service discovery and configuration. In many
cases, this leads to organizations building home grown solutions.
It is an undisputed fact that distributed systems are hard; building one is error prone and time consuming.
Most systems cut corners by introducing single points of failure such
as a single Redis or RDBMS to maintain cluster state. These solutions may work in the short term,
but they are rarely fault tolerant or scalable. Besides these limitations,
they require time and resources to build and maintain.
Terraform provides the core set of features needed by a SOA out of the box. By using Terraform,
organizations can leverage open source work to reduce their time and resource commitment to
re-inventing the wheel and focus on their business applications.
Terraform is built on well-cited research, and is designed with the constraints of
distributed systems in mind. At every step, Terraform takes efforts to provide a robust
and scalable solution for organizations of any size.

View File

@ -0,0 +1,16 @@
---
layout: "intro"
page_title: "Terraform vs. Other Software"
sidebar_current: "vs-other"
---
# Terraform vs. Other Software
The problems Terraform solves are varied, but each individual feature has been
solved by many different systems. Although there is no single system that provides
all the features of Terraform, there are other options available to solve some of these problems.
In this section, we compare Terraform to some other options. In most cases, Terraform is not
mutually exclusive with any other system.
Use the navigation to the left to read the comparison of Terraform to specific
systems.

View File

@ -0,0 +1,49 @@
---
layout: "intro"
page_title: "Terraform vs. Nagios, Sensu"
sidebar_current: "vs-other-nagios-sensu"
---
# Terraform vs. Nagios, Sensu
Nagios and Sensu are both tools built for monitoring. They are used
to quickly notify operators when an issue occurs.
Nagios uses a group of central servers that are configured to perform
checks on remote hosts. This design makes it difficult to scale Nagios,
as large fleets quickly reach the limit of vertical scaling, and Nagios
does not easily scale horizontally. Nagios is also notoriously
difficult to use with modern DevOps and configuration management tools,
as local configurations must be updated when remote servers are added
or removed.
Sensu has a much more modern design, relying on local agents to run
checks and pushing results to an AMQP broker. A number of servers
ingest and handle the result of the health checks from the broker. This model
is more scalable than Nagios, as it allows for much more horizontal scaling,
and a weaker coupling between the servers and agents. However, the central broker
has scaling limits, and acts as a single point of failure in the system.
Terraform provides the same health checking abilities as both Nagios and Sensu,
is friendly to modern DevOps, and avoids the scaling issues inherent in the
other systems. Terraform runs all checks locally, like Sensu, avoiding placing
a burden on central servers. The status of checks is maintained by the Terraform
servers, which are fault tolerant and have no single point of failure.
Lastly, Terraform can scale to vastly more checks because it relies on edge triggered
updates. This means that an update is only triggered when a check transitions
from "passing" to "failing" or vice versa.
In a large fleet, the majority of checks are passing, and even the minority
that are failing are persistent. By capturing changes only, Terraform reduces
the amount of networking and compute resources used by the health checks,
allowing the system to be much more scalable.
An astute reader may notice that if a Terraform agent dies, then no edge triggered
updates will occur. From the perspective of other nodes all checks will appear
to be in a steady state. However, Terraform guards against this as well. The
[gossip protocol](/docs/internals/gossip.html) used between clients and servers
integrates a distributed failure detector. This means that if a Terraform agent fails,
the failure will be detected, and thus all checks being run by that node can be
assumed failed. This failure detector distributes the work among the entire cluster,
and critically enables the edge triggered architecture to work.

View File

@ -0,0 +1,46 @@
---
layout: "intro"
page_title: "Terraform vs. Serf"
sidebar_current: "vs-other-serf"
---
# Terraform vs. Serf
[Serf](http://www.serfdom.io) is a node discovery and orchestration tool and is the only
tool discussed so far that is built on an eventually consistent gossip model,
with no centralized servers. It provides a number of features, including group
membership, failure detection, event broadcasts and a query mechanism. However,
Serf does not provide any high-level features such as service discovery, health
checking or key/value storage. To clarify, the discovery feature of Serf is at a node
level, while Terraform provides a service and node level abstraction.
Terraform is a complete system providing all of those features. In fact, the internal
[gossip protocol](/docs/internals/gossip.html) used within Terraform, is powered by
the Serf library. Terraform leverages the membership and failure detection features,
and builds upon them.
The health checking provided by Serf is very low level, and only indicates if the
agent is alive. Terraform extends this to provide a rich health checking system,
that handles liveness, in addition to arbitrary host and service-level checks.
Health checks are integrated with a central catalog that operators can easily
query to gain insight into the cluster.
The membership provided by Serf is at a node level, while Terraform focuses
on the service level abstraction, with a single node to multiple service model.
This can be simulated in Serf using tags, but it is much more limited, and does
not provide useful query interfaces. Terraform also makes use of a strongly consistent
Catalog, while Serf is only eventually consistent.
In addition to the service level abstraction and improved health checking,
Terraform provides a key/value store and support for multiple datacenters.
Serf can run across the WAN but with degraded performance. Terraform makes use
of [multiple gossip pools](/docs/internals/architecture.html), so that
the performance of Serf over a LAN can be retained while still using it over
a WAN for linking together multiple datacenters.
Terraform is opinionated in its usage, while Serf is a more flexible and
general purpose tool. Terraform uses a CP architecture, favoring consistency over
availability. Serf is a AP system, and sacrifices consistency for availability.
This means Terraform cannot operate if the central servers cannot form a quorum,
while Serf will continue to function under almost all circumstances.

View File

@ -0,0 +1,41 @@
---
layout: "intro"
page_title: "Terraform vs. SkyDNS"
sidebar_current: "vs-other-skydns"
---
# Terraform vs. SkyDNS
SkyDNS is a relatively new tool designed to solve service discovery.
It uses multiple central servers that are strongly consistent and
fault tolerant. Nodes register services using an HTTP API, and
queries can be made over HTTP or DNS to perform discovery.
Terraform is very similar, but provides a superset of features. Terraform
also relies on multiple central servers to provide strong consistency
and fault tolerance. Nodes can use an HTTP API or use an agent to
register services, and queries are made over HTTP or DNS.
However, the systems differ in many ways. Terraform provides a much richer
health checking framework, with support for arbitrary checks and
a highly scalable failure detection scheme. SkyDNS relies on naive
heartbeating and TTLs, which have known scalability issues. Additionally,
the heartbeat only provides a limited liveness check, versus the rich
health checks that Terraform is capable of.
Multiple datacenters can be supported by using "regions" in SkyDNS,
however the data is managed and queried from a single cluster. If servers
are split between datacenters the replication protocol will suffer from
very long commit times. If all the SkyDNS servers are in a central datacenter, then
connectivity issues can cause entire datacenters to lose availability.
Additionally, even without a connectivity issue, query performance will
suffer as requests must always be performed in a remote datacenter.
Terraform supports multiple datacenters out of the box, and it purposely
scopes the managed data to be per-datacenter. This means each datacenter
runs an independent cluster of servers. Requests are forwarded to remote
datacenters if necessary. This means requests for services within a datacenter
never go over the WAN, and connectivity issues between datacenters do not
affect availability within a datacenter. Additionally, the unavailability
of one datacenter does not affect the service discovery of services
in any other datacenter.

View File

@ -0,0 +1,57 @@
---
layout: "intro"
page_title: "Terraform vs. SmartStack"
sidebar_current: "vs-other-smartstack"
---
# Terraform vs. SmartStack
SmartStack is another tool which tackles the service discovery problem.
It has a rather unique architecture, and has 4 major components: ZooKeeper,
HAProxy, Synapse, and Nerve. The ZooKeeper servers are responsible for storing cluster
state in a consistent and fault tolerant manner. Each node in the SmartStack
cluster then runs both Nerves and Synapses. The Nerve is responsible for running
health checks against a service, and registering with the ZooKeeper servers.
Synapse queries ZooKeeper for service providers and dynamically configures
HAProxy. Finally, clients speak to HAProxy, which does health checking and
load balancing across service providers.
Terraform is a much simpler and more contained system, as it does not rely on any external
components. Terraform uses an integrated [gossip protocol](/docs/internals/gossip.html)
to track all nodes and perform server discovery. This means that server addresses
do not need to be hardcoded and updated fleet wide on changes, unlike SmartStack.
Service registration for both Terraform and Nerves can be done with a configuration file,
but Terraform also supports an API to dynamically change the services and checks that are in use.
For discovery, SmartStack clients must use HAProxy, requiring that Synapse be
configured with all desired endpoints in advance. Terraform clients instead
use the DNS or HTTP APIs without any configuration needed in advance. Terraform
also provides a "tag" abstraction, allowing services to provide metadata such
as versions, primary/secondary designations, or opaque labels that can be used for
filtering. Clients can then request only the service providers which have
matching tags.
The systems also differ in how they manage health checking.
Nerve's performs local health checks in a manner similar to Terraform agents.
However, Terraform maintains separate catalog and health systems, which allow
operators to see which nodes are in each service pool, as well as providing
insight into failing checks. Nerve simply deregisters nodes on failed checks,
providing limited operator insight. Synapse also configures HAProxy to perform
additional health checks. This causes all potential service clients to check for
liveness. With large fleets, this N-to-N style health checking may be prohibitively
expensive.
Terraform generally provides a much richer health checking system. Terraform supports
Nagios style plugins, enabling a vast catalog of checks to be used. It also
allows for service and host-level checks. There is also a "dead man's switch"
check that allows applications to easily integrate custom health checks. All of this
is also integrated into a Health and Catalog system with APIs enabling operator
to gain insight into the broader system.
In addition to the service discovery and health checking, Terraform also provides
an integrated key/value store for configuration and multi-datacenter support.
While it may be possible to configure SmartStack for multiple datacenters,
the central ZooKeeper cluster would be a serious impediment to a fault tolerant
deployment.

View File

@ -0,0 +1,61 @@
---
layout: "intro"
page_title: "Terraform vs. ZooKeeper, doozerd, etcd"
sidebar_current: "vs-other-zk"
---
# Terraform vs. ZooKeeper, doozerd, etcd
ZooKeeper, doozerd and etcd are all similar in their architecture.
All three have server nodes that require a quorum of nodes to operate (usually a simple majority).
They are strongly consistent, and expose various primitives that can be used
through client libraries within applications to build complex distributed systems.
Terraform works in a similar way within a single datacenter with only server nodes.
In each datacenter, Terraform servers require a quorum to operate
and provide strong consistency. However, Terraform has native support for multiple datacenters,
as well as a more complex gossip system that links server nodes and clients.
If any of these systems are used for pure key/value storage, then they all
roughly provide the same semantics. Reads are strongly consistent, and availability
is sacrificed for consistency in the face of a network partition. However, the differences
become more apparent when these systems are used for advanced cases.
The semantics provided by these systems are attractive for building
service discovery systems. ZooKeeper et al. provide only a primitive K/V store,
and require that application developers build their own system to provide service
discovery. Terraform provides an opinionated framework for service discovery, and
eliminates the guess work and development effort. Clients simply register services
and then perform discovery using a DNS or HTTP interface. Other systems
require a home-rolled solution.
A compelling service discovery framework must incorporate health checking and the
possibility of failures as well. It is not useful to know that Node A
provides the Foo service if that node has failed or the service crashed. Naive systems
make use of heartbeating, using periodic updates and TTLs. These schemes require work linear
to the number of nodes and place the demand on a fixed number of servers. Additionally, the
failure detection window is at least as long as the TTL. ZooKeeper provides ephemeral
nodes which are K/V entries that are removed when a client disconnects. These are more
sophisticated than a heartbeat system, but also have inherent scalability issues and add
client side complexity. All clients must maintain active connections to the ZooKeeper servers,
and perform keep-alives. Additionally, this requires "thick clients", which are difficult
to write and often result in difficult to debug issues.
Terraform uses a very different architecture for health checking. Instead of only
having server nodes, Terraform clients run on every node in the cluster.
These clients are part of a [gossip pool](/docs/internals/gossip.html), which
serves several functions including distributed health checking. The gossip protocol implements
an efficient failure detector that can scale to clusters of any size without concentrating
the work on any select group of servers. The clients also enable a much richer set of health checks to be run locally,
whereas ZooKeeper ephemeral nodes are a very primitive check of liveness. Clients can check that
a web server is returning 200 status codes, that memory utilization is not critical, there is sufficient
disk space, etc. The Terraform clients expose a simple HTTP interface and avoid exposing the complexity
of the system is to clients in the same way as ZooKeeper.
Terraform provides first class support for service discovery, health checking,
K/V storage, and multiple datacenters. To support anything more than simple K/V storage,
all these other systems require additional tools and libraries to be built on
top. By using client nodes, Terraform provides a simple API that only requires thin clients.
Additionally, the API can be avoided entirely by using configuration files and the
DNS interface to have a complete service discovery solution with no development at all.

View File

@ -0,0 +1,20 @@
//
// app.js
//
var APP = (function() {
function initialize (){
APP.Utils.runIfClassNamePresent('page-home', initHome);
}
function initHome() {
APP.Homepage.init();
}
//api
return {
initialize: initialize
}
})();

View File

@ -0,0 +1,101 @@
//
// app.js
//
var APP = (function() {
function initialize (){
APP.Utils.runIfClassNamePresent('page-home', initHome);
}
function initHome() {
APP.Homepage.init();
}
//api
return {
initialize: initialize
}
})();
;//
// util.js
//
var APP = APP || {};
APP.Utils = (function () {
return {
//check for mobile user agents
isMobile : (function(){
if( navigator.userAgent.match(/Android/i)
|| navigator.userAgent.match(/webOS/i)
|| navigator.userAgent.match(/iPhone/i)
//|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)
|| navigator.userAgent.match(/BlackBerry/i)
|| navigator.userAgent.match(/Windows Phone/i)
){
return true;
}
else {
return false;
}
})(),
runIfClassNamePresent: function(selector, initFunction) {
var elms = document.getElementsByClassName(selector);
if (elms.length > 0) {
initFunction();
}
}
}
}());;//homepage.js
var APP = APP || {};
(function () {
APP.Homepage = (function () {
return {
ui : null,
init: function () {
var _this = this;
//cache elements
this.ui = {
$doc: $(window),
$hero: $('#jumbotron'),
$collapse: $('.navbar-collapse')
}
this.addEventListeners();
},
addEventListeners: function(){
var _this = this;
if(APP.Utils.isMobile)
return;
_this.ui.$doc.scroll(function() {
//if collapseable menu is open dont do parrallax. It looks wonky. Bootstrap conflict
if( _this.ui.$collapse.hasClass('in'))
return;
var top = _this.ui.$doc.scrollTop(),
speedAdj = (top*0.8),
speedAdjOffset = speedAdj - top;
_this.ui.$hero.css('webkitTransform', 'translate(0, '+ speedAdj +'px)');
_this.ui.$hero.find('.container').css('webkitTransform', 'translate(0, '+ speedAdjOffset +'px)');
})
}
}
}());
}(jQuery, this));

View File

@ -0,0 +1 @@
var APP=function(){function a(){APP.Utils.runIfClassNamePresent("page-home",b)}function b(){APP.Homepage.init()}return{initialize:a}}(),APP=APP||{};APP.Utils=function(){return{isMobile:function(){return navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/webOS/i)||navigator.userAgent.match(/iPhone/i)||navigator.userAgent.match(/iPod/i)||navigator.userAgent.match(/BlackBerry/i)||navigator.userAgent.match(/Windows Phone/i)?!0:!1}(),runIfClassNamePresent:function(a,b){var c=document.getElementsByClassName(a);c.length>0&&b()}}}();var APP=APP||{};!function(){APP.Homepage=function(){return{ui:null,init:function(){this.ui={$doc:$(window),$hero:$("#jumbotron"),$collapse:$(".navbar-collapse")},this.addEventListeners()},addEventListeners:function(){var a=this;APP.Utils.isMobile||a.ui.$doc.scroll(function(){if(!a.ui.$collapse.hasClass("in")){var b=a.ui.$doc.scrollTop(),c=.8*b,d=c-b;a.ui.$hero.css("webkitTransform","translate(0, "+c+"px)"),a.ui.$hero.find(".container").css("webkitTransform","translate(0, "+d+"px)")}})}}}()}(jQuery,this);

View File

@ -0,0 +1,49 @@
//homepage.js
var APP = APP || {};
(function () {
APP.Homepage = (function () {
return {
ui : null,
init: function () {
var _this = this;
//cache elements
this.ui = {
$doc: $(window),
$hero: $('#jumbotron'),
$collapse: $('.navbar-collapse')
}
this.addEventListeners();
},
addEventListeners: function(){
var _this = this;
if(APP.Utils.isMobile)
return;
_this.ui.$doc.scroll(function() {
//if collapseable menu is open dont do parrallax. It looks wonky. Bootstrap conflict
if( _this.ui.$collapse.hasClass('in'))
return;
var top = _this.ui.$doc.scrollTop(),
speedAdj = (top*0.8),
speedAdjOffset = speedAdj - top;
_this.ui.$hero.css('webkitTransform', 'translate(0, '+ speedAdj +'px)');
_this.ui.$hero.find('.container').css('webkitTransform', 'translate(0, '+ speedAdjOffset +'px)');
})
}
}
}());
}(jQuery, this));

View File

@ -0,0 +1,33 @@
//
// util.js
//
var APP = APP || {};
APP.Utils = (function () {
return {
//check for mobile user agents
isMobile : (function(){
if( navigator.userAgent.match(/Android/i)
|| navigator.userAgent.match(/webOS/i)
|| navigator.userAgent.match(/iPhone/i)
//|| navigator.userAgent.match(/iPad/i)
|| navigator.userAgent.match(/iPod/i)
|| navigator.userAgent.match(/BlackBerry/i)
|| navigator.userAgent.match(/Windows Phone/i)
){
return true;
}
else {
return false;
}
})(),
runIfClassNamePresent: function(selector, initFunction) {
var elms = document.getElementsByClassName(selector);
if (elms.length > 0) {
initFunction();
}
}
}
}());

View File

@ -0,0 +1,158 @@
/**
* Classy - classy classes for JavaScript
*
* :copyright: (c) 2011 by Armin Ronacher.
* :license: BSD.
*/
;(function(undefined) {
var
CLASSY_VERSION = '1.4',
root = this,
old_class = root.Class,
disable_constructor = false;
/* we check if $super is in use by a class if we can. But first we have to
check if the JavaScript interpreter supports that. This also matches
to false positives later, but that does not do any harm besides slightly
slowing calls down. */
var probe_super = (function(){$super();}).toString().indexOf('$super') > 0;
function usesSuper(obj) {
return !probe_super || /\B\$super\b/.test(obj.toString());
}
/* helper function to set the attribute of something to a value or
removes it if the value is undefined. */
function setOrUnset(obj, key, value) {
if (value === undefined)
delete obj[key];
else
obj[key] = value;
}
/* gets the own property of an object */
function getOwnProperty(obj, name) {
return Object.prototype.hasOwnProperty.call(obj, name)
? obj[name] : undefined;
}
/* instanciate a class without calling the constructor */
function cheapNew(cls) {
disable_constructor = true;
var rv = new cls;
disable_constructor = false;
return rv;
}
/* the base class we export */
var Class = function() {};
/* restore the global Class name and pass it to a function. This allows
different versions of the classy library to be used side by side and
in combination with other libraries. */
Class.$noConflict = function() {
try {
setOrUnset(root, 'Class', old_class);
}
catch (e) {
// fix for IE that does not support delete on window
root.Class = old_class;
}
return Class;
};
/* what version of classy are we using? */
Class.$classyVersion = CLASSY_VERSION;
/* extend functionality */
Class.$extend = function(properties) {
var super_prototype = this.prototype;
/* disable constructors and instanciate prototype. Because the
prototype can't raise an exception when created, we are safe
without a try/finally here. */
var prototype = cheapNew(this);
/* copy all properties of the includes over if there are any */
if (properties.__include__)
for (var i = 0, n = properties.__include__.length; i != n; ++i) {
var mixin = properties.__include__[i];
for (var name in mixin) {
var value = getOwnProperty(mixin, name);
if (value !== undefined)
prototype[name] = mixin[name];
}
}
/* copy class vars from the superclass */
properties.__classvars__ = properties.__classvars__ || {};
if (prototype.__classvars__)
for (var key in prototype.__classvars__)
if (!properties.__classvars__[key]) {
var value = getOwnProperty(prototype.__classvars__, key);
properties.__classvars__[key] = value;
}
/* copy all properties over to the new prototype */
for (var name in properties) {
var value = getOwnProperty(properties, name);
if (name === '__include__' ||
value === undefined)
continue;
prototype[name] = typeof value === 'function' && usesSuper(value) ?
(function(meth, name) {
return function() {
var old_super = getOwnProperty(this, '$super');
this.$super = super_prototype[name];
try {
return meth.apply(this, arguments);
}
finally {
setOrUnset(this, '$super', old_super);
}
};
})(value, name) : value
}
/* dummy constructor */
var rv = function() {
if (disable_constructor)
return;
var proper_this = root === this ? cheapNew(arguments.callee) : this;
if (proper_this.__init__)
proper_this.__init__.apply(proper_this, arguments);
proper_this.$class = rv;
return proper_this;
}
/* copy all class vars over of any */
for (var key in properties.__classvars__) {
var value = getOwnProperty(properties.__classvars__, key);
if (value !== undefined)
rv[key] = value;
}
/* copy prototype and constructor over, reattach $extend and
return the class */
rv.prototype = prototype;
rv.constructor = rv;
rv.$extend = Class.$extend;
rv.$withData = Class.$withData;
return rv;
};
/* instanciate with data functionality */
Class.$withData = function(data) {
var rv = cheapNew(this);
for (var key in data) {
var value = getOwnProperty(data, key);
if (value !== undefined)
rv[key] = value;
}
return rv;
};
/* export the class */
root.Class = Class;
})();

8
website/source/javascripts/html5shiv.js vendored Executable file
View File

@ -0,0 +1,8 @@
/*
HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);

View File

@ -0,0 +1,58 @@
// Copyright (C) 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview
* Registers a language handler for the Go language..
* <p>
* Based on the lexical grammar at
* http://golang.org/doc/go_spec.html#Lexical_elements
* <p>
* Go uses a minimal style for highlighting so the below does not distinguish
* strings, keywords, literals, etc. by design.
* From a discussion with the Go designers:
* <pre>
* On Thursday, July 22, 2010, Mike Samuel <...> wrote:
* > On Thu, Jul 22, 2010, Rob 'Commander' Pike <...> wrote:
* >> Personally, I would vote for the subdued style godoc presents at http://golang.org
* >>
* >> Not as fancy as some like, but a case can be made it's the official style.
* >> If people want more colors, I wouldn't fight too hard, in the interest of
* >> encouragement through familiarity, but even then I would ask to shy away
* >> from technicolor starbursts.
* >
* > Like http://golang.org/pkg/go/scanner/ where comments are blue and all
* > other content is black? I can do that.
* </pre>
*
* @author mikesamuel@gmail.com
*/
PR['registerLangHandler'](
PR['createSimpleLexer'](
[
// Whitespace is made up of spaces, tabs and newline characters.
[PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
// Not escaped as a string. See note on minimalism above.
[PR['PR_PLAIN'], /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])+(?:\'|$)|`[^`]*(?:`|$))/, null, '"\'']
],
[
// Block comments are delimited by /* and */.
// Single-line comments begin with // and extend to the end of a line.
[PR['PR_COMMENT'], /^(?:\/\/[^\r\n]*|\/\*[\s\S]*?\*\/)/],
[PR['PR_PLAIN'], /^(?:[^\/\"\'`]|\/(?![\/\*]))+/i]
]),
['go']);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,30 @@
!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a=
b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&"-"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])),
h[1]>h[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l==="("?++h:"\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l==="("?(++h,d[h]||(a[f]="(?:")):"\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&&
(a[f]="\\"+d[l]);for(f=0;f<c;++f)"^"===a[f]&&"^"!==a[f+1]&&(a[f]="");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11,
f:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(""+i);n.push("(?:"+s(i)+")")}return RegExp(n.join("|"),j?"gi":"g")}function T(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)s[j]="\n",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]=
a)}var b=/(?:^|\s)nocode(?:\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join("").replace(/\n$/,""),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function U(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?V.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function C(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w==="string")f=!1;else{var h=b[z.charAt(0)];
if(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w="pln")}if((f=w.length>=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r=
g[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com",
/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+
s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,
q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d=
c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol");
r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a;
a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}),
["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q,
hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]);
p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1});
return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\??prettify\b/.test(o):m!==3||/\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&&
o.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=U(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue("white-space"):0)&&"pre"===o.substring(0,3);u=j.linenums;if(!(u=u==="true"||+u))u=(u=k.match(/\blinenums\b(?::(\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r=
{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):"function"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\blang(?:uage)?-([\w.]+)(?!\S)/,e=/\bprettyprint\b/,v=/\bprettyprinted\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i,
h={};g()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Y})})();}()

6
website/source/javascripts/respond.min.js vendored Executable file
View File

@ -0,0 +1,6 @@
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
window.matchMedia=window.matchMedia||function(a){"use strict";var c,d=a.documentElement,e=d.firstElementChild||d.firstChild,f=a.createElement("body"),g=a.createElement("div");return g.id="mq-test-1",g.style.cssText="position:absolute;top:-100em",f.style.background="none",f.appendChild(g),function(a){return g.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',d.insertBefore(f,e),c=42===g.offsetWidth,d.removeChild(f),{matches:c,media:a}}}(document);
/*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
(function(a){"use strict";function x(){u(!0)}var b={};a.respond=b,b.update=function(){},b.mediaQueriesSupported=a.matchMedia&&a.matchMedia("only all").matches,b.mediaQueriesSupported;var q,r,t,c=a.document,d=c.documentElement,e=[],f=[],g=[],h={},i=30,j=c.getElementsByTagName("head")[0]||d,k=c.getElementsByTagName("base")[0],l=j.getElementsByTagName("link"),m=[],n=function(){for(var b=0;l.length>b;b++){var c=l[b],d=c.href,e=c.media,f=c.rel&&"stylesheet"===c.rel.toLowerCase();d&&f&&!h[d]&&(c.styleSheet&&c.styleSheet.rawCssText?(p(c.styleSheet.rawCssText,d,e),h[d]=!0):(!/^([a-zA-Z:]*\/\/)/.test(d)&&!k||d.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&m.push({href:d,media:e}))}o()},o=function(){if(m.length){var a=m.shift();v(a.href,function(b){p(b,a.href,a.media),h[a.href]=!0,setTimeout(function(){o()},0)})}},p=function(a,b,c){var d=a.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),g=d&&d.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+b+"$2$3")},i=!g&&c;b.length&&(b+="/"),i&&(g=1);for(var j=0;g>j;j++){var k,l,m,n;i?(k=c,f.push(h(a))):(k=d[j].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1,f.push(RegExp.$2&&h(RegExp.$2))),m=k.split(","),n=m.length;for(var o=0;n>o;o++)l=m[o],e.push({media:l.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:f.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},s=function(){var a,b=c.createElement("div"),e=c.body,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",e||(e=f=c.createElement("body"),e.style.background="none"),e.appendChild(b),d.insertBefore(e,d.firstChild),a=b.offsetWidth,f?d.removeChild(e):e.removeChild(b),a=t=parseFloat(a)},u=function(a){var b="clientWidth",h=d[b],k="CSS1Compat"===c.compatMode&&h||c.body[b]||h,m={},n=l[l.length-1],o=(new Date).getTime();if(a&&q&&i>o-q)return clearTimeout(r),r=setTimeout(u,i),void 0;q=o;for(var p in e)if(e.hasOwnProperty(p)){var v=e[p],w=v.minw,x=v.maxw,y=null===w,z=null===x,A="em";w&&(w=parseFloat(w)*(w.indexOf(A)>-1?t||s():1)),x&&(x=parseFloat(x)*(x.indexOf(A)>-1?t||s():1)),v.hasquery&&(y&&z||!(y||k>=w)||!(z||x>=k))||(m[v.media]||(m[v.media]=[]),m[v.media].push(f[v.rules]))}for(var B in g)g.hasOwnProperty(B)&&g[B]&&g[B].parentNode===j&&j.removeChild(g[B]);for(var C in m)if(m.hasOwnProperty(C)){var D=c.createElement("style"),E=m[C].join("\n");D.type="text/css",D.media=C,j.insertBefore(D,n.nextSibling),D.styleSheet?D.styleSheet.cssText=E:D.appendChild(c.createTextNode(E)),g.push(D)}},v=function(a,b){var c=w();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},w=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}();n(),b.update=n,a.addEventListener?a.addEventListener("resize",x,!1):a.attachEvent&&a.attachEvent("onresize",x)})(this);

View File

@ -0,0 +1,35 @@
<div id="footer">
<div class="container">
<div class="footer-links">
<ul class="main-links nav navbar-nav rls-sb">
<li class="li-under"><a href="/intro/index.html">Intro</a></li>
<li class="active li-under"><a href="/docs/index.html">Docs</a></li>
<li class="li-under"><a href="/community.html">Community</a></li>
<li class="li-under"><a href="http://demo.terraform.io/">Demo</a></li>
</ul>
<ul class="buttons nav navbar-nav rls-sb">
<li class="first download outline-btn purple"><a href="/downloads.html">Download</a></li>
<li class="github outline-btn purple"><a href="https://github.com/hashicorp/terraform">Github</a></li>
</ul>
</div>
<div class="footer-logo">
<span></span>
</div>
<div class="footer-hashi os">
<span>&copy; 2014. A <a href="http://www.hashicorp.com">HashiCorp</a> Project.</span>
<a class="hashi-logo" href="http://www.hashicorp.com"><img src="/images/footer-hashicorp-logo.png"></a>
</div>
</div>
</div>
<script src="/javascripts/lib/jquery-2.0.3.min.js"></script>
<script src="/javascripts/lib/bootstrap.min.js"></script>
<script src="/javascripts/app/deploy/site.js"></script>
<script>
APP.initialize();
</script>
</body>
</html>

View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Service discovery and configuration made easy. Distributed, highly available, and datacenter-aware.">
<link rel="shortcut icon" href="/images/favicon.png">
<title><%= current_page.data.page_title ? "#{current_page.data.page_title} - " : "" %>Terraform</title>
<!-- Bootstrap core CSS -->
<%= stylesheet_link_tag "bootstrap.min" %>
<%= stylesheet_link_tag "main" %>
<!-- google fonts -->
<!-- <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700' rel='stylesheet' type='text/css'>
-->
<!-- typekit -->
<script type="text/javascript" src="//use.typekit.net/kgv0shi.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<%= javascript_include_tag "html5shiv", "respond.min" %>
<![endif]-->
<%= yield_content :head %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-50021714-1', 'terraform.io');
ga('send', 'pageview');
</script>
</head>
<body class="page-<%= current_page.data.page_title ? "#{current_page.data.page_title} layout-#{current_page.data.layout} page-sub" : "home layout-#{current_page.data.layout}" %>">
<div id="header" class="<%= current_page.data.page_title == "home" ? "" : "navbar-static-top" %>">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand logo" href="/">
<span></span>
</a>
</div>
<nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation">
<ul class="buttons nav navbar-nav navbar-right rls-sb">
<li class="first download outline-btn"><a href="/downloads.html">Download</a></li>
<li class="github outline-btn"><a href="https://github.com/hashicorp/terraform">Github</a></li>
</ul>
<ul class="main-links nav navbar-nav navbar-right rls-sb">
<li class="first li-under"><a href="/intro/index.html">Intro</a></li>
<li class="li-under"><a href="/docs/index.html">Docs</a></li>
<li class="li-under"><a href="/community.html">Community</a></li>
<li class="li-under"><a href="http://demo.terraform.io/">Demo</a></li>
</ul>
</nav>
</div>
</div>

View File

@ -0,0 +1,169 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("docs-home") %>>
<a href="/docs/index.html">Documentation Home</a>
</li>
<li<%= sidebar_current("docs-upgrading") %>>
<a href="/docs/upgrading.html">Upgrading and Compatibility</a>
<ul class="nav">
<li<%= sidebar_current("docs-upgrading-upgrading") %>>
<a href="/docs/upgrading.html">Upgrading Terraform</a>
</li>
<li<%= sidebar_current("docs-upgrading-compat") %>>
<a href="/docs/compatibility.html">Compatibility Promise</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-internals") %>>
<a href="/docs/internals/index.html">Terraform Internals</a>
<ul class="nav">
<li<%= sidebar_current("docs-internals-architecture") %>>
<a href="/docs/internals/architecture.html">Architecture</a>
</li>
<li<%= sidebar_current("docs-internals-consensus") %>>
<a href="/docs/internals/consensus.html">Consensus Protocol</a>
</li>
<li<%= sidebar_current("docs-internals-gossip") %>>
<a href="/docs/internals/gossip.html">Gossip Protocol</a>
</li>
<li<%= sidebar_current("docs-internals-sessions") %>>
<a href="/docs/internals/sessions.html">Sessions</a>
</li>
<li<%= sidebar_current("docs-internals-security") %>>
<a href="/docs/internals/security.html">Security Model</a>
</li>
<li<%= sidebar_current("docs-internals-jepsen") %>>
<a href="/docs/internals/jepsen.html">Jepsen Testing</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-commands") %>>
<a href="/docs/commands/index.html">Terraform Commands (CLI)</a>
<ul class="nav">
<li<%= sidebar_current("docs-commands-agent") %>>
<a href="/docs/commands/agent.html">agent</a>
</li>
<li<%= sidebar_current("docs-commands-forceleave") %>>
<a href="/docs/commands/force-leave.html">force-leave</a>
</li>
<li<%= sidebar_current("docs-commands-join") %>>
<a href="/docs/commands/join.html">join</a>
</li>
<li<%= sidebar_current("docs-commands-keygen") %>>
<a href="/docs/commands/keygen.html">keygen</a>
</li>
<li<%= sidebar_current("docs-commands-leave") %>>
<a href="/docs/commands/leave.html">leave</a>
</li>
<li<%= sidebar_current("docs-commands-members") %>>
<a href="/docs/commands/members.html">members</a>
</li>
<li<%= sidebar_current("docs-commands-monitor") %>>
<a href="/docs/commands/monitor.html">monitor</a>
</li>
<li<%= sidebar_current("docs-commands-info") %>>
<a href="/docs/commands/info.html">info</a>
</li>
</ul>
</li>
<li<%= sidebar_current("docs-agent") %>>
<a href="/docs/agent/basics.html">Terraform Agent</a>
<ul class="nav">
<li<%= sidebar_current("docs-agent-running") %>>
<a href="/docs/agent/basics.html">Running and Stopping</a>
</li>
<li<%= sidebar_current("docs-agent-dns") %>>
<a href="/docs/agent/dns.html">DNS Interface</a>
</li>
<li<%= sidebar_current("docs-agent-http") %>>
<a href="/docs/agent/http.html">HTTP API</a>
</li>
<li<%= sidebar_current("docs-agent-config") %>>
<a href="/docs/agent/options.html">Configuration</a>
</li>
<li<%= sidebar_current("docs-agent-services") %>>
<a href="/docs/agent/services.html">Service Definitions</a>
</li>
<li<%= sidebar_current("docs-agent-checks") %>>
<a href="/docs/agent/checks.html">Check Definitions</a>
</li>
<li<%= sidebar_current("docs-agent-encryption") %>>
<a href="/docs/agent/encryption.html">Encryption</a>
</li>
<li<%= sidebar_current("docs-agent-rpc") %>>
<a href="/docs/agent/rpc.html">RPC Protocol</a>
</li>
<li<%= sidebar_current("docs-agent-telemetry") %>>
<a href="/docs/agent/telemetry.html">Telemetry</a>
</li>
</ul>
<li<%= sidebar_current("docs-guides") %>>
<a href="/docs/guides/index.html">Guides</a>
<ul class="nav">
<li<%= sidebar_current("docs-guides-servers") %>>
<a href="/docs/guides/servers.html">Adding/Removing Servers</a>
</li>
<li<%= sidebar_current("docs-guides-bootstrapping") %>>
<a href="/docs/guides/bootstrapping.html">Bootstrapping</a>
</li>
<li<%= sidebar_current("docs-guides-dns-cache") %>>
<a href="/docs/guides/dns-cache.html">DNS Caching</a>
</li>
<li<%= sidebar_current("docs-guides-forwarding") %>>
<a href="/docs/guides/forwarding.html">DNS Forwarding</a>
</li>
<li<%= sidebar_current("docs-guides-external") %>>
<a href="/docs/guides/external.html">External Services</a>
</li>
<li<%= sidebar_current("docs-guides-leader") %>>
<a href="/docs/guides/leader-election.html">Leader Election</a>
</li>
<li<%= sidebar_current("docs-guides-datacenters") %>>
<a href="/docs/guides/datacenters.html">Multiple Datacenters</a>
</li>
<li<%= sidebar_current("docs-guides-outage") %>>
<a href="/docs/guides/outage.html">Outage Recovery</a>
</li>
</ul>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>

View File

@ -0,0 +1,17 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("downloads-terraform") %>>
<a href="/downloads.html">Download Terraform</a>
</li>
<li<%= sidebar_current("downloads-ui") %>>
<a href="/downloads_web_ui.html">Download Web UI</a>
</li>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>

View File

@ -0,0 +1,12 @@
<% wrap_layout :layout do %>
<div class="container">
<div class="col-md-4">
<%= yield_content :sidebar %>
</div> <!-- /col-md-4 -->
<div class="col-md-8" role="main">
<div class="bs-docs-section">
<%= yield %>
</div>
</div>
</div>
<% end %>

View File

@ -0,0 +1,84 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("what") %>>
<a href="/intro/index.html">What is Terraform?</a>
</li>
<li<%= sidebar_current("vs-other") %>>
<a href="/intro/vs/index.html">Terraform vs. Other Software</a>
<ul class="nav">
<li<%= sidebar_current("vs-other-zk") %>>
<a href="/intro/vs/zookeeper.html">ZooKeeper, doozerd, etcd</a>
</li>
<li<%= sidebar_current("vs-other-chef") %>>
<a href="/intro/vs/chef-puppet.html">Chef, Puppet, etc.</a>
</li>
<li<%= sidebar_current("vs-other-nagios-sensu") %>>
<a href="/intro/vs/nagios-sensu.html">Nagios, Sensu</a>
</li>
<li<%= sidebar_current("vs-other-skydns") %>>
<a href="/intro/vs/skydns.html">SkyDNS</a>
</li>
<li<%= sidebar_current("vs-other-smartstack") %>>
<a href="/intro/vs/smartstack.html">SmartStack</a>
</li>
<li<%= sidebar_current("vs-other-serf") %>>
<a href="/intro/vs/serf.html">Serf</a>
</li>
<li<%= sidebar_current("vs-other-custom") %>>
<a href="/intro/vs/custom.html">Custom Solutions</a>
</li>
</ul>
</li>
<li<%= sidebar_current("gettingstarted") %>>
<a href="/intro/getting-started/install.html">Getting Started</a>
<ul class="nav">
<li<%= sidebar_current("gettingstarted-install") %>>
<a href="/intro/getting-started/install.html">Install Terraform</a>
</li>
<li<%= sidebar_current("gettingstarted-agent") %>>
<a href="/intro/getting-started/agent.html">Run the Agent</a>
</li>
<li<%= sidebar_current("gettingstarted-services") %>>
<a href="/intro/getting-started/services.html">Services</a>
</li>
<li<%= sidebar_current("gettingstarted-join") %>>
<a href="/intro/getting-started/join.html">Terraform Cluster</a>
</li>
<li<%= sidebar_current("gettingstarted-checks") %>>
<a href="/intro/getting-started/checks.html">Health Checks</a>
</li>
<li<%= sidebar_current("gettingstarted-kv") %>>
<a href="/intro/getting-started/kv.html">Key/Value Data</a>
</li>
<li<%= sidebar_current("gettingstarted-ui") %>>
<a href="/intro/getting-started/ui.html">Web UI</a>
</li>
<li<%= sidebar_current("gettingstarted-nextsteps") %>>
<a href="/intro/getting-started/next-steps.html">Next Steps</a>
</li>
</ul>
</li>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>

View File

@ -0,0 +1,3 @@
<%= partial "layouts/header" %>
<%= yield %>
<%= partial "layouts/footer" %>

Some files were not shown because too many files have changed in this diff Show More