Compare commits

...

370 Commits

Author SHA1 Message Date
Michael Crosby
e99a99eb6e Bump to v0.5.2 2013-08-09 00:17:35 +00:00
Michael Crosby
df9712f1c8 Change daemon to listen on unix socket by default
Conflicts:
	docs/sources/api/docker_remote_api.rst
2013-08-09 00:16:43 +00:00
Jérôme Petazzoni
5c56b597a9 change network range to avoid conflict with EC2 DNS 2013-08-08 23:27:55 +00:00
Michael Crosby
f712e10cb2 Forbid certain paths within docker build ADD
Conflicts:
	buildfile_test.go
2013-08-08 23:22:14 +00:00
Michael Crosby
8a851af5e6 Merge pull request #1364 from dotcloud/bump_0.5.1
Bump to v0.5.1
2013-08-05 12:10:03 -07:00
Guillaume J. Charmes
3b89d13aaf Bump to v0.5.1 2013-07-31 10:53:36 -07:00
Victor Vieux
16225c473f Merge pull request #1291 from dotcloud/ensure_mount_commit
*Builder: Allow the commit of a non-started container
2013-07-30 05:19:17 -07:00
Victor Vieux
dd2f0d89bf Merge pull request #1238 from dotcloud/1237-improve_docker_top-feature
*Client: add ps args to docker top
2013-07-30 04:54:44 -07:00
Victor Vieux
0b57e4483a Merge branch 'master' into 1237-improve_docker_top-feature 2013-07-30 11:51:16 +00:00
Victor Vieux
f2dc49292f Merge pull request #1342 from dsissitka/patch-4
Fixed a couple of minor syntax errors.
2013-07-30 04:20:05 -07:00
Victor Vieux
a7ace535c3 Merge pull request #1339 from dhrp/docker-run-d-description
Updated the description of run -d
2013-07-30 04:15:41 -07:00
Victor Vieux
c99e8de5a4 Merge branch 'cleanup_signal_handling' of https://github.com/calavera/docker into calavera-cleanup_signal_handling 2013-07-30 11:14:36 +00:00
Victor Vieux
c06aa62bda Merge pull request #1306 from dotcloud/1294_fix_wrong_untag_using_id_rmi
Fix wrong untag using id rmi
2013-07-30 04:09:55 -07:00
dsissitka
9ba998312d Fixed a couple of minor syntax errors. 2013-07-30 01:39:29 -04:00
Daniel Mizyrycki
7d68afb2d2 Merge pull request #1209 from zimbatm/upstart-improvements
Upstart improvements
2013-07-29 18:28:40 -07:00
Daniel Mizyrycki
bfdf1839e0 Merge pull request #1312 from titanous/vagrant-bind
Bind daemon to 0.0.0.0 in Vagrant
2013-07-29 17:06:37 -07:00
Thatcher Peskens
5dc86d7bca Updated the description of run -d
The goal is to make it more clear this will give you the container id after run completes.

Since stdout is now standard on run, "docker run -d" is the best (or only) way to get the container ID returned from docker after a plain run, but the description (help) does not hint any such thing.
2013-07-29 14:17:15 -07:00
Guillaume J. Charmes
f35491190a Merge pull request #1233 from fmd/1136-environment-variables
+ Builder: CmdAdd and CmdEnv now respect Dockerfile-set ENV variables
2013-07-29 13:43:13 -07:00
David Calavera
10e37198aa Keep the loop to allow resizing more than once. 2013-07-29 11:13:59 -07:00
Guillaume J. Charmes
950d0312dc Merge pull request #1322 from calavera/prompt_without_defaults
Do not show empty parenthesis if the default configuration is missing.
2013-07-29 10:53:43 -07:00
David Calavera
c8ec36d1b9 Remove unnecessary signal conditional. 2013-07-29 10:28:41 -07:00
Solomon Hykes
97a2dc96f2 Remove deprecated copy from README 2013-07-28 12:57:09 -07:00
David Calavera
88b6ea993d Remove unused argument. 2013-07-27 10:17:57 -07:00
David Calavera
d4f7039793 Do not show empty parenthesis if the default configuration is missing. 2013-07-27 10:00:36 -07:00
Guillaume J. Charmes
4399f65fb8 Merge pull request #1318 from gaffo/compile_docs
Add required go version for compilation
2013-07-26 18:33:10 -07:00
Mike Gaffney
2d85a20c71 Add required go version for compilation 2013-07-26 18:29:27 -07:00
Guillaume J. Charmes
c01d17d77d Merge pull request #1313 from titanous/update-authors
Update AUTHORS
2013-07-26 17:04:05 -07:00
Guillaume J. Charmes
ed0ba04da6 Merge pull request #1316 from dotcloud/1295-mkdir_ADD_issue
- Builder: Create directories with 755 instead of 700 within ADD instruction
2013-07-26 15:12:45 -07:00
Guillaume J. Charmes
b15cfd3530 - Builder: Create directories with 755 instead of 700 within ADD instruction 2013-07-26 14:57:16 -07:00
Guillaume J. Charmes
a438d505ba Merge pull request #1272 from dotcloud/improve_registry_cookie
Make sure the cookie is used in all registry queries
2013-07-26 14:26:29 -07:00
Jonathan Rudenberg
5eb590e79d Update AUTHORS 2013-07-26 15:48:01 -04:00
Jonathan Rudenberg
bdc79ac8b2 Bind daemon to 0.0.0.0 in Vagrant. Fixes #1304 2013-07-26 15:45:00 -04:00
Solomon Hykes
a97d858b2a Clean up 'manifesto' in docs 2013-07-26 10:21:17 -07:00
Victor Vieux
e592f1b298 add regression test 2013-07-26 10:30:36 +00:00
Victor Vieux
513a567483 fix docs 2013-07-26 10:04:46 +00:00
Victor Vieux
faf103e6ec Merge pull request #1305 from gaffo/fix-spelling
Change reserve-compatibility to reverse-compatibility
2013-07-26 02:40:56 -07:00
Victor Vieux
e608296bc6 fix wrong untag when using rmi via id 2013-07-26 09:19:26 +00:00
Mike Gaffney
4ebe2cf348 Change reserve-compatibility to reverse-compatibility 2013-07-26 01:10:42 -07:00
Andy Rothfusz
422378cb85 Merge pull request #1274 from dhrp/headings_website
Removed website and updated headings.
2013-07-25 16:43:27 -07:00
Guillaume J. Charmes
594c818d85 Merge pull request #1281 from dotcloud/505-output_after_pipe-fix
- Runtime: Fixes #505 - Make sure all output is send on the network before closing
2013-07-25 13:01:31 -07:00
Fareed Dudhia
d86898b014 Fixes 1136; Reopened from 1175 with latest changes. 2013-07-25 19:45:49 +00:00
Guillaume J. Charmes
be087c9c82 Merge pull request #1293 from dotcloud/585_use_0755_instead_of_0700
use 0755 instead of 0700
2013-07-25 12:40:44 -07:00
Guillaume J. Charmes
9cc8b72a38 Merge pull request #1288 from dlintw/1286-improve-import-txz-description
Fixes #1286 improve-import-txz-description
2013-07-25 12:37:37 -07:00
Guillaume J. Charmes
3425c1b84c Make sure the cookie is used in all registry queries 2013-07-25 12:31:23 -07:00
Victor Vieux
1c509f4350 use 0755 instead of 0700 2013-07-25 15:45:15 +00:00
Victor Vieux
48833c7b07 add regression test + go fmt 2013-07-25 15:20:56 +00:00
Victor Vieux
f385f1860b ensure mount in commit 2013-07-25 15:18:34 +00:00
Victor Vieux
7df6c4b9ad Merge pull request #1283 from crosbymichael/username-not-set
Copy authConfigs on save so data is not modified
2013-07-25 06:31:34 -07:00
Daniel YC Lin
8f6b6d5784 Fixes #1286 2013-07-25 15:36:32 +08:00
Michael Crosby
0fc11699ab Add regression test for authConfig overwrite 2013-07-25 03:25:16 +00:00
Michael Crosby
9332c00ca5 Copy authConfigs on save so data is not modified
SaveConfig sets the Username and Password to an empty string
on save.  A copy of the authConfigs need to be made so that the
in memory data is not modified.
2013-07-25 00:35:52 +00:00
Guillaume J. Charmes
fd9ad1a194 Fixes #505 - Make sure all output is send on the network before closing 2013-07-24 15:48:51 -07:00
Guillaume J. Charmes
6ae3305040 Merge pull request #1277 from dotcloud/add_commands_unit_tests
* Tests: Reimplement old Commands unit tests in order to insure behavior
2013-07-24 15:24:51 -07:00
Andy Rothfusz
cc0e091a6b Merge pull request #1278 from metalivedev/logotweaks
Cleaned up long lines, switched graphic to Docker logo. General cleanup.
2013-07-24 10:37:45 -07:00
Victor Vieux
dfc076a123 Merge pull request #1243 from dotcloud/add_lxc_version_docker_info
*Client: LXC and Kernel version to docker info in debug mode
2013-07-24 07:44:23 -07:00
Victor Vieux
f6e1055727 Merge pull request #1064 from monnand/156-user-agent-header
Add user agent when calling the registry
2013-07-24 06:40:53 -07:00
Victor Vieux
6057e6ad70 add kernel version 2013-07-24 13:36:55 +00:00
Victor Vieux
ca39f15fa3 bump master 2013-07-24 13:28:01 +00:00
Victor Vieux
7953d1becb Merge pull request #1271 from dotcloud/1246_change_cfg_format
*Auth: Change dockercfg to json and support multiple auth remote
2013-07-24 05:29:51 -07:00
Victor Vieux
f4b41e1a6c fix tests 2013-07-24 12:28:22 +00:00
Victor Vieux
4bc3328e80 bump master 2013-07-24 12:18:53 +00:00
Victor Vieux
ebe17f57ff Merge pull request #1180 from dotcloud/1167_events_endpoint-feature
*Api: Add the /events endpoint
*Client: Add the docker events command
2013-07-24 04:53:36 -07:00
Victor Vieux
ee05f97c9a Merge branch 'master' into 1167_events_endpoint-feature 2013-07-24 11:49:04 +00:00
Andy Rothfusz
78c02d038f Cleaned up long lines, switched graphic to Docker logo. General cleanup. 2013-07-23 18:13:53 -07:00
Guillaume J. Charmes
bc823acc25 Reimplement old Commands unit tests in order to insure behavior 2013-07-23 17:27:49 -07:00
Daniel Mizyrycki
c21c5afe00 Merge pull request #1147 from dotcloud/1104-testing-static
testing, issue #1104: Make the test use static flags
2013-07-23 17:07:36 -07:00
Nan Monnand Deng
1ae54707a0 versionCheckers()->versionInfos(). 2013-07-23 17:17:31 -04:00
Nan Monnand Deng
ede1e6d475 Rename: VersionChecker->VersionInfo. 2013-07-23 17:05:13 -04:00
Thatcher Peskens
e701dce339 Docs: Fixed navigaton links to about page and community page
Website: Removed the website sources from the repo. The website sources are now hosted on github.com/dotcloud/www.docker.io/
2013-07-23 13:05:06 -07:00
Victor Vieux
a93a87f64a Merge branch 'stfp-858-disable-network-configuration' 2013-07-23 19:55:50 +00:00
Victor Vieux
7aba68cd54 update AUTHORS 2013-07-23 19:55:38 +00:00
Victor Vieux
dfc64d157a Merge pull request #1241 from ryfow/patch-1
Make the ENTRYPOINT example work
2013-07-23 08:45:04 -07:00
Victor Vieux
a41384ad73 add die event 2013-07-23 15:42:34 +00:00
Victor Vieux
ed7a4236b3 Add tests for the api 2013-07-23 15:42:34 +00:00
Victor Vieux
040c3b50d0 use non-blocking channel to prevent dead-lock and add test for server 2013-07-23 15:42:34 +00:00
Victor Vieux
8b3519c5f7 getEvents a bit simpler 2013-07-23 15:42:34 +00:00
Victor Vieux
ec559c02b8 add docs 2013-07-23 15:42:34 +00:00
Victor Vieux
2e4d4c9f60 add since for polling, rename some vars 2013-07-23 15:41:19 +00:00
Victor Vieux
b8d52ec266 add timestamp and change untagged -> untag 2013-07-23 15:41:19 +00:00
Victor Vieux
b5da816487 basic version of the /events endpoint 2013-07-23 15:41:19 +00:00
Victor Vieux
3bae188b8d change dockercfg to json and support multiple auth remote 2013-07-23 15:07:18 +00:00
Victor Vieux
8165e51ecc Merge branch '858-disable-network-configuration' of https://github.com/stfp/docker into stfp-858-disable-network-configuration 2013-07-23 08:44:12 +00:00
Thatcher
9a15db21a6 Merge pull request #1269 from dhrp/new-website-links
Added new docker logo to the documentation header, and added other links to docs header. Tnx @keeb !
2013-07-22 20:48:29 -07:00
Thatcher Peskens
58a1c5720a Added new docker logo to the documentation header, and added other links. 2013-07-22 20:26:40 -07:00
Stefan Praszalowicz
bc172e5e5f Invert network disable flag and logic (unbreaks TestAllocate*PortLocalhost) 2013-07-22 19:00:35 -07:00
Solomon Hykes
6745bdd0b3 Typo in 3rd-party 2013-07-22 18:39:58 -07:00
Solomon Hykes
5714f0a74e Hack: completed step 12 of the bootcamp 2013-07-22 18:36:36 -07:00
Solomon Hykes
ce43f4af1c Hack: first draft of the maintainer boot camp. Work in progress! 2013-07-22 18:32:55 -07:00
Victor Vieux
5d1609f5a2 Merge pull request #1265 from dotcloud/better-bridge-defaults
*Network: Improve default network configuration
2013-07-22 13:54:35 -07:00
Solomon Hykes
4714f102d7 Allocate a /16 IP range by default, with fallback to /24. Try a total of 12 ranges instead of 3. 2013-07-22 12:06:24 -07:00
Guillaume J. Charmes
a675da65e9 Merge pull request #1262 from dotcloud/1253_add_directory_check
* Runtime: fix error message when invalid directory
2013-07-22 11:54:22 -07:00
Victor Vieux
e39755666b Merge pull request #1236 from dotcloud/1234_overwrites_expose-fix
*Builder: fix overwrites EXPOSE
2013-07-22 09:51:11 -07:00
Victor Vieux
9adba5e2e6 Merge pull request #1264 from dotcloud/fix_tests_env
fix test env
2013-07-22 09:26:34 -07:00
Victor Vieux
5c1af383eb fix test env 2013-07-22 16:26:05 +00:00
Victor Vieux
c81662eae4 Merge branch 'master' into 1237-improve_docker_top-feature
Conflicts:
	docs/sources/api/docker_remote_api.rst
2013-07-22 16:22:11 +00:00
Victor Vieux
8ea9ccf3a7 Merge pull request #1244 from dotcloud/1020_add_variable
*Runtime: Add container=lxc in default env
2013-07-22 09:17:30 -07:00
Victor Vieux
74a2b13687 fix error message when invalid directory 2013-07-22 14:52:05 +00:00
Victor Vieux
4e7f2b757e Merge pull request #1158 from cespare/1142-docker-add-fix
*Buildfile: determine a filename from a URL if the destination is a directory
2013-07-22 07:07:04 -07:00
Ken Cochrane
2bba279cf1 Merge pull request #1259 from dsissitka/patch-3
*Documentation: Updated the stop command's docs.
2013-07-22 06:59:02 -07:00
Ken Cochrane
56da77a548 Merge pull request #1258 from dsissitka/patch-2
* Documentation: Added top to the list of commands in the sidebar.
2013-07-22 06:58:09 -07:00
Victor Vieux
494b575213 Merge pull request #1255 from dsissitka/patch-1
Fixed a couple of minor syntax errors.
2013-07-22 06:45:25 -07:00
Caleb Spare
c383d59880 Update ADD documentation to specify new behavior. 2013-07-21 23:32:06 -07:00
Caleb Spare
416fdaa3d5 Remove some trailing whitespace. 2013-07-21 23:32:06 -07:00
Caleb Spare
2b0ebf5d32 Buildfile: for ADD command, determine filename from URL.
This is used if the destination is a directory. This makes the URL
download behavior more closely match file copying.

Fixes #1142.
2013-07-21 23:32:06 -07:00
Caleb Spare
f236e62d9d Test pulling remote files using ADD in a buildfile. 2013-07-21 23:32:01 -07:00
Stefan Praszalowicz
964e826a9b Document -b none 2013-07-21 18:01:52 -07:00
Stefan Praszalowicz
49673fc45c Support completely disabling network configuration with docker -d -b none 2013-07-21 17:49:09 -07:00
Stefan Praszalowicz
3342bdb331 Support networkless containers with new docker run option '-n' 2013-07-21 17:11:47 -07:00
David Sissitka
1d02a7ffb6 Updated the stop command's docs. 2013-07-21 19:00:18 -04:00
dsissitka
788935175e Added top to the list of commands in the sidebar. 2013-07-21 18:30:51 -04:00
dsissitka
32663bf431 Fixed a couple of minor syntax errors. 2013-07-20 21:27:55 -04:00
Guillaume J. Charmes
e3be2e959b Merge pull request #1242 from dotcloud/remove_usage_from_test
remove usage from tests
2013-07-19 14:07:24 -07:00
Victor Vieux
67f1e3f5ed add container=lxc in default env 2013-07-19 17:22:16 +00:00
Andy Rothfusz
23ea9b8968 Merge pull request #1235 from metalivedev/cleandocbld
Make docs build without warnings or errors. Minor additional cleanup.
2013-07-19 09:44:53 -07:00
Victor Vieux
921c6994b1 add LXC version to docker info in debug mode 2013-07-19 16:36:23 +00:00
Victor Vieux
ea12588524 remove usage from tests 2013-07-19 15:56:00 +00:00
Ryan Fowler
e8ad82f9ba Make the ENTRYPOINT example work
The incantation listed in the ENTRYPOINT example didn't actually pass the arguments to your script. Changing the definition to an array fixes this.
2013-07-19 10:11:21 -05:00
Victor Vieux
6e2e4cad73 Merge pull request #1204 from dotcloud/tests-less-copypaste
Hack: use helper functions in tests for less copy-pasting
2013-07-19 07:55:04 -07:00
Victor Vieux
2e0e455fa6 rebase master 2013-07-19 14:48:32 +00:00
Victor Vieux
d93742fe9a Merge pull request #1239 from dotcloud/fix_utils_tests
fix error in utils tests
2013-07-19 06:59:07 -07:00
Victor Vieux
2e3b660dd0 fix error in utils tests 2013-07-19 13:56:36 +00:00
Victor Vieux
0bd534adcf Merge pull request #1211 from dotcloud/new_logs
*Runtime: Logs are now synchronised
2013-07-19 06:43:29 -07:00
Victor Vieux
e59dd2c62c Merge pull request #1159 from unclejack/add_container_id_file_to_run
*Client: Add support for container ID files (a la pidfile)
2013-07-19 06:11:22 -07:00
unclejack
25be79208a create the cidfile before creating the container
This change makes docker attempt to create the container ID file and
open it before attempting to create the container. This avoids leaving
a stale container behind if docker has failed to create and open the
container ID file.

The container ID is written to the file after the container is created.
2013-07-19 16:03:45 +03:00
unclejack
2a3b91e3b6 docs - add example for cidfile 2013-07-19 16:03:45 +03:00
unclejack
221ee504aa docs - add cidfile flag to run docs 2013-07-19 16:03:45 +03:00
unclejack
64e74cefb7 add support for container ID files (a la pidfile) 2013-07-19 16:03:45 +03:00
Victor Vieux
eb4a0271fb bump api version to 1.4 2013-07-19 10:34:55 +00:00
Victor Vieux
cfec1c3e1b add ps args to docker top 2013-07-19 10:06:32 +00:00
Victor Vieux
2b5386f039 add regression test from @crosbymichael 2013-07-19 03:01:39 +00:00
Victor Vieux
a0eec14c7d fix overwrites EXPOSE 2013-07-19 02:47:35 +00:00
Andy Rothfusz
54f9cdb0c3 Make docs build without warnings or errors. Minor additional cleanup. 2013-07-18 19:04:51 -07:00
Guillaume J. Charmes
d6fb313220 Merge pull request #1207 from crosbymichael/819-use-persistent-volume
* Runtime: Do not overwrite container volumes from config
2013-07-18 18:51:00 -07:00
Daniel Mizyrycki
0aa2470c76 Merge pull request #1232 from dotcloud/1217-testing-coverage
Testing, issue #1217: Add coverage testing into docker-ci
2013-07-18 14:27:37 -07:00
Victor Vieux
edc68f84f3 Merge pull request #1230 from dotcloud/switch_dev
switch version to -dev
2013-07-18 13:50:40 -07:00
Victor Vieux
0089dd05e9 switch version to -dev 2013-07-18 20:50:04 +00:00
Victor Vieux
51f6c4a737 Merge pull request #1227 from dotcloud/bump_0.5.0
Bump to 0.5.0
2013-07-18 11:51:29 -07:00
Nan Monnand Deng
cd209f406e documentation. 2013-07-18 14:22:49 -04:00
Andy Rothfusz
f4eaec3e1e Merge pull request #1226 from metalivedev/easydockerfile
Make dockerfile docs easier to find. Clean up formatting.
2013-07-18 10:14:22 -07:00
Victor Vieux
b083418257 change -b -> -v and add udp example 2013-07-18 16:25:14 +00:00
Victor Vieux
5794857f7a Merge pull request #1169 from crosbymichael/buildfile-tests
Add unit tests for buildfile config instructions
2013-07-18 08:35:23 -07:00
Michael Crosby
e7f3f6fa5a Add unit tests for buildfile config instructions
Add tests for instructions in the buildfile that
modify the config of the resulting image.
2013-07-18 05:37:28 -09:00
Victor Vieux
1b0fd7ead3 add debug and simplify docker logs 2013-07-18 13:29:40 +00:00
Victor Vieux
a926cd4d88 add legacy support 2013-07-18 13:25:47 +00:00
Andy Rothfusz
aa5671411b Make dockerfile docs easier to find. Clean up formatting. 2013-07-17 18:56:40 -07:00
Victor Vieux
f8dfd0aa5e Merge pull request #1225 from dotcloud/hotfix_docker_rmi
*Runtime: improve docker rmi via id
2013-07-17 14:31:56 -07:00
Andy Rothfusz
3dbf9c6560 Merge pull request #1219 from metalivedev/docs-repoupdate
Update docs with 0.5 repository information.
2013-07-17 13:53:12 -07:00
Guillaume J. Charmes
de563a3ea3 Merge pull request #1194 from crosbymichael/build-verbose
* Builder: Add verbose output to docker build
2013-07-17 12:53:06 -07:00
Victor Vieux
9cf2b41c05 change rm usage in docs 2013-07-17 19:24:54 +00:00
Victor Vieux
f310b875f8 Merge branch 'master' of https://github.com/kencochrane/docker into kencochrane-master 2013-07-17 19:23:06 +00:00
Solomon Hykes
ac14c463d5 Changed date on changelog 2013-07-17 11:51:26 -07:00
Guillaume J. Charmes
578e888915 Merge pull request #1212 from dotcloud/merge_v_b_options
* Runtime: Merge -b and -v options
2013-07-17 11:43:47 -07:00
Victor Vieux
5231bf3653 Merge pull request #1222 from lopter/master
Always stop the opposite goroutine in network_proxy.go (closes #1213)
2013-07-17 11:40:33 -07:00
Solomon Hykes
8af945f353 Small changes in changelog wording 2013-07-17 11:39:38 -07:00
Ken Cochrane
d0e8ca1257 updated with notes from @vieux 2013-07-17 13:46:11 -04:00
Victor Vieux
5a934fc923 fix docker rmi via id 2013-07-17 15:48:53 +00:00
Louis Opter
c766d064ac Always stop the opposite goroutine in network_proxy.go (closes #1213) 2013-07-17 01:05:11 -07:00
Andy Rothfusz
0356081c0a Update repository information. 2013-07-16 17:04:41 -07:00
Daniel Mizyrycki
6e8bfc8d12 Testing, issue #1217: Add coverage testing into docker-ci 2013-07-16 13:45:43 -07:00
Guillaume J. Charmes
18e91d5f85 Update docs 2013-07-16 10:14:21 -07:00
Guillaume J. Charmes
1004d57b85 Hotfix: make sure ./utils tests pass 2013-07-15 17:58:23 -07:00
Nick Stinemates
f9e4ef5eb0 Merge pull request #1210 from dotcloud/improve_configmerge
improve mergeconfig, ...
2013-07-15 18:04:12 -07:00
Guillaume J. Charmes
eefbadd230 Merge -b and -v options 2013-07-15 17:51:32 -07:00
Guillaume J. Charmes
bc21b3ebf0 Bump version to 0.5.0 2013-07-15 14:57:52 -07:00
Solomon Hykes
608fb2a21e Merge pull request #1184 from dotcloud/1176-packaging-release
Hack: document PPA release step
2013-07-15 13:59:55 -07:00
Michael Crosby
92cbb7cc80 Do not overwrite container volumes from config
Fixes #819 Use same persistent volume when a container is restarted
2013-07-15 11:59:11 -09:00
Solomon Hykes
45050d9887 Merge pull request #1188 from dotcloud/1174-packaging-binary
Packaging: add pure binary to docker release
2013-07-15 13:59:06 -07:00
Daniel Mizyrycki
75a0052e64 packaging, issue #1176: Document PPA release step 2013-07-15 12:13:51 -07:00
Guillaume J. Charmes
c8efd08384 Merge pull request #1208 from crosbymichael/1201-rw-volumes-from
- Volumes: Copy VolumesRW values when using --volumes-from
2013-07-15 10:59:51 -07:00
Guillaume J. Charmes
454cd147fb Merge pull request #1096 from dotcloud/remove_os_user
* Runtime: Remove the os.user dependency and manually lookup /etc/passwd instead
2013-07-15 10:19:09 -07:00
Guillaume J. Charmes
e41507bde2 Add unit test to check wrong uid case 2013-07-15 10:05:09 -07:00
Victor Vieux
599f85d4e4 store both logs in a same file, as JSON 2013-07-15 16:17:58 +00:00
Victor Vieux
5756ba9bc4 Merge branch 'master' into new_logs 2013-07-15 13:57:54 +00:00
Victor Vieux
193a7e1dc1 improve mergeconfig, if dns, portspec, env or volumes specify in docker run, apend and not replace 2013-07-15 13:12:33 +00:00
Jonas Pfenniger
0900d3b7a6 docker.upstart: use the same start/stop events as sshd
Is probably more solid
2013-07-15 11:41:19 +01:00
Jonas Pfenniger
24dd50490a docker.upstart: avoid spawning a sh process
start script / end script create an intermediate sh process.
2013-07-15 11:40:35 +01:00
Michael Crosby
5ae8c7a985 Copy VolumesRW values when using --volumes-from
Fixes #1201
2013-07-14 18:23:20 -09:00
Victor Vieux
9b57f9187b Merge pull request #1200 from ToothlessGear/fix-whitespaces_progessbar
Fix progressbar, without messing up other outputs
2013-07-13 08:50:50 -07:00
Victor Vieux
50e45b485f Merge pull request #1190 from dotcloud/1189-add_debug_error
* RemoteAPI: Improve debug
2013-07-13 08:15:59 -07:00
Victor Vieux
2051ebc0eb Merge pull request #1198 from dotcloud/fix_pull_tag
Fixed tag option for "docker pull" (the option was ignored)
2013-07-13 08:14:47 -07:00
Solomon Hykes
080243f040 Hack: use helper functions in tests for less copy-pasting 2013-07-12 17:56:55 -07:00
Guillaume J. Charmes
933b9d44e1 Merge pull request #1054 from nickstenning/getimage-by-tag
* Runtime: Reverse priority of tag lookup in TagStore.GetImage
2013-07-12 16:15:04 -07:00
Nick Stenning
44b3e8d51b Reverse priority of tag lookup in TagStore.GetImage
Currently, if you have the following images:

    foo/bar      1       23b27d50fb49
    foo/bar      2       f2b86ec3fcc4

And you issue the following command:

    docker tag foo/bar:2 foo/bar latest

docker will tag the "wrong" image, because the image id for foo/bar:1 starts
with a "2". That is, you'll end up with the following:

    foo/bar      1       23b27d50fb49
    foo/bar      2       f2b86ec3fcc4
    foo/bar      latest  23b27d50fb49

This commit reverses the priority given to tags vs. image ids in the
construction `<user>/<repo>:<tagOrId>`, meaning that if a tag that is an exact
match for the specified `tagOrId`, it will be tagged in preference to an image
with an id that happens to start with the correct character sequence.
2013-07-12 23:56:36 +01:00
Daniel Mizyrycki
9bf8ad741f Merge pull request #1083 from hukeli/debian
Keep debian package up-to-date
2013-07-12 15:24:37 -07:00
Daniel Mizyrycki
9913ebbe21 Merge pull request #1203 from dotcloud/1202-packaging-debian
Packaging, issue #1202: Upgrade vagrantfile go in debian packaging
2013-07-12 15:11:57 -07:00
Daniel Mizyrycki
c7a48e91d8 Packaging, issue #1202: Upgrade vagrantfile go in debian packaging 2013-07-12 15:06:12 -07:00
Solomon Hykes
2cbf2200ac Merge pull request #1195 from dotcloud/tests-cleanup
* Hack: tests cleanup
2013-07-12 14:51:59 -07:00
Marcus Farkas
bac5772312 *Client: Fix the progressbar, without manipulating other outputs
Prior this commit, 'docker images' and other cmd's, which used utils.HumanSize(),
showed unnecessary whitespaces.
Formatting of progress has been moved to FormatProgess(), justifing the string
directly in the template.
2013-07-12 20:15:25 +02:00
Marcus Farkas
a6e5a397bd Revert "Client: better progressbar output"
This reverts commit 3ac68f1966.
2013-07-12 20:08:45 +02:00
Ken Cochrane
364f48d6c7 updated the rmi command docs, the had typos 2013-07-12 14:05:26 -04:00
Ken Cochrane
4174e7aa7a updated the help commands on a few commands that were not correct 2013-07-12 13:55:26 -04:00
Guillaume J. Charmes
eb38750d99 Remove the os.user dependency and manually lookup /etc/passwd instead 2013-07-12 10:49:47 -07:00
Sam Alba
cd0fef633c Fixed tag option for "docker pull" (the option was ignored) 2013-07-12 10:42:54 -07:00
Michael Crosby
d0c73c28df Add param to api docs for verbose build output 2013-07-12 06:22:56 -09:00
Victor Vieux
8e6c249e48 Merge pull request #1197 from crosbymichael/buildfile-doc-ordering
Fix Docker Builder documentation section numbers
2013-07-12 05:27:47 -07:00
Victor Vieux
752f99e8a1 Merge pull request #977 from dotcloud/966-improve_docker_login_parameters-feature
* Client: Add options to docker login to be able to use it via script
2013-07-12 05:07:25 -07:00
Victor Vieux
a909223ee2 Merge pull request #1102 from dotcloud/1098-store_hostconfig_tmp
* Runtime: bind mounts are now preserved upon container restart
2013-07-12 05:04:10 -07:00
Victor Vieux
8ff271fc74 Merge pull request #1192 from dotcloud/docker_port-fix
hotfix: fix broken docker port
2013-07-12 04:57:53 -07:00
Victor Vieux
9dfac1dd65 Merge pull request #1055 from dotcloud/list_container_processes-feature
* RemoteApi: /top to list running processes in a container
* Client: docker top to list running processes in a container
2013-07-12 04:56:12 -07:00
Victor Vieux
a8a6848ce0 fix tests regarding the new test image 2013-07-12 11:54:53 +00:00
Victor Vieux
9232d1ef62 Merge branch 'master' into list_container_processes-feature 2013-07-12 11:47:27 +00:00
Michael Crosby
90483dc912 Fix Docker Builder documentation numbering 2013-07-11 16:41:19 -09:00
Solomon Hykes
6bdb6f226b Simplify unit tests code with mkRuntime() 2013-07-11 17:59:25 -07:00
Solomon Hykes
2ac1141980 Don't leave broken, commented out tests lying around. 2013-07-11 17:58:45 -07:00
Michael Crosby
1104d443cc Revert changes from PR 1030
With streaming output of the build
changes in 1030 are no longer required.
2013-07-11 15:52:08 -09:00
Michael Crosby
49044a9608 Fix buildfile tests after rebase 2013-07-11 15:37:26 -09:00
Guillaume J. Charmes
71d2ff4946 Hotfix: check the length of entrypoint before comparing. 2013-07-11 17:31:07 -07:00
Michael Crosby
474191dd7b Add verbose output to docker build
Verbose output is enabled by default and
the flag -q can be used to suppress the verbose output.
2013-07-11 15:27:33 -09:00
Guillaume J. Charmes
637eceb6a7 Merge pull request #1124 from crosbymichael/buildfile-volumes
+ Builder: Add VOLUME instruction to buildfile
2013-07-11 17:16:57 -07:00
Victor Vieux
976428f505 change output 2013-07-11 21:04:23 +02:00
Victor Vieux
affe7caf78 fix broken docker port 2013-07-11 19:28:15 +02:00
Victor Vieux
941e3e2ef0 wip 2013-07-11 17:18:28 +00:00
Victor Vieux
b7937e268f add debug for error in the server 2013-07-11 12:21:43 +00:00
Louis Opter
5a411fa38e Make the TestAllocate{UDP,TCP}PortLocalhost more reliable
- For the TCP test try again if socat wasn't listening yet;
- For the UDP test raise the timeout to a minute to workaround what
  seems to be an issue with Linux.
2013-07-10 18:25:53 -07:00
Daniel Mizyrycki
bf26ae03cf Packaging, issue #1174: Add pure binary to docker release 2013-07-10 17:39:00 -07:00
Andy Rothfusz
3363cd5cd0 Merge pull request #1178 from dotcloud/fix-dev-environment
Fix outdated docs explaining how to setup a dev environment
2013-07-10 16:53:22 -07:00
Daniel Mizyrycki
5c49a61353 Merge pull request #1183 from dotcloud/960-packaging-PPA
Packaging, issue #960: Document PUBLISH_PPA for staging/production release
2013-07-10 16:16:31 -07:00
Daniel Mizyrycki
f83c31e188 Packaging, issue #960: Document PUBLISH_PPA for staging/production release 2013-07-10 16:06:49 -07:00
Louis Opter
8f36467107 Raise the timeouts for the TCP/UDP localhost proxy tests
Sometimes these tests fail, let's see if that improves the situation.
2013-07-10 16:05:14 -07:00
Nan Monnand Deng
73e79a3310 reduce the number of string copy operations. 2013-07-10 18:59:43 -04:00
Nan Monnand Deng
34cf976866 format in the user agent header should follow RFC 2616 2013-07-10 18:59:43 -04:00
Nan Monnand Deng
e832b01349 Removed an unnecessary nil assignment 2013-07-10 18:56:49 -04:00
Nan Monnand Deng
26c8eae6fe Removed an unnecessary error check. 2013-07-10 18:56:49 -04:00
Nan Monnand Deng
d40efc4648 added client's kernel version 2013-07-10 18:56:49 -04:00
Nan Monnand Deng
5705a49308 Insert version checkers when call NewRegistry() 2013-07-10 18:56:49 -04:00
Nan Monnand Deng
65185a565b added APIVersion when call NewRegistry 2013-07-10 18:53:38 -04:00
Nan Monnand Deng
1bb8f60d5a inserted setUserAgent in each HTTP request 2013-07-10 18:49:01 -04:00
Nan Monnand Deng
1d01189f04 Added version checker interface 2013-07-10 18:49:01 -04:00
Louis Opter
8e49cb453f Merge pull request #1181 from dotcloud/export_portmapping
Export PortMapping in container.go
2013-07-10 14:24:20 -07:00
Michael Crosby
40f1e4edbe Rebased changes buildfile_test 2013-07-10 07:12:57 -09:00
Michael Crosby
1267e15b0f Add unittest for volume config verification 2013-07-10 06:59:16 -09:00
Michael Crosby
eb9fef2c42 Add VOLUME instruction to buildfile 2013-07-10 06:59:16 -09:00
Victor Vieux
43b346d93b Merge pull request #1151 from alex/patch-1
Replaced gendered language in the README
2013-07-10 07:52:30 -07:00
Victor Vieux
d918c7d9de export portmapping in network.go 2013-07-10 14:09:35 +00:00
Victor Vieux
e962e9edcf Merge pull request #1168 from dotcloud/standalone_registry
* Server: Allow push on standalone registry
2013-07-10 04:14:23 -07:00
Victor Vieux
b7a62f1f1b Merge pull request #1177 from lopter/udp-support-final
* Network: Add UDP support
2013-07-10 03:55:18 -07:00
Victor Vieux
2e5d1a2d48 Merge pull request #1164 from dotcloud/1162-import_hangs-fix
* Runtime: Untar is now faster
2013-07-10 03:37:24 -07:00
Louis Opter
fac0d87d00 Add support for UDP (closes #33)
API Changes
-----------

The port notation is extended to support "/udp" or "/tcp" at the *end*
of the specifier string (and defaults to tcp if "/tcp" or "/udp" are
missing)

`docker ps` now shows UDP ports as "frontend->backend/udp". Nothing
changes for TCP ports.

`docker inspect` now displays two sub-dictionaries: "Tcp" and "Udp",
under "PortMapping" in "NetworkSettings".

Theses changes stand true for the values returned by the HTTP API too.

This changeset will definitely break tools built upon the API (or upon
`docker inspect`). A less intrusive way to add UDP ports in `docker
inspect` would be to simply add "/udp" for UDP ports but it will still
break existing applications which tries to convert the whole field to an
integer. I believe that having two TCP/UDP sub-dictionaries is better
because it makes the whole thing more clear and more easy to parse right
away (i.e: you don't have to check the format of the string, split it
and convert the right part to an integer)

Code Changes
------------

Significant changes in network.go:

- A second PortAllocator is instantiated for the UDP range;
- PortMapper maintains separate mapping for TCP and UDP;
- The extPorts array in NetworkInterface is now an array of Nat objects
  (so we can know on which protocol a given port was mapped when
  NetworkInterface.Release() is called);
- TCP proxying on localhost has been moved away in network_proxy.go.

localhost proxy code rewrite in network_proxy.go:

We have to proxy the traffic between localhost:frontend-port and
container:backend-port because Netfilter doesn't work properly on the
loopback interface and DNAT iptable rules aren't applied there.

- Goroutines in the TCP proxying code are now explicitly stopped when
  the proxy is stopped;
- UDP connection tracking using a map (more infos in [1]);
- Support for IPv6 (to be more accurate, the code is transparent to the
  Go net package, so you can use, tcp/tcp4/tcp6/udp/udp4/udp6);
- Single Proxy interface for both UDP and TCP proxying;
- Full test suite.

[1] https://github.com/dotcloud/docker/issues/33#issuecomment-20010400
2013-07-09 17:42:35 -07:00
Solomon Hykes
a839b36e55 Fix outdated docs explaining how to setup a dev environment. Building docker with docker ftw 2013-07-09 16:48:16 -07:00
Sam Alba
316c8328aa Hardened repos name validation 2013-07-09 16:46:55 -07:00
Sam Alba
e8db031112 Fixed tag parsing when the repos name contains both a port and a tag 2013-07-09 16:46:25 -07:00
Sam Alba
59b785a282 Fixing missing tag field when pulling containers which does not exist 2013-07-09 16:45:32 -07:00
Louis Opter
1a1daca621 Fix a typo in runtime_test.go: Availalble -> Available 2013-07-09 11:52:33 -07:00
Sam Alba
837be914ca Merge branch 'master' of github.com:dotcloud/docker into standalone_registry 2013-07-09 11:31:14 -07:00
Sam Alba
f44eac49fa Fixed potential security issue (never try http on official index when polling the endpoint). Also fixed local repos name when pulling index.docker.io/foo/bar 2013-07-09 11:30:12 -07:00
Guillaume J. Charmes
0acdef4549 Merge pull request #1166 from dotcloud/networkless_tests-2
* Tests: Remove all network dependencies from the test suite
2013-07-09 11:20:18 -07:00
Guillaume J. Charmes
7d8ef90ccb Merge pull request #1173 from dotcloud/1172-ghost_restart-fix
Make sure container is not marked as ghost when it starts
2013-07-09 10:49:17 -07:00
Guillaume J. Charmes
91520838fc Make sure container is not marked as ghost when it starts 2013-07-09 10:48:33 -07:00
Guillaume J. Charmes
ada0e1fb08 Merge pull request #1049 from dotcloud/1040_ignore_stderr_tests-fix
- Tests: Ignore stderr while doing tests
2013-07-09 10:32:24 -07:00
Sam Alba
33d97e81eb Removed DOCKER_INDEX_URL 2013-07-09 08:10:43 -07:00
Sam Alba
019324015b Moved parseRepositoryTag to the utils package 2013-07-09 08:06:10 -07:00
Victor Vieux
72d278fdac Merge pull request #1170 from dotcloud/fix_type_socket
Fix typo socket
2013-07-09 03:57:45 -07:00
Victor Vieux
05d7f85af9 fix typo 2013-07-09 10:55:28 +00:00
Solomon Hykes
7fba358ae2 Merge pull request #1013 from dotcloud/standardize-build
* Hack: standardized docker's build environment in a Dockerfile
2013-07-08 21:33:45 -07:00
Solomon Hykes
9f1fc40a64 * Hack: standardized docker's build environment in a Dockerfile 2013-07-08 21:30:29 -07:00
Sam Alba
3be7bc38e0 Fixed typo (thanks unit tests) 2013-07-08 17:42:18 -07:00
Sam Alba
31c66d5a00 Re-implemented a notion of local and private repos. This allows to consider the full qualified name of the repos as the name for the local repository without breaking the calls to the Registry API. 2013-07-08 17:26:50 -07:00
Sam Alba
e7d36c9590 It is now possible to include a ":" in a local repository name (it will not be the case for a remote name). This adds support for full qualified repository name in order to support private registry server 2013-07-08 17:22:41 -07:00
Sam Alba
3e8626c4a1 Changed the tag parsing to it will work even if there is a port in the repos registry url (full qualified name for pushing on a standalone registry) 2013-07-08 17:20:41 -07:00
Guillaume J. Charmes
e14dd4d33e Merge pull request #1157 from kstaken/1156-entrypoint-builder
Builder: Fix #1156 entrypoint override from base image
2013-07-08 16:57:26 -07:00
Kimbro Staken
87a69e6753 Merge branch '1156-entrypoint-builder' of github.com:kstaken/docker into 1156-entrypoint-builder 2013-07-08 16:06:09 -07:00
Kimbro Staken
f64dbdbe3a Override Entrypoint picked up from the base image that breaks run commands in builder 2013-07-08 16:04:39 -07:00
Kimbro Staken
2b5553144a Removing the save to disk as it was not really necessary 2013-07-08 16:03:18 -07:00
Guillaume J. Charmes
e43ef364cb Remove all network dependencies from the test suite 2013-07-08 15:23:04 -07:00
Guillaume J. Charmes
08a87d4b3b Fix #1162 - Remove bufio from Untar 2013-07-08 13:42:17 -07:00
Victor Vieux
90f372af5c Merge pull request #1163 from dotcloud/1137-change_search_size-feature
* Client : uses the terminal size to display search output, add -notrunc
2013-07-08 11:47:25 -07:00
Victor Vieux
3ec29eb5da Merge pull request #1066 from mhennings/fix-broken-streaming-result
* Server: Fix streaming status to the docker client while pushing images
2013-07-08 11:21:29 -07:00
Victor Vieux
3a20e4e15d add if to prevent crash 2013-07-08 18:19:12 +00:00
Victor Vieux
fd97190ee7 uses the terminal size to display search output, add -notrunc and fix bug in resize 2013-07-08 17:20:13 +00:00
Victor Vieux
70480ce7bc Merge pull request #1030 from dotcloud/builder_display_err_log
*Builder : Display containers logs in case of build failure
2013-07-08 07:26:46 -07:00
Victor Vieux
bf7d6cbb4a rebase master 2013-07-08 13:26:29 +00:00
Victor Vieux
c059785ffb Merge pull request #1161 from dotcloud/add_remote_addr_debug
Add remote addr in debug
2013-07-08 05:46:49 -07:00
Victor Vieux
a0f5fb7394 add remote addr in debug 2013-07-08 12:45:50 +00:00
Victor Vieux
ad33e9f388 Merge pull request #1138 from dotcloud/1123-rmi_conflict-fix
* Runtime: Fix error in rmi when conflict
2013-07-08 05:19:05 -07:00
Kimbro Staken
1d1d81b0bc Cleanup white space 2013-07-08 00:18:47 -07:00
Kimbro Staken
f3d2969560 Override Entrypoint picked up from the base image that breaks run commands in builder 2013-07-08 00:11:45 -07:00
Alex Gaynor
758ea61b77 Replaced gendered language in the README 2013-07-07 13:55:02 +10:00
Daniel Mizyrycki
4388bef996 testing, issue #1104: Make the test use static flags 2013-07-05 16:49:55 -07:00
Sam Alba
e2b8ee2723 Fixed runtime_test (ImagePull prototyped changed) 2013-07-05 16:03:22 -07:00
Guillaume J. Charmes
07dc0a5120 Merge pull request #1144 from dotcloud/standalone_registry
* Registry: Standalone registry
2013-07-05 15:56:48 -07:00
Sam Alba
d3125d8570 Code cleaning 2013-07-05 15:26:08 -07:00
Sam Alba
283ebf3ff9 fmt.Errorf instead of errors.New 2013-07-05 14:56:56 -07:00
Sam Alba
4c174e0bfb Fixed ping URL 2013-07-05 14:55:48 -07:00
Sam Alba
57a6c83547 Allowing namespaces in standalone registry 2013-07-05 14:30:43 -07:00
Sam Alba
cfc7684b7d Restoring old changeset lost by previous merge 2013-07-05 12:37:07 -07:00
Sam Alba
be49f0a118 Merging from master 2013-07-05 12:27:10 -07:00
Sam Alba
66a9d06d9f Adding support for nicer URLs to support standalone registry (+ some registry code cleaning) 2013-07-05 12:20:58 -07:00
Guillaume J. Charmes
6940cf1ecd Merge pull request #1127 from cespare/patch-1
Typo fix
2013-07-05 10:48:59 -07:00
Guillaume J. Charmes
4e0cdc016a Revert #1126. Remove mount shm 2013-07-05 10:47:00 -07:00
Guillaume J. Charmes
8a8109648a Merge pull request #1129 from cespare/style-fixes-2
Style fixes for fmt + err usage.
2013-07-05 10:31:53 -07:00
Guillaume J. Charmes
dc8b359319 Merge pull request #1126 from karanlyons/patch-1
* Runtime: Mount /dev/shm as a tmpfs.
2013-07-05 10:31:05 -07:00
Victor Vieux
dea29e7c99 Fix error in rmi when conflict 2013-07-05 16:58:39 +00:00
Daniel Mizyrycki
ab6379b3e0 Merge pull request #1133 from dotcloud/775-testing-notifications
testing, issue #775: Add automatic testing notifications to docker-ci
2013-07-04 21:48:00 -07:00
Daniel Mizyrycki
f7fed2ea5f testing, issue #775: Add automatic testing notifications to docker-ci 2013-07-04 21:43:46 -07:00
Daniel Mizyrycki
35e87ee571 Merge pull request #1132 from dotcloud/776-testing-commit
testing, issue #776: Ensure docker-ci test docker code as it was at commit time
2013-07-04 20:37:51 -07:00
Daniel Mizyrycki
ab3893ff4d testing, issue #776: Ensure docker-ci test docker code as it was at commit time 2013-07-04 20:28:54 -07:00
Caleb Spare
1277dca335 Style fixes for fmt + err usage.
fmt.Printf and friends will automatically format using the error
interface (.Error()) preferentially; no need to do err.Error().
2013-07-04 14:33:17 -07:00
Caleb Spare
ba9aef6f2c Typo fix
Error message grammar tweak
2013-07-04 12:40:14 -07:00
Karan Lyons
dd619d2bd6 Mount /dev/shm as a tmpfs.
Fixes #1122.
2013-07-04 09:58:50 -07:00
Marco Hennings
1e2ef274cd Pushing an Image causes the docker client to give an error message instead of
writing out streamed status.

This is caused by a Buffering message that is not in the correct json format:

[...]
{"status"
:"Pushing 6bba11a28f1ca247de9a47071355ce5923a45b8fea3182389f992f4
24b93edae"}Buffering to disk 244/? (n/a)..
{"status":"Pushing",[...]

The "Buffering to disk" message is originated in
srv.runtime.graph.TempLayerArchive

I am now using the StreamFormatter provided by the context from which the
method is called.
2013-07-04 10:50:37 +02:00
Guillaume J. Charmes
bcb5e36dd9 Merge pull request #1111 from cespare/style-fixes
Style fixes
2013-07-03 14:46:05 -07:00
Caleb Spare
19121c16d9 Implement several golint suggestions, including:
* Removing type declarations where they're inferred
* Changing Url -> URL, Id -> ID in names
* Fixing snake-case names
2013-07-03 14:36:04 -07:00
Caleb Spare
27ee261e60 Simplify the NopWriter code. 2013-07-03 14:35:18 -07:00
Caleb Spare
da3962266a Gofmt -s (simplify) 2013-07-03 14:35:18 -07:00
Caleb Spare
e93afcdd2b Use fmt.Errorf when appropriate. 2013-07-03 14:35:18 -07:00
Caleb Spare
dd1b9e38e9 Typo correction: Excepted -> Expected' 2013-07-03 14:35:18 -07:00
Guillaume J. Charmes
96bc9ea7c1 Merge pull request #1112 from cespare/mutex-style
Mutex style change.
2013-07-03 10:34:32 -07:00
Guillaume J. Charmes
16c8a10ef9 Merge pull request #1053 from dynport/do-not-copy-hostname-from-image
do not merge hostname from image
2013-07-03 10:34:15 -07:00
Joffrey F
5dcd11be16 Merge pull request #1109 from dynport/remote-lookup-fix
Fix remote lookup when pushing into registry
2013-07-03 06:29:19 -07:00
Ken Cochrane
dc91a7b641 Merge pull request #1113 from metalivedev/docs20130702
* Documentation: fix broken link on the documentation index page
2013-07-03 05:52:25 -07:00
Andy Rothfusz
11998ae7d6 Fix installation link from welcome page. 2013-07-02 16:48:57 -07:00
Caleb Spare
1cf9c80e97 Mutex style change.
For structs protected by a single mutex, embed the mutex for more
concise usage.

Also use a sync.Mutex directly, rather than a pointer, to avoid the
need for initialization (because a Mutex's zero-value is valid and
ready to be used).
2013-07-02 15:53:08 -07:00
Andy Rothfusz
6dbcdd3ed5 Merge pull request #1095 from metalivedev/docs20130627
Docs and images updates
2013-07-02 15:13:31 -07:00
Tobias Schwab
9632cf09bf fix two obvious bugs??? 2013-07-02 22:11:03 +00:00
Andy Rothfusz
96ab3c540d Merge branch 'docs20130627' of github.com:metalivedev/docker into docs20130627
Conflicts:
	docs/sources/concepts/manifesto.rst
	docs/sources/index.rst
2013-07-02 15:10:07 -07:00
Andy Rothfusz
ff964d327d Cleaning up the welcome page, terminology, and images. 2013-07-02 15:03:29 -07:00
Andy Rothfusz
4b8688f1e5 Fix broken quickstart link 2013-07-02 14:10:06 -07:00
Andy Rothfusz
55b5889a0f Merge branch 'docs20130627' of github.com:metalivedev/docker into docs20130627
Conflicts:
	docs/sources/concepts/manifesto.rst
2013-07-02 13:00:08 -07:00
Andy Rothfusz
dd4c6f6a09 Shortened lines to 80 columns 2013-07-02 12:09:57 -07:00
Andy Rothfusz
6058261a26 Clean up image text, minor updates to docs. 2013-07-02 12:09:57 -07:00
Andy Rothfusz
b461e4607d Adding files for terms 2013-07-02 12:09:57 -07:00
Andy Rothfusz
d399f72098 Cleaning up the welcome page, terminology. 2013-07-02 12:09:57 -07:00
Guillaume J. Charmes
c9e1c65c64 Merge pull request #1107 from eliasp/issue-1020
* Runtime: Don't remove the container= environment variable.
2013-07-02 11:42:44 -07:00
Victor Vieux
3042f11666 never remove the file and try to load it in start 2013-07-02 18:02:16 +00:00
Elias Probst
e5e47c9862 Don't remove the container= environment variable, as it is crucial for a lot of tools to detect, whether they're run inside an LXC container or not. 2013-07-02 19:13:37 +02:00
Victor Vieux
1c5083315d Merge pull request #1103 from shin-/1060-pull-only-tagged-images
*Registry: When no tag is specified in docker pull, skip images that are not tagged
2013-07-02 10:08:21 -07:00
Victor Vieux
27a137ccab change file location 2013-07-02 17:02:42 +00:00
shin-
7cc294e777 When no tag is specified in docker pull, skip images that are not tagged 2013-07-02 18:25:06 +02:00
Daniel Mizyrycki
a20dcfb049 Merge pull request #987 from dotcloud/601-packaging-ubuntu
Packaging|ubuntu, issue #601: Allow packaging prerm to do its job
2013-07-02 08:51:01 -07:00
Victor Vieux
06b53e3fc7 store hostConfig to /tmp while container is running 2013-07-02 12:19:25 +00:00
Victor Vieux
8f9dd86146 Merge pull request #1101 from dotcloud/fix-unit_tests
add sleep in tests and go fmt
2013-07-02 03:48:24 -07:00
Victor Vieux
ebba0a6024 add sleep in tests and go fmt 2013-07-02 10:47:37 +00:00
Victor Vieux
c9236d99d2 Merge pull request #1099 from lopter/master
*Test :  Fix
2013-07-02 02:42:21 -07:00
Louis Opter
f03c1b8eeb More unit test fixes
- Fix TestGetImagesJSON when there is more than one image in the test
  repository;
- Remove an hardcoded constant use in TestGetImagesByName;
- Wait in a loop in TestKillDifferentUser;
- Use env instead of /usr/bin/env in TestEnv;
- Create a daemon user in contrib/mkimage-unittest.sh.
2013-07-01 17:24:21 -07:00
Guillaume J. Charmes
6f23e39e6b Merge pull request #1097 from dotcloud/bump_0.4.8
Bump version to 0.4.8
2013-07-01 17:13:19 -07:00
Solomon Hykes
fe0378e9b3 Rephrase changelog 2013-07-01 17:05:49 -07:00
Guillaume J. Charmes
96a1d7c645 Bump version to 0.4.8 2013-07-01 16:58:25 -07:00
Guillaume J. Charmes
79ee8b46f4 Merge pull request #1046 from dotcloud/1043-output_id_non_attach-fix
- Runtime: Make sure the ID is displayed usgin run -d
2013-07-01 16:49:43 -07:00
Victor Vieux
55a7a8b8c9 Merge pull request #1092 from lopter/master
Fix TestGetInfo when there is more than one image in the test repository
2013-07-01 16:41:01 -07:00
Andy Rothfusz
b47873c5ac Clean up image text, minor updates to docs. 2013-07-01 16:37:13 -07:00
Andy Rothfusz
adf75d402a Adding files for terms 2013-07-01 16:37:13 -07:00
Andy Rothfusz
cb1fdb2f03 Cleaning up the welcome page, terminology. 2013-07-01 16:37:13 -07:00
Victor Vieux
d1d66b9c5f Merge pull request #1078 from kstaken/fix_json_error
* Remote API: Small fix in /start if empty host config
2013-07-01 16:36:58 -07:00
Louis Opter
6dacbb451f Fix TestGetInfo when there is more than one image in the test repository
See also #1089, #1072.
2013-07-01 15:06:08 -07:00
Guillaume J. Charmes
ead9cefadb Merge pull request #1089 from dotcloud/multiple_test_images-fix
- Tests: Fix unit tests when there is more than one tag within the test image
2013-07-01 13:58:04 -07:00
Guillaume J. Charmes
185a2fc55e Merge pull request #1086 from crosbymichael/1008-image-entrypoint
+ Builder: Add Entrypoint to builder and container config
2013-07-01 13:33:12 -07:00
Ken Cochrane
fb8fac6c60 Merge pull request #1088 from kpelykh/master
* Documentation: Update Docker Remote API client list to include Java library
2013-07-01 12:50:31 -07:00
Guillaume J. Charmes
b6f288a1ce Fix unit tests when there is more than one tag within the test image 2013-07-01 11:45:45 -07:00
zettaset-kpelykh
aa9bec96b1 Issue #1087 Docker Java API client -- added java to Docker Remote API Client document 2013-07-01 11:28:40 -07:00
Victor Vieux
11e28842ac change to top 2013-07-01 15:19:42 +00:00
Michael Crosby
b16ff9f859 Add Entrypoint to builder and container config
By setting an entrypoint in the Dockerfile this
allows one to run an image and only pass arguments.
2013-07-01 05:34:27 -09:00
Victor Vieux
348c5c4838 Merge pull request #1085 from dotcloud/1076-doc_delete-fix
fix status code in doc
2013-07-01 06:30:21 -07:00
Victor Vieux
8dcc6a0280 fix status code in doc 2013-07-01 13:28:58 +00:00
Victor Vieux
3b5ad44647 rebase master 2013-07-01 12:31:16 +00:00
Victor Vieux
5e029f7600 Merge pull request #1061 from proppy/fix-slices-ref
api,server: slice are already refs, no need to return ptr
2013-07-01 04:51:56 -07:00
Keli Hu
52cebe19e5 Keep debian package up-to-date 2013-07-01 16:15:56 +08:00
Kimbro Staken
d8d33e8b8b Adding check for content-type header 2013-06-30 10:46:09 -07:00
Solomon Hykes
b37f7d49d8 Documented release process for maintainers in hack/RELEASE.md 2013-06-29 22:08:25 -07:00
Johan Euphrosine
54da339b2c api,server: slice are already refs, no need to return ptr 2013-06-28 12:41:09 -07:00
Victor Vieux
648c4f198b Add test 2013-06-28 16:27:00 +00:00
Victor Vieux
8589fd6db8 Add doc 2013-06-28 18:05:41 +02:00
Victor Vieux
2e79719622 add /proc to list running processes inside a container 2013-06-28 15:51:58 +00:00
Tobias Schwab
9bfec5a538 do not merge hostname from image 2013-06-28 15:22:01 +02:00
Guillaume J. Charmes
800d900688 Ignore stderr while doing tests 2013-06-27 15:25:31 -07:00
Guillaume J. Charmes
bd144a64f6 Make sure the ID is displayed usgin run -d 2013-06-27 12:48:25 -07:00
Guillaume J. Charmes
2a20e85203 Improve last log output 2013-06-27 11:10:19 -07:00
Guillaume J. Charmes
27d6777376 Display containers logs in case of build failure 2013-06-26 12:50:20 -07:00
Daniel Mizyrycki
41cdd9b27f Packaging|ubuntu, issue #601: Allow packaging prerm to do its job 2013-06-21 17:37:32 -07:00
Victor Vieux
ec6b35240e fix raw terminal 2013-06-22 00:37:02 +00:00
Victor Vieux
42bcfcc927 add options to docker login 2013-06-21 10:00:25 +00:00
114 changed files with 6568 additions and 3276 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@ docs/_build
docs/_static
docs/_templates
.gopath/
.dotcloud

View File

@@ -23,3 +23,5 @@ Thatcher Peskens <thatcher@dotcloud.com>
Walter Stanish <walter@pratyeka.org>
<daniel@gasienica.ch> <dgasienica@zynga.com>
Roberto Hashioka <roberto_hashioka@hotmail.com>
Konstantin Pelykh <kpelykh@zettaset.com>
David Sissitka <me@dsissitka.com>

26
AUTHORS
View File

@@ -4,12 +4,15 @@
# For a list of active project maintainers, see the MAINTAINERS file.
#
Al Tobey <al@ooyala.com>
Alex Gaynor <alex.gaynor@gmail.com>
Alexey Shamrin <shamrin@gmail.com>
Andrea Luzzardi <aluzzardi@gmail.com>
Andreas Tiefenthaler <at@an-ti.eu>
Andrew Munsell <andrew@wizardapps.net>
Andrews Medina <andrewsmedina@gmail.com>
Andy Rothfusz <github@metaliveblog.com>
Andy Smith <github@anarkystic.com>
Anthony Bishopric <git@anthonybishopric.com>
Antony Messerli <amesserl@rackspace.com>
Barry Allard <barry.allard@gmail.com>
Brandon Liu <bdon@bdon.org>
@@ -23,17 +26,23 @@ Daniel Gasienica <daniel@gasienica.ch>
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
Daniel Robinson <gottagetmac@gmail.com>
Daniel Von Fange <daniel@leancoder.com>
Daniel YC Lin <dlin.tw@gmail.com>
David Calavera <david.calavera@gmail.com>
David Sissitka <me@dsissitka.com>
Dominik Honnef <dominik@honnef.co>
Don Spaulding <donspauldingii@gmail.com>
Dr Nic Williams <drnicwilliams@gmail.com>
Elias Probst <mail@eliasprobst.eu>
Eric Hanchrow <ehanchrow@ine.com>
Evan Wies <evan@neomantra.net>
Eric Myhre <hash@exultant.us>
Erno Hopearuoho <erno.hopearuoho@gmail.com>
Evan Wies <evan@neomantra.net>
ezbercih <cem.ezberci@gmail.com>
Fabrizio Regini <freegenie@gmail.com>
Flavio Castelli <fcastelli@suse.com>
Francisco Souza <f@souza.cc>
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
Gabriel Monroy <gabriel@opdemand.com>
Gareth Rushgrove <gareth@morethanseven.net>
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
Harley Laue <losinggeneration@gmail.com>
@@ -41,6 +50,7 @@ Hunter Blanks <hunter@twilio.com>
Jeff Lindsay <progrium@gmail.com>
Jeremy Grosser <jeremy@synack.me>
Joffrey F <joffrey@dotcloud.com>
Johan Euphrosine <proppy@google.com>
John Costa <john.costa@gmail.com>
Jon Wedaman <jweede@gmail.com>
Jonas Pfenniger <jonas@pfenniger.name>
@@ -48,40 +58,54 @@ Jonathan Rudenberg <jonathan@titanous.com>
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
Julien Barbier <write0@gmail.com>
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
Karan Lyons <karan@karanlyons.com>
Keli Hu <dev@keli.hu>
Ken Cochrane <kencochrane@gmail.com>
Kevin J. Lynagh <kevin@keminglabs.com>
kim0 <email.ahmedkamal@googlemail.com>
Kimbro Staken <kstaken@kstaken.com>
Kiran Gangadharan <kiran.daredevil@gmail.com>
Konstantin Pelykh <kpelykh@zettaset.com>
Louis Opter <kalessin@kalessin.fr>
Marco Hennings <marco.hennings@freiheit.com>
Marcus Farkas <toothlessgear@finitebox.com>
Mark McGranaghan <mmcgrana@gmail.com>
Maxim Treskin <zerthurd@gmail.com>
meejah <meejah@meejah.ca>
Michael Crosby <crosby.michael@gmail.com>
Mike Gaffney <mike@uberu.com>
Mikhail Sobolev <mss@mawhrin.net>
Nan Monnand Deng <monnand@gmail.com>
Nate Jones <nate@endot.org>
Nelson Chen <crazysim@gmail.com>
Niall O'Higgins <niallo@unworkable.org>
Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
Nick Stinemates <nick@stinemates.org>
odk- <github@odkurzacz.org>
Paul Bowsher <pbowsher@globalpersonals.co.uk>
Paul Hammond <paul@paulhammond.org>
Phil Spitler <pspitler@gmail.com>
Piotr Bogdan <ppbogdan@gmail.com>
Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
Rhys Hiltner <rhys@twitch.tv>
Robert Obryk <robryk@gmail.com>
Roberto Hashioka <roberto_hashioka@hotmail.com>
Ryan Fowler <rwfowler@gmail.com>
Sam Alba <sam.alba@gmail.com>
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
Shawn Siefkas <shawn.siefkas@meredith.com>
Silas Sewell <silas@sewell.org>
Solomon Hykes <solomon@dotcloud.com>
Sridhar Ratnakumar <sridharr@activestate.com>
Stefan Praszalowicz <stefan@greplin.com>
Thatcher Peskens <thatcher@dotcloud.com>
Thomas Bikeev <thomas.bikeev@mac.com>
Thomas Hansen <thomas.hansen@gmail.com>
Tianon Gravi <admwiggin@gmail.com>
Tim Terhorst <mynamewastaken+git@gmail.com>
Tobias Bieniek <Tobias.Bieniek@gmx.de>
Tobias Schwab <tobias.schwab@dynport.de>
Tom Hulihan <hulihan.tom159@gmail.com>
unclejack <unclejacksons@gmail.com>
Victor Vieux <victor.vieux@dotcloud.com>
Vivek Agarwal <me@vivek.im>

View File

@@ -1,5 +1,47 @@
# Changelog
## 0.5.2 (2013-08-08)
* Builder: Forbid certain paths within docker build ADD
- Runtime: Change network range to avoid conflict with EC2 DNS
* API: Change daemon to listen on unix socket by default
## 0.5.1 (2013-07-30)
+ API: Docker client now sets useragent (RFC 2616)
+ Runtime: Add `ps` args to `docker top`
+ Runtime: Add support for container ID files (pidfile like)
+ Runtime: Add container=lxc in default env
+ Runtime: Support networkless containers with `docker run -n` and `docker -d -b=none`
+ API: Add /events endpoint
+ Builder: ADD command now understands URLs
+ Builder: CmdAdd and CmdEnv now respect Dockerfile-set ENV variables
* Hack: Simplify unit tests with helpers
* Hack: Improve docker.upstart event
* Hack: Add coverage testing into docker-ci
* Runtime: Stdout/stderr logs are now stored in the same file as JSON
* Runtime: Allocate a /16 IP range by default, with fallback to /24. Try 12 ranges instead of 3.
* Runtime: Change .dockercfg format to json and support multiple auth remote
- Runtime: Do not override volumes from config
- Runtime: Fix issue with EXPOSE override
- Builder: Create directories with 755 instead of 700 within ADD instruction
## 0.5.0 (2013-07-17)
+ Runtime: List all processes running inside a container with 'docker top'
+ Runtime: Host directories can be mounted as volumes with 'docker run -v'
+ Runtime: Containers can expose public UDP ports (eg, '-p 123/udp')
+ Runtime: Optionally specify an exact public port (eg. '-p 80:4500')
+ Registry: New image naming scheme inspired by Go packaging convention allows arbitrary combinations of registries
+ Builder: ENTRYPOINT instruction sets a default binary entry point to a container
+ Builder: VOLUME instruction marks a part of the container as persistent data
* Builder: 'docker build' displays the full output of a build by default
* Runtime: 'docker login' supports additional options
- Runtime: Dont save a container's hostname when committing an image.
- Registry: Fix issues when uploading images to a private registry
## 0.4.8 (2013-07-01)
+ Builder: New build operation ENTRYPOINT adds an executable entry point to the container.
- Runtime: Fix a bug which caused 'docker run -d' to no longer print the container ID.
- Tests: Fix issues in the test suite
## 0.4.7 (2013-06-28)
* Registry: easier push/pull to a custom registry
* Remote API: the progress bar updates faster when downloading and uploading large files

30
Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
# This file describes the standard way to build Docker, using docker
docker-version 0.4.2
from ubuntu:12.04
maintainer Solomon Hykes <solomon@dotcloud.com>
# Build dependencies
run apt-get install -y -q curl
run apt-get install -y -q git
# Install Go
run curl -s https://go.googlecode.com/files/go1.1.1.linux-amd64.tar.gz | tar -v -C /usr/local -xz
env PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
env GOPATH /go
env CGO_ENABLED 0
run cd /tmp && echo 'package main' > t.go && go test -a -i -v
# Download dependencies
run PKG=github.com/kr/pty REV=27435c699; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
run PKG=github.com/gorilla/context/ REV=708054d61e5; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
run PKG=github.com/gorilla/mux/ REV=9b36453141c; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
# Run dependencies
run apt-get install -y iptables
# lxc requires updating ubuntu sources
run echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
run apt-get update
run apt-get install -y lxc
run apt-get install -y aufs-tools
# Upload docker source
add . /go/src/github.com/dotcloud/docker
# Build the binary
run cd /go/src/github.com/dotcloud/docker/docker && go install -ldflags "-X main.GITCOMMIT '??' -d -w"
env PATH /usr/local/go/bin:/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
cmd ["docker"]

View File

@@ -11,7 +11,7 @@ BUILD_DIR := $(CURDIR)/.gopath
GOPATH ?= $(BUILD_DIR)
export GOPATH
GO_OPTIONS ?=
GO_OPTIONS ?= -a -ldflags='-w -d'
ifeq ($(VERBOSE), 1)
GO_OPTIONS += -v
endif
@@ -49,6 +49,7 @@ whichrelease:
release: $(BINRELEASE)
s3cmd -P put $(BINRELEASE) s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-$(RELEASE_VERSION).tgz
s3cmd -P put docker-latest.tgz s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-latest.tgz
s3cmd -P put $(SRCRELEASE)/bin/docker s3://get.docker.io/builds/`uname -s`/`uname -m`/docker
srcrelease: $(SRCRELEASE)
deps: $(DOCKER_DIR)
@@ -79,10 +80,10 @@ test:
tar --exclude=${BUILD_SRC} -cz . | tar -xz -C ${BUILD_PATH}
GOPATH=${CURDIR}/${BUILD_SRC} go get -d
# Do the test
sudo -E GOPATH=${CURDIR}/${BUILD_SRC} go test ${GO_OPTIONS}
sudo -E GOPATH=${CURDIR}/${BUILD_SRC} CGO_ENABLED=0 go test ${GO_OPTIONS}
testall: all
@(cd $(DOCKER_DIR); sudo -E go test ./... $(GO_OPTIONS))
@(cd $(DOCKER_DIR); CGO_ENABLED=0 sudo -E go test ./... $(GO_OPTIONS))
fmt:
@gofmt -s -l -w .

334
README.md
View File

@@ -1,80 +1,129 @@
Docker: the Linux container engine
==================================
Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers.
Docker is an open-source engine which automates the deployment of
applications as highly portable, self-sufficient containers.
Docker containers are both *hardware-agnostic* and *platform-agnostic*. This means that they can run anywhere, from your
laptop to the largest EC2 compute instance and everything in between - and they don't require that you use a particular
language, framework or packaging system. That makes them great building blocks for deploying and scaling web apps, databases
and backend services without depending on a particular stack or provider.
Docker containers are both *hardware-agnostic* and
*platform-agnostic*. This means that they can run anywhere, from your
laptop to the largest EC2 compute instance and everything in between -
and they don't require that you use a particular language, framework
or packaging system. That makes them great building blocks for
deploying and scaling web apps, databases and backend services without
depending on a particular stack or provider.
Docker is an open-source implementation of the deployment engine which powers [dotCloud](http://dotcloud.com), a popular Platform-as-a-Service.
It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
of applications and databases.
Docker is an open-source implementation of the deployment engine which
powers [dotCloud](http://dotcloud.com), a popular
Platform-as-a-Service. It benefits directly from the experience
accumulated over several years of large-scale operation and support of
hundreds of thousands of applications and databases.
![Docker L](docs/sources/concepts/images/lego_docker.jpg "Docker")
![Docker L](docs/sources/concepts/images/dockerlogo-h.png "Docker")
## Better than VMs
A common method for distributing applications and sandbox their execution is to use virtual machines, or VMs. Typical VM formats
are VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory these formats should allow every developer to
automatically package their application into a "machine" for easy distribution and deployment. In practice, that almost never
happens, for a few reasons:
A common method for distributing applications and sandbox their
execution is to use virtual machines, or VMs. Typical VM formats are
VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In
theory these formats should allow every developer to automatically
package their application into a "machine" for easy distribution and
deployment. In practice, that almost never happens, for a few reasons:
* *Size*: VMs are very large which makes them impractical to store and transfer.
* *Performance*: running VMs consumes significant CPU and memory, which makes them impractical in many scenarios, for example local development of multi-tier applications, and
large-scale deployment of cpu and memory-intensive applications on large numbers of machines.
* *Portability*: competing VM environments don't play well with each other. Although conversion tools do exist, they are limited and add even more overhead.
* *Hardware-centric*: VMs were designed with machine operators in mind, not software developers. As a result, they offer very limited tooling for what developers need most:
building, testing and running their software. For example, VMs offer no facilities for application versioning, monitoring, configuration, logging or service discovery.
* *Size*: VMs are very large which makes them impractical to store
and transfer.
* *Performance*: running VMs consumes significant CPU and memory,
which makes them impractical in many scenarios, for example local
development of multi-tier applications, and large-scale deployment
of cpu and memory-intensive applications on large numbers of
machines.
* *Portability*: competing VM environments don't play well with each
other. Although conversion tools do exist, they are limited and
add even more overhead.
* *Hardware-centric*: VMs were designed with machine operators in
mind, not software developers. As a result, they offer very
limited tooling for what developers need most: building, testing
and running their software. For example, VMs offer no facilities
for application versioning, monitoring, configuration, logging or
service discovery.
By contrast, Docker relies on a different sandboxing method known as *containerization*. Unlike traditional virtualization,
containerization takes place at the kernel level. Most modern operating system kernels now support the primitives necessary
for containerization, including Linux with [openvz](http://openvz.org), [vserver](http://linux-vserver.org) and more recently [lxc](http://lxc.sourceforge.net),
Solaris with [zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc) and FreeBSD with [Jails](http://www.freebsd.org/doc/handbook/jails.html).
By contrast, Docker relies on a different sandboxing method known as
*containerization*. Unlike traditional virtualization,
containerization takes place at the kernel level. Most modern
operating system kernels now support the primitives necessary for
containerization, including Linux with [openvz](http://openvz.org),
[vserver](http://linux-vserver.org) and more recently
[lxc](http://lxc.sourceforge.net), Solaris with
[zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc)
and FreeBSD with
[Jails](http://www.freebsd.org/doc/handbook/jails.html).
Docker builds on top of these low-level primitives to offer developers a portable format and runtime environment that solves
all 4 problems. Docker containers are small (and their transfer can be optimized with layers), they have basically zero memory and cpu overhead,
they are completely portable and are designed from the ground up with an application-centric design.
Docker builds on top of these low-level primitives to offer developers
a portable format and runtime environment that solves all 4
problems. Docker containers are small (and their transfer can be
optimized with layers), they have basically zero memory and cpu
overhead, they are completely portable and are designed from the
ground up with an application-centric design.
The best part: because docker operates at the OS level, it can still be run inside a VM!
The best part: because ``docker`` operates at the OS level, it can
still be run inside a VM!
## Plays well with others
Docker does not require that you buy into a particular programming language, framework, packaging system or configuration language.
Docker does not require that you buy into a particular programming
language, framework, packaging system or configuration language.
Is your application a unix process? Does it use files, tcp connections, environment variables, standard unix streams and command-line
arguments as inputs and outputs? Then docker can run it.
Is your application a Unix process? Does it use files, tcp
connections, environment variables, standard Unix streams and
command-line arguments as inputs and outputs? Then ``docker`` can run
it.
Can your application's build be expressed as a sequence of such commands? Then docker can build it.
Can your application's build be expressed as a sequence of such
commands? Then ``docker`` can build it.
## Escape dependency hell
A common problem for developers is the difficulty of managing all their application's dependencies in a simple and automated way.
A common problem for developers is the difficulty of managing all
their application's dependencies in a simple and automated way.
This is usually difficult for several reasons:
* *Cross-platform dependencies*. Modern applications often depend on a combination of system libraries and binaries, language-specific packages, framework-specific modules,
internal components developed for another project, etc. These dependencies live in different "worlds" and require different tools - these tools typically don't work
well with each other, requiring awkward custom integrations.
* *Cross-platform dependencies*. Modern applications often depend on
a combination of system libraries and binaries, language-specific
packages, framework-specific modules, internal components
developed for another project, etc. These dependencies live in
different "worlds" and require different tools - these tools
typically don't work well with each other, requiring awkward
custom integrations.
* Conflicting dependencies. Different applications may depend on different versions of the same dependency. Packaging tools handle these situations with various degrees of ease -
but they all handle them in different and incompatible ways, which again forces the developer to do extra work.
* Conflicting dependencies. Different applications may depend on
different versions of the same dependency. Packaging tools handle
these situations with various degrees of ease - but they all
handle them in different and incompatible ways, which again forces
the developer to do extra work.
* Custom dependencies. A developer may need to prepare a custom version of his application's dependency. Some packaging systems can handle custom versions of a dependency,
others can't - and all of them handle it differently.
* Custom dependencies. A developer may need to prepare a custom
version of their application's dependency. Some packaging systems
can handle custom versions of a dependency, others can't - and all
of them handle it differently.
Docker solves dependency hell by giving the developer a simple way to express *all* his application's dependencies in one place,
and streamline the process of assembling them. If this makes you think of [XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
*replace* your favorite packaging systems. It simply orchestrates their use in a simple and repeatable way. How does it do that? With layers.
Docker solves dependency hell by giving the developer a simple way to
express *all* their application's dependencies in one place, and
streamline the process of assembling them. If this makes you think of
[XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
*replace* your favorite packaging systems. It simply orchestrates
their use in a simple and repeatable way. How does it do that? With
layers.
Docker defines a build as running a sequence of unix commands, one after the other, in the same container. Build commands modify the contents of the container
(usually by installing new files on the filesystem), the next command modifies it some more, etc. Since each build command inherits the result of the previous
commands, the *order* in which the commands are executed expresses *dependencies*.
Docker defines a build as running a sequence of Unix commands, one
after the other, in the same container. Build commands modify the
contents of the container (usually by installing new files on the
filesystem), the next command modifies it some more, etc. Since each
build command inherits the result of the previous commands, the
*order* in which the commands are executed expresses *dependencies*.
Here's a typical docker build process:
Here's a typical Docker build process:
```bash
from ubuntu:12.10
@@ -87,7 +136,8 @@ run curl -L https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xz
run cd helloflask-master && pip install -r requirements.txt
```
Note that Docker doesn't care *how* dependencies are built - as long as they can be built by running a unix command in a container.
Note that Docker doesn't care *how* dependencies are built - as long
as they can be built by running a Unix command in a container.
Install instructions
@@ -103,8 +153,9 @@ curl get.docker.io | sudo sh -x
Binary installs
----------------
Docker supports the following binary installation methods.
Note that some methods are community contributions and not yet officially supported.
Docker supports the following binary installation methods. Note that
some methods are community contributions and not yet officially
supported.
* [Ubuntu 12.04 and 12.10 (officially supported)](http://docs.docker.io/en/latest/installation/ubuntulinux/)
* [Arch Linux](http://docs.docker.io/en/latest/installation/archlinux/)
@@ -115,15 +166,15 @@ Note that some methods are community contributions and not yet officially suppor
Installing from source
----------------------
1. Make sure you have a [Go language](http://golang.org/doc/install) compiler and [git](http://git-scm.com) installed.
1. Make sure you have a [Go language](http://golang.org/doc/install)
compiler >= 1.1 and [git](http://git-scm.com) installed.
2. Checkout the source code
```bash
git clone http://github.com/dotcloud/docker
```
3. Build the docker binary
3. Build the ``docker`` binary
```bash
cd docker
@@ -134,17 +185,20 @@ Installing from source
Usage examples
==============
First run the docker daemon
---------------------------
First run the ``docker`` daemon
-------------------------------
All the examples assume your machine is running the docker daemon. To run the docker daemon in the background, simply type:
All the examples assume your machine is running the ``docker``
daemon. To run the ``docker`` daemon in the background, simply type:
```bash
# On a production system you want this running in an init script
sudo docker -d &
```
Now you can run docker in client mode: all commands will be forwarded to the docker daemon, so the client can run from any account.
Now you can run ``docker`` in client mode: all commands will be
forwarded to the ``docker`` daemon, so the client can run from any
account.
```bash
# Now you can run docker commands from any account.
@@ -152,7 +206,7 @@ docker help
```
Throwaway shell in a base ubuntu image
Throwaway shell in a base Ubuntu image
--------------------------------------
```bash
@@ -202,7 +256,8 @@ docker commit -m "Installed curl" $CONTAINER $USER/betterbase
docker push $USER/betterbase
```
A list of publicly available images is [available here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
A list of publicly available images is [available
here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
Expose a service on a TCP port
------------------------------
@@ -229,32 +284,40 @@ Under the hood
Under the hood, Docker is built on the following components:
* The [cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c) and [namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part) capabilities of the Linux kernel;
* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union filesystem with copy-on-write capabilities;
* The
[cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c)
and
[namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part)
capabilities of the Linux kernel;
* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union
filesystem with copy-on-write capabilities;
* The [Go](http://golang.org) programming language;
* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to simplify the creation of linux containers.
* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to
simplify the creation of Linux containers.
Contributing to Docker
======================
Want to hack on Docker? Awesome! There are instructions to get you started on the website: http://docs.docker.io/en/latest/contributing/contributing/
Want to hack on Docker? Awesome! There are instructions to get you
started on the website:
http://docs.docker.io/en/latest/contributing/contributing/
They are probably not perfect, please let us know if anything feels wrong or incomplete.
They are probably not perfect, please let us know if anything feels
wrong or incomplete.
Note
----
We also keep the documentation in this repository. The website documentation is generated using sphinx using these sources.
Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/tree/master/docs/README.md
We also keep the documentation in this repository. The website
documentation is generated using Sphinx using these sources. Please
find it under docs/sources/ and read more about it
https://github.com/dotcloud/docker/tree/master/docs/README.md
Please feel free to fix / update the documentation and send us pull requests. More tutorials are also welcome.
Please feel free to fix / update the documentation and send us pull
requests. More tutorials are also welcome.
Setting up a dev environment
@@ -289,93 +352,104 @@ Run the `go install` command (above) to recompile docker.
What is a Standard Container?
=============================
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependencies, regardless of the underlying machine and the contents of the container.
Docker defines a unit of software delivery called a Standard
Container. The goal of a Standard Container is to encapsulate a
software component and all its dependencies in a format that is
self-describing and portable, so that any compliant runtime can run it
without extra dependencies, regardless of the underlying machine and
the contents of the container.
The spec for Standard Containers is currently a work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
The spec for Standard Containers is currently a work in progress, but
it is very straightforward. It mostly defines 1) an image format, 2) a
set of standard operations, and 3) an execution environment.
A great analogy for this is the shipping container. Just like how Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
A great analogy for this is the shipping container. Just like how
Standard Containers are a fundamental unit of software delivery,
shipping containers are a fundamental unit of physical delivery.
### 1. STANDARD OPERATIONS
Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
Just like shipping containers, Standard Containers define a set of
STANDARD OPERATIONS. Shipping containers can be lifted, stacked,
locked, loaded, unloaded and labelled. Similarly, Standard Containers
can be started, stopped, copied, snapshotted, downloaded, uploaded and
tagged.
### 2. CONTENT-AGNOSTIC
Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
Just like shipping containers, Standard Containers are
CONTENT-AGNOSTIC: all standard operations have the same effect
regardless of the contents. A shipping container will be stacked in
exactly the same way whether it contains Vietnamese powder coffee or
spare Maserati parts. Similarly, Standard Containers are started or
uploaded in the same way whether they contain a postgres database, a
php application with its dependencies and application server, or Java
build artifacts.
### 3. INFRASTRUCTURE-AGNOSTIC
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be
transported to thousands of facilities around the world, and
manipulated by a wide variety of equipment. A shipping container can
be packed in a factory in Ukraine, transported by truck to the nearest
routing center, stacked onto a train, loaded into a German boat by an
Australian-built crane, stored in a warehouse at a US facility,
etc. Similarly, a standard container can be bundled on my laptop,
uploaded to S3, downloaded, run and snapshotted by a build server at
Equinix in Virginia, uploaded to 10 staging servers in a home-made
Openstack cluster, then sent to 30 production instances across 3 EC2
regions.
### 4. DESIGNED FOR AUTOMATION
Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
Because they offer the same standard operations regardless of content
and infrastructure, Standard Containers, just like their physical
counterparts, are extremely well-suited for automation. In fact, you
could say automation is their secret weapon.
Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
Many things that once required time-consuming and error-prone human
effort can now be programmed. Before shipping containers, a bag of
powder coffee was hauled, dragged, dropped, rolled and stacked by 10
different people in 10 different locations by the time it reached its
destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The
process was slow, inefficient and cost a fortune - and was entirely
different depending on the facility and the type of goods.
Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
Similarly, before Standard Containers, by the time a software
component ran in production, it had been individually built,
configured, bundled, documented, patched, vendored, templated, tweaked
and instrumented by 10 different people on 10 different
computers. Builds failed, libraries conflicted, mirrors crashed,
post-it notes were lost, logs were misplaced, cluster updates were
half-broken. The process was slow, inefficient and cost a fortune -
and was entirely different depending on the language and
infrastructure provider.
### 5. INDUSTRIAL-GRADE DELIVERY
There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded onto the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
There are 17 million shipping containers in existence, packed with
every physical good imaginable. Every single one of them can be loaded
onto the same boats, by the same cranes, in the same facilities, and
sent anywhere in the World with incredible efficiency. It is
embarrassing to think that a 30 ton shipment of coffee can safely
travel half-way across the World in *less time* than it takes a
software team to deliver its code from one datacenter to another
sitting 10 miles away.
With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
With Standard Containers we can put an end to that embarrassment, by
making INDUSTRIAL-GRADE DELIVERY of software a reality.
Standard Container Specification
--------------------------------
(TODO)
### Image format
### Standard operations
* Copy
* Run
* Stop
* Wait
* Commit
* Attach standard streams
* List filesystem changes
* ...
### Execution environment
#### Root filesystem
#### Environment variables
#### Process arguments
#### Networking
#### Process namespacing
#### Resource limits
#### Process monitoring
#### Logging
#### Signals
#### Pseudo-terminal allocation
#### Security
### Legal
Transfers of Docker shall be in accordance with applicable export controls of any country and all other applicable
legal requirements. Docker shall not be distributed or downloaded to or in Cuba, Iran, North Korea, Sudan or Syria
and shall not be distributed or downloaded to any person on the Denied Persons List administered by the U.S.
Transfers of Docker shall be in accordance with applicable export
controls of any country and all other applicable legal requirements.
Docker shall not be distributed or downloaded to or in Cuba, Iran,
North Korea, Sudan or Syria and shall not be distributed or downloaded
to any person on the Denied Persons List administered by the U.S.
Department of Commerce.

2
Vagrantfile vendored
View File

@@ -20,6 +20,8 @@ Vagrant::Config.run do |config|
pkg_cmd = "apt-get update -qq; apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:dotcloud/lxc-docker; apt-get update -qq; " \
"apt-get install -q -y lxc-docker; "
# Listen on all interfaces so that the daemon is accessible from the host
pkg_cmd << "sed -i -E 's| /usr/bin/docker -d| /usr/bin/docker -d -H 0.0.0.0|' /etc/init/docker.conf;"
# Add X.org Ubuntu backported 3.8 kernel
pkg_cmd << "add-apt-repository -y ppa:ubuntu-x-swat/r-lts-backport; " \
"apt-get update -qq; apt-get install -q -y linux-image-3.8.0-19-generic; "

200
api.go
View File

@@ -17,9 +17,10 @@ import (
"strings"
)
const APIVERSION = 1.3
const DEFAULTHTTPHOST string = "127.0.0.1"
const DEFAULTHTTPPORT int = 4243
const APIVERSION = 1.4
const DEFAULTHTTPHOST = "127.0.0.1"
const DEFAULTHTTPPORT = 4243
const DEFAULTUNIXSOCKET = "/var/run/docker.sock"
func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
conn, _, err := w.(http.Hijacker).Hijack()
@@ -47,21 +48,22 @@ func parseMultipartForm(r *http.Request) error {
}
func httpError(w http.ResponseWriter, err error) {
statusCode := http.StatusInternalServerError
if strings.HasPrefix(err.Error(), "No such") {
http.Error(w, err.Error(), http.StatusNotFound)
statusCode = http.StatusNotFound
} else if strings.HasPrefix(err.Error(), "Bad parameter") {
http.Error(w, err.Error(), http.StatusBadRequest)
statusCode = http.StatusBadRequest
} else if strings.HasPrefix(err.Error(), "Conflict") {
http.Error(w, err.Error(), http.StatusConflict)
statusCode = http.StatusConflict
} else if strings.HasPrefix(err.Error(), "Impossible") {
http.Error(w, err.Error(), http.StatusNotAcceptable)
statusCode = http.StatusNotAcceptable
} else if strings.HasPrefix(err.Error(), "Wrong login/password") {
http.Error(w, err.Error(), http.StatusUnauthorized)
statusCode = http.StatusUnauthorized
} else if strings.Contains(err.Error(), "hasn't been activated") {
http.Error(w, err.Error(), http.StatusForbidden)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
statusCode = http.StatusForbidden
}
utils.Debugf("[error %d] %s", statusCode, err)
http.Error(w, err.Error(), statusCode)
}
func writeJSON(w http.ResponseWriter, b []byte) {
@@ -80,54 +82,15 @@ func getBoolParam(value string) (bool, error) {
return ret, nil
}
func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version > 1.1 {
w.WriteHeader(http.StatusNotFound)
return nil
}
authConfig, err := auth.LoadConfig(srv.runtime.root)
if err != nil {
if err != auth.ErrConfigFileMissing {
return err
}
authConfig = &auth.AuthConfig{}
}
b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
if err != nil {
return err
}
writeJSON(w, b)
return nil
}
func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
authConfig := &auth.AuthConfig{}
err := json.NewDecoder(r.Body).Decode(authConfig)
if err != nil {
return err
}
status := ""
if version > 1.1 {
status, err = auth.Login(authConfig, false)
if err != nil {
return err
}
} else {
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
if err != nil {
if err != auth.ErrConfigFileMissing {
return err
}
}
if authConfig.Username == localAuthConfig.Username {
authConfig.Password = localAuthConfig.Password
}
newAuthConfig := auth.NewAuthConfig(authConfig.Username, authConfig.Password, authConfig.Email, srv.runtime.root)
status, err = auth.Login(newAuthConfig, true)
if err != nil {
return err
}
status, err := auth.Login(authConfig)
if err != nil {
return err
}
if status != "" {
b, err := json.Marshal(&APIAuth{Status: status})
@@ -170,7 +133,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r
name := vars["name"]
if err := srv.ContainerExport(name, w); err != nil {
utils.Debugf("%s", err.Error())
utils.Debugf("%s", err)
return err
}
return nil
@@ -216,6 +179,64 @@ func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
return nil
}
func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
sendEvent := func(wf *utils.WriteFlusher, event *utils.JSONMessage) error {
b, err := json.Marshal(event)
if err != nil {
return fmt.Errorf("JSON error")
}
_, err = wf.Write(b)
if err != nil {
// On error, evict the listener
utils.Debugf("%s", err)
srv.Lock()
delete(srv.listeners, r.RemoteAddr)
srv.Unlock()
return err
}
return nil
}
if err := parseForm(r); err != nil {
return err
}
listener := make(chan utils.JSONMessage)
srv.Lock()
srv.listeners[r.RemoteAddr] = listener
srv.Unlock()
since, err := strconv.ParseInt(r.Form.Get("since"), 10, 0)
if err != nil {
since = 0
}
w.Header().Set("Content-Type", "application/json")
wf := utils.NewWriteFlusher(w)
if since != 0 {
// If since, send previous events that happened after the timestamp
for _, event := range srv.events {
if event.Time >= since {
err := sendEvent(wf, &event)
if err != nil && err.Error() == "JSON error" {
continue
}
if err != nil {
return err
}
}
}
}
for {
event := <-listener
err := sendEvent(wf, &event)
if err != nil && err.Error() == "JSON error" {
continue
}
if err != nil {
return err
}
}
return nil
}
func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
@@ -250,6 +271,30 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r
return nil
}
func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version < 1.4 {
return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
name := vars["name"]
ps_args := r.Form.Get("ps_args")
procsStr, err := srv.ContainerTop(name, ps_args)
if err != nil {
return err
}
b, err := json.Marshal(procsStr)
if err != nil {
return err
}
writeJSON(w, b)
return nil
}
func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
@@ -306,7 +351,7 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req
}
config := &Config{}
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
utils.Debugf("%s", err.Error())
utils.Debugf("%s", err)
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
@@ -342,8 +387,7 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
}
sf := utils.NewStreamFormatter(version > 1.0)
if image != "" { //pull
registry := r.Form.Get("registry")
if err := srv.ImagePull(image, tag, registry, w, sf, &auth.AuthConfig{}); err != nil {
if err := srv.ImagePull(image, tag, w, sf, &auth.AuthConfig{}); err != nil {
if sf.Used() {
w.Write(sf.FormatError(err))
return nil
@@ -412,21 +456,12 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
authConfig := &auth.AuthConfig{}
if version > 1.1 {
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return err
}
} else {
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
if err != nil && err != auth.ErrConfigFileMissing {
return err
}
authConfig = localAuthConfig
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return err
}
if err := parseForm(r); err != nil {
return err
}
registry := r.Form.Get("registry")
if vars == nil {
return fmt.Errorf("Missing parameter")
@@ -436,7 +471,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
w.Header().Set("Content-Type", "application/json")
}
sf := utils.NewStreamFormatter(version > 1.0)
if err := srv.ImagePush(name, registry, w, sf, authConfig); err != nil {
if err := srv.ImagePush(name, w, sf, authConfig); err != nil {
if sf.Used() {
w.Write(sf.FormatError(err))
return nil
@@ -535,7 +570,7 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
return err
}
if imgs != nil {
if len(*imgs) != 0 {
if len(imgs) != 0 {
b, err := json.Marshal(imgs)
if err != nil {
return err
@@ -555,8 +590,10 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r
// allow a nil body for backwards compatibility
if r.Body != nil {
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
return err
if r.Header.Get("Content-Type") == "application/json" {
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
return err
}
}
}
@@ -756,6 +793,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
}
remoteURL := r.FormValue("remote")
repoName := r.FormValue("t")
rawSuppressOutput := r.FormValue("q")
tag := ""
if strings.Contains(repoName, ":") {
remoteParts := strings.Split(repoName, ":")
@@ -802,7 +840,13 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
}
context = c
}
b := NewBuildFile(srv, utils.NewWriteFlusher(w))
suppressOutput, err := getBoolParam(rawSuppressOutput)
if err != nil {
return err
}
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput)
id, err := b.Build(context)
if err != nil {
fmt.Fprintf(w, "Error build: %s\n", err)
@@ -829,9 +873,9 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
"GET": {
"/auth": getAuth,
"/version": getVersion,
"/events": getEvents,
"/info": getInfo,
"/version": getVersion,
"/images/json": getImagesJSON,
"/images/viz": getImagesViz,
"/images/search": getImagesSearch,
@@ -842,6 +886,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
"/containers/{name:.*}/export": getContainersExport,
"/containers/{name:.*}/changes": getContainersChanges,
"/containers/{name:.*}/json": getContainersByName,
"/containers/{name:.*}/top": getContainersTop,
},
"POST": {
"/auth": postAuth,
@@ -878,7 +923,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
localMethod := method
localFct := fct
f := func(w http.ResponseWriter, r *http.Request) {
utils.Debugf("Calling %s %s", localMethod, localRoute)
utils.Debugf("Calling %s %s from %s", localMethod, localRoute, r.RemoteAddr)
if logging {
log.Println(r.Method, r.RequestURI)
@@ -928,9 +973,8 @@ func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
if e != nil {
return e
}
//as the daemon is launched as root, change to permission of the socket to allow non-root to connect
if proto == "unix" {
os.Chmod(addr, 0777)
os.Chmod(addr, 0700)
}
httpSrv := http.Server{Addr: addr, Handler: r}
return httpSrv.Serve(l)

View File

@@ -17,13 +17,21 @@ type APIImages struct {
}
type APIInfo struct {
Debug bool
Containers int
Images int
NFd int `json:",omitempty"`
NGoroutines int `json:",omitempty"`
MemoryLimit bool `json:",omitempty"`
SwapLimit bool `json:",omitempty"`
Debug bool
Containers int
Images int
NFd int `json:",omitempty"`
NGoroutines int `json:",omitempty"`
MemoryLimit bool `json:",omitempty"`
SwapLimit bool `json:",omitempty"`
LXCVersion string `json:",omitempty"`
NEventsListener int `json:",omitempty"`
KernelVersion string `json:",omitempty"`
}
type APITop struct {
Titles []string
Processes [][]string
}
type APIRmi struct {

View File

@@ -5,7 +5,6 @@ import (
"bufio"
"bytes"
"encoding/json"
"github.com/dotcloud/docker/auth"
"github.com/dotcloud/docker/utils"
"io"
"net"
@@ -41,49 +40,9 @@ func TestGetBoolParam(t *testing.T) {
}
}
func TestPostAuth(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
}
r := httptest.NewRecorder()
authConfig := &auth.AuthConfig{
Username: "utest",
Password: "utest",
Email: "utest@yopmail.com",
}
authConfigJSON, err := json.Marshal(authConfig)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJSON))
if err != nil {
t.Fatal(err)
}
if err := postAuth(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
if r.Code != http.StatusOK && r.Code != 0 {
t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
}
}
func TestGetVersion(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
var err error
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -99,19 +58,21 @@ func TestGetVersion(t *testing.T) {
t.Fatal(err)
}
if v.Version != VERSION {
t.Errorf("Excepted version %s, %s found", VERSION, v.Version)
t.Errorf("Expected version %s, %s found", VERSION, v.Version)
}
}
func TestGetInfo(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
initialImages, err := srv.runtime.graph.All()
if err != nil {
t.Fatal(err)
}
r := httptest.NewRecorder()
if err := getInfo(srv, APIVERSION, r, nil, nil); err != nil {
@@ -123,21 +84,62 @@ func TestGetInfo(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if infos.Images != 1 {
t.Errorf("Excepted images: %d, %d found", 1, infos.Images)
if infos.Images != len(initialImages) {
t.Errorf("Expected images: %d, %d found", len(initialImages), infos.Images)
}
}
func TestGetImagesJSON(t *testing.T) {
runtime, err := newTestRuntime()
func TestGetEvents(t *testing.T) {
runtime := mkRuntime(t)
srv := &Server{
runtime: runtime,
events: make([]utils.JSONMessage, 0, 64),
listeners: make(map[string]chan utils.JSONMessage),
}
srv.LogEvent("fakeaction", "fakeid")
srv.LogEvent("fakeaction2", "fakeid")
req, err := http.NewRequest("GET", "/events?since=1", nil)
if err != nil {
t.Fatal(err)
}
r := httptest.NewRecorder()
setTimeout(t, "", 500*time.Millisecond, func() {
if err := getEvents(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
})
dec := json.NewDecoder(r.Body)
for i := 0; i < 2; i++ {
var jm utils.JSONMessage
if err := dec.Decode(&jm); err == io.EOF {
break
} else if err != nil {
t.Fatal(err)
}
if jm != srv.events[i] {
t.Fatalf("Event received it different than expected")
}
}
}
func TestGetImagesJSON(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
// all=0
initialImages, err := srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("GET", "/images/json?all=0", nil)
if err != nil {
t.Fatal(err)
@@ -154,17 +156,30 @@ func TestGetImagesJSON(t *testing.T) {
t.Fatal(err)
}
if len(images) != 1 {
t.Errorf("Excepted 1 image, %d found", len(images))
if len(images) != len(initialImages) {
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
}
if images[0].Repository != unitTestImageName {
t.Errorf("Excepted image %s, %s found", unitTestImageName, images[0].Repository)
found := false
for _, img := range images {
if img.Repository == unitTestImageName {
found = true
break
}
}
if !found {
t.Errorf("Expected image %s, %+v found", unitTestImageName, images)
}
r2 := httptest.NewRecorder()
// all=1
initialImages, err = srv.Images(true, "")
if err != nil {
t.Fatal(err)
}
req2, err := http.NewRequest("GET", "/images/json?all=true", nil)
if err != nil {
t.Fatal(err)
@@ -179,18 +194,25 @@ func TestGetImagesJSON(t *testing.T) {
t.Fatal(err)
}
if len(images2) != 1 {
t.Errorf("Excepted 1 image, %d found", len(images2))
if len(images2) != len(initialImages) {
t.Errorf("Expected %d image, %d found", len(initialImages), len(images2))
}
if images2[0].ID != GetTestImage(runtime).ID {
t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ID, images2[0].ID)
found = false
for _, img := range images2 {
if img.ID == GetTestImage(runtime).ID {
found = true
break
}
}
if !found {
t.Errorf("Retrieved image Id differs, expected %s, received %+v", GetTestImage(runtime).ID, images2)
}
r3 := httptest.NewRecorder()
// filter=a
req3, err := http.NewRequest("GET", "/images/json?filter=a", nil)
req3, err := http.NewRequest("GET", "/images/json?filter=aaaaaaaaaa", nil)
if err != nil {
t.Fatal(err)
}
@@ -205,7 +227,7 @@ func TestGetImagesJSON(t *testing.T) {
}
if len(images3) != 0 {
t.Errorf("Excepted 1 image, %d found", len(images3))
t.Errorf("Expected 0 image, %d found", len(images3))
}
r4 := httptest.NewRecorder()
@@ -228,10 +250,7 @@ func TestGetImagesJSON(t *testing.T) {
}
func TestGetImagesViz(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -251,46 +270,12 @@ func TestGetImagesViz(t *testing.T) {
t.Fatal(err)
}
if line != "digraph docker {\n" {
t.Errorf("Excepted digraph docker {\n, %s found", line)
}
}
func TestGetImagesSearch(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
}
r := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/images/search?term=redis", nil)
if err != nil {
t.Fatal(err)
}
if err := getImagesSearch(srv, APIVERSION, r, req, nil); err != nil {
t.Fatal(err)
}
results := []APISearch{}
if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil {
t.Fatal(err)
}
if len(results) < 2 {
t.Errorf("Excepted at least 2 lines, %d found", len(results))
t.Errorf("Expected digraph docker {\n, %s found", line)
}
}
func TestGetImagesHistory(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -306,15 +291,12 @@ func TestGetImagesHistory(t *testing.T) {
t.Fatal(err)
}
if len(history) != 1 {
t.Errorf("Excepted 1 line, %d found", len(history))
t.Errorf("Expected 1 line, %d found", len(history))
}
}
func TestGetImagesByName(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -328,16 +310,13 @@ func TestGetImagesByName(t *testing.T) {
if err := json.Unmarshal(r.Body.Bytes(), img); err != nil {
t.Fatal(err)
}
if img.ID != GetTestImage(runtime).ID || img.Comment != "Imported from http://get.docker.io/images/busybox" {
if img.ID != unitTestImageID {
t.Errorf("Error inspecting image")
}
}
func TestGetContainersJSON(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -365,7 +344,7 @@ func TestGetContainersJSON(t *testing.T) {
t.Fatal(err)
}
if len(containers) != 1 {
t.Fatalf("Excepted %d container, %d found", 1, len(containers))
t.Fatalf("Expected %d container, %d found", 1, len(containers))
}
if containers[0].ID != container.ID {
t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
@@ -373,10 +352,7 @@ func TestGetContainersJSON(t *testing.T) {
}
func TestGetContainersExport(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -428,10 +404,7 @@ func TestGetContainersExport(t *testing.T) {
}
func TestGetContainersChanges(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -475,7 +448,7 @@ func TestGetContainersChanges(t *testing.T) {
}
}
func TestGetContainersByName(t *testing.T) {
func TestGetContainersTop(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
@@ -486,6 +459,67 @@ func TestGetContainersByName(t *testing.T) {
builder := NewBuilder(runtime)
container, err := builder.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "sleep 2"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err)
}
// Give some time to the process to start
container.WaitTimeout(500 * time.Millisecond)
if !container.State.Running {
t.Errorf("Container should be running")
}
r := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/"+container.ID+"/top?ps_args=u", bytes.NewReader([]byte{}))
if err != nil {
t.Fatal(err)
}
if err := getContainersTop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
}
procs := APITop{}
if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil {
t.Fatal(err)
}
if len(procs.Titles) != 11 {
t.Fatalf("Expected 11 titles, found %d.", len(procs.Titles))
}
if procs.Titles[0] != "USER" || procs.Titles[10] != "COMMAND" {
t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.Titles[0], procs.Titles[10])
}
if len(procs.Processes) != 2 {
t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes))
}
if procs.Processes[0][10] != "/bin/sh" && procs.Processes[0][10] != "sleep" {
t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[0][10])
}
if procs.Processes[1][10] != "/bin/sh" && procs.Processes[1][10] != "sleep" {
t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[1][10])
}
}
func TestGetContainersByName(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
builder := NewBuilder(runtime)
// Create a container and remove a file
container, err := builder.Create(
&Config{
@@ -512,10 +546,7 @@ func TestGetContainersByName(t *testing.T) {
}
func TestPostCommit(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -560,249 +591,8 @@ func TestPostCommit(t *testing.T) {
}
}
func TestPostImagesCreate(t *testing.T) {
// FIXME: Use the staging in order to perform tests
// runtime, err := newTestRuntime()
// if err != nil {
// t.Fatal(err)
// }
// defer nuke(runtime)
// srv := &Server{runtime: runtime}
// stdin, stdinPipe := io.Pipe()
// stdout, stdoutPipe := io.Pipe()
// c1 := make(chan struct{})
// go func() {
// defer close(c1)
// r := &hijackTester{
// ResponseRecorder: httptest.NewRecorder(),
// in: stdin,
// out: stdoutPipe,
// }
// req, err := http.NewRequest("POST", "/images/create?fromImage="+unitTestImageName, bytes.NewReader([]byte{}))
// if err != nil {
// t.Fatal(err)
// }
// body, err := postImagesCreate(srv, r, req, nil)
// if err != nil {
// t.Fatal(err)
// }
// if body != nil {
// t.Fatalf("No body expected, received: %s\n", body)
// }
// }()
// // Acknowledge hijack
// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
// stdout.Read([]byte{})
// stdout.Read(make([]byte, 4096))
// })
// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
// reader := bufio.NewReader(stdout)
// line, err := reader.ReadString('\n')
// if err != nil {
// t.Fatal(err)
// }
// if !strings.HasPrefix(line, "Pulling repository d from") {
// t.Fatalf("Expected Pulling repository docker-ut from..., found %s", line)
// }
// })
// // Close pipes (client disconnects)
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
// t.Fatal(err)
// }
// // Wait for imagesCreate to finish, the client disconnected, therefore, Create finished his job
// setTimeout(t, "Waiting for imagesCreate timed out", 10*time.Second, func() {
// <-c1
// })
}
func TestPostImagesInsert(t *testing.T) {
// runtime, err := newTestRuntime()
// if err != nil {
// t.Fatal(err)
// }
// defer nuke(runtime)
// srv := &Server{runtime: runtime}
// stdin, stdinPipe := io.Pipe()
// stdout, stdoutPipe := io.Pipe()
// // Attach to it
// c1 := make(chan struct{})
// go func() {
// defer close(c1)
// r := &hijackTester{
// ResponseRecorder: httptest.NewRecorder(),
// in: stdin,
// out: stdoutPipe,
// }
// req, err := http.NewRequest("POST", "/images/"+unitTestImageName+"/insert?path=%2Ftest&url=https%3A%2F%2Fraw.github.com%2Fdotcloud%2Fdocker%2Fmaster%2FREADME.md", bytes.NewReader([]byte{}))
// if err != nil {
// t.Fatal(err)
// }
// if err := postContainersCreate(srv, r, req, nil); err != nil {
// t.Fatal(err)
// }
// }()
// // Acknowledge hijack
// setTimeout(t, "hijack acknowledge timed out", 5*time.Second, func() {
// stdout.Read([]byte{})
// stdout.Read(make([]byte, 4096))
// })
// id := ""
// setTimeout(t, "Waiting for imagesInsert output", 10*time.Second, func() {
// for {
// reader := bufio.NewReader(stdout)
// id, err = reader.ReadString('\n')
// if err != nil {
// t.Fatal(err)
// }
// }
// })
// // Close pipes (client disconnects)
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
// t.Fatal(err)
// }
// // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
// setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
// <-c1
// })
// img, err := srv.runtime.repositories.LookupImage(id)
// if err != nil {
// t.Fatalf("New image %s expected but not found", id)
// }
// layer, err := img.layer()
// if err != nil {
// t.Fatal(err)
// }
// if _, err := os.Stat(path.Join(layer, "test")); err != nil {
// t.Fatalf("The test file has not been found")
// }
// if err := srv.runtime.graph.Delete(img.ID); err != nil {
// t.Fatal(err)
// }
}
func TestPostImagesPush(t *testing.T) {
//FIXME: Use staging in order to perform tests
// runtime, err := newTestRuntime()
// if err != nil {
// t.Fatal(err)
// }
// defer nuke(runtime)
// srv := &Server{runtime: runtime}
// stdin, stdinPipe := io.Pipe()
// stdout, stdoutPipe := io.Pipe()
// c1 := make(chan struct{})
// go func() {
// r := &hijackTester{
// ResponseRecorder: httptest.NewRecorder(),
// in: stdin,
// out: stdoutPipe,
// }
// req, err := http.NewRequest("POST", "/images/docker-ut/push", bytes.NewReader([]byte{}))
// if err != nil {
// t.Fatal(err)
// }
// body, err := postImagesPush(srv, r, req, map[string]string{"name": "docker-ut"})
// close(c1)
// if err != nil {
// t.Fatal(err)
// }
// if body != nil {
// t.Fatalf("No body expected, received: %s\n", body)
// }
// }()
// // Acknowledge hijack
// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
// stdout.Read([]byte{})
// stdout.Read(make([]byte, 4096))
// })
// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
// reader := bufio.NewReader(stdout)
// line, err := reader.ReadString('\n')
// if err != nil {
// t.Fatal(err)
// }
// if !strings.HasPrefix(line, "Processing checksum") {
// t.Fatalf("Processing checksum..., found %s", line)
// }
// })
// // Close pipes (client disconnects)
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
// t.Fatal(err)
// }
// // Wait for imagesPush to finish, the client disconnected, therefore, Push finished his job
// setTimeout(t, "Waiting for imagesPush timed out", 10*time.Second, func() {
// <-c1
// })
}
func TestPostImagesTag(t *testing.T) {
// FIXME: Use staging in order to perform tests
// runtime, err := newTestRuntime()
// if err != nil {
// t.Fatal(err)
// }
// defer nuke(runtime)
// srv := &Server{runtime: runtime}
// r := httptest.NewRecorder()
// req, err := http.NewRequest("POST", "/images/docker-ut/tag?repo=testrepo&tag=testtag", bytes.NewReader([]byte{}))
// if err != nil {
// t.Fatal(err)
// }
// body, err := postImagesTag(srv, r, req, map[string]string{"name": "docker-ut"})
// if err != nil {
// t.Fatal(err)
// }
// if body != nil {
// t.Fatalf("No body expected, received: %s\n", body)
// }
// if r.Code != http.StatusCreated {
// t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
// }
}
func TestPostContainersCreate(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -853,10 +643,7 @@ func TestPostContainersCreate(t *testing.T) {
}
func TestPostContainersKill(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -898,10 +685,7 @@ func TestPostContainersKill(t *testing.T) {
}
func TestPostContainersRestart(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -955,10 +739,7 @@ func TestPostContainersRestart(t *testing.T) {
}
func TestPostContainersStart(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -1008,10 +789,7 @@ func TestPostContainersStart(t *testing.T) {
}
func TestPostContainersStop(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -1058,10 +836,7 @@ func TestPostContainersStop(t *testing.T) {
}
func TestPostContainersWait(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -1103,10 +878,7 @@ func TestPostContainersWait(t *testing.T) {
}
func TestPostContainersAttach(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -1132,6 +904,12 @@ func TestPostContainersAttach(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
// Try to avoid the timeoout in destroy. Best effort, don't check error
defer func() {
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
container.Kill()
}()
// Attach to it
c1 := make(chan struct{})
go func() {
@@ -1171,7 +949,7 @@ func TestPostContainersAttach(t *testing.T) {
}
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
<-c1
})
@@ -1192,10 +970,7 @@ func TestPostContainersAttach(t *testing.T) {
// FIXME: Test deleting container with volume
// FIXME: Test deleting volume in use by other container
func TestDeleteContainers(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -1235,10 +1010,7 @@ func TestDeleteContainers(t *testing.T) {
}
func TestOptionsRoute(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
@@ -1261,10 +1033,7 @@ func TestOptionsRoute(t *testing.T) {
}
func TestGetEnabledCors(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime, enableCors: true}
@@ -1302,14 +1071,16 @@ func TestGetEnabledCors(t *testing.T) {
}
func TestDeleteImages(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
initialImages, err := srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
if err := srv.runtime.repositories.Set("test", "test", unitTestImageName, true); err != nil {
t.Fatal(err)
}
@@ -1319,25 +1090,35 @@ func TestDeleteImages(t *testing.T) {
t.Fatal(err)
}
if len(images) != 2 {
t.Errorf("Excepted 2 images, %d found", len(images))
if len(images) != len(initialImages)+1 {
t.Errorf("Expected %d images, %d found", len(initialImages)+1, len(images))
}
req, err := http.NewRequest("DELETE", "/images/test:test", nil)
req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
if err != nil {
t.Fatal(err)
}
r := httptest.NewRecorder()
if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": "test:test"}); err != nil {
if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": unitTestImageID}); err == nil {
t.Fatalf("Expected conflict error, got none")
}
req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
if err != nil {
t.Fatal(err)
}
if r.Code != http.StatusOK {
r2 := httptest.NewRecorder()
if err := deleteImages(srv, APIVERSION, r2, req2, map[string]string{"name": "test:test"}); err != nil {
t.Fatal(err)
}
if r2.Code != http.StatusOK {
t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
}
var outs []APIRmi
if err := json.Unmarshal(r.Body.Bytes(), &outs); err != nil {
if err := json.Unmarshal(r2.Body.Bytes(), &outs); err != nil {
t.Fatal(err)
}
if len(outs) != 1 {
@@ -1348,8 +1129,8 @@ func TestDeleteImages(t *testing.T) {
t.Fatal(err)
}
if len(images) != 1 {
t.Errorf("Excepted 1 image, %d found", len(images))
if len(images) != len(initialImages) {
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
}
/* if c := runtime.Get(container.Id); c != nil {

View File

@@ -2,9 +2,7 @@ package docker
import (
"archive/tar"
"bufio"
"bytes"
"errors"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
@@ -27,10 +25,6 @@ const (
)
func DetectCompression(source []byte) Compression {
for _, c := range source[:10] {
utils.Debugf("%x", c)
}
sourceLen := len(source)
for compression, m := range map[Compression][]byte{
Bzip2: {0x42, 0x5A, 0x68},
@@ -111,17 +105,26 @@ func Untar(archive io.Reader, path string) error {
if archive == nil {
return fmt.Errorf("Empty archive")
}
bufferedArchive := bufio.NewReaderSize(archive, 10)
buf, err := bufferedArchive.Peek(10)
if err != nil {
return err
buf := make([]byte, 10)
totalN := 0
for totalN < 10 {
if n, err := archive.Read(buf[totalN:]); err != nil {
if err == io.EOF {
return fmt.Errorf("Tarball too short")
}
return err
} else {
totalN += n
utils.Debugf("[tar autodetect] n: %d", n)
}
}
compression := DetectCompression(buf)
utils.Debugf("Archive compression detected: %s", compression.Extension())
cmd := exec.Command("tar", "--numeric-owner", "-f", "-", "-C", path, "-x"+compression.Flag())
cmd.Stdin = bufferedArchive
cmd.Stdin = io.MultiReader(bytes.NewReader(buf), archive)
// Hardcode locale environment for predictable outcome regardless of host configuration.
// (see https://github.com/dotcloud/docker/issues/355)
cmd.Env = []string{"LANG=en_US.utf-8", "LC_ALL=en_US.utf-8"}
@@ -251,7 +254,7 @@ func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
}
errText := <-errChan
if err := cmd.Wait(); err != nil {
pipeW.CloseWithError(errors.New(err.Error() + ": " + string(errText)))
pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errText))
} else {
pipeW.Close()
}

View File

@@ -16,7 +16,7 @@ func TestCmdStreamLargeStderr(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello")
out, err := CmdStream(cmd)
if err != nil {
t.Fatalf("Failed to start command: " + err.Error())
t.Fatalf("Failed to start command: %s", err)
}
errCh := make(chan error)
go func() {
@@ -26,7 +26,7 @@ func TestCmdStreamLargeStderr(t *testing.T) {
select {
case err := <-errCh:
if err != nil {
t.Fatalf("Command should not have failed (err=%s...)", err.Error()[:100])
t.Fatalf("Command should not have failed (err=%.100s...)", err)
}
case <-time.After(5 * time.Second):
t.Fatalf("Command did not complete in 5 seconds; probable deadlock")
@@ -37,12 +37,12 @@ func TestCmdStreamBad(t *testing.T) {
badCmd := exec.Command("/bin/sh", "-c", "echo hello; echo >&2 error couldn\\'t reverse the phase pulser; exit 1")
out, err := CmdStream(badCmd)
if err != nil {
t.Fatalf("Failed to start command: " + err.Error())
t.Fatalf("Failed to start command: %s", err)
}
if output, err := ioutil.ReadAll(out); err == nil {
t.Fatalf("Command should have failed")
} else if err.Error() != "exit status 1: error couldn't reverse the phase pulser\n" {
t.Fatalf("Wrong error value (%s)", err.Error())
t.Fatalf("Wrong error value (%s)", err)
} else if s := string(output); s != "hello\n" {
t.Fatalf("Command output should be '%s', not '%s'", "hello\\n", output)
}

View File

@@ -15,8 +15,8 @@ import (
// Where we store the config file
const CONFIGFILE = ".dockercfg"
// the registry server we want to login against
const INDEXSERVER = "https://index.docker.io/v1"
// Only used for user auth + account creation
const INDEXSERVER = "https://index.docker.io/v1/"
//const INDEXSERVER = "http://indexstaging-docker.dotcloud.com/"
@@ -25,25 +25,18 @@ var (
)
type AuthConfig struct {
Username string `json:"username"`
Password string `json:"password"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Auth string `json:"auth"`
Email string `json:"email"`
}
type ConfigFile struct {
Configs map[string]AuthConfig `json:"configs,omitempty"`
rootPath string
}
func NewAuthConfig(username, password, email, rootPath string) *AuthConfig {
return &AuthConfig{
Username: username,
Password: password,
Email: email,
rootPath: rootPath,
}
}
func IndexServerAddress() string {
if os.Getenv("DOCKER_INDEX_URL") != "" {
return os.Getenv("DOCKER_INDEX_URL") + "/v1"
}
return INDEXSERVER
}
@@ -57,61 +50,89 @@ func encodeAuth(authConfig *AuthConfig) string {
}
// decode the auth string
func decodeAuth(authStr string) (*AuthConfig, error) {
func decodeAuth(authStr string) (string, string, error) {
decLen := base64.StdEncoding.DecodedLen(len(authStr))
decoded := make([]byte, decLen)
authByte := []byte(authStr)
n, err := base64.StdEncoding.Decode(decoded, authByte)
if err != nil {
return nil, err
return "", "", err
}
if n > decLen {
return nil, fmt.Errorf("Something went wrong decoding auth config")
return "", "", fmt.Errorf("Something went wrong decoding auth config")
}
arr := strings.Split(string(decoded), ":")
if len(arr) != 2 {
return nil, fmt.Errorf("Invalid auth configuration file")
return "", "", fmt.Errorf("Invalid auth configuration file")
}
password := strings.Trim(arr[1], "\x00")
return &AuthConfig{Username: arr[0], Password: password}, nil
return arr[0], password, nil
}
// load up the auth config information and return values
// FIXME: use the internal golang config parser
func LoadConfig(rootPath string) (*AuthConfig, error) {
func LoadConfig(rootPath string) (*ConfigFile, error) {
configFile := ConfigFile{Configs: make(map[string]AuthConfig), rootPath: rootPath}
confFile := path.Join(rootPath, CONFIGFILE)
if _, err := os.Stat(confFile); err != nil {
return &AuthConfig{rootPath: rootPath}, ErrConfigFileMissing
return &configFile, ErrConfigFileMissing
}
b, err := ioutil.ReadFile(confFile)
if err != nil {
return nil, err
}
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return nil, fmt.Errorf("The Auth config file is empty")
if err := json.Unmarshal(b, &configFile.Configs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return nil, fmt.Errorf("The Auth config file is empty")
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
if err != nil {
return nil, err
}
origEmail := strings.Split(arr[1], " = ")
authConfig.Email = origEmail[1]
configFile.Configs[IndexServerAddress()] = authConfig
} else {
for k, authConfig := range configFile.Configs {
authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
if err != nil {
return nil, err
}
authConfig.Auth = ""
configFile.Configs[k] = authConfig
}
}
origAuth := strings.Split(arr[0], " = ")
origEmail := strings.Split(arr[1], " = ")
authConfig, err := decodeAuth(origAuth[1])
if err != nil {
return nil, err
}
authConfig.Email = origEmail[1]
authConfig.rootPath = rootPath
return authConfig, nil
return &configFile, nil
}
// save the auth config
func SaveConfig(authConfig *AuthConfig) error {
confFile := path.Join(authConfig.rootPath, CONFIGFILE)
if len(authConfig.Email) == 0 {
func SaveConfig(configFile *ConfigFile) error {
confFile := path.Join(configFile.rootPath, CONFIGFILE)
if len(configFile.Configs) == 0 {
os.Remove(confFile)
return nil
}
lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n"
b := []byte(lines)
err := ioutil.WriteFile(confFile, b, 0600)
configs := make(map[string]AuthConfig, len(configFile.Configs))
for k, authConfig := range configFile.Configs {
authCopy := authConfig
authCopy.Auth = encodeAuth(&authCopy)
authCopy.Username = ""
authCopy.Password = ""
configs[k] = authCopy
}
b, err := json.Marshal(configs)
if err != nil {
return err
}
err = ioutil.WriteFile(confFile, b, 0600)
if err != nil {
return err
}
@@ -119,8 +140,7 @@ func SaveConfig(authConfig *AuthConfig) error {
}
// try to register/login to the registry server
func Login(authConfig *AuthConfig, store bool) (string, error) {
storeConfig := false
func Login(authConfig *AuthConfig) (string, error) {
client := &http.Client{}
reqStatusCode := 0
var status string
@@ -132,7 +152,7 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
b := strings.NewReader(string(jsonBody))
req1, err := http.Post(IndexServerAddress()+"/users/", "application/json; charset=utf-8", b)
req1, err := http.Post(IndexServerAddress()+"users/", "application/json; charset=utf-8", b)
if err != nil {
return "", fmt.Errorf("Server Error: %s", err)
}
@@ -146,13 +166,12 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
if reqStatusCode == 201 {
status = "Account created. Please use the confirmation link we sent" +
" to your e-mail to activate it."
storeConfig = true
} else if reqStatusCode == 403 {
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
"Please check your e-mail for a confirmation link.")
} else if reqStatusCode == 400 {
if string(reqBody) == "\"Username or email already exists\"" {
req, err := http.NewRequest("GET", IndexServerAddress()+"/users/", nil)
req, err := http.NewRequest("GET", IndexServerAddress()+"users/", nil)
req.SetBasicAuth(authConfig.Username, authConfig.Password)
resp, err := client.Do(req)
if err != nil {
@@ -165,14 +184,7 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
}
if resp.StatusCode == 200 {
status = "Login Succeeded"
storeConfig = true
} else if resp.StatusCode == 401 {
if store {
authConfig.Email = ""
if err := SaveConfig(authConfig); err != nil {
return "", err
}
}
return "", fmt.Errorf("Wrong login/password, please try again")
} else {
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
@@ -184,10 +196,5 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
} else {
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
}
if storeConfig && store {
if err := SaveConfig(authConfig); err != nil {
return "", err
}
}
return status, nil
}

View File

@@ -3,6 +3,7 @@ package auth
import (
"crypto/rand"
"encoding/hex"
"io/ioutil"
"os"
"strings"
"testing"
@@ -11,7 +12,9 @@ import (
func TestEncodeAuth(t *testing.T) {
newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
authStr := encodeAuth(newAuthConfig)
decAuthConfig, err := decodeAuth(authStr)
decAuthConfig := &AuthConfig{}
var err error
decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr)
if err != nil {
t.Fatal(err)
}
@@ -29,8 +32,8 @@ func TestEncodeAuth(t *testing.T) {
func TestLogin(t *testing.T) {
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
defer os.Setenv("DOCKER_INDEX_URL", "")
authConfig := NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", "/tmp")
status, err := Login(authConfig, false)
authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
status, err := Login(authConfig)
if err != nil {
t.Fatal(err)
}
@@ -49,8 +52,8 @@ func TestCreateAccount(t *testing.T) {
}
token := hex.EncodeToString(tokenBuffer)[:12]
username := "ut" + token
authConfig := NewAuthConfig(username, "test42", "docker-ut+"+token+"@example.com", "/tmp")
status, err := Login(authConfig, false)
authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
status, err := Login(authConfig)
if err != nil {
t.Fatal(err)
}
@@ -60,7 +63,7 @@ func TestCreateAccount(t *testing.T) {
t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
}
status, err = Login(authConfig, false)
status, err = Login(authConfig)
if err == nil {
t.Fatalf("Expected error but found nil instead")
}
@@ -68,6 +71,42 @@ func TestCreateAccount(t *testing.T) {
expectedError := "Login: Account is not Active"
if !strings.Contains(err.Error(), expectedError) {
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err.Error())
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
}
}
func TestSameAuthDataPostSave(t *testing.T) {
root, err := ioutil.TempDir("", "docker-test")
if err != nil {
t.Fatal(err)
}
configFile := &ConfigFile{
rootPath: root,
Configs: make(map[string]AuthConfig, 1),
}
configFile.Configs["testIndex"] = AuthConfig{
Username: "docker-user",
Password: "docker-pass",
Email: "docker@docker.io",
}
err = SaveConfig(configFile)
if err != nil {
t.Fatal(err)
}
authConfig := configFile.Configs["testIndex"]
if authConfig.Username != "docker-user" {
t.Fail()
}
if authConfig.Password != "docker-pass" {
t.Fail()
}
if authConfig.Email != "docker@docker.io" {
t.Fail()
}
if authConfig.Auth != "" {
t.Fail()
}
}

View File

@@ -50,12 +50,23 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
config.Hostname = id[:12]
}
var args []string
var entrypoint string
if len(config.Entrypoint) != 0 {
entrypoint = config.Entrypoint[0]
args = append(config.Entrypoint[1:], config.Cmd...)
} else {
entrypoint = config.Cmd[0]
args = config.Cmd[1:]
}
container := &Container{
// FIXME: we should generate the ID here instead of receiving it as an argument
ID: id,
Created: time.Now(),
Path: config.Cmd[0],
Args: config.Cmd[1:], //FIXME: de-duplicate from config
Path: entrypoint,
Args: args, //FIXME: de-duplicate from config
Config: config,
Image: img.ID, // Always use the resolved image id
NetworkSettings: &NetworkSettings{},
@@ -113,6 +124,10 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
// FIXME: freeze the container before copying it to avoid data corruption?
// FIXME: this shouldn't be in commands.
if err := container.EnsureMounted(); err != nil {
return nil, err
}
rwTar, err := container.ExportRw()
if err != nil {
return nil, err

View File

@@ -7,9 +7,11 @@ import (
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"net/url"
"os"
"path"
"reflect"
"regexp"
"strings"
)
@@ -28,6 +30,7 @@ type buildFile struct {
maintainer string
config *Config
context string
verbose bool
tmpContainers map[string]struct{}
tmpImages map[string]struct{}
@@ -51,20 +54,10 @@ func (b *buildFile) CmdFrom(name string) error {
image, err := b.runtime.repositories.LookupImage(name)
if err != nil {
if b.runtime.graph.IsNotExist(err) {
var tag, remote string
if strings.Contains(name, ":") {
remoteParts := strings.Split(name, ":")
tag = remoteParts[1]
remote = remoteParts[0]
} else {
remote = name
}
if err := b.srv.ImagePull(remote, tag, "", b.out, utils.NewStreamFormatter(false), nil); err != nil {
remote, tag := utils.ParseRepositoryTag(name)
if err := b.srv.ImagePull(remote, tag, b.out, utils.NewStreamFormatter(false), nil); err != nil {
return err
}
image, err = b.runtime.repositories.LookupImage(name)
if err != nil {
return err
@@ -75,6 +68,9 @@ func (b *buildFile) CmdFrom(name string) error {
}
b.image = image.ID
b.config = &Config{}
if b.config.Env == nil || len(b.config.Env) == 0 {
b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
}
return nil
}
@@ -120,6 +116,40 @@ func (b *buildFile) CmdRun(args string) error {
return nil
}
func (b *buildFile) FindEnvKey(key string) int {
for k, envVar := range b.config.Env {
envParts := strings.SplitN(envVar, "=", 2)
if key == envParts[0] {
return k
}
}
return -1
}
func (b *buildFile) ReplaceEnvMatches(value string) (string, error) {
exp, err := regexp.Compile("(\\\\\\\\+|[^\\\\]|\\b|\\A)\\$({?)([[:alnum:]_]+)(}?)")
if err != nil {
return value, err
}
matches := exp.FindAllString(value, -1)
for _, match := range matches {
match = match[strings.Index(match, "$"):]
matchKey := strings.Trim(match, "${}")
for _, envVar := range b.config.Env {
envParts := strings.SplitN(envVar, "=", 2)
envKey := envParts[0]
envValue := envParts[1]
if envKey == matchKey {
value = strings.Replace(value, match, envValue, -1)
break
}
}
}
return value, nil
}
func (b *buildFile) CmdEnv(args string) error {
tmp := strings.SplitN(args, " ", 2)
if len(tmp) != 2 {
@@ -128,20 +158,25 @@ func (b *buildFile) CmdEnv(args string) error {
key := strings.Trim(tmp[0], " \t")
value := strings.Trim(tmp[1], " \t")
for i, elem := range b.config.Env {
if strings.HasPrefix(elem, key+"=") {
b.config.Env[i] = key + "=" + value
return nil
}
envKey := b.FindEnvKey(key)
replacedValue, err := b.ReplaceEnvMatches(value)
if err != nil {
return err
}
b.config.Env = append(b.config.Env, key+"="+value)
return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
replacedVar := fmt.Sprintf("%s=%s", key, replacedValue)
if envKey >= 0 {
b.config.Env[envKey] = replacedVar
return nil
}
b.config.Env = append(b.config.Env, replacedVar)
return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s", replacedVar))
}
func (b *buildFile) CmdCmd(args string) error {
var cmd []string
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err)
cmd = []string{"/bin/sh", "-c", args}
}
if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
@@ -165,6 +200,44 @@ func (b *buildFile) CmdCopy(args string) error {
return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
}
func (b *buildFile) CmdEntrypoint(args string) error {
if args == "" {
return fmt.Errorf("Entrypoint cannot be empty")
}
var entrypoint []string
if err := json.Unmarshal([]byte(args), &entrypoint); err != nil {
b.config.Entrypoint = []string{"/bin/sh", "-c", args}
} else {
b.config.Entrypoint = entrypoint
}
if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %s", args)); err != nil {
return err
}
return nil
}
func (b *buildFile) CmdVolume(args string) error {
if args == "" {
return fmt.Errorf("Volume cannot be empty")
}
var volume []string
if err := json.Unmarshal([]byte(args), &volume); err != nil {
volume = []string{args}
}
if b.config.Volumes == nil {
b.config.Volumes = NewPathOpts()
}
for _, v := range volume {
b.config.Volumes[v] = struct{}{}
}
if err := b.commit("", b.config.Cmd, fmt.Sprintf("VOLUME %s", args)); err != nil {
return err
}
return nil
}
func (b *buildFile) addRemote(container *Container, orig, dest string) error {
file, err := utils.Download(orig, ioutil.Discard)
if err != nil {
@@ -172,6 +245,24 @@ func (b *buildFile) addRemote(container *Container, orig, dest string) error {
}
defer file.Body.Close()
// If the destination is a directory, figure out the filename.
if strings.HasSuffix(dest, "/") {
u, err := url.Parse(orig)
if err != nil {
return err
}
path := u.Path
if strings.HasSuffix(path, "/") {
path = path[:len(path)-1]
}
parts := strings.Split(path, "/")
filename := parts[len(parts)-1]
if filename == "" {
return fmt.Errorf("cannot determine filename from url: %s", u)
}
dest = dest + filename
}
return container.Inject(file.Body, dest)
}
@@ -179,9 +270,12 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
origPath := path.Join(b.context, orig)
destPath := path.Join(container.RootfsPath(), dest)
// Preserve the trailing '/'
if dest[len(dest)-1] == '/' {
if strings.HasSuffix(dest, "/") {
destPath = destPath + "/"
}
if !strings.HasPrefix(origPath, b.context) {
return fmt.Errorf("Forbidden path: %s", origPath)
}
fi, err := os.Stat(origPath)
if err != nil {
return err
@@ -194,7 +288,7 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
} else if err := UntarPath(origPath, destPath); err != nil {
utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
// If that fails, just copy it as a regular file
if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
return err
}
if err := CopyWithTar(origPath, destPath); err != nil {
@@ -212,8 +306,16 @@ func (b *buildFile) CmdAdd(args string) error {
if len(tmp) != 2 {
return fmt.Errorf("Invalid ADD format")
}
orig := strings.Trim(tmp[0], " \t")
dest := strings.Trim(tmp[1], " \t")
orig, err := b.ReplaceEnvMatches(strings.Trim(tmp[0], " \t"))
if err != nil {
return err
}
dest, err := b.ReplaceEnvMatches(strings.Trim(tmp[1], " \t"))
if err != nil {
return err
}
cmd := b.config.Cmd
b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}
@@ -262,12 +364,23 @@ func (b *buildFile) run() (string, error) {
b.tmpContainers[c.ID] = struct{}{}
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
// override the entry point that may have been picked up from the base image
c.Path = b.config.Cmd[0]
c.Args = b.config.Cmd[1:]
//start the container
hostConfig := &HostConfig{}
if err := c.Start(hostConfig); err != nil {
return "", err
}
if b.verbose {
err = <-c.Attach(nil, nil, b.out, b.out)
if err != nil {
return "", err
}
}
// Wait for it to finish
if ret := c.Wait(); ret != 0 {
return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
@@ -390,7 +503,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
return "", fmt.Errorf("An error occured during the build\n")
}
func NewBuildFile(srv *Server, out io.Writer) BuildFile {
func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
return &buildFile{
builder: NewBuilder(srv.runtime),
runtime: srv.runtime,
@@ -399,5 +512,6 @@ func NewBuildFile(srv *Server, out io.Writer) BuildFile {
out: out,
tmpContainers: make(map[string]struct{}),
tmpImages: make(map[string]struct{}),
verbose: verbose,
}
}

View File

@@ -1,16 +1,19 @@
package docker
import (
"io/ioutil"
"sync"
"testing"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// mkTestContext generates a build context from the contents of the provided dockerfile.
// This context is suitable for use as an argument to BuildFile.Build()
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) Archive {
context, err := mkBuildContext(fmt.Sprintf(dockerfile, unitTestImageId), files)
context, err := mkBuildContext(dockerfile, files)
if err != nil {
t.Fatal(err)
}
@@ -23,34 +26,40 @@ type testContextTemplate struct {
dockerfile string
// Additional files in the context, eg [][2]string{"./passwd", "gordon"}
files [][2]string
// Additional remote files to host on a local HTTP server.
remoteFiles [][2]string
}
// A table of all the contexts to build and test.
// A new docker runtime will be created and torn down for each context.
var testContexts []testContextTemplate = []testContextTemplate{
var testContexts = []testContextTemplate{
{
`
from %s
from {IMAGE}
run sh -c 'echo root:testpass > /tmp/passwd'
run mkdir -p /var/run/sshd
run [ "$(cat /tmp/passwd)" = "root:testpass" ]
run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
`,
nil,
nil,
},
{
`
from %s
from {IMAGE}
add foo /usr/lib/bla/bar
run [ "$(cat /usr/lib/bla/bar)" = 'hello world!' ]
run [ "$(cat /usr/lib/bla/bar)" = 'hello' ]
add http://{SERVERADDR}/baz /usr/lib/baz/quux
run [ "$(cat /usr/lib/baz/quux)" = 'world!' ]
`,
[][2]string{{"foo", "hello world!"}},
[][2]string{{"foo", "hello"}},
[][2]string{{"/baz", "world!"}},
},
{
`
from %s
from {IMAGE}
add f /
run [ "$(cat /f)" = "hello" ]
add f /abc
@@ -72,38 +81,296 @@ run [ "$(cat /somewheeeere/over/the/rainbooow/ga)" = "bu" ]
{"f", "hello"},
{"d/ga", "bu"},
},
nil,
},
{
`
from %s
from {IMAGE}
add http://{SERVERADDR}/x /a/b/c
run [ "$(cat /a/b/c)" = "hello" ]
add http://{SERVERADDR}/x?foo=bar /
run [ "$(cat /x)" = "hello" ]
add http://{SERVERADDR}/x /d/
run [ "$(cat /d/x)" = "hello" ]
add http://{SERVERADDR} /e
run [ "$(cat /e)" = "blah" ]
`,
nil,
[][2]string{{"/x", "hello"}, {"/", "blah"}},
},
{
`
from {IMAGE}
env FOO BAR
run [ "$FOO" = "BAR" ]
`,
nil,
nil,
},
{
`
from {IMAGE}
ENTRYPOINT /bin/echo
CMD Hello world
`,
nil,
nil,
},
{
`
from {IMAGE}
VOLUME /test
CMD Hello world
`,
nil,
nil,
},
{
`
from {IMAGE}
env FOO /foo/baz
env BAR /bar
env BAZ $BAR
env FOOPATH $PATH:$FOO
run [ "$BAR" = "$BAZ" ]
run [ "$FOOPATH" = "$PATH:/foo/baz" ]
`,
nil,
nil,
},
{
`
from {IMAGE}
env FOO /bar
env TEST testdir
env BAZ /foobar
add testfile $BAZ/
add $TEST $FOO
run [ "$(cat /foobar/testfile)" = "test1" ]
run [ "$(cat /bar/withfile)" = "test2" ]
`,
[][2]string{
{"testfile", "test1"},
{"testdir/withfile", "test2"},
},
nil,
},
}
// FIXME: test building with 2 successive overlapping ADD commands
func constructDockerfile(template string, ip net.IP, port string) string {
serverAddr := fmt.Sprintf("%s:%s", ip, port)
replacer := strings.NewReplacer("{IMAGE}", unitTestImageID, "{SERVERADDR}", serverAddr)
return replacer.Replace(template)
}
func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
mux := http.NewServeMux()
for _, file := range files {
name, contents := file[0], file[1]
mux.HandleFunc(name, func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(contents))
})
}
// This is how httptest.NewServer sets up a net.Listener, except that our listener must accept remote
// connections (from the container).
listener, err := net.Listen("tcp", ":0")
if err != nil {
return nil, err
}
s := httptest.NewUnstartedServer(mux)
s.Listener = listener
s.Start()
return s, nil
}
func TestBuild(t *testing.T) {
for _, ctx := range testContexts {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
buildImage(ctx, t)
}
}
srv := &Server{
runtime: runtime,
lock: &sync.Mutex{},
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
func buildImage(context testContextTemplate, t *testing.T) *Image {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
buildfile := NewBuildFile(srv, ioutil.Discard)
if _, err := buildfile.Build(mkTestContext(ctx.dockerfile, ctx.files, t)); err != nil {
t.Fatal(err)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
httpServer, err := mkTestingFileServer(context.remoteFiles)
if err != nil {
t.Fatal(err)
}
defer httpServer.Close()
idx := strings.LastIndex(httpServer.URL, ":")
if idx < 0 {
t.Fatalf("could not get port from test http server address %s", httpServer.URL)
}
port := httpServer.URL[idx+1:]
ip := runtime.networkManager.bridgeNetwork.IP
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := NewBuildFile(srv, ioutil.Discard, false)
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
if err != nil {
t.Fatal(err)
}
img, err := srv.ImageInspect(id)
if err != nil {
t.Fatal(err)
}
return img
}
func TestVolume(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
volume /test
cmd Hello world
`, nil, nil}, t)
if len(img.Config.Volumes) == 0 {
t.Fail()
}
for key := range img.Config.Volumes {
if key != "/test" {
t.Fail()
}
}
}
func TestBuildMaintainer(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
maintainer dockerio
`, nil, nil}, t)
if img.Author != "dockerio" {
t.Fail()
}
}
func TestBuildEnv(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
env port 4243
`,
nil, nil}, t)
hasEnv := false
for _, envVar := range img.Config.Env {
if envVar == "port=4243" {
hasEnv = true
break
}
}
if !hasEnv {
t.Fail()
}
}
func TestBuildCmd(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
cmd ["/bin/echo", "Hello World"]
`,
nil, nil}, t)
if img.Config.Cmd[0] != "/bin/echo" {
t.Log(img.Config.Cmd[0])
t.Fail()
}
if img.Config.Cmd[1] != "Hello World" {
t.Log(img.Config.Cmd[1])
t.Fail()
}
}
func TestBuildExpose(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
expose 4243
`,
nil, nil}, t)
if img.Config.PortSpecs[0] != "4243" {
t.Fail()
}
}
func TestBuildEntrypoint(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
entrypoint ["/bin/echo"]
`,
nil, nil}, t)
if img.Config.Entrypoint[0] != "/bin/echo" {
}
}
func TestForbiddenContextPath(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
context := testContextTemplate{`
from {IMAGE}
maintainer dockerio
add ../../ test/
`,
[][2]string{{"test.txt", "test1"}, {"other.txt", "other"}}, nil}
httpServer, err := mkTestingFileServer(context.remoteFiles)
if err != nil {
t.Fatal(err)
}
defer httpServer.Close()
idx := strings.LastIndex(httpServer.URL, ":")
if idx < 0 {
t.Fatalf("could not get port from test http server address %s", httpServer.URL)
}
port := httpServer.URL[idx+1:]
ip := srv.runtime.networkManager.bridgeNetwork.IP
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := NewBuildFile(srv, ioutil.Discard, false)
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
if err == nil {
t.Log("Error should not be nil")
t.Fail()
}
if err.Error() != "Forbidden path: /" {
t.Logf("Error message is not expected: %s", err.Error())
t.Fail()
}
}

View File

@@ -19,7 +19,6 @@ import (
"os/signal"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"syscall"
@@ -28,7 +27,7 @@ import (
"unicode"
)
const VERSION = "0.4.7"
const VERSION = "0.5.2"
var (
GITCOMMIT string
@@ -73,12 +72,13 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
return nil
}
}
help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socker to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT)
help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT)
for _, command := range [][]string{
{"attach", "Attach to a running container"},
{"build", "Build a container from a Dockerfile"},
{"commit", "Create a new image from a container's changes"},
{"diff", "Inspect changes on a container's filesystem"},
{"events", "Get real time events from the server"},
{"export", "Stream the contents of a container as a tar archive"},
{"history", "Show the history of an image"},
{"images", "List images"},
@@ -90,12 +90,13 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
{"login", "Register or Login to the docker registry server"},
{"logs", "Fetch the logs of a container"},
{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
{"top", "Lookup the running processes of a container"},
{"ps", "List containers"},
{"pull", "Pull an image or a repository from the docker registry server"},
{"push", "Push an image or a repository to the docker registry server"},
{"restart", "Restart a running container"},
{"rm", "Remove a container"},
{"rmi", "Remove an image"},
{"rm", "Remove one or more containers"},
{"rmi", "Remove one or more images"},
{"run", "Run a command in a new container"},
{"search", "Search for an image in the docker index"},
{"start", "Start a stopped container"},
@@ -158,6 +159,8 @@ func mkBuildContext(dockerfile string, files [][2]string) (Archive, error) {
func (cli *DockerCli) CmdBuild(args ...string) error {
cmd := Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
tag := cmd.String("t", "", "Tag to be applied to the resulting image in case of success")
suppressOutput := cmd.Bool("q", false, "Suppress verbose build output")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -183,6 +186,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
} else if utils.IsURL(cmd.Arg(0)) || utils.IsGIT(cmd.Arg(0)) {
isRemote = true
} else {
if _, err := os.Stat(cmd.Arg(0)); err != nil {
return err
}
context, err = Tar(cmd.Arg(0), Uncompressed)
}
var body io.Reader
@@ -195,6 +201,10 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
// Upload the build context
v := &url.Values{}
v.Set("t", *tag)
if *suppressOutput {
v.Set("q", "1")
}
if isRemote {
v.Set("remote", cmd.Arg(0))
}
@@ -280,57 +290,88 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
return readStringOnRawTerminal(stdin, stdout, false)
}
oldState, err := term.SetRawTerminal(cli.terminalFd)
cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server")
flUsername := cmd.String("u", "", "username")
flPassword := cmd.String("p", "", "password")
flEmail := cmd.String("e", "", "email")
err := cmd.Parse(args)
if err != nil {
return err
}
defer term.RestoreTerminal(cli.terminalFd, oldState)
cmd := Subcmd("login", "", "Register or Login to the docker registry server")
if err := cmd.Parse(args); err != nil {
return nil
}
var oldState *term.State
if *flUsername == "" || *flPassword == "" || *flEmail == "" {
oldState, err = term.SetRawTerminal(cli.terminalFd)
if err != nil {
return err
}
defer term.RestoreTerminal(cli.terminalFd, oldState)
}
var (
username string
password string
email string
)
fmt.Fprintf(cli.out, "Username (%s):", cli.authConfig.Username)
username = readAndEchoString(cli.in, cli.out)
if username == "" {
username = cli.authConfig.Username
}
if username != cli.authConfig.Username {
fmt.Fprintf(cli.out, "Password: ")
password = readString(cli.in, cli.out)
if password == "" {
return fmt.Errorf("Error : Password Required")
var promptDefault = func(prompt string, configDefault string) {
if configDefault == "" {
fmt.Fprintf(cli.out, "%s: ", prompt)
} else {
fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
}
}
fmt.Fprintf(cli.out, "Email (%s): ", cli.authConfig.Email)
email = readAndEchoString(cli.in, cli.out)
if email == "" {
email = cli.authConfig.Email
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
if !ok {
authconfig = auth.AuthConfig{}
}
if *flUsername == "" {
promptDefault("Username", authconfig.Username)
username = readAndEchoString(cli.in, cli.out)
if username == "" {
username = authconfig.Username
}
} else {
password = cli.authConfig.Password
email = cli.authConfig.Email
username = *flUsername
}
term.RestoreTerminal(cli.terminalFd, oldState)
if username != authconfig.Username {
if *flPassword == "" {
fmt.Fprintf(cli.out, "Password: ")
password = readString(cli.in, cli.out)
if password == "" {
return fmt.Errorf("Error : Password Required")
}
} else {
password = *flPassword
}
cli.authConfig.Username = username
cli.authConfig.Password = password
cli.authConfig.Email = email
if *flEmail == "" {
promptDefault("Email", authconfig.Email)
email = readAndEchoString(cli.in, cli.out)
if email == "" {
email = authconfig.Email
}
} else {
email = *flEmail
}
} else {
password = authconfig.Password
email = authconfig.Email
}
if oldState != nil {
term.RestoreTerminal(cli.terminalFd, oldState)
}
authconfig.Username = username
authconfig.Password = password
authconfig.Email = email
cli.configFile.Configs[auth.IndexServerAddress()] = authconfig
body, statusCode, err := cli.call("POST", "/auth", cli.authConfig)
body, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[auth.IndexServerAddress()])
if statusCode == 401 {
cli.authConfig.Username = ""
cli.authConfig.Password = ""
cli.authConfig.Email = ""
auth.SaveConfig(cli.authConfig)
delete(cli.configFile.Configs, auth.IndexServerAddress())
auth.SaveConfig(cli.configFile)
return err
}
if err != nil {
@@ -340,10 +381,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
var out2 APIAuth
err = json.Unmarshal(body, &out2)
if err != nil {
auth.LoadConfig(os.Getenv("HOME"))
cli.configFile, _ = auth.LoadConfig(os.Getenv("HOME"))
return err
}
auth.SaveConfig(cli.authConfig)
auth.SaveConfig(cli.configFile)
if out2.Status != "" {
fmt.Fprintf(cli.out, "%s\n", out2.Status)
}
@@ -438,6 +479,9 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
fmt.Fprintf(cli.out, "Fds: %d\n", out.NFd)
fmt.Fprintf(cli.out, "Goroutines: %d\n", out.NGoroutines)
fmt.Fprintf(cli.out, "LXC Version: %s\n", out.LXCVersion)
fmt.Fprintf(cli.out, "EventsListeners: %d\n", out.NEventsListener)
fmt.Fprintf(cli.out, "Kernel Version: %s\n", out.KernelVersion)
}
if !out.MemoryLimit {
fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
@@ -450,7 +494,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
func (cli *DockerCli) CmdStop(args ...string) error {
cmd := Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container")
nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
nSeconds := cmd.Int("t", 10, "Number of seconds to wait for the container to stop before killing it.")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -475,7 +519,7 @@ func (cli *DockerCli) CmdStop(args ...string) error {
func (cli *DockerCli) CmdRestart(args ...string) error {
cmd := Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
nSeconds := cmd.Int("t", 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -555,6 +599,38 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
return nil
}
func (cli *DockerCli) CmdTop(args ...string) error {
cmd := Subcmd("top", "CONTAINER", "Lookup the running processes of a container")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() == 0 {
cmd.Usage()
return nil
}
val := url.Values{}
if cmd.NArg() > 1 {
val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
}
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil)
if err != nil {
return err
}
procs := APITop{}
err = json.Unmarshal(body, &procs)
if err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, strings.Join(procs.Titles, "\t"))
for _, proc := range procs.Processes {
fmt.Fprintln(w, strings.Join(proc, "\t"))
}
w.Flush()
return nil
}
func (cli *DockerCli) CmdPort(args ...string) error {
cmd := Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
if err := cmd.Parse(args); err != nil {
@@ -565,6 +641,13 @@ func (cli *DockerCli) CmdPort(args ...string) error {
return nil
}
port := cmd.Arg(1)
proto := "Tcp"
parts := strings.SplitN(port, "/", 2)
if len(parts) == 2 && len(parts[1]) != 0 {
port = parts[0]
proto = strings.ToUpper(parts[1][:1]) + strings.ToLower(parts[1][1:])
}
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)
if err != nil {
return err
@@ -575,7 +658,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
return err
}
if frontend, exists := out.NetworkSettings.PortMapping[cmd.Arg(1)]; exists {
if frontend, exists := out.NetworkSettings.PortMapping[proto][port]; exists {
fmt.Fprintf(cli.out, "%s\n", frontend)
} else {
return fmt.Errorf("Error: No private port '%s' allocated on %s", cmd.Arg(1), cmd.Arg(0))
@@ -585,7 +668,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
// 'docker rmi IMAGE' removes all images with the name IMAGE
func (cli *DockerCli) CmdRmi(args ...string) error {
cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -650,7 +733,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
}
func (cli *DockerCli) CmdRm(args ...string) error {
cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove a container")
cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
v := cmd.Bool("v", false, "Remove the volumes associated to the container")
if err := cmd.Parse(args); err != nil {
return nil
@@ -697,7 +780,7 @@ func (cli *DockerCli) CmdKill(args ...string) error {
}
func (cli *DockerCli) CmdImport(args ...string) error {
cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).")
if err := cmd.Parse(args); err != nil {
return nil
@@ -720,8 +803,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
}
func (cli *DockerCli) CmdPush(args ...string) error {
cmd := Subcmd("push", "[OPTION] NAME", "Push an image or a repository to the registry")
registry := cmd.String("registry", "", "Registry host to push the image to")
cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -732,37 +814,24 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return nil
}
if err := cli.checkIfLogged(*registry == "", "push"); err != nil {
if err := cli.checkIfLogged("push"); err != nil {
return err
}
if *registry == "" {
// If we're not using a custom registry, we know the restrictions
// applied to repository names and can warn the user in advance.
// Custom repositories can have different rules, and we must also
// allow pushing by image ID.
if len(strings.SplitN(name, "/", 2)) == 1 {
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
}
nameParts := strings.SplitN(name, "/", 2)
validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
if !validNamespace.MatchString(nameParts[0]) {
return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", nameParts[0])
}
validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
if !validRepo.MatchString(nameParts[1]) {
return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", nameParts[1])
}
// If we're not using a custom registry, we know the restrictions
// applied to repository names and can warn the user in advance.
// Custom repositories can have different rules, and we must also
// allow pushing by image ID.
if len(strings.SplitN(name, "/", 2)) == 1 {
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
}
buf, err := json.Marshal(cli.authConfig)
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
if err != nil {
return err
}
v := url.Values{}
v.Set("registry", *registry)
if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out); err != nil {
return err
}
@@ -772,7 +841,6 @@ func (cli *DockerCli) CmdPush(args ...string) error {
func (cli *DockerCli) CmdPull(args ...string) error {
cmd := Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
tag := cmd.String("t", "", "Download tagged image in repository")
registry := cmd.String("registry", "", "Registry to download from. Necessary if image is pulled by ID")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -782,17 +850,14 @@ func (cli *DockerCli) CmdPull(args ...string) error {
return nil
}
remote := cmd.Arg(0)
if strings.Contains(remote, ":") {
remoteParts := strings.Split(remote, ":")
tag = &remoteParts[1]
remote = remoteParts[0]
remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
if *tag == "" {
*tag = parsedTag
}
v := url.Values{}
v.Set("fromImage", remote)
v.Set("tag", *tag)
v.Set("registry", *registry)
if err := cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out); err != nil {
return err
@@ -1011,6 +1076,29 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
return nil
}
func (cli *DockerCli) CmdEvents(args ...string) error {
cmd := Subcmd("events", "[OPTIONS]", "Get real time events from the server")
since := cmd.String("since", "", "Show events previously created (used for polling).")
if err := cmd.Parse(args); err != nil {
return nil
}
if cmd.NArg() != 0 {
cmd.Usage()
return nil
}
v := url.Values{}
if *since != "" {
v.Set("since", *since)
}
if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out); err != nil {
return err
}
return nil
}
func (cli *DockerCli) CmdExport(args ...string) error {
cmd := Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive")
if err := cmd.Parse(args); err != nil {
@@ -1064,10 +1152,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
return nil
}
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1", false, nil, cli.out); err != nil {
return err
}
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stderr=1", false, nil, cli.err); err != nil {
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1&stderr=1", false, nil, cli.out); err != nil {
return err
}
return nil
@@ -1118,6 +1203,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
func (cli *DockerCli) CmdSearch(args ...string) error {
cmd := Subcmd("search", "NAME", "Search the docker index for images")
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
if err := cmd.Parse(args); err != nil {
return nil
}
@@ -1139,13 +1225,19 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
return err
}
fmt.Fprintf(cli.out, "Found %d results matching your query (\"%s\")\n", len(outs), cmd.Arg(0))
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
w := tabwriter.NewWriter(cli.out, 33, 1, 3, ' ', 0)
fmt.Fprintf(w, "NAME\tDESCRIPTION\n")
_, width := cli.getTtySize()
if width == 0 {
width = 45
} else {
width = width - 33 //remote the first column
}
for _, out := range outs {
desc := strings.Replace(out.Description, "\n", " ", -1)
desc = strings.Replace(desc, "\r", " ", -1)
if len(desc) > 45 {
desc = utils.Trunc(desc, 42) + "..."
if !*noTrunc && len(desc) > width {
desc = utils.Trunc(desc, width-3) + "..."
}
fmt.Fprintf(w, "%s\t%s\n", out.Name, desc)
}
@@ -1207,10 +1299,22 @@ func (opts PathOpts) String() string {
}
func (opts PathOpts) Set(val string) error {
if !filepath.IsAbs(val) {
return fmt.Errorf("%s is not an absolute path", val)
var containerPath string
splited := strings.SplitN(val, ":", 2)
if len(splited) == 1 {
containerPath = splited[0]
val = filepath.Clean(splited[0])
} else {
containerPath = splited[1]
val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
}
opts[filepath.Clean(val)] = struct{}{}
if !filepath.IsAbs(containerPath) {
utils.Debugf("%s is not an absolute path", containerPath)
return fmt.Errorf("%s is not an absolute path", containerPath)
}
opts[val] = struct{}{}
return nil
}
@@ -1251,12 +1355,26 @@ func (cli *DockerCli) CmdRun(args ...string) error {
return nil
}
var containerIDFile *os.File
if len(hostConfig.ContainerIDFile) > 0 {
if _, err := ioutil.ReadFile(hostConfig.ContainerIDFile); err == nil {
return fmt.Errorf("cid file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
}
containerIDFile, err = os.Create(hostConfig.ContainerIDFile)
if err != nil {
return fmt.Errorf("failed to create the container ID file: %s", err)
}
defer containerIDFile.Close()
}
//create the container
body, statusCode, err := cli.call("POST", "/containers/create", config)
//if image not found try to pull it
if statusCode == 404 {
v := url.Values{}
v.Set("fromImage", config.Image)
repos, tag := utils.ParseRepositoryTag(config.Image)
v.Set("fromImage", repos)
v.Set("tag", tag)
err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err)
if err != nil {
return err
@@ -1277,7 +1395,12 @@ func (cli *DockerCli) CmdRun(args ...string) error {
}
for _, warning := range runResult.Warnings {
fmt.Fprintln(cli.err, "WARNING: ", warning)
fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
}
if len(hostConfig.ContainerIDFile) > 0 {
if _, err = containerIDFile.WriteString(runResult.ID); err != nil {
return fmt.Errorf("failed to write the container ID to the file: %s", err)
}
}
//start the container
@@ -1285,15 +1408,21 @@ func (cli *DockerCli) CmdRun(args ...string) error {
return err
}
var wait chan struct{}
if !config.AttachStdout && !config.AttachStderr {
// Make this asynchrone in order to let the client write to stdin before having to read the ID
go fmt.Fprintf(cli.out, "%s\n", runResult.ID)
wait = make(chan struct{})
go func() {
defer close(wait)
fmt.Fprintf(cli.out, "%s\n", runResult.ID)
}()
}
if config.AttachStdin || config.AttachStdout || config.AttachStderr {
if config.Tty {
if err := cli.monitorTtySize(runResult.ID); err != nil {
return err
utils.Debugf("Error monitoring TTY size: %s\n", err)
}
}
@@ -1316,16 +1445,20 @@ func (cli *DockerCli) CmdRun(args ...string) error {
return err
}
}
if !config.AttachStdout && !config.AttachStderr {
<-wait
}
return nil
}
func (cli *DockerCli) checkIfLogged(condition bool, action string) error {
func (cli *DockerCli) checkIfLogged(action string) error {
// If condition AND the login failed
if condition && cli.authConfig.Username == "" {
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
if err := cli.CmdLogin(""); err != nil {
return err
}
if cli.authConfig.Username == "" {
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
return fmt.Errorf("Please login prior to %s. ('docker login')", action)
}
}
@@ -1420,19 +1553,13 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
if resp.Header.Get("Content-Type") == "application/json" {
dec := json.NewDecoder(resp.Body)
for {
var m utils.JSONMessage
if err := dec.Decode(&m); err == io.EOF {
var jm utils.JSONMessage
if err := dec.Decode(&jm); err == io.EOF {
break
} else if err != nil {
return err
}
if m.Progress != "" {
fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
} else if m.Error != "" {
return fmt.Errorf(m.Error)
} else {
fmt.Fprintf(out, "%s\n", m.Status)
}
jm.Display(out)
}
} else {
if _, err := io.Copy(out, resp.Body); err != nil {
@@ -1466,6 +1593,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
receiveStdout := utils.Go(func() error {
_, err := io.Copy(out, br)
utils.Debugf("[hijack] End of stdout")
return err
})
@@ -1480,6 +1608,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
sendStdin := utils.Go(func() error {
if in != nil {
io.Copy(rwc, in)
utils.Debugf("[hijack] End of stdin")
}
if tcpc, ok := rwc.(*net.TCPConn); ok {
if err := tcpc.CloseWrite(); err != nil {
@@ -1509,17 +1638,28 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
}
func (cli *DockerCli) resizeTty(id string) {
func (cli *DockerCli) getTtySize() (int, int) {
if !cli.isTerminal {
return
return 0, 0
}
ws, err := term.GetWinsize(cli.terminalFd)
if err != nil {
utils.Debugf("Error getting size: %s", err)
if ws == nil {
return 0, 0
}
}
return int(ws.Height), int(ws.Width)
}
func (cli *DockerCli) resizeTty(id string) {
height, width := cli.getTtySize()
if height == 0 && width == 0 {
return
}
v := url.Values{}
v.Set("h", strconv.Itoa(int(ws.Height)))
v.Set("w", strconv.Itoa(int(ws.Width)))
v.Set("h", strconv.Itoa(height))
v.Set("w", strconv.Itoa(width))
if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil {
utils.Debugf("Error resize: %s", err)
}
@@ -1531,13 +1671,12 @@ func (cli *DockerCli) monitorTtySize(id string) error {
}
cli.resizeTty(id)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGWINCH)
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGWINCH)
go func() {
for sig := range c {
if sig == syscall.SIGWINCH {
cli.resizeTty(id)
}
for {
<-sigchan
cli.resizeTty(id)
}
}()
return nil
@@ -1555,7 +1694,7 @@ func Subcmd(name, signature, description string) *flag.FlagSet {
func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
var (
isTerminal bool = false
isTerminal = false
terminalFd uintptr
)
@@ -1570,11 +1709,11 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
err = out
}
authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
configFile, _ := auth.LoadConfig(os.Getenv("HOME"))
return &DockerCli{
proto: proto,
addr: addr,
authConfig: authConfig,
configFile: configFile,
in: in,
out: out,
err: err,
@@ -1586,7 +1725,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
type DockerCli struct {
proto string
addr string
authConfig *auth.AuthConfig
configFile *auth.ConfigFile
in io.ReadCloser
out io.Writer
err io.Writer

View File

@@ -38,7 +38,7 @@ func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
f()
c <- false
}()
if <-c {
if <-c && msg != "" {
t.Fatal(msg)
}
}
@@ -59,94 +59,21 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error
return nil
}
/*TODO
func cmdImages(srv *Server, args ...string) (string, error) {
stdout, stdoutPipe := io.Pipe()
go func() {
if err := srv.CmdImages(nil, stdoutPipe, args...); err != nil {
return
}
// force the pipe closed, so that the code below gets an EOF
stdoutPipe.Close()
}()
output, err := ioutil.ReadAll(stdout)
if err != nil {
return "", err
}
// Cleanup pipes
return string(output), closeWrap(stdout, stdoutPipe)
}
// TestImages checks that 'docker images' displays information correctly
func TestImages(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime}
output, err := cmdImages(srv)
if !strings.Contains(output, "REPOSITORY") {
t.Fatal("'images' should have a header")
}
if !strings.Contains(output, "docker-ut") {
t.Fatal("'images' should show the docker-ut image")
}
if !strings.Contains(output, "e9aa60c60128") {
t.Fatal("'images' should show the docker-ut image id")
}
output, err = cmdImages(srv, "-q")
if strings.Contains(output, "REPOSITORY") {
t.Fatal("'images -q' should not have a header")
}
if strings.Contains(output, "docker-ut") {
t.Fatal("'images' should not show the docker-ut image name")
}
if !strings.Contains(output, "e9aa60c60128") {
t.Fatal("'images' should show the docker-ut image id")
}
output, err = cmdImages(srv, "-viz")
if !strings.HasPrefix(output, "digraph docker {") {
t.Fatal("'images -v' should start with the dot header")
}
if !strings.HasSuffix(output, "}\n") {
t.Fatal("'images -v' should end with a '}'")
}
if !strings.Contains(output, "base -> \"e9aa60c60128\" [style=invis]") {
t.Fatal("'images -v' should have the docker-ut image id node")
}
// todo: add checks for -a
}
*/
// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
func TestRunHostname(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(nil, stdoutPipe, nil, testDaemonProto, testDaemonAddr)
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("-h", "foobar", unitTestImageId, "hostname"); err != nil {
if err := cli.CmdRun("-h", "foobar", unitTestImageID, "hostname"); err != nil {
t.Fatal(err)
}
}()
utils.Debugf("--")
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
if err != nil {
@@ -163,21 +90,16 @@ func TestRunHostname(t *testing.T) {
}
/*
func TestRunExit(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime}
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c1 := make(chan struct{})
go func() {
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
cli.CmdRun("-i", unitTestImageID, "/bin/cat")
close(c1)
}()
@@ -187,21 +109,24 @@ func TestRunExit(t *testing.T) {
}
})
container := runtime.List()[0]
container := globalRuntime.List()[0]
// Closing /bin/cat stdin, expect it to exit
p, err := container.StdinPipe()
if err != nil {
t.Fatal(err)
}
if err := p.Close(); err != nil {
if err := stdin.Close(); err != nil {
t.Fatal(err)
}
// as the process exited, CmdRun must finish and unblock. Wait for it
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
<-c1
cmdWait(srv, container)
go func() {
cli.CmdWait(container.ID)
}()
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
t.Fatal(err)
}
})
// Make sure that the client has been disconnected
@@ -218,21 +143,18 @@ func TestRunExit(t *testing.T) {
// Expected behaviour: the process dies when the client disconnects
func TestRunDisconnect(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime}
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c1 := make(chan struct{})
go func() {
// We're simulating a disconnect so the return value doesn't matter. What matters is the
// fact that CmdRun returns.
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
cli.CmdRun("-i", unitTestImageID, "/bin/cat")
close(c1)
}()
@@ -256,7 +178,7 @@ func TestRunDisconnect(t *testing.T) {
// Client disconnect after run -i should cause stdin to be closed, which should
// cause /bin/cat to exit.
setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
container := runtime.List()[0]
container := globalRuntime.List()[0]
container.Wait()
if container.State.Running {
t.Fatalf("/bin/cat is still running after closing stdin")
@@ -266,40 +188,39 @@ func TestRunDisconnect(t *testing.T) {
// Expected behaviour: the process dies when the client disconnects
func TestRunDisconnectTty(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime}
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
c1 := make(chan struct{})
go func() {
// We're simulating a disconnect so the return value doesn't matter. What matters is the
// fact that CmdRun returns.
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-t", GetTestImage(runtime).Id, "/bin/cat")
if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil {
utils.Debugf("Error CmdRun: %s\n", err)
}
close(c1)
}()
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
for {
// Client disconnect after run -i should keep stdin out in TTY mode
l := runtime.List()
l := globalRuntime.List()
if len(l) == 1 && l[0].State.Running {
break
}
time.Sleep(10 * time.Millisecond)
}
})
// Client disconnect after run -i should keep stdin out in TTY mode
container := runtime.List()[0]
container := globalRuntime.List()[0]
setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
setTimeout(t, "Read/Write assertion timed out", 2000*time.Second, func() {
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
t.Fatal(err)
}
@@ -319,7 +240,6 @@ func TestRunDisconnectTty(t *testing.T) {
t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)")
}
}
*/
// TestAttachStdin checks attaching to stdin without stdout and stderr.
// 'docker run -i -a stdin' should sends the client's stdin to the command,
@@ -329,13 +249,13 @@ func TestRunAttachStdin(t *testing.T) {
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, nil, testDaemonProto, testDaemonAddr)
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
ch := make(chan struct{})
go func() {
defer close(ch)
cli.CmdRun("-i", "-a", "stdin", unitTestImageId, "sh", "-c", "echo hello && cat")
cli.CmdRun("-i", "-a", "stdin", unitTestImageID, "sh", "-c", "echo hello && cat")
}()
// Send input to the command, close stdin
@@ -373,59 +293,61 @@ func TestRunAttachStdin(t *testing.T) {
})
// Check logs
if cmdLogs, err := container.ReadLog("stdout"); err != nil {
if cmdLogs, err := container.ReadLog("json"); err != nil {
t.Fatal(err)
} else {
if output, err := ioutil.ReadAll(cmdLogs); err != nil {
t.Fatal(err)
} else {
expectedLog := "hello\nhi there\n"
if string(output) != expectedLog {
t.Fatalf("Unexpected logs: should be '%s', not '%s'\n", expectedLog, output)
expectedLogs := []string{"{\"log\":\"hello\\n\",\"stream\":\"stdout\"", "{\"log\":\"hi there\\n\",\"stream\":\"stdout\""}
for _, expectedLog := range expectedLogs {
if !strings.Contains(string(output), expectedLog) {
t.Fatalf("Unexpected logs: should contains '%s', it is not '%s'\n", expectedLog, output)
}
}
}
}
}
/*
// Expected behaviour, the process stays alive when the client disconnects
func TestAttachDisconnect(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{runtime: runtime}
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).Id,
CpuShares: 1000,
Memory: 33554432,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
// Start the process
if err := container.Start(); err != nil {
t.Fatal(err)
}
stdin, stdinPipe := io.Pipe()
stdout, stdoutPipe := io.Pipe()
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalRuntime)
go func() {
// Start a process in daemon mode
if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
utils.Debugf("Error CmdRun: %s\n", err)
}
}()
setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
t.Fatal(err)
}
})
setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
for {
l := globalRuntime.List()
if len(l) == 1 && l[0].State.Running {
break
}
time.Sleep(10 * time.Millisecond)
}
})
container := globalRuntime.List()[0]
// Attach to it
c1 := make(chan struct{})
go func() {
// We're simulating a disconnect so the return value doesn't matter. What matters is the
// fact that CmdAttach returns.
srv.CmdAttach(stdin, rcli.NewDockerLocalConn(stdoutPipe), container.Id)
cli.CmdAttach(container.ID)
close(c1)
}()
@@ -446,7 +368,7 @@ func TestAttachDisconnect(t *testing.T) {
// We closed stdin, expect /bin/cat to still be running
// Wait a little bit to make sure container.monitor() did his thing
err = container.WaitTimeout(500 * time.Millisecond)
err := container.WaitTimeout(500 * time.Millisecond)
if err == nil || !container.State.Running {
t.Fatalf("/bin/cat is not running after closing stdin")
}
@@ -456,4 +378,3 @@ func TestAttachDisconnect(t *testing.T) {
cStdin.Close()
container.Wait()
}
*/

View File

@@ -52,34 +52,37 @@ type Container struct {
waitLock chan struct{}
Volumes map[string]string
// Store rw/ro in a separate structure to preserve reserve-compatibility on-disk.
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
// Easier than migrating older container configs :)
VolumesRW map[string]bool
}
type Config struct {
Hostname string
User string
Memory int64 // Memory limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
CpuShares int64 // CPU shares (relative weight vs. other containers)
AttachStdin bool
AttachStdout bool
AttachStderr bool
PortSpecs []string
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Env []string
Cmd []string
Dns []string
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
Volumes map[string]struct{}
VolumesFrom string
Hostname string
User string
Memory int64 // Memory limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
CpuShares int64 // CPU shares (relative weight vs. other containers)
AttachStdin bool
AttachStdout bool
AttachStderr bool
PortSpecs []string
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
OpenStdin bool // Open stdin
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
Env []string
Cmd []string
Dns []string
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
Volumes map[string]struct{}
VolumesFrom string
Entrypoint []string
NetworkDisabled bool
}
type HostConfig struct {
Binds []string
Binds []string
ContainerIDFile string
}
type BindMap struct {
@@ -92,16 +95,19 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
if len(args) > 0 && args[0] != "--help" {
cmd.SetOutput(ioutil.Discard)
cmd.Usage = nil
}
flHostname := cmd.String("h", "", "Container host name")
flUser := cmd.String("u", "", "Username or UID")
flDetach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
flDetach := cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
flAttach := NewAttachOpts()
cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
flContainerIDFile := cmd.String("cidfile", "", "Write the container ID to the file")
flNetwork := cmd.Bool("n", true, "Enable networking for this container")
if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
@@ -120,12 +126,10 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
cmd.Var(&flDns, "dns", "Set custom dns servers")
flVolumes := NewPathOpts()
cmd.Var(flVolumes, "v", "Attach a data volume")
cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
var flBinds ListOpts
cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)")
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
if err := cmd.Parse(args); err != nil {
return nil, nil, cmd, err
@@ -144,15 +148,22 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
}
}
var binds []string
// add any bind targets to the list of container volumes
for _, bind := range flBinds {
for bind := range flVolumes {
arr := strings.Split(bind, ":")
dstDir := arr[1]
flVolumes[dstDir] = struct{}{}
if len(arr) > 1 {
dstDir := arr[1]
flVolumes[dstDir] = struct{}{}
binds = append(binds, bind)
delete(flVolumes, bind)
}
}
parsedArgs := cmd.Args()
runCmd := []string{}
entrypoint := []string{}
image := ""
if len(parsedArgs) >= 1 {
image = cmd.Arg(0)
@@ -160,26 +171,33 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
if len(parsedArgs) > 1 {
runCmd = parsedArgs[1:]
}
if *flEntrypoint != "" {
entrypoint = []string{*flEntrypoint}
}
config := &Config{
Hostname: *flHostname,
PortSpecs: flPorts,
User: *flUser,
Tty: *flTty,
OpenStdin: *flStdin,
Memory: *flMemory,
CpuShares: *flCpuShares,
AttachStdin: flAttach.Get("stdin"),
AttachStdout: flAttach.Get("stdout"),
AttachStderr: flAttach.Get("stderr"),
Env: flEnv,
Cmd: runCmd,
Dns: flDns,
Image: image,
Volumes: flVolumes,
VolumesFrom: *flVolumesFrom,
Hostname: *flHostname,
PortSpecs: flPorts,
User: *flUser,
Tty: *flTty,
NetworkDisabled: !*flNetwork,
OpenStdin: *flStdin,
Memory: *flMemory,
CpuShares: *flCpuShares,
AttachStdin: flAttach.Get("stdin"),
AttachStdout: flAttach.Get("stdout"),
AttachStderr: flAttach.Get("stderr"),
Env: flEnv,
Cmd: runCmd,
Dns: flDns,
Image: image,
Volumes: flVolumes,
VolumesFrom: *flVolumesFrom,
Entrypoint: entrypoint,
}
hostConfig := &HostConfig{
Binds: flBinds,
Binds: binds,
ContainerIDFile: *flContainerIDFile,
}
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
@@ -194,20 +212,25 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
return config, hostConfig, cmd, nil
}
type PortMapping map[string]string
type NetworkSettings struct {
IPAddress string
IPPrefixLen int
Gateway string
Bridge string
PortMapping map[string]string
PortMapping map[string]PortMapping
}
// String returns a human-readable description of the port mapping defined in the settings
func (settings *NetworkSettings) PortMappingHuman() string {
var mapping []string
for private, public := range settings.PortMapping {
for private, public := range settings.PortMapping["Tcp"] {
mapping = append(mapping, fmt.Sprintf("%s->%s", public, private))
}
for private, public := range settings.PortMapping["Udp"] {
mapping = append(mapping, fmt.Sprintf("%s->%s/udp", public, private))
}
sort.Strings(mapping)
return strings.Join(mapping, ", ")
}
@@ -257,6 +280,26 @@ func (container *Container) ToDisk() (err error) {
return ioutil.WriteFile(container.jsonPath(), data, 0666)
}
func (container *Container) ReadHostConfig() (*HostConfig, error) {
data, err := ioutil.ReadFile(container.hostConfigPath())
if err != nil {
return &HostConfig{}, err
}
hostConfig := &HostConfig{}
if err := json.Unmarshal(data, hostConfig); err != nil {
return &HostConfig{}, err
}
return hostConfig, nil
}
func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) {
data, err := json.Marshal(hostConfig)
if err != nil {
return
}
return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
}
func (container *Container) generateLXCConfig() error {
fo, err := os.Create(container.lxcConfigPath())
if err != nil {
@@ -336,14 +379,15 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
utils.Debugf("[start] attach stdin\n")
defer utils.Debugf("[end] attach stdin\n")
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
if cStdout != nil {
defer cStdout.Close()
}
if cStderr != nil {
defer cStderr.Close()
}
if container.Config.StdinOnce && !container.Config.Tty {
defer cStdin.Close()
} else {
if cStdout != nil {
defer cStdout.Close()
}
if cStderr != nil {
defer cStderr.Close()
}
}
if container.Config.Tty {
_, err = utils.CopyEscapable(cStdin, stdin)
@@ -458,8 +502,12 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
}
func (container *Container) Start(hostConfig *HostConfig) error {
container.State.lock()
defer container.State.unlock()
container.State.Lock()
defer container.State.Unlock()
if len(hostConfig.Binds) == 0 {
hostConfig, _ = container.ReadHostConfig()
}
if container.State.Running {
return fmt.Errorf("The container %s is already running.", container.ID)
@@ -467,8 +515,12 @@ func (container *Container) Start(hostConfig *HostConfig) error {
if err := container.EnsureMounted(); err != nil {
return err
}
if err := container.allocateNetwork(); err != nil {
return err
if container.runtime.networkManager.disabled {
container.Config.NetworkDisabled = true
} else {
if err := container.allocateNetwork(); err != nil {
return err
}
}
// Make sure the config is compatible with the current kernel
@@ -480,13 +532,11 @@ func (container *Container) Start(hostConfig *HostConfig) error {
log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
container.Config.MemorySwap = -1
}
container.Volumes = make(map[string]string)
container.VolumesRW = make(map[string]bool)
// Create the requested bind mounts
binds := make(map[string]BindMap)
// Define illegal container destinations
illegal_dsts := []string{"/", "."}
illegalDsts := []string{"/", "."}
for _, bind := range hostConfig.Binds {
// FIXME: factorize bind parsing in parseBind
@@ -505,7 +555,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
}
// Bail if trying to mount to an illegal destination
for _, illegal := range illegal_dsts {
for _, illegal := range illegalDsts {
if dst == illegal {
return fmt.Errorf("Illegal bind destination: %s", dst)
}
@@ -521,30 +571,35 @@ func (container *Container) Start(hostConfig *HostConfig) error {
// FIXME: evaluate volumes-from before individual volumes, so that the latter can override the former.
// Create the requested volumes volumes
for volPath := range container.Config.Volumes {
volPath = path.Clean(volPath)
// If an external bind is defined for this volume, use that as a source
if bindMap, exists := binds[volPath]; exists {
container.Volumes[volPath] = bindMap.SrcPath
if strings.ToLower(bindMap.Mode) == "rw" {
container.VolumesRW[volPath] = true
if container.Volumes == nil || len(container.Volumes) == 0 {
container.Volumes = make(map[string]string)
container.VolumesRW = make(map[string]bool)
for volPath := range container.Config.Volumes {
volPath = path.Clean(volPath)
// If an external bind is defined for this volume, use that as a source
if bindMap, exists := binds[volPath]; exists {
container.Volumes[volPath] = bindMap.SrcPath
if strings.ToLower(bindMap.Mode) == "rw" {
container.VolumesRW[volPath] = true
}
// Otherwise create an directory in $ROOT/volumes/ and use that
} else {
c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
if err != nil {
return err
}
srcPath, err := c.layer()
if err != nil {
return err
}
container.Volumes[volPath] = srcPath
container.VolumesRW[volPath] = true // RW by default
}
// Otherwise create an directory in $ROOT/volumes/ and use that
} else {
c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
if err != nil {
return err
// Create the mountpoint
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
return nil
}
srcPath, err := c.layer()
if err != nil {
return err
}
container.Volumes[volPath] = srcPath
container.VolumesRW[volPath] = true // RW by default
}
// Create the mountpoint
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
return nil
}
}
@@ -561,6 +616,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
return nil
}
container.Volumes[volPath] = id
if isRW, exists := c.VolumesRW[volPath]; exists {
container.VolumesRW[volPath] = isRW
}
}
}
@@ -576,7 +634,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
}
// Networking
params = append(params, "-g", container.network.Gateway.String())
if !container.Config.NetworkDisabled {
params = append(params, "-g", container.network.Gateway.String())
}
// User
if container.Config.User != "" {
@@ -591,6 +651,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
params = append(params,
"-e", "HOME=/",
"-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"-e", "container=lxc",
)
for _, elem := range container.Config.Env {
@@ -604,10 +665,10 @@ func (container *Container) Start(hostConfig *HostConfig) error {
container.cmd = exec.Command("lxc-start", params...)
// Setup logging of stdout and stderr to disk
if err := container.runtime.LogToDisk(container.stdout, container.logPath("stdout")); err != nil {
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
return err
}
if err := container.runtime.LogToDisk(container.stderr, container.logPath("stderr")); err != nil {
if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
return err
}
@@ -628,6 +689,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
container.waitLock = make(chan struct{})
container.ToDisk()
container.SaveHostConfig(hostConfig)
go container.monitor()
return nil
}
@@ -665,29 +727,37 @@ func (container *Container) StdinPipe() (io.WriteCloser, error) {
func (container *Container) StdoutPipe() (io.ReadCloser, error) {
reader, writer := io.Pipe()
container.stdout.AddWriter(writer)
container.stdout.AddWriter(writer, "")
return utils.NewBufReader(reader), nil
}
func (container *Container) StderrPipe() (io.ReadCloser, error) {
reader, writer := io.Pipe()
container.stderr.AddWriter(writer)
container.stderr.AddWriter(writer, "")
return utils.NewBufReader(reader), nil
}
func (container *Container) allocateNetwork() error {
if container.Config.NetworkDisabled {
return nil
}
iface, err := container.runtime.networkManager.Allocate()
if err != nil {
return err
}
container.NetworkSettings.PortMapping = make(map[string]string)
container.NetworkSettings.PortMapping = make(map[string]PortMapping)
container.NetworkSettings.PortMapping["Tcp"] = make(PortMapping)
container.NetworkSettings.PortMapping["Udp"] = make(PortMapping)
for _, spec := range container.Config.PortSpecs {
nat, err := iface.AllocatePort(spec)
if err != nil {
iface.Release()
return err
}
container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
proto := strings.Title(nat.Proto)
backend, frontend := strconv.Itoa(nat.Backend), strconv.Itoa(nat.Frontend)
container.NetworkSettings.PortMapping[proto][backend] = frontend
}
container.network = iface
container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
@@ -698,6 +768,9 @@ func (container *Container) allocateNetwork() error {
}
func (container *Container) releaseNetwork() {
if container.Config.NetworkDisabled {
return
}
container.network.Release()
container.network = nil
container.NetworkSettings = &NetworkSettings{}
@@ -733,7 +806,9 @@ func (container *Container) monitor() {
}
}
utils.Debugf("Process finished")
if container.runtime != nil && container.runtime.srv != nil {
container.runtime.srv.LogEvent("die", container.ShortID())
}
exitCode := -1
if container.cmd != nil {
exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
@@ -813,8 +888,8 @@ func (container *Container) kill() error {
}
func (container *Container) Kill() error {
container.State.lock()
defer container.State.unlock()
container.State.Lock()
defer container.State.Unlock()
if !container.State.Running {
return nil
}
@@ -822,8 +897,8 @@ func (container *Container) Kill() error {
}
func (container *Container) Stop(seconds int) error {
container.State.lock()
defer container.State.unlock()
container.State.Lock()
defer container.State.Unlock()
if !container.State.Running {
return nil
}
@@ -962,6 +1037,10 @@ func (container *Container) ReadLog(name string) (io.Reader, error) {
return os.Open(container.logPath(name))
}
func (container *Container) hostConfigPath() string {
return path.Join(container.root, "hostconfig.json")
}
func (container *Container) jsonPath() string {
return path.Join(container.root, "config.json")
}

View File

@@ -39,16 +39,11 @@ func TestIDFormat(t *testing.T) {
func TestMultipleAttachRestart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c",
"i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"},
},
container, hostConfig, _ := mkContainer(
runtime,
[]string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"},
t,
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
// Simulate 3 client attaching to the container and stop/restart
@@ -65,7 +60,6 @@ func TestMultipleAttachRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err)
}
@@ -140,19 +134,8 @@ func TestMultipleAttachRestart(t *testing.T) {
func TestDiff(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
builder := NewBuilder(runtime)
// Create a container and remove a file
container1, err := builder.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/rm", "/etc/passwd"},
},
)
if err != nil {
t.Fatal(err)
}
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
defer runtime.Destroy(container1)
if err := container1.Run(); err != nil {
@@ -185,15 +168,7 @@ func TestDiff(t *testing.T) {
}
// Create a new container from the commited image
container2, err := builder.Create(
&Config{
Image: img.ID,
Cmd: []string{"cat", "/etc/passwd"},
},
)
if err != nil {
t.Fatal(err)
}
container2, _, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
defer runtime.Destroy(container2)
if err := container2.Run(); err != nil {
@@ -212,15 +187,7 @@ func TestDiff(t *testing.T) {
}
// Create a new containere
container3, err := builder.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"rm", "/bin/httpd"},
},
)
if err != nil {
t.Fatal(err)
}
container3, _, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
defer runtime.Destroy(container3)
if err := container3.Run(); err != nil {
@@ -246,17 +213,7 @@ func TestDiff(t *testing.T) {
func TestCommitAutoRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
builder := NewBuilder(runtime)
container1, err := builder.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "echo hello > /world"},
},
)
if err != nil {
t.Fatal(err)
}
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
defer runtime.Destroy(container1)
if container1.State.Running {
@@ -279,14 +236,7 @@ func TestCommitAutoRun(t *testing.T) {
}
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
container2, err := builder.Create(
&Config{
Image: img.ID,
},
)
if err != nil {
t.Fatal(err)
}
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID}, t)
defer runtime.Destroy(container2)
stdout, err := container2.StdoutPipe()
if err != nil {
@@ -296,7 +246,6 @@ func TestCommitAutoRun(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container2.Start(hostConfig); err != nil {
t.Fatal(err)
}
@@ -324,17 +273,7 @@ func TestCommitRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
builder := NewBuilder(runtime)
container1, err := builder.Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/sh", "-c", "echo hello > /world"},
},
)
if err != nil {
t.Fatal(err)
}
container1, hostConfig, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
defer runtime.Destroy(container1)
if container1.State.Running {
@@ -357,16 +296,7 @@ func TestCommitRun(t *testing.T) {
}
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
container2, err := builder.Create(
&Config{
Image: img.ID,
Cmd: []string{"cat", "/world"},
},
)
if err != nil {
t.Fatal(err)
}
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
defer runtime.Destroy(container2)
stdout, err := container2.StdoutPipe()
if err != nil {
@@ -376,7 +306,6 @@ func TestCommitRun(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container2.Start(hostConfig); err != nil {
t.Fatal(err)
}
@@ -403,18 +332,7 @@ func TestCommitRun(t *testing.T) {
func TestStart(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Memory: 33554432,
CpuShares: 1000,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
)
if err != nil {
t.Fatal(err)
}
container, hostConfig, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
defer runtime.Destroy(container)
cStdin, err := container.StdinPipe()
@@ -422,7 +340,6 @@ func TestStart(t *testing.T) {
t.Fatal(err)
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
t.Fatal(err)
}
@@ -445,15 +362,7 @@ func TestStart(t *testing.T) {
func TestRun(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "-al"},
},
)
if err != nil {
t.Fatal(err)
}
container, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
defer runtime.Destroy(container)
if container.State.Running {
@@ -511,12 +420,14 @@ func TestKillDifferentUser(t *testing.T) {
t.Fatal(err)
}
// Give some time to lxc to spawn the process (setuid might take some time)
container.WaitTimeout(500 * time.Millisecond)
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
for !container.State.Running {
time.Sleep(10 * time.Millisecond)
}
})
if !container.State.Running {
t.Errorf("Container should be running")
}
// Even if the state is running, lets give some time to lxc to spawn the process
container.WaitTimeout(500 * time.Millisecond)
if err := container.Kill(); err != nil {
t.Fatal(err)
@@ -847,6 +758,23 @@ func TestUser(t *testing.T) {
if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
t.Error(string(output))
}
// Test an wrong username
container, err = builder.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"id"},
User: "unkownuser",
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
output, err = container.Output()
if container.State.ExitCode == 0 {
t.Fatal("Starting container with wrong uid should fail but it passed.")
}
}
func TestMultipleContainers(t *testing.T) {
@@ -1001,7 +929,7 @@ func TestEnv(t *testing.T) {
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/usr/bin/env"},
Cmd: []string{"env"},
},
)
if err != nil {
@@ -1031,6 +959,7 @@ func TestEnv(t *testing.T) {
goodEnv := []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/",
"container=lxc",
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {
@@ -1043,6 +972,29 @@ func TestEnv(t *testing.T) {
}
}
func TestEntrypoint(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Entrypoint: []string{"/bin/echo"},
Cmd: []string{"-n", "foobar"},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
output, err := container.Output()
if err != nil {
t.Fatal(err)
}
if string(output) != "foobar" {
t.Error(string(output))
}
}
func grepFile(t *testing.T, path string, pattern string) {
f, err := os.Open(path)
if err != nil {
@@ -1097,10 +1049,7 @@ func TestLXCConfig(t *testing.T) {
}
func BenchmarkRunSequencial(b *testing.B) {
runtime, err := newTestRuntime()
if err != nil {
b.Fatal(err)
}
runtime := mkRuntime(b)
defer nuke(runtime)
for i := 0; i < b.N; i++ {
container, err := NewBuilder(runtime).Create(&Config{
@@ -1126,10 +1075,7 @@ func BenchmarkRunSequencial(b *testing.B) {
}
func BenchmarkRunParallel(b *testing.B) {
runtime, err := newTestRuntime()
if err != nil {
b.Fatal(err)
}
runtime := mkRuntime(b)
defer nuke(runtime)
var tasks []chan error
@@ -1195,18 +1141,152 @@ func TestBindMounts(t *testing.T) {
writeFile(path.Join(tmpDir, "touch-me"), "", t)
// Test reading from a read-only bind mount
stdout, _ := runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
if !strings.Contains(stdout, "touch-me") {
t.Fatal("Container failed to read from bind mount")
}
// test writing to bind mount
runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
// test mounting to an illegal destination directory
if _, err := runContainer(r, []string{"-b", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
t.Fatal("Container bind mounted illegal directory")
}
}
// Test that VolumesRW values are copied to the new container. Regression test for #1201
func TestVolumesFromReadonlyMount(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
if !container.VolumesRW["/test"] {
t.Fail()
}
container2, err := NewBuilder(runtime).Create(
&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"/bin/echo", "-n", "foobar"},
VolumesFrom: container.ID,
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container2)
_, err = container2.Output()
if err != nil {
t.Fatal(err)
}
if container.Volumes["/test"] != container2.Volumes["/test"] {
t.Fail()
}
actual, exists := container2.VolumesRW["/test"]
if !exists {
t.Fail()
}
if container.VolumesRW["/test"] != actual {
t.Fail()
}
}
// Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
func TestRestartWithVolumes(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"echo", "-n", "foobar"},
Volumes: map[string]struct{}{"/test": {}},
},
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
for key := range container.Config.Volumes {
if key != "/test" {
t.Fail()
}
}
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
expected := container.Volumes["/test"]
if expected == "" {
t.Fail()
}
// Run the container again to verify the volume path persists
_, err = container.Output()
if err != nil {
t.Fatal(err)
}
actual := container.Volumes["/test"]
if expected != actual {
t.Fatalf("Expected volume path: %s Actual path: %s", expected, actual)
}
}
func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
config, hc, _, err := ParseRun([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
if err != nil {
t.Fatal(err)
}
c, err := NewBuilder(runtime).Create(config)
if err != nil {
t.Fatal(err)
}
stdout, err := c.StdoutPipe()
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(c)
if err := c.Start(hc); err != nil {
t.Fatal(err)
}
c.WaitTimeout(500 * time.Millisecond)
c.Wait()
output, err := ioutil.ReadAll(stdout)
if err != nil {
t.Fatal(err)
}
interfaces := regexp.MustCompile(`(?m)^[0-9]+: [a-zA-Z0-9]+`).FindAllString(string(output), -1)
if len(interfaces) != 1 {
t.Fatalf("Wrong interface count in test container: expected [1: lo], got [%s]", interfaces)
}
if interfaces[0] != "1: lo" {
t.Fatalf("Wrong interface in test container: expected [1: lo], got [%s]", interfaces)
}
}

View File

@@ -23,7 +23,9 @@ mkdir bin etc dev dev/pts lib proc sys tmp
touch etc/resolv.conf
cp /etc/nsswitch.conf etc/nsswitch.conf
echo root:x:0:0:root:/:/bin/sh > etc/passwd
echo daemon:x:1:1:daemon:/usr/sbin:/bin/sh >> etc/passwd
echo root:x:0: > etc/group
echo daemon:x:1: >> etc/group
ln -s lib lib64
ln -s bin sbin
cp $BUSYBOX $SOCAT bin
@@ -41,6 +43,7 @@ do
cp -a /dev/$X dev
done
chmod 0755 $ROOTFS # See #486
tar -cf- . | docker import - docker-ut
docker run -i -u root docker-ut /bin/echo Success.
rm -rf $ROOTFS

View File

@@ -28,16 +28,16 @@ func main() {
flDaemon := flag.Bool("d", false, "Daemon mode")
flDebug := flag.Bool("D", false, "Debug mode")
flAutoRestart := flag.Bool("r", false, "Restart previously running containers")
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge. Use 'none' to disable container networking")
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
flGraphPath := flag.String("g", "/var/lib/docker", "Path to graph storage base dir.")
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
flDns := flag.String("dns", "", "Set custom dns servers")
flHosts := docker.ListOpts{fmt.Sprintf("tcp://%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT)}
flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use")
flag.Parse()
if len(flHosts) > 1 {
flHosts = flHosts[1:len(flHosts)] //trick to display a nice defaul value in the usage
flHosts = flHosts[1:] //trick to display a nice defaul value in the usage
}
for i, flHost := range flHosts {
flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)

View File

@@ -2,6 +2,9 @@
:description: API Documentation for Docker
:keywords: API, Docker, rcli, REST, documentation
.. COMMENT use http://pythonhosted.org/sphinxcontrib-httpdomain/ to
.. document the REST API.
=================
Docker Remote API
=================
@@ -12,31 +15,62 @@ Docker Remote API
=====================
- The Remote API is replacing rcli
- Default port in the docker deamon is 4243
- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
- Since API version 1.2, the auth configuration is now handled client side, so the client has to send the authConfig as POST in /images/(name)/push
- By default the Docker daemon listens on unix:///var/run/docker.sock and the client must have root access to interact with the daemon
- The API tends to be REST, but for some complex commands, like attach
or pull, the HTTP connection is hijacked to transport stdout stdin
and stderr
- Since API version 1.2, the auth configuration is now handled client
side, so the client has to send the authConfig as POST in
/images/(name)/push
2. Versions
===========
The current verson of the API is 1.3
Calling /images/<name>/insert is the same as calling /v1.3/images/<name>/insert
You can still call an old version of the api using /v1.0/images/<name>/insert
The current verson of the API is 1.4
:doc:`docker_remote_api_v1.3`
Calling /images/<name>/insert is the same as calling
/v1.4/images/<name>/insert
You can still call an old version of the api using
/v1.0/images/<name>/insert
:doc:`docker_remote_api_v1.4`
*****************************
What's new
----------
.. http:get:: /containers/(id)/top
**New!** You can now use ps args with docker top, like `docker top <container_id> aux`
:doc:`docker_remote_api_v1.3`
*****************************
docker v0.5.0 51f6c4a_
What's new
----------
.. http:get:: /containers/(id)/top
List the processes running inside a container.
.. http:get:: /events:
**New!** Monitor docker's events via streaming or via polling
Builder (/build):
- Simplify the upload of the build context
- Simply stream a tarball instead of multipart upload with 4 intermediary buffers
- Simply stream a tarball instead of multipart upload with 4
intermediary buffers
- Simpler, less memory usage, less disk usage and faster
.. Note::
The /build improvements are not reverse-compatible. Pre 1.3 clients will break on /build.
.. Warning::
The /build improvements are not reverse-compatible. Pre 1.3 clients
will break on /build.
List containers (/containers/json):
@@ -44,7 +78,8 @@ List containers (/containers/json):
Start containers (/containers/<id>/start):
- You can now pass host-specific configuration (e.g. bind mounts) in the POST body for start calls
- You can now pass host-specific configuration (e.g. bind mounts) in
the POST body for start calls
:doc:`docker_remote_api_v1.2`
*****************************
@@ -55,14 +90,25 @@ What's new
----------
The auth configuration is now handled by the client.
The client should send it's authConfig as POST on each call of /images/(name)/push
.. http:get:: /auth is now deprecated
.. http:post:: /auth only checks the configuration but doesn't store it on the server
The client should send it's authConfig as POST on each call of
/images/(name)/push
Deleting an image is now improved, will only untag the image if it has chidrens and remove all the untagged parents if has any.
.. http:get:: /auth
.. http:post:: /images/<name>/delete now returns a JSON with the list of images deleted/untagged
**Deprecated.**
.. http:post:: /auth
Only checks the configuration but doesn't store it on the server
Deleting an image is now improved, will only untag the image if it
has chidren and remove all the untagged parents if has any.
.. http:post:: /images/<name>/delete
Now returns a JSON structure with the list of images
deleted/untagged.
:doc:`docker_remote_api_v1.1`
@@ -77,7 +123,7 @@ What's new
.. http:post:: /images/(name)/insert
.. http:post:: /images/(name)/push
Uses json stream instead of HTML hijack, it looks like this:
Uses json stream instead of HTML hijack, it looks like this:
.. sourcecode:: http
@@ -104,6 +150,7 @@ Initial version
.. _a8ae398: https://github.com/dotcloud/docker/commit/a8ae398bf52e97148ee7bd0d5868de2e15bd297f
.. _8d73740: https://github.com/dotcloud/docker/commit/8d73740343778651c09160cde9661f5f387b36f4
.. _2e7649b: https://github.com/dotcloud/docker/commit/2e7649beda7c820793bd46766cbc2cfeace7b168
.. _51f6c4a: https://github.com/dotcloud/docker/commit/51f6c4a7372450d164c61e0054daf0223ddbd909
==================================
Docker Remote API Client Libraries
@@ -130,3 +177,6 @@ and we will add the libraries here.
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
| **WebUI** | | |
+----------------------+----------------+--------------------------------------------+
| Java | docker-java | https://github.com/kpelykh/docker-java |
+----------------------+----------------+--------------------------------------------+

View File

@@ -1,3 +1,8 @@
.. use orphan to suppress "WARNING: document isn't included in any toctree"
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
:orphan:
:title: Remote API v1.0
:description: API Documentation for Docker
:keywords: API, Docker, rcli, REST, documentation
@@ -300,8 +305,8 @@ Start a container
:statuscode 500: server error
Stop a contaier
***************
Stop a container
****************
.. http:post:: /containers/(id)/stop

View File

@@ -1,3 +1,7 @@
.. use orphan to suppress "WARNING: document isn't included in any toctree"
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
:orphan:
:title: Remote API v1.1
:description: API Documentation for Docker

View File

@@ -1,3 +1,8 @@
.. use orphan to suppress "WARNING: document isn't included in any toctree"
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
:orphan:
:title: Remote API v1.2
:description: API Documentation for Docker
:keywords: API, Docker, rcli, REST, documentation

View File

@@ -1,3 +1,8 @@
.. use orphan to suppress "WARNING: document isn't included in any toctree"
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
:orphan:
:title: Remote API v1.3
:description: API Documentation for Docker
:keywords: API, Docker, rcli, REST, documentation
@@ -220,6 +225,46 @@ Inspect a container
:statuscode 500: server error
List processes running inside a container
*****************************************
.. http:get:: /containers/(id)/top
List processes running inside the container ``id``
**Example request**:
.. sourcecode:: http
GET /containers/4fa6e0f0c678/top HTTP/1.1
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"PID":"11935",
"Tty":"pts/2",
"Time":"00:00:00",
"Cmd":"sh"
},
{
"PID":"12140",
"Tty":"pts/2",
"Time":"00:00:00",
"Cmd":"sleep"
}
]
:statuscode 200: no error
:statuscode 404: no such container
:statuscode 500: server error
Inspect changes on a container's filesystem
*******************************************
@@ -800,7 +845,7 @@ Remove an image
{"Deleted":"53b4f83ac9"}
]
:statuscode 204: no error
:statuscode 200: no error
:statuscode 404: no such image
:statuscode 409: conflict
:statuscode 500: server error
@@ -881,6 +926,7 @@ Build an image from Dockerfile via stdin
The Content-type header should be set to "application/tar".
:query t: tag to be applied to the resulting image in case of success
:query q: suppress verbose build output
:statuscode 200: no error
:statuscode 500: server error
@@ -943,7 +989,10 @@ Display system-wide information
"NFd": 11,
"NGoroutines":21,
"MemoryLimit":true,
"SwapLimit":false
"SwapLimit":false,
"EventsListeners":"0",
"LXCVersion":"0.7.5",
"KernelVersion":"3.8.0-19-generic"
}
:statuscode 200: no error
@@ -1013,6 +1062,36 @@ Create a new image from a container's changes
:statuscode 500: server error
Monitor Docker's events
***********************
.. http:get:: /events
Get events from docker, either in real time via streaming, or via polling (using `since`)
**Example request**:
.. sourcecode:: http
POST /events?since=1374067924
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{"status":"create","id":"dfdf82bd3881","time":1374067924}
{"status":"start","id":"dfdf82bd3881","time":1374067924}
{"status":"stop","id":"dfdf82bd3881","time":1374067966}
{"status":"destroy","id":"dfdf82bd3881","time":1374067970}
:query since: timestamp used for polling
:statuscode 200: no error
:statuscode 500: server error
3. Going further
================

File diff suppressed because it is too large Load Diff

View File

@@ -452,7 +452,7 @@ User Register
"username": "foobar"'}
:jsonparameter email: valid email address, that needs to be confirmed
:jsonparameter username: min 4 character, max 30 characters, must match the regular expression [a-z0-9_].
:jsonparameter username: min 4 character, max 30 characters, must match the regular expression [a-z0-9\_].
:jsonparameter password: min 5 characters
**Example Response**:

View File

@@ -367,7 +367,8 @@ POST /v1/users
{"email": "sam@dotcloud.com", "password": "toto42", "username": "foobar"'}
**Validation**:
- **username** : min 4 character, max 30 characters, must match the regular expression [a-z0-9_].
- **username**: min 4 character, max 30 characters, must match the regular
expression [a-z0-9\_].
- **password**: min 5 characters
**Valid**: return HTTP 200
@@ -566,4 +567,4 @@ Next request::
---------------------
- 1.0 : May 6th 2013 : initial release
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new source namespace.
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new source namespace.

View File

@@ -52,5 +52,6 @@ Available Commands
command/start
command/stop
command/tag
command/top
command/version
command/wait

View File

@@ -11,6 +11,7 @@
Usage: docker build [OPTIONS] PATH | URL | -
Build a new container image from the source code at PATH
-t="": Tag to be applied to the resulting image in case of success.
-q=false: Suppress verbose build output.
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context

View File

@@ -12,8 +12,9 @@
Create a new filesystem image from the contents of a tarball
At this time, the URL must start with ``http`` and point to a single file archive (.tar, .tar.gz, .bzip)
containing a root filesystem. If you would like to import from a local directory or archive,
At this time, the URL must start with ``http`` and point to a single file archive
(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
containing a root filesystem. If you would like to import from a local directory or archive,
you can use the ``-`` parameter to take the data from standard in.
Examples
@@ -30,7 +31,7 @@ Import from a local file
Import to docker via pipe and standard in
``$ cat exampleimage.tgz | docker import - exampleimagelocal``
Import from a local directory
.............................

View File

@@ -8,6 +8,10 @@
::
Usage: docker login
Usage: docker login [OPTIONS]
Register or Login to the docker registry server
-e="": email
-p="": password
-u="": username

View File

@@ -10,4 +10,4 @@
Usage: docker rm [OPTIONS] CONTAINER
Remove a container
Remove one or more containers

View File

@@ -8,6 +8,6 @@
::
Usage: docker rmimage [OPTIONS] IMAGE
Usage: docker rmi IMAGE [IMAGE...]
Remove an image
Remove one or more images

View File

@@ -14,15 +14,27 @@
-a=map[]: Attach to stdin, stdout or stderr.
-c=0: CPU shares (relative weight)
-d=false: Detached mode: leave the container running in the background
-cidfile="": Write the container ID to the file
-d=false: Detached mode: Run container in the background, print new container id
-e=[]: Set environment variables
-h="": Container host name
-i=false: Keep stdin open even if not attached
-m=0: Memory limit (in bytes)
-n=true: Enable networking for this container
-p=[]: Map a network port to the container
-t=false: Allocate a pseudo-tty
-u="": Username or UID
-d=[]: Set custom dns servers for the container
-v=[]: Creates a new volume and mounts it at the specified path.
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "host-dir" is missing, then docker creates a new volume.
-volumes-from="": Mount all volumes from the given container.
-b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
-entrypoint="": Overwrite the default entrypoint set by the image.
Examples
--------
.. code-block:: bash
docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
| This will create a container and print "test" to the console. The cidfile flag makes docker attempt to create a new file and write the container ID to it. If the file exists already, docker will return an error. Docker will close this file when docker run exits.

View File

@@ -8,6 +8,8 @@
::
Usage: docker stop [OPTIONS] NAME
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Stop a running container
-t=10: Number of seconds to wait for the container to stop before killing it.

View File

@@ -0,0 +1,13 @@
:title: Top Command
:description: Lookup the running processes of a container
:keywords: top, docker, container, documentation
=======================================================
``top`` -- Lookup the running processes of a container
=======================================================
::
Usage: docker top CONTAINER
Lookup the running processes of a container

View File

@@ -37,5 +37,6 @@ Contents:
start <command/start>
stop <command/stop>
tag <command/tag>
top <command/top>
version <command/version>
wait <command/wait>
wait <command/wait>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -1,10 +1,10 @@
:title: Concepts
:description: -- todo: change me
:title: Overview
:description: Docker documentation summary
:keywords: concepts, documentation, docker, containers
Concepts
Overview
========
Contents:
@@ -13,4 +13,4 @@ Contents:
:maxdepth: 1
../index
manifesto

View File

@@ -0,0 +1,129 @@
:title: Manifesto
:description: An overview of Docker and standard containers
:keywords: containers, lxc, concepts, explanation
.. _dockermanifesto:
Docker Manifesto
----------------
Docker complements LXC with a high-level API which operates at the
process level. It runs unix processes with strong guarantees of
isolation and repeatability across servers.
Docker is a great building block for automating distributed systems:
large-scale web deployments, database clusters, continuous deployment
systems, private PaaS, service-oriented architectures, etc.
- **Heterogeneous payloads** Any combination of binaries, libraries,
configuration files, scripts, virtualenvs, jars, gems, tarballs, you
name it. No more juggling between domain-specific tools. Docker can
deploy and run them all.
- **Any server** Docker can run on any x64 machine with a modern linux
kernel - whether it's a laptop, a bare metal server or a VM. This
makes it perfect for multi-cloud deployments.
- **Isolation** docker isolates processes from each other and from the
underlying host, using lightweight containers.
- **Repeatability** Because containers are isolated in their own
filesystem, they behave the same regardless of where, when, and
alongside what they run.
.. image:: images/lego_docker.jpg
:target: http://bricks.argz.com/ins/7823-1/12
What is a Standard Container?
.............................
Docker defines a unit of software delivery called a Standard
Container. The goal of a Standard Container is to encapsulate a
software component and all its dependencies in a format that is
self-describing and portable, so that any compliant runtime can run it
without extra dependency, regardless of the underlying machine and the
contents of the container.
The spec for Standard Containers is currently work in progress, but it
is very straightforward. It mostly defines 1) an image format, 2) a
set of standard operations, and 3) an execution environment.
A great analogy for this is the shipping container. Just like Standard
Containers are a fundamental unit of software delivery, shipping
containers are a fundamental unit of physical delivery.
Standard operations
~~~~~~~~~~~~~~~~~~~
Just like shipping containers, Standard Containers define a set of
STANDARD OPERATIONS. Shipping containers can be lifted, stacked,
locked, loaded, unloaded and labelled. Similarly, standard containers
can be started, stopped, copied, snapshotted, downloaded, uploaded and
tagged.
Content-agnostic
~~~~~~~~~~~~~~~~~~~
Just like shipping containers, Standard Containers are
CONTENT-AGNOSTIC: all standard operations have the same effect
regardless of the contents. A shipping container will be stacked in
exactly the same way whether it contains Vietnamese powder coffee or
spare Maserati parts. Similarly, Standard Containers are started or
uploaded in the same way whether they contain a postgres database, a
php application with its dependencies and application server, or Java
build artifacts.
Infrastructure-agnostic
~~~~~~~~~~~~~~~~~~~~~~~~~~
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be
transported to thousands of facilities around the world, and
manipulated by a wide variety of equipment. A shipping container can
be packed in a factory in Ukraine, transported by truck to the nearest
routing center, stacked onto a train, loaded into a German boat by an
Australian-built crane, stored in a warehouse at a US facility,
etc. Similarly, a standard container can be bundled on my laptop,
uploaded to S3, downloaded, run and snapshotted by a build server at
Equinix in Virginia, uploaded to 10 staging servers in a home-made
Openstack cluster, then sent to 30 production instances across 3 EC2
regions.
Designed for automation
~~~~~~~~~~~~~~~~~~~~~~~
Because they offer the same standard operations regardless of content
and infrastructure, Standard Containers, just like their physical
counterpart, are extremely well-suited for automation. In fact, you
could say automation is their secret weapon.
Many things that once required time-consuming and error-prone human
effort can now be programmed. Before shipping containers, a bag of
powder coffee was hauled, dragged, dropped, rolled and stacked by 10
different people in 10 different locations by the time it reached its
destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The
process was slow, inefficient and cost a fortune - and was entirely
different depending on the facility and the type of goods.
Similarly, before Standard Containers, by the time a software
component ran in production, it had been individually built,
configured, bundled, documented, patched, vendored, templated, tweaked
and instrumented by 10 different people on 10 different
computers. Builds failed, libraries conflicted, mirrors crashed,
post-it notes were lost, logs were misplaced, cluster updates were
half-broken. The process was slow, inefficient and cost a fortune -
and was entirely different depending on the language and
infrastructure provider.
Industrial-grade delivery
~~~~~~~~~~~~~~~~~~~~~~~~~
There are 17 million shipping containers in existence, packed with
every physical good imaginable. Every single one of them can be loaded
on the same boats, by the same cranes, in the same facilities, and
sent anywhere in the World with incredible efficiency. It is
embarrassing to think that a 30 ton shipment of coffee can safely
travel half-way across the World in *less time* than it takes a
software team to deliver its code from one datacenter to another
sitting 10 miles away.
With Standard Containers we can put an end to that embarrassment, by
making INDUSTRIAL-GRADE DELIVERY of software a reality.

View File

@@ -5,53 +5,54 @@
Setting Up a Dev Environment
============================
Instructions that have been verified to work on Ubuntu Precise 12.04 (LTS) (64-bit),
To make it easier to contribute to Docker, we provide a standard development environment. It is important that
the same environment be used for all tests, builds and releases. The standard development environment defines
all build dependencies: system libraries and binaries, go environment, go dependencies, etc.
Dependencies
------------
Step 1: install docker
----------------------
**Linux kernel 3.8**
Docker's build environment itself is a docker container, so the first step is to install docker on your system.
Due to a bug in LXC docker works best on the 3.8 kernel. Precise comes with a 3.2 kernel, so we need to upgrade it. The kernel we install comes with AUFS built in.
You can follow the `install instructions most relevant to your system <https://docs.docker.io/en/latest/installation/>`.
Make sure you have a working, up-to-date docker installation, then continue to the next step.
.. code-block:: bash
Step 2: check out the source
----------------------------
# install the backported kernel
sudo apt-get update && sudo apt-get install linux-image-generic-lts-raring
::
# reboot
sudo reboot
Installation
------------
.. code-block:: bash
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:gophers/go
sudo apt-get update
sudo apt-get -y install lxc xz-utils curl golang-stable git aufs-tools
export GOPATH=~/go/
export PATH=$GOPATH/bin:$PATH
mkdir -p $GOPATH/src/github.com/dotcloud
cd $GOPATH/src/github.com/dotcloud
git clone git://github.com/dotcloud/docker.git
git clone http://git@github.com/dotcloud/docker
cd docker
go get -v github.com/dotcloud/docker/...
go install -v github.com/dotcloud/docker/...
Step 3: build
-------------
When you are ready to build docker, run this command:
::
docker build -t docker .
This will build the revision currently checked out in the repository. Feel free to check out the version
of your choice.
If the build is successful, congratulations! You have produced a clean build of docker, neatly encapsulated
in a standard build environment.
You can run an interactive session in the newly built container:
::
docker run -i -t docker bash
Then run the docker daemon,
To extract the binaries from the container:
.. code-block:: bash
::
sudo $GOPATH/bin/docker -d
docker run docker sh -c 'cat $(which docker)' > docker-build && chmod +x docker-build
Run the ``go install`` command (above) to recompile docker.

View File

@@ -39,7 +39,7 @@ This time, we're requesting shared access to $COUCH1's volumes.
.. code-block:: bash
COUCH2=$(docker run -d -volumes-from $COUCH1) shykes/couchdb:2013-05-03)
COUCH2=$(docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
Browse data on the second database
----------------------------------
@@ -48,6 +48,6 @@ Browse data on the second database
HOST=localhost
URL="http://$HOST:$(docker port $COUCH2 5984)/_utils/"
echo "Navigate to $URL in your browser. You should see the same data as in the first database!"
echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
Congratulations, you are running 2 Couchdb containers, completely isolated from each other *except* for their data.

View File

@@ -1,127 +1,36 @@
:title: Introduction
:description: An introduction to docker and standard containers?
:title: Welcome to the Docker Documentation
:description: An overview of the Docker Documentation
:keywords: containers, lxc, concepts, explanation
.. _introduction:
Welcome
=======
Introduction
============
.. image:: concepts/images/dockerlogo-h.png
Docker -- The Linux container runtime
-------------------------------------
``docker``, the Linux Container Runtime, runs Unix processes with
strong guarantees of isolation across servers. Your software runs
repeatably everywhere because its :ref:`container_def` includes any
dependencies.
Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
``docker`` runs three ways:
Docker is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc.
* as a daemon to manage LXC containers on your :ref:`Linux host
<kernel>` (``sudo docker -d``)
* as a :ref:`CLI <cli>` which talks to the daemon's `REST API
<api/docker_remote_api>`_ (``docker run ...``)
* as a client of :ref:`Repositories <working_with_the_repository>`
that let you share what you've built (``docker pull, docker
commit``).
Each use of ``docker`` is documented here. The features of Docker are
currently in active development, so this documention will change
frequently.
- **Heterogeneous payloads** Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.
- **Any server** Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.
- **Isolation** docker isolates processes from each other and from the underlying host, using lightweight containers.
- **Repeatability** Because containers are isolated in their own filesystem, they behave the same regardless of where, when, and alongside what they run.
.. image:: concepts/images/lego_docker.jpg
What is a Standard Container?
-----------------------------
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependency, regardless of the underlying machine and the contents of the container.
The spec for Standard Containers is currently work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
A great analogy for this is the shipping container. Just like Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
Standard operations
~~~~~~~~~~~~~~~~~~~
Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
Content-agnostic
~~~~~~~~~~~~~~~~~~~
Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
Infrastructure-agnostic
~~~~~~~~~~~~~~~~~~~~~~~~~~
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
Designed for automation
~~~~~~~~~~~~~~~~~~~~~~~~~~
Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
Industrial-grade delivery
~~~~~~~~~~~~~~~~~~~~~~~~~~
There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded on the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
Standard Container Specification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(TODO)
Image format
~~~~~~~~~~~~
Standard operations
~~~~~~~~~~~~~~~~~~~
- Copy
- Run
- Stop
- Wait
- Commit
- Attach standard streams
- List filesystem changes
- ...
Execution environment
~~~~~~~~~~~~~~~~~~~~~
Root filesystem
^^^^^^^^^^^^^^^
Environment variables
^^^^^^^^^^^^^^^^^^^^^
Process arguments
^^^^^^^^^^^^^^^^^
Networking
^^^^^^^^^^
Process namespacing
^^^^^^^^^^^^^^^^^^^
Resource limits
^^^^^^^^^^^^^^^
Process monitoring
^^^^^^^^^^^^^^^^^^
Logging
^^^^^^^
Signals
^^^^^^^
Pseudo-terminal allocation
^^^^^^^^^^^^^^^^^^^^^^^^^^
Security
^^^^^^^^
For an overview of Docker, please see the `Introduction
<http://www.docker.io>`_. When you're ready to start working with
Docker, we have a `quick start <http://www.docker.io/gettingstarted>`_
and a more in-depth guide to :ref:`ubuntu_linux` and other
:ref:`installation_list` paths including prebuilt binaries,
Vagrant-created VMs, Rackspace and Amazon instances.
Enough reading! :ref:`Try it out! <running_examples>`

View File

@@ -1,12 +1,17 @@
:title: Documentation
:description: -- todo: change me
:keywords: todo, docker, documentation, installation, OS support
:title: Docker Installation
:description: many ways to install Docker
:keywords: docker, installation
.. _installation_list:
Installation
============
There are a number of ways to install Docker, depending on where you
want to run the daemon. The :ref:`ubuntu_linux` installation is the
officially-tested version, and the community adds more techniques for
installing Docker all the time.
Contents:
.. toctree::

View File

@@ -0,0 +1,40 @@
:title: Container
:description: Definitions of a container
:keywords: containers, lxc, concepts, explanation, image, container
.. _container_def:
Container
=========
.. image:: images/docker-filesystems-busyboxrw.png
Once you start a process in Docker from an :ref:`image_def`, Docker
fetches the image and its :ref:`parent_image_def`, and repeats the
process until it reaches the :ref:`base_image_def`. Then the
:ref:`ufs_def` adds a read-write layer on top. That read-write layer,
plus the information about its :ref:`parent_image_def` and some
additional information like its unique id, networking configuration,
and resource limits is called a **container**.
.. _container_state_def:
Container State
...............
Containers can change, and so they have state. A container may be
**running** or **exited**.
When a container is running, the idea of a "container" also includes a
tree of processes running on the CPU, isolated from the other
processes running on the host.
When the container is exited, the state of the file system and
its exit value is preserved. You can start, stop, and restart a
container. The processes restart from scratch (their memory state is
**not** preserved in a container), but the file system is just as it
was when the container was stopped.
You can promote a container to an :ref:`image_def` with ``docker
commit``. Once a container is an image, you can use it as a parent for
new containers.

View File

@@ -0,0 +1,38 @@
:title: File Systems
:description: How Linux organizes its persistent storage
:keywords: containers, files, linux
.. _filesystem_def:
File System
===========
.. image:: images/docker-filesystems-generic.png
In order for a Linux system to run, it typically needs two `file
systems <http://en.wikipedia.org/wiki/Filesystem>`_:
1. boot file system (bootfs)
2. root file system (rootfs)
The **boot file system** contains the bootloader and the kernel. The
user never makes any changes to the boot file system. In fact, soon
after the boot process is complete, the entire kernel is in memory,
and the boot file system is unmounted to free up the RAM associated
with the initrd disk image.
The **root file system** includes the typical directory structure we
associate with Unix-like operating systems: ``/dev, /proc, /bin, /etc,
/lib, /usr,`` and ``/tmp`` plus all the configuration files, binaries
and libraries required to run user applications (like bash, ls, and so
forth).
While there can be important kernel differences between different
Linux distributions, the contents and organization of the root file
system are usually what make your software packages dependent on one
distribution versus another. Docker can help solve this problem by
running multiple distributions at the same time.
.. image:: images/docker-filesystems-multiroot.png

View File

@@ -1,97 +0,0 @@
:title: Image & Container
:description: Definitions of an image and container
:keywords: containers, lxc, concepts, explanation, image, container
File Systems
============
.. image:: images/docker-filesystems-generic.png
In order for a Linux system to run, it typically needs two `file
systems <http://en.wikipedia.org/wiki/Filesystem>`_:
1. boot file system (bootfs)
2. root file system (rootfs)
The **boot file system** contains the bootloader and the kernel. The
user never makes any changes to the boot file system. In fact, soon
after the boot process is complete, the entire kernel is in memory,
and the boot file system is unmounted to free up the RAM associated
with the initrd disk image.
The **root file system** includes the typical directory structure we
associate with Unix-like operating systems: ``/dev, /proc, /bin, /etc,
/lib, /usr,`` and ``/tmp`` plus all the configuration files, binaries
and libraries required to run user applications (like bash, ls, and so
forth).
While there can be important kernal differences between different
Linux distributions, the contents and organization of the root file
system are usually what make your software packages dependent on one
distribution versus another. Docker can help solve this problem by
running multiple distributions at the same time.
.. image:: images/docker-filesystems-multiroot.png
Layers and Union Mounts
=======================
In a traditional Linux boot, the kernel first mounts the root file
system as read-only, checks its integrity, and then switches the whole
rootfs volume to read-write mode. Docker does something similar,
*except* that instead of changing the file system to read-write mode,
it takes advantage of a `union mount
<http://en.wikipedia.org/wiki/Union_mount>`_ to add a read-write file
system *over* the read-only file system. In fact there may be multiple
read-only file systems stacked on top of each other.
.. image:: images/docker-filesystems-multilayer.png
At first, the top layer has nothing in it, but any time a process
creates a file, this happens in the top layer. And if something needs
to update an existing file in a lower layer, then the file gets copied
to the upper layer and changes go into the copy. The version of the
file on the lower layer cannot be seen by the applications anymore,
but it is there, unchanged.
We call the union of the read-write layer and all the read-only layers
a **union file system**.
Image
=====
In Docker terminology, a read-only layer is called an **image**. An
image never changes. Because Docker uses a union file system, the
applications think the whole file system is mounted read-write,
because any file can be changed. But all the changes go to the
top-most layer, and underneath, the image is unchanged. Since they
don't change, images do not have state.
Each image may depend on one more image which forms the layer beneath
it. We sometimes say that the lower image is the **parent** of the
upper image.
Base Image
==========
An image that has no parent is a **base image**.
Container
=========
Once you start a process in Docker from an image, Docker fetches the
image and its parent, and repeats the process until it reaches the
base image. Then the union file system adds a read-write layer on
top. That read-write layer, plus the information about its parent and
some additional information like its unique id, is called a
**container**.
Containers can change, and so they have state. A container may be
running or exited. In either case, the state of the file system and
its exit value is preserved. You can start, stop, and restart a
container. The processes restart from scratch (their memory state is
**not** preserved in a container), but the file system is just as it
was when the container was stopped.
You can promote a container to an image with ``docker commit``. Once a
container is an image, you can use it as a parent for new containers.

View File

@@ -0,0 +1,38 @@
:title: Images
:description: Definition of an image
:keywords: containers, lxc, concepts, explanation, image, container
.. _image_def:
Image
=====
.. image:: images/docker-filesystems-debian.png
In Docker terminology, a read-only :ref:`layer_def` is called an
**image**. An image never changes.
Since Docker uses a :ref:`ufs_def`, the processes think the whole file
system is mounted read-write. But all the changes go to the top-most
writeable layer, and underneath, the original file in the read-only
image is unchanged. Since images don't change, images do not have state.
.. image:: images/docker-filesystems-debianrw.png
.. _parent_image_def:
Parent Image
............
.. image:: images/docker-filesystems-multilayer.png
Each image may depend on one more image which forms the layer beneath
it. We sometimes say that the lower image is the **parent** of the
upper image.
.. _base_image_def:
Base Image
..........
An image that has no parent is a **base image**.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -9,15 +9,15 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="0.48.2 r9819"
version="1.1"
id="svg2"
height="600"
width="800"
sodipodi:docname="docker-filesystems.svg"
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multilayer.png"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
sodipodi:docname="docker-filesystems.svg"
width="800"
height="600"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@@ -26,10 +26,10 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.82666667"
inkscape:cx="361.59949"
inkscape:cy="396.77419"
inkscape:cx="382.45968"
inkscape:cy="348.3871"
inkscape:document-units="px"
inkscape:current-layer="layer8"
inkscape:current-layer="layer4"
showgrid="false"
width="800px"
inkscape:window-width="1327"
@@ -84,12 +84,34 @@
position="-404.80241,590.32258"
id="guide4281" />
<sodipodi:guide
orientation="1,0"
position="518.95161,347.17742"
id="guide9339" />
id="guide5235"
position="400.40322,131.85484"
orientation="1,0" />
<sodipodi:guide
id="guide5237"
position="143.95161,295.16129"
orientation="1,0" />
<sodipodi:guide
id="guide5239"
position="281.85484,384.67742"
orientation="1,0" />
</sodipodi:namedview>
<defs
id="defs4">
<inkscape:perspective
id="perspective11489"
inkscape:persp3d-origin="403.62904 : 221.23862 : 1"
inkscape:vp_z="1196.7644 : 521.45993 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="-406.34117 : 522.93291 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="-407.55086 : 591.21042 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="1200.3935 : 584.89873 : 1"
inkscape:persp3d-origin="400 : 200 : 1"
id="perspective5786" />
<inkscape:perspective
id="perspective4014"
inkscape:persp3d-origin="406.04839 : 290.19023 : 1"
@@ -132,6 +154,7 @@
</rdf:RDF>
</metadata>
<g
sodipodi:insensitive="true"
inkscape:groupmode="layer"
id="layer8"
inkscape:label="Background"
@@ -197,38 +220,6 @@
inkscape:box3dsidetype="3"
d="m 132.72634,765.18707 253.32517,142.55608 0,96.58025 -253.32517,-173.38536 z" />
</g>
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
id="text8376"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
transform="matrix(0.58237543,0,0,0.58237543,219.84375,178.6359)">
<path
id="path8383"
d="m 407.6752,504.83554 c 0,0 0,16.04632 0,16.04632 0,0 4.1431,-2.64344 4.1431,-2.64344 2.73806,-1.74697 4.66912,-2.30333 5.80495,-1.67953 1.16895,0.55219 1.75215,1.89552 1.75218,4.03129 -3e-5,2.08935 -0.58323,4.1876 -1.75218,6.29934 -1.13583,2.04747 -3.06689,3.96726 -5.80495,5.76429 0,0 -17.71025,11.62348 -17.71025,11.62348 -2.88271,1.89195 -4.96006,2.58018 -6.21946,2.05325 -1.22381,-0.60271 -1.83708,-2.01825 -1.83708,-4.24517 0,-2.17847 0.63304,-4.35207 1.8962,-6.51576 1.25921,-2.20514 3.31673,-4.21714 6.16034,-6.03146 0,0 1.8589,-1.18604 1.8589,-1.18604 0,0 0,-57.52956 0,-57.52956 0,0 -1.8589,1.05311 -1.8589,1.05311 -2.88271,1.63317 -4.96006,2.13486 -6.21946,1.49476 -1.22381,-0.71252 -1.83708,-2.1831 -1.83708,-4.41009 0,-2.22685 0.61327,-4.35683 1.83708,-6.38541 1.2594,-2.09209 3.33675,-3.93007 6.21946,-5.51029 0,0 17.71025,-9.63763 17.71025,-9.63763 2.73806,-1.50103 4.66912,-1.90729 5.80495,-1.22806 1.16895,0.65733 1.75215,2.05308 1.75218,4.18878 -3e-5,2.13588 -0.58323,4.20494 -1.75218,6.21164 -1.13583,1.94555 -3.06689,3.69194 -5.80495,5.24303 0,0 -4.1431,2.34713 -4.1431,2.34713 0,0 0,21.48932 0,21.48932 0,0 19.97055,-33.42313 19.97055,-33.42313 -1.14267,-0.41166 -1.9302,-0.95733 -2.36038,-1.63677 -0.43077,-0.67999 -0.64629,-1.68902 -0.64626,-3.02649 -3e-5,-2.16742 0.55652,-4.22734 1.66728,-6.17561 1.14317,-1.96205 3.0292,-3.66214 5.64725,-5.09729 0,0 10.89672,-5.90556 10.89672,-5.90556 2.52713,-1.3854 4.30988,-1.73587 5.35863,-1.05974 1.07944,0.65586 1.61801,2.00928 1.61806,4.0617 -5e-5,2.00797 -0.53862,3.96169 -1.61806,5.86527 -1.04875,1.89005 -2.71237,3.4818 -4.99901,4.77715 0,0 -19.38021,33.27709 -19.38021,33.27709 3.69112,0.51378 7.11765,2.57896 10.28615,6.17689 3.1772,3.54703 5.96596,8.60211 8.37448,15.15605 0,0 2.81906,-1.79866 2.81906,-1.79866 2.47696,-1.58038 4.23151,-2.05261 5.27367,-1.42578 1.07264,0.55918 1.60782,1.86117 1.60788,3.90719 -6e-5,2.00157 -0.5185,3.98542 -1.55753,5.95553 -1.042,1.93101 -2.81324,3.71837 -5.32402,5.36622 0,0 -9.61907,6.31312 -9.61907,6.31312 -2.24123,-5.50482 -4.70762,-10.58658 -7.40337,-15.2454 -2.2133,-3.8066 -4.33127,-6.27087 -6.35225,-7.38073 -1.99524,-1.18421 -4.40301,-1.64069 -7.23093,-1.36339 0,0 -7.02864,11.83882 -7.02864,11.83882"
inkscape:connector-curvature="0" />
<path
id="path8385"
d="m 504.33889,450.20724 c 0,0 -38.51263,24.07437 -38.51263,24.07437 1.02952,2.84505 2.84029,4.51025 5.42072,4.99903 2.59378,0.4652 6.06003,-0.69838 10.37364,-3.4633 3.4995,-2.24309 8.09778,-6.22556 13.75209,-11.8953 2.30731,-2.30433 3.8959,-3.73056 4.77538,-4.2889 1.19829,-0.76067 2.20348,-0.79709 3.01722,-0.11236 0.81174,0.68323 1.21692,1.93451 1.21697,3.75503 -5e-5,1.65511 -0.43419,3.34335 -1.30407,5.06802 -1.16332,2.29253 -4.01513,5.63253 -8.59699,10.05719 -4.6422,4.44071 -9.16261,8.11778 -13.55534,11.01372 -7.68449,5.06604 -13.95767,6.17145 -18.74216,3.20582 -4.81441,-3.02556 -7.24522,-9.05127 -7.24522,-18.04744 0,-9.57222 2.62856,-18.90863 7.83044,-27.91368 5.16157,-8.94171 11.00878,-15.25277 17.50729,-18.97607 3.84969,-2.20557 7.3401,-3.27314 10.4811,-3.22069 3.14318,0.0349 5.46016,0.68067 6.96696,1.93361 2.1162,1.8432 3.85544,4.61873 5.22325,8.32396 0.92815,2.58851 1.39131,5.94912 1.39135,10.087 0,0 0,5.39999 0,5.39999 m -9.99158,-6.66099 c -1.40179,-2.8503 -3.2444,-4.50369 -5.53473,-4.95378 -2.30521,-0.49538 -5.06978,0.20545 -8.3042,2.11763 -3.23259,1.91123 -6.05351,4.52841 -8.45282,7.85517 -2.41524,3.30543 -4.39745,7.34338 -5.93945,12.11231 0,0 28.2312,-17.13133 28.2312,-17.13133"
inkscape:connector-curvature="0" />
<path
id="path8387"
d="m 532.28648,399.49334 c 0,0 0,7.62581 0,7.62581 3.42049,-5.6818 6.08733,-9.67191 8.01819,-12.00361 1.94545,-2.33281 3.75091,-3.97369 5.41859,-4.92923 2.54908,-1.4604 5.00284,-1.43726 7.3632,0.0528 1.59719,0.99371 2.39286,2.48554 2.3929,4.47907 -4e-5,1.68701 -0.38521,3.35331 -1.15685,5.00185 -0.74861,1.59928 -1.66169,2.72207 -2.74065,3.36726 -0.95657,0.57205 -1.9665,0.4409 -3.03028,-0.39672 -1.06733,-0.84026 -2.02323,-1.01257 -2.86671,-0.51395 -1.10244,0.65184 -2.763,2.68889 -4.99017,6.12693 -2.21624,3.44588 -5.01411,8.32326 -8.40822,14.66299 0,0 0,18.4092 0,18.4092 0,0 11.47319,-7.32028 11.47319,-7.32028 1.89957,-1.21199 3.2406,-1.50439 4.02992,-0.88361 0.81268,0.56434 1.2183,1.73659 1.21834,3.51786 -4e-5,1.74257 -0.40566,3.43988 -1.21834,5.0949 -0.78932,1.60367 -2.13035,3.0276 -4.02992,4.27431 0,0 -24.80701,16.28117 -24.80701,16.28117 -2.05798,1.35069 -3.53958,1.75299 -4.43724,1.19972 -0.87187,-0.6139 -1.30863,-1.86107 -1.30863,-3.74027 0,-1.83831 0.43676,-3.60993 1.30863,-5.31162 0.89766,-1.75595 2.37926,-3.2917 4.43724,-4.60477 0,0 5.03647,-3.21343 5.03647,-3.21343 0,0 0,-30.03766 0,-30.03766 0,0 -3.04598,1.80817 -3.04598,1.80817 -2.04596,1.2146 -3.51888,1.52055 -4.41127,0.91117 -0.86675,-0.66806 -1.30094,-1.93958 -1.30094,-3.81328 0,-1.8329 0.43419,-3.57126 1.30094,-5.212 0.89239,-1.6931 2.36531,-3.12925 4.41127,-4.30644 0,0 11.34333,-6.52633 11.34333,-6.52633"
inkscape:connector-curvature="0" />
<path
id="path8389"
d="m 572.24194,376.50516 c 0,0 0,3.86493 0,3.86493 1.31657,-2.55421 2.75611,-4.72562 4.31689,-6.51554 1.57611,-1.79414 3.27078,-3.20898 5.08203,-4.24677 4.13268,-2.36771 7.36362,-2.16528 9.72036,0.56776 1.85468,2.16735 2.77779,5.877 2.77783,11.1389 0,0 0,20.59729 0,20.59729 1.42308,-0.90797 2.46973,-1.05531 3.1438,-0.44622 0.67249,0.572 1.00821,1.68074 1.00824,3.32725 -3e-5,1.61072 -0.34658,3.16111 -1.04082,4.65362 -0.67414,1.44584 -1.81921,2.6999 -3.44058,3.76403 0,0 -6.15847,4.04189 -6.15847,4.04189 -1.66347,1.09175 -2.8604,1.36497 -3.58533,0.81425 -0.70395,-0.6035 -1.0565,-1.74997 -1.05647,-3.4383 -3e-5,-1.65157 0.35252,-3.21764 1.05647,-4.6957 0.70228,-1.51122 1.78658,-2.73371 3.24886,-3.66669 0,0 0,-21.15717 0,-21.15717 -2e-5,-2.44186 -0.40426,-3.98655 -1.21429,-4.63538 -1.06085,-0.83225 -2.65895,-0.61904 -4.8027,0.64833 -1.62916,0.96324 -3.07036,2.33311 -4.32094,4.11119 -1.23237,1.73432 -2.80892,4.8321 -4.73488,9.30874 0,0 0,21.34125 0,21.34125 1.85569,-1.184 3.04789,-1.66582 3.58407,-1.45135 1.13919,0.38348 1.70724,1.64851 1.70726,3.79612 -2e-5,1.66625 -0.37088,3.27815 -1.11389,4.83837 -0.72152,1.51157 -1.94723,2.83594 -3.68307,3.97519 0,0 -8.33029,5.46728 -8.33029,5.46728 -1.79222,1.17626 -3.08205,1.49092 -3.86336,0.938 -0.75872,-0.60834 -1.13874,-1.78952 -1.13874,-3.54238 0,-2.1339 0.58824,-4.16867 1.76149,-6.09901 0.58501,-0.94353 1.83674,-2.02693 3.74738,-3.24598 0,0 0,-28.22034 0,-28.22034 -1.57121,0.93277 -2.73648,1.07437 -3.4913,0.42017 -0.75664,-0.65565 -1.13561,-1.84028 -1.13561,-3.55271 0,-1.71238 0.37897,-3.32097 1.13561,-4.82316 0.77916,-1.55048 2.06546,-2.84066 3.85278,-3.86905 0,0 6.96767,-4.00881 6.96767,-4.00881"
inkscape:connector-curvature="0" />
<path
id="path8391"
d="m 634.34141,368.94225 c 0,0 -25.20953,15.75856 -25.20953,15.75856 0.6672,2.39172 1.84157,3.9121 3.51707,4.56242 1.68646,0.63355 3.94388,0.0402 6.75893,-1.7642 2.28854,-1.46689 5.30217,-4.23703 9.01804,-8.27952 1.51956,-1.64558 2.56684,-2.64955 3.14705,-3.0179 0.79096,-0.50209 1.45484,-0.43448 1.99254,0.20091 0.53661,0.63426 0.80455,1.6912 0.8046,3.17172 -5e-5,1.34601 -0.28714,2.67618 -0.86216,3.99258 -0.7686,1.7482 -2.65074,4.17765 -5.66863,7.30949 -3.05013,3.13106 -6.01295,5.64891 -8.88527,7.54251 -5.00854,3.3019 -9.08208,3.5476 -12.17982,0.67175 -3.10916,-2.91974 -4.67598,-8.00122 -4.67598,-15.22147 0,-7.68257 1.69435,-14.92957 5.05447,-21.68353 3.34323,-6.72524 7.14168,-11.28617 11.37713,-13.71287 2.51598,-1.44145 4.80162,-1.99625 6.86211,-1.67548 2.06538,0.30724 3.59011,1.03724 4.58269,2.18866 1.39536,1.68649 2.54336,4.09846 3.44695,7.23454 0.6135,2.18975 0.91977,4.96536 0.91981,8.3304 0,0 0,4.39143 0,4.39143 m -6.5902,-6.34854 c -0.92175,-2.4412 -2.13235,-3.95102 -3.6354,-4.52578 -1.51099,-0.61206 -3.3206,-0.29783 -5.4344,0.95183 -2.10895,1.2469 -3.94636,3.09915 -5.50696,5.55983 -1.56898,2.43888 -2.85515,5.5053 -3.85476,9.19879 0,0 18.43152,-11.18467 18.43152,-11.18467"
inkscape:connector-curvature="0" />
<path
id="path8393"
d="m 656.82836,308.98356 c 0,0 0,52.93031 0,52.93031 0,0 6.4328,-4.10434 6.4328,-4.10434 1.27173,-0.81141 2.17036,-0.92363 2.69958,-0.34039 0.54515,0.53946 0.81731,1.53839 0.81734,2.99761 -3e-5,1.42751 -0.27219,2.77874 -0.81734,4.05558 -0.52922,1.23647 -1.42785,2.27149 -2.69958,3.10614 0,0 -18.63545,12.2307 -18.63545,12.2307 -1.36813,0.89792 -2.35216,1.07925 -2.94796,0.53978 -0.57842,-0.58603 -0.86806,-1.64466 -0.86806,-3.17491 0,-1.49696 0.28964,-2.89722 0.86806,-4.19875 0.5958,-1.34387 1.57983,-2.45281 2.94796,-3.32572 0,0 6.72309,-4.28956 6.72309,-4.28956 0,0 0,-43.42716 0,-43.42716 0,0 -4.49128,2.51035 -4.49128,2.51035 -1.33877,0.74834 -2.3056,0.82613 -2.89655,0.22966 -0.59221,-0.63072 -0.88879,-1.70864 -0.88879,-3.23275 0,-1.49086 0.28731,-2.85673 0.86106,-4.0957 0.59101,-1.27931 1.56713,-2.28621 2.92428,-3.02004 0,0 9.97084,-5.39081 9.97084,-5.39081"
inkscape:connector-curvature="0" />
</g>
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
@@ -269,45 +260,99 @@
d="m 574.61499,283.99905 c -3.31444,-0.15435 -6.08369,-0.11845 -8.31443,0.10735 -2.30321,0.20508 -4.07372,0.60048 -5.31424,1.18721 -2.46838,1.16767 -3.01224,2.51015 -1.61447,4.03327 0.60292,0.67291 1.64413,1.22527 3.12534,1.65615 1.70913,0.49721 3.82744,0.77332 6.35381,0.8271 1.87073,0.0245 4.53088,-0.36099 7.97382,-1.15539 6.3436,-1.44672 11.39483,-2.26881 15.17355,-2.47016 4.98619,-0.25925 10.88971,0.10784 17.75075,1.10837 6.92387,1.00975 13.65666,2.40914 20.21272,4.20821 9.03796,2.4802 15.73657,5.10339 20.02734,7.86932 6.35081,4.06357 7.3,7.36394 2.70673,9.84732 -1.85312,1.00191 -4.27563,1.73258 -7.2635,2.1895 -2.88132,0.47104 -6.28692,0.6849 -10.20845,0.64145 0.80272,0.49803 1.32719,0.93276 1.57202,1.30366 0.24495,0.37149 0.1769,0.66031 -0.20564,0.86576 -1.02151,0.54865 -3.18409,0.59244 -6.47634,0.13197 -3.34347,-0.49542 -8.15753,-1.67755 -14.39541,-3.53092 0,0 -8.59884,-2.55485 -8.59884,-2.55485 -6.05987,-1.80048 -10.01632,-3.2171 -11.91481,-4.26116 -1.94556,-1.07213 -2.42442,-1.85248 -1.44701,-2.34539 0.78497,-0.39581 2.2796,-0.48123 4.48868,-0.25629 2.13397,0.20198 5.36767,0.81735 9.72187,1.85154 4.26215,0.44403 7.96002,0.55921 11.08074,0.3439 3.04016,-0.23936 5.45895,-0.82613 7.25042,-1.75782 2.92404,-1.52066 3.35798,-3.20948 1.3294,-5.05875 -1.04765,-0.89657 -2.55062,-1.61718 -4.50718,-2.1636 -3.2445,-0.90604 -6.44882,-1.37387 -9.62339,-1.4077 -3.16808,-0.0337 -7.17813,0.6088 -12.04806,1.93106 -7.21679,1.99422 -14.62018,2.58337 -22.13286,1.76443 -7.37333,-0.78946 -15.08696,-2.38082 -23.08624,-4.74933 -8.08729,-2.39456 -13.72809,-4.81726 -16.98815,-7.27133 -4.41938,-3.29135 -4.47329,-5.88661 -0.24956,-7.8229 1.46281,-0.6705 3.34863,-1.17273 5.65981,-1.50788 2.26094,-0.36411 4.98687,-0.55216 8.18326,-0.56429 -0.60143,-0.45433 -0.98542,-0.82473 -1.153,-1.11182 -0.14687,-0.2959 -0.0782,-0.50905 0.20561,-0.63976 0.85095,-0.3916 2.68442,-0.40633 5.50914,-0.0436 2.76417,0.34452 6.79329,1.24528 12.1235,2.71337 0,0 5.46229,1.50449 5.46229,1.50449 4.9316,1.35835 8.14703,2.36621 9.61371,3.01537 2.80152,1.26506 3.65218,2.17198 2.53312,2.71381 -0.75407,0.36519 -2.28486,0.44438 -4.58735,0.23757 -2.2968,-0.20623 -4.94238,-0.66681 -7.9287,-1.37921"
id="path9377" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 386.05151,551.96125 0,-96.58028 280.72657,-151.77679 0,63.28635 z"
id="path4672"
inkscape:connector-curvature="0" />
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
transform="matrix(0.79944175,0,0,0.79944175,52.022588,84.530657)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
id="text12064">
id="text7447"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic">
<path
id="path7454"
d="m 147.58834,332.81239 c 0,0 -1.75619,37.90152 -1.75619,37.90152 0,0 -1.88054,-1.21673 -1.88054,-1.21673 0,0 1.76021,-37.74043 1.76021,-37.74043 0,0 1.87652,1.05564 1.87652,1.05564"
inkscape:connector-curvature="0" />
<path
id="path7456"
d="m 155.5998,356.97158 c 0,0 -0.24054,5.14593 -0.24054,5.14593 -0.40443,-1.61247 -0.78977,-2.82699 -1.15617,-3.64502 -0.35987,-0.7974 -0.78335,-1.34369 -1.27013,-1.63943 -0.73705,-0.44773 -1.33999,-0.091 -1.81,1.06776 -0.46924,1.15688 -0.70259,2.86881 -0.7006,5.13825 0.002,2.13082 0.22404,3.97436 0.6673,5.53232 0.4501,1.58081 1.03211,2.60051 1.7469,3.05745 0.68755,0.43955 1.39964,0.10214 2.13626,-1.01548 0,0 -0.24938,5.3343 -0.24938,5.3343 -0.75516,0.32879 -1.47328,0.27142 -2.15455,-0.1704 -1.21082,-0.78524 -2.19272,-2.47392 -2.94825,-5.0617 -0.74689,-2.57425 -1.12029,-5.52395 -1.12234,-8.85412 -0.002,-3.41998 0.39606,-6.0285 1.19618,-7.83178 0.80817,-1.82041 1.81762,-2.37095 3.0313,-1.64489 0.99666,0.59627 1.95471,2.12313 2.87402,4.58681"
inkscape:connector-curvature="0" />
<path
id="path7458"
d="m 162.12519,369.14836 c 0,0 3.15558,14.14905 3.15558,14.14905 0,0 -2.36428,-1.52972 -2.36428,-1.52972 0,0 -2.06013,-9.88013 -2.06013,-9.88013 0,0 -2.73436,6.77803 -2.73436,6.77803 0,0 -2.55294,-1.65178 -2.55294,-1.65178 0,0 4.27078,-9.71399 4.27078,-9.71399 0,0 -2.54931,-11.45318 -2.54931,-11.45318 0,0 2.27488,1.36446 2.27488,1.36446 0,0 1.52855,7.34113 1.52855,7.34113 0,0 2.03981,-5.20084 2.03981,-5.20084 0,0 2.60043,1.55972 2.60043,1.55972 0,0 -3.60901,8.23725 -3.60901,8.23725"
inkscape:connector-curvature="0" />
<path
id="path7460"
d="m 169.92343,379.36559 c 0,0 -3.25195,12.16924 -3.25195,12.16924 0,0 -1.27259,-2.63135 -1.27259,-2.63135 0,0 2.90583,-12.86349 2.90583,-12.86349 0,0 1.61871,3.3256 1.61871,3.3256"
inkscape:connector-curvature="0" />
<path
id="path7462"
d="m 189.30148,375.04665 c 0,0 -1.03888,23.12027 -1.03888,23.12027 0,0 -2.24228,-1.45077 -2.24228,-1.45077 0,0 0.11673,-2.49125 0.11673,-2.49125 -0.94298,1.47092 -1.92196,1.87493 -2.93613,1.21763 -1.24207,-0.80501 -2.25567,-2.51652 -3.04325,-5.13028 -0.78468,-2.60409 -1.18382,-5.57547 -1.1996,-8.91911 -0.0182,-3.85301 0.40809,-6.73894 1.2807,-8.66498 0.88831,-1.92374 2.04012,-2.46472 3.45951,-1.61503 0.6727,0.40274 1.24847,1.02201 1.72666,1.85828 0.48587,0.84208 0.98515,2.09412 1.498,3.75781 0,0 0.13357,-3.0291 0.13357,-3.0291 0,0 2.24497,1.34653 2.24497,1.34653 m -2.66567,9.53882 c -0.0121,-2.10019 -0.26427,-3.95362 -0.75572,-5.55842 -0.49044,-1.61785 -1.11651,-2.65716 -1.8773,-3.11967 -0.82492,-0.50144 -1.51048,-0.11404 -2.058,1.15924 -0.54646,1.28764 -0.81341,3.10968 -0.80158,5.46904 0.0103,2.06152 0.24981,3.89591 0.71924,5.50498 0.47047,1.61265 1.07146,2.65376 1.80379,3.12165 0.81474,0.52057 1.51683,0.14096 2.10513,-1.14196 0.58925,-1.31904 0.87768,-3.13164 0.86444,-5.43486"
inkscape:connector-curvature="0" />
<path
id="path7464"
d="m 200.98417,382.05386 c 0,0 -0.60701,13.76386 -0.60701,13.76386 -0.0478,1.17529 -0.11093,2.18594 -0.18949,3.03183 -0.0786,0.8458 -0.16535,1.53989 -0.26032,2.08222 -0.1903,1.03239 -0.51634,1.84794 -0.97764,2.4463 -0.78121,1.00906 -1.81569,1.09476 -3.10016,0.26227 -1.21534,-0.78769 -2.18714,-2.17556 -2.91798,-4.16161 -0.72858,-1.99666 -1.10026,-4.27781 -1.1168,-6.84699 -0.003,-0.39117 10e-4,-0.84599 0.0118,-1.36445 0.0173,-0.51405 0.0409,-1.10033 0.0709,-1.75873 0,0 0.55615,-12.57127 0.55615,-12.57127 0,0 2.29365,1.37572 2.29365,1.37572 0,0 -0.58535,13.12163 -0.58535,13.12163 -0.0239,0.56331 -0.0413,1.06266 -0.0521,1.49808 -0.011,0.4184 -0.0156,0.77281 -0.0136,1.06329 0.0172,2.54701 0.63463,4.21014 1.85674,4.9909 0.66588,0.42543 1.15463,0.31796 1.46518,-0.3237 0.31086,-0.6423 0.51161,-1.98957 0.60201,-4.04108 0,0 0.62456,-13.97146 0.62456,-13.97146 0,0 2.33946,1.40319 2.33946,1.40319"
inkscape:connector-curvature="0" />
<path
id="path7466"
d="m 206.63389,390.78613 c 0,0 -0.82079,18.73618 -0.82079,18.73618 0,0 -2.40115,-1.55357 -2.40115,-1.55357 0,0 0.82954,-18.64209 0.82954,-18.64209 0,0 -1.55408,-0.94806 -1.55408,-0.94806 0,0 0.22678,-5.16711 0.22678,-5.16711 0,0 1.55445,0.93235 1.55445,0.93235 0,0 0.47336,-10.6332 0.47336,-10.6332 0.12045,-2.83044 0.43153,-4.7841 0.93387,-5.86279 0.50314,-1.08033 1.23473,-1.3513 2.1968,-0.81014 0.58479,0.32902 1.27387,1.15978 2.06817,2.49496 0,0 -0.21954,4.94262 -0.21954,4.94262 -0.4636,-1.13664 -0.88579,-1.81328 -1.26683,-2.03137 -0.43899,-0.25118 -0.76101,-0.0798 -0.96652,0.51359 -0.19081,0.60146 -0.32899,1.83118 -0.41464,3.6896 0,0 -0.40076,9.13858 -0.40076,9.13858 0,0 2.19474,1.3164 2.19474,1.3164 0,0 -0.22825,5.2293 -0.22825,5.2293 0,0 -2.20515,-1.34525 -2.20515,-1.34525"
inkscape:connector-curvature="0" />
<path
id="path7468"
d="m 217.52646,394.74253 c 0,0 -1.38661,2.48014 -1.38661,2.48014 -0.67725,-1.8109 -1.29703,-2.88559 -1.8599,-3.22743 -0.38208,-0.23202 -0.69765,-0.16825 -0.94697,0.19084 -0.24182,0.34568 -0.3592,0.89013 -0.3523,1.63368 0.007,0.72604 0.11693,1.40131 0.33073,2.02617 0.21414,0.64318 0.65861,1.60559 1.33464,2.88942 0.96807,1.85739 1.62118,3.41663 1.95681,4.67361 0.3587,1.2553 0.54644,2.71574 0.56281,4.38041 0.0236,2.39986 -0.31049,4.09968 -1.00105,5.09661 -0.70429,0.96703 -1.62822,1.07848 -2.76933,0.33845 -1.54613,-1.0027 -2.83506,-3.48418 -3.86988,-7.43484 0,0 1.58533,-1.65255 1.58533,-1.65255 0.67846,2.3152 1.39501,3.71619 2.14973,4.19878 0.42688,0.27296 0.76562,0.22407 1.01586,-0.14723 0.25795,-0.3668 0.38295,-0.97802 0.37484,-1.83329 -0.007,-0.74819 -0.12185,-1.42257 -0.34408,-2.02287 -0.10729,-0.29756 -0.29412,-0.7335 -0.56031,-1.30745 -0.26591,-0.57331 -0.6257,-1.28445 -1.07896,-2.13273 -0.79912,-1.53842 -1.35435,-2.89536 -1.66731,-4.07336 -0.31299,-1.22922 -0.47603,-2.59245 -0.48943,-4.09057 -0.0202,-2.25482 0.31059,-3.91075 0.99349,-4.97061 0.68445,-1.0622 1.56745,-1.27103 2.65118,-0.62272 1.20102,0.71853 2.32478,2.58513 3.37071,5.60754"
inkscape:connector-curvature="0" />
<path
id="path7470"
d="m 230.10477,380.45134 c 0,0 -10.56007,50.00187 -10.56007,50.00187 0,0 -1.7864,-3.10109 -1.7864,-3.10109 0,0 10.48761,-49.78707 10.48761,-49.78707 0,0 1.85886,2.88629 1.85886,2.88629"
inkscape:connector-curvature="0" />
<path
id="path7472"
d="m 235.60558,382.32627 c 0,0 -0.96703,22.30206 -0.96703,22.30206 0.68945,-0.7749 1.29198,-1.21024 1.8071,-1.30486 0.54025,-0.0986 1.12911,0.0426 1.76693,0.4244 1.5763,0.94367 2.90043,2.95835 3.96916,6.05018 1.07316,3.08672 1.63707,6.54247 1.68823,10.35998 0.0562,4.19815 -0.49112,7.31628 -1.63901,9.3455 -1.15172,2.0543 -2.57758,2.52687 -4.27282,1.42815 -1.57073,-1.01801 -2.95455,-3.2779 -4.15367,-6.7709 0,0 -0.15177,3.37409 -0.15177,3.37409 0,0 -2.66427,-1.72381 -2.66427,-1.72381 0,0 1.94788,-44.98639 1.94788,-44.98639 0,0 2.66927,1.5016 2.66927,1.5016 m 5.4938,36.24781 c -0.0307,-2.35775 -0.3661,-4.47468 -1.00488,-6.34826 -0.63711,-1.86861 -1.44772,-3.10059 -2.43047,-3.69802 -1.06071,-0.64478 -1.92383,-0.28834 -2.59137,1.06538 -0.66665,1.31409 -0.98282,3.34554 -0.94953,6.09789 0.028,2.31062 0.34566,4.35609 0.9543,6.13874 0.61062,1.82429 1.3932,3.04273 2.34903,3.65337 1.05772,0.67576 1.9389,0.3393 2.64164,-1.01349 0.72078,-1.34522 1.06493,-3.31161 1.03128,-5.89561"
inkscape:connector-curvature="0" />
<path
id="path7474"
d="m 250.36366,417.46334 c 0,0 -0.86865,20.3217 -0.86865,20.3217 0,0 -2.82008,-1.82462 -2.82008,-1.82462 0,0 0.86643,-20.21881 0.86643,-20.21881 0,0 -1.58388,-0.96624 -1.58388,-0.96624 0,0 0.23648,-5.60491 0.23648,-5.60491 0,0 1.5842,0.9502 1.5842,0.9502 0,0 0.51345,-11.96899 0.51345,-11.96899 0,0 2.8242,1.63235 2.8242,1.63235 0,0 -0.51476,12.02979 -0.51476,12.02979 0,0 2.631,1.57806 2.631,1.57806 0,0 -0.23791,5.67619 -0.23791,5.67619 0,0 -2.63048,-1.60472 -2.63048,-1.60472"
inkscape:connector-curvature="0" />
<path
id="path7476"
d="m 258.21202,416.37883 c 0,0 -0.096,2.26144 -0.096,2.26144 0.95454,-1.4502 1.93663,-1.87534 2.94687,-1.27069 0.8891,0.53219 1.71186,1.72674 2.46789,3.5865 0,0 -1.80434,4.16015 -1.80434,4.16015 -0.55854,-1.34027 -1.10799,-2.17406 -1.64849,-2.50309 -0.37157,-0.22615 -0.69596,-0.26088 -0.97335,-0.10449 -0.27744,0.13698 -0.51645,0.48836 -0.7171,1.05404 -0.19204,0.55148 -0.35012,1.32418 -0.47428,2.31814 -0.11535,0.99924 -0.20109,2.22694 -0.25723,3.68339 0,0 -0.55745,13.1404 -0.55745,13.1404 0,0 -2.89641,-1.87402 -2.89641,-1.87402 0,0 1.11066,-26.19071 1.11066,-26.19071 0,0 2.89923,1.73894 2.89923,1.73894"
inkscape:connector-curvature="0" />
<path
id="path7478"
d="m 268.68987,428.64319 c 0,0 -0.86895,20.99894 -0.86895,20.99894 0,0 -3.0058,-1.94479 -3.0058,-1.94479 0,0 0.88041,-20.88084 0.88041,-20.88084 0,0 -1.94335,-1.18553 -1.94335,-1.18553 0,0 0.24005,-5.7852 0.24005,-5.7852 0,0 1.94372,1.16583 1.94372,1.16583 0,0 0.50232,-11.90806 0.50232,-11.90806 0.12679,-3.17002 0.49833,-5.34145 1.11549,-6.5165 0.61826,-1.17706 1.52819,-1.42867 2.73266,-0.75115 0.7324,0.41206 1.59932,1.39576 2.60215,2.95457 0,0 -0.233,5.54102 -0.233,5.54102 -0.58832,-1.31228 -1.12097,-2.10411 -1.59836,-2.37735 -0.54989,-0.31462 -0.95023,-0.14571 -1.2017,0.50598 -0.23303,0.66182 -0.39522,2.0335 -0.48667,4.11558 0,0 -0.42429,10.24046 -0.42429,10.24046 0,0 2.74973,1.64927 2.74973,1.64927 0,0 -0.24152,5.86326 -0.24152,5.86326 0,0 -2.76289,-1.68549 -2.76289,-1.68549"
inkscape:connector-curvature="0" />
<path
id="path7480"
d="m 282.34177,433.95542 c 0,0 -1.71638,2.6839 -1.71638,2.6839 -0.86347,-2.09418 -1.64851,-3.35394 -2.35592,-3.78356 -0.48009,-0.29154 -0.8744,-0.24473 -1.1833,0.13981 -0.29959,0.37 -0.44186,0.97364 -0.42698,1.8113 0.0145,0.81794 0.15802,1.58703 0.43072,2.30771 0.27333,0.74144 0.83759,1.86101 1.69454,3.3616 1.22784,2.17108 2.05909,3.98138 2.49024,5.42552 0.46013,1.4444 0.70781,3.10618 0.74244,4.98411 0.0499,2.7075 -0.35443,4.59578 -1.21137,5.66132 -0.87414,1.03039 -2.03028,1.07769 -3.4649,0.14731 -1.94263,-1.25984 -3.57478,-4.16196 -4.90072,-8.69458 0,0 1.96723,-1.72943 1.96723,-1.72943 0.86759,2.66246 1.77547,4.29951 2.72371,4.90584 0.53649,0.34304 0.96004,0.31621 1.27016,-0.0812 0.31984,-0.39178 0.47119,-1.07004 0.45383,-2.03432 -0.0152,-0.84353 -0.16454,-1.61277 -0.44778,-2.30734 -0.1368,-0.34403 -0.37432,-0.85044 -0.71229,-1.51877 -0.33757,-0.66749 -0.7937,-1.49777 -1.36782,-2.48995 -1.01224,-1.79695 -1.71772,-3.36927 -2.11873,-4.7203 -0.4014,-1.40844 -0.6165,-2.95548 -0.64576,-4.64225 -0.044,-2.5386 0.35547,-4.37575 1.20006,-5.51489 0.84671,-1.14196 1.94916,-1.30825 3.31041,-0.49392 1.50935,0.90299 2.93246,3.09378 4.26861,6.58212"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(1.2096774,-17.209677)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier New;-inkscape-font-specification:Sans"
id="text6884">
<path
inkscape:connector-curvature="0"
d="m 140.43945,317.16536 c 0,0 0,50.22095 0,50.22095 0,0 5.54852,3.63087 5.54852,3.63087 0.35121,0.22983 0.60073,0.56653 0.7483,1.01023 0.14762,0.41494 0.22147,0.89737 0.22148,1.44707 -1e-5,0.52077 -0.0739,0.90601 -0.22148,1.15574 -0.14757,0.24955 -0.39709,0.25809 -0.7483,0.026 0,0 -12.35403,-8.16552 -12.35403,-8.16552 -0.3245,-0.21448 -0.55681,-0.53722 -0.69718,-0.9684 -0.1403,-0.43091 -0.21043,-0.89998 -0.21042,-1.40739 -1e-5,-0.53558 0.0701,-0.91246 0.21042,-1.13062 0.14037,-0.2465 0.37268,-0.26371 0.69718,-0.0514 0,0 5.41088,3.54079 5.41088,3.54079 0,0 0,-46.45699 0,-46.45699 0,0 -3.97848,-2.26531 -3.97848,-2.26531 -0.32622,-0.1857 -0.56519,-0.49145 -0.71716,-0.91726 -0.14103,-0.41932 -0.21152,-0.89742 -0.21151,-1.43445 -1e-5,-0.50868 0.0705,-0.89287 0.21151,-1.1526 0.14111,-0.25979 0.38007,-0.295 0.71716,-0.10537 0,0 5.37311,3.02366 5.37311,3.02366"
id="path12071" />
d="m 405.68539,517.2315 c 0,0 -0.0193,16.2617 -0.0193,16.2617 0,0 3.17768,-2.015 3.17768,-2.015 0.42104,-0.26699 0.71912,-0.28408 0.89461,-0.0515 0.17538,0.20367 0.26245,0.57777 0.26128,1.12234 -0.001,0.51582 -0.0901,1.00179 -0.26671,1.45807 -0.1768,0.45653 -0.47536,0.81943 -0.89606,1.08884 0,0 -7.2615,4.65021 -7.2615,4.65021 -0.4181,0.26775 -0.71809,0.2856 -0.89962,0.053 -0.18168,-0.23276 -0.27256,-0.61101 -0.27256,-1.13472 0,-0.55292 0.0909,-1.0473 0.27272,-1.48298 0.18171,-0.4645 0.48198,-0.82951 0.90042,-1.09484 0,0 2.35294,-1.49203 2.35294,-1.49203 0,0 0.0349,-43.95921 0.0349,-43.95921 0,0 -2.3762,1.32682 -2.3762,1.32682 -0.4226,0.23601 -0.72583,0.24206 -0.90932,0.0178 -0.18363,-0.25407 -0.2755,-0.66358 -0.2755,-1.22844 0,-0.56489 0.0919,-1.06185 0.27567,-1.49066 0.18367,-0.45823 0.48718,-0.80413 0.91014,-1.03765 0,0 7.3447,-4.05398 7.3447,-4.05398 0.42546,-0.23477 0.72666,-0.22523 0.90398,0.0279 0.17721,0.22388 0.26518,0.61389 0.26399,1.17006 -0.001,0.55615 -0.0911,1.05925 -0.26963,1.50941 -0.1786,0.42125 -0.48025,0.7505 -0.90536,0.98782 0,0 -3.20861,1.79162 -3.20861,1.79162 0,0 -0.027,22.7262 -0.027,22.7262 0,0 11.85347,-29.32986 11.85347,-29.32986 0,0 -1.84356,1.0294 -1.84356,1.0294 -0.4158,0.23222 -0.71071,0.23758 -0.8844,0.0157 -0.17376,-0.25093 -0.25981,-0.65252 -0.25806,-1.20465 0.002,-0.55216 0.0906,-1.03662 0.2666,-1.4532 0.17596,-0.44532 0.4722,-0.78288 0.88832,-1.01263 0,0 4.9265,-2.71923 4.9265,-2.71923 0.39516,-0.21804 0.67722,-0.2015 0.84652,0.049 0.16926,0.22176 0.25255,0.60547 0.24997,1.15114 -0.003,0.54567 -0.0901,1.03822 -0.26231,1.47778 -0.17228,0.41121 -0.45565,0.72699 -0.8505,0.94742 0,0 -0.67254,0.37553 -0.67254,0.37553 0,0 -9.34163,23.22298 -9.34163,23.22298 1.39299,0.391 2.54214,1.22247 3.45037,2.49219 0.90456,1.26471 1.76961,3.30318 2.59512,6.10986 0.47018,1.56163 1.32542,5.36141 2.55962,11.3683 0,0 2.05678,-1.30423 2.05678,-1.30423 0.40304,-0.25557 0.68792,-0.26799 0.85497,-0.0375 0.16702,0.20219 0.24918,0.57016 0.24656,1.10393 -0.003,0.5056 -0.0889,0.98066 -0.25892,1.42533 -0.17022,0.44492 -0.45652,0.79627 -0.85925,1.05417 0,0 -3.17718,2.03464 -3.17718,2.03464 -1.70416,-9.14138 -3.15817,-14.85521 -4.35315,-17.0766 -1.2016,-2.2625 -2.71697,-3.45967 -4.55059,-3.58265 0,0 -3.48846,8.71251 -3.48846,8.71251"
id="path6891" />
<path
inkscape:connector-curvature="0"
d="m 161.94121,365.01042 c 0,0 7.0063,21.03115 7.0063,21.03115 0.46705,0.30563 0.76243,0.55906 0.88562,0.76022 0.1232,0.17114 0.22797,0.45063 0.31431,0.83876 0.0987,0.39631 0.14801,0.7905 0.14803,1.18245 -2e-5,0.54268 -0.0803,0.94201 -0.24052,1.19797 -0.16024,0.25578 -0.43119,0.25745 -0.81253,0.005 0,0 -4.93644,-3.26279 -4.93644,-3.26279 -0.37439,-0.24745 -0.63978,-0.60162 -0.79646,-1.06272 -0.15663,-0.46083 -0.23491,-0.95918 -0.2349,-1.49528 -1e-5,-0.56586 0.0782,-0.9613 0.2349,-1.1863 0.15668,-0.25496 0.42207,-0.2601 0.79646,-0.0151 0,0 2.53075,1.65609 2.53075,1.65609 0,0 -5.91837,-17.79825 -5.91837,-17.79825 0,0 -5.76255,10.15443 -5.76255,10.15443 0,0 2.46795,1.61498 2.46795,1.61498 0.35431,0.23186 0.60853,0.57528 0.76236,1.03037 0.15389,0.42575 0.23088,0.91936 0.23089,1.48061 -1e-5,0.53172 -0.077,0.92408 -0.23089,1.17691 -0.15383,0.25271 -0.40805,0.26179 -0.76236,0.0276 0,0 -4.79262,-3.16772 -4.79262,-3.16772 -0.34791,-0.22996 -0.59698,-0.56977 -0.74747,-1.01963 -0.15042,-0.44957 -0.2256,-0.93694 -0.2256,-1.46232 0,-0.37944 0.0405,-0.7031 0.12145,-0.9711 0.0926,-0.26048 0.19095,-0.40043 0.29517,-0.41982 0.11584,-0.0411 0.39404,0.0826 0.83509,0.37127 0,0 6.7894,-11.94448 6.7894,-11.94448 0,0 -6.03916,-18.18905 -6.03916,-18.18905 -0.41899,-0.2513 -0.68634,-0.4701 -0.8025,-0.65681 -0.1045,-0.17967 -0.20317,-0.45801 -0.29599,-0.83523 -0.0812,-0.37005 -0.12179,-0.74507 -0.12179,-1.12508 0,-0.52607 0.0754,-0.91967 0.22622,-1.18084 0.15091,-0.26129 0.40649,-0.28516 0.76703,-0.0713 0,0 4.02618,2.38826 4.02618,2.38826 0.36619,0.21727 0.62043,0.54511 0.76245,0.98383 0.15392,0.44591 0.23091,0.94962 0.23092,1.51086 -10e-6,0.5318 -0.077,0.92889 -0.23092,1.19109 -0.14202,0.26926 -0.39626,0.29387 -0.76245,0.0742 0,0 -1.76525,-1.05886 -1.76525,-1.05886 0,0 5.02444,15.1596 5.02444,15.1596 0,0 5.15132,-9.05581 5.15132,-9.05581 0,0 -1.81808,-1.09055 -1.81808,-1.09055 -0.36224,-0.21727 -0.62759,-0.5552 -0.79631,-1.01393 -0.15659,-0.45115 -0.23486,-0.95956 -0.23484,-1.52543 -2e-5,-0.53601 0.0782,-0.93617 0.23484,-1.20056 0.15666,-0.2645 0.422,-0.2859 0.79631,-0.0639 0,0 4.18055,2.47983 4.18055,2.47983 0.368,0.21834 0.63204,0.55537 0.79183,1.01139 0.15983,0.45621 0.23979,0.97042 0.23981,1.54238 -2e-5,0.3613 -0.0492,0.67811 -0.14761,0.95034 -0.0861,0.27955 -0.19055,0.44264 -0.3134,0.48931 -0.11055,0.0541 -0.38669,-0.0515 -0.82796,-0.3162 0,0 -6.23361,10.87982 -6.23361,10.87982"
id="path12073" />
d="m 443.47158,496.16573 c 0,0 -15.92023,9.70195 -15.92023,9.70195 0.25261,4.3947 1.09424,7.53188 2.51855,9.41247 1.42789,1.83288 3.19316,2.07344 5.2907,0.7382 1.15976,-0.73828 2.37336,-1.93312 3.64044,-3.58163 1.2617,-1.64151 2.29067,-3.40363 3.08952,-5.2883 0.23317,-0.55259 0.43412,-0.88169 0.60291,-0.98752 0.19273,-0.12084 0.35959,-0.0498 0.50059,0.2133 0.14113,0.23564 0.20944,0.58439 0.20501,1.04631 -0.004,0.46186 -0.1049,0.97075 -0.30138,1.52697 -0.59063,1.72481 -1.63435,3.65941 -3.13604,5.80979 -1.49675,2.12595 -3.03903,3.70146 -4.62822,4.72308 -2.68176,1.72399 -4.92977,1.22514 -6.73564,-1.52638 -1.80812,-2.81062 -2.70176,-7.0448 -2.66946,-12.69552 0.0295,-5.15711 0.92218,-10.10229 2.67206,-14.81044 1.75462,-4.69402 3.89166,-7.75636 6.39992,-9.19327 2.55976,-1.46633 4.63179,-0.79081 6.22479,2.00024 1.58113,2.74246 2.3269,7.04454 2.24648,12.91075 m -1.50759,-2.55533 c -0.26805,-3.63428 -1.04266,-6.26807 -2.32893,-7.90085 -1.28159,-1.6495 -2.8345,-1.95112 -4.66221,-0.89235 -1.83997,1.06596 -3.44162,3.19609 -4.79954,6.39411 -1.36305,3.21016 -2.22473,6.90224 -2.58104,11.06526 0,0 14.37172,-8.66617 14.37172,-8.66617"
id="path6893" />
<path
inkscape:connector-curvature="0"
d="m 190.66329,367.61999 c 0,0 0,-1.31091 0,-1.31091 -2e-5,-0.96754 0.0793,-1.60701 0.23812,-1.91848 0.15885,-0.31161 0.35754,-0.39675 0.59615,-0.25526 0.25205,0.14956 0.45784,0.47505 0.61728,0.97627 0.15948,0.50164 0.23926,1.23771 0.23929,2.20799 0,0 0,8.92054 0,8.92054 -0.0133,0.96219 -0.0998,1.59756 -0.25923,1.90613 -0.14614,0.31665 -0.34529,0.39709 -0.59734,0.24155 -0.22536,-0.13902 -0.41744,-0.4293 -0.57629,-0.87076 -0.14557,-0.46428 -0.23155,-1.12587 -0.25798,-1.98485 -0.0793,-2.26435 -0.70007,-4.74694 -1.8588,-7.44034 -1.14118,-2.67507 -2.67549,-4.58556 -4.59684,-5.73359 -2.40997,-1.43988 -4.22691,-0.73221 -5.46164,2.10531 -1.22955,2.82567 -1.84239,6.53635 -1.84239,11.1409 0,4.97054 0.67609,9.5068 2.03299,13.62309 1.3632,4.13542 3.13715,6.92641 5.32927,8.36657 1.2711,0.83507 2.56726,1.1284 3.88879,0.87642 1.34056,-0.24449 2.55488,-1.26285 3.64142,-3.05912 0.27887,-0.4458 0.52476,-0.60042 0.73762,-0.46347 0.22628,0.14563 0.41277,0.45355 0.55941,0.92409 0.16,0.44793 0.24005,0.93848 0.24007,1.47145 -2e-5,1.3481 -0.67306,2.61811 -2.01459,3.80604 -2.1525,1.92107 -4.53114,2.00839 -7.13036,0.2837 -2.61508,-1.73522 -4.74914,-5.12664 -6.41235,-10.16426 -1.64124,-5.03145 -2.45842,-10.56254 -2.45841,-16.61439 -1e-5,-6.17346 0.83605,-10.78915 2.51538,-13.86032 1.70176,-3.08124 3.85575,-3.86089 6.47185,-2.31525 2.50885,1.48237 4.63121,4.52585 6.35858,9.14095"
id="path12075" />
d="m 455.58667,470.66722 c 0,0 -0.10498,8.56019 -0.10498,8.56019 1.93651,-5.08183 3.37081,-8.44336 4.30858,-10.1013 0.94661,-1.68612 1.80908,-2.7511 2.58784,-3.19777 0.84383,-0.48395 1.61379,-0.25336 2.31017,0.68823 0.70553,0.90558 1.05243,1.70098 1.04247,2.38832 -0.007,0.50226 -0.0857,0.96734 -0.23511,1.3954 -0.13804,0.39541 -0.31278,0.65513 -0.52432,0.77918 -0.11142,0.0654 -0.20559,0.0813 -0.28249,0.0476 -0.0766,-0.0601 -0.21729,-0.27954 -0.42229,-0.65871 -0.37824,-0.6994 -0.71083,-1.13744 -0.99754,-1.31325 -0.2871,-0.17598 -0.57132,-0.18255 -0.85261,-0.0195 -0.61996,0.35957 -1.37941,1.38224 -2.27917,3.07105 -0.89096,1.68702 -2.45801,5.46216 -4.70984,11.34948 0,0 -0.22596,18.42612 -0.22596,18.42612 0,0 6.33459,-4.01684 6.33459,-4.01684 0.34746,-0.22033 0.59161,-0.21895 0.7327,0.004 0.14133,0.1965 0.2085,0.54399 0.2016,1.04251 -0.007,0.47221 -0.0847,0.91205 -0.23427,1.31965 -0.14973,0.40781 -0.39805,0.72284 -0.74529,0.94521 0,0 -11.32013,7.24932 -11.32013,7.24932 -0.35123,0.22493 -0.6016,0.23885 -0.75084,0.0414 -0.14907,-0.22443 -0.22099,-0.57831 -0.21571,-1.0616 0.005,-0.45652 0.0796,-0.87735 0.22375,-1.26235 0.15613,-0.41912 0.41594,-0.74392 0.77913,-0.97432 0,0 3.54132,-2.24639 3.54132,-2.24639 0,0 0.33638,-28.17047 0.33638,-28.17047 0,0 -2.71509,1.57907 -2.71509,1.57907 -0.35236,0.20495 -0.60335,0.18908 -0.75268,-0.0481 -0.14946,-0.2372 -0.22135,-0.61416 -0.2156,-1.13086 0.005,-0.48951 0.0807,-0.93834 0.22572,-1.34628 0.15673,-0.41449 0.41745,-0.72656 0.78182,-0.93616 0,0 4.17785,-2.40283 4.17785,-2.40283"
id="path6895" />
<path
inkscape:connector-curvature="0"
d="m 205.10727,399.25125 c 0,0 5.73306,3.65382 5.73306,3.65382 0,0 -6.23199,22.47411 -6.23199,22.47411 -0.37367,1.34168 -0.82284,1.83225 -1.34718,1.47339 -0.34449,-0.2358 -0.64043,-0.72486 -0.88797,-1.46697 -0.23361,-0.70036 -0.35034,-1.44789 -0.35034,-2.243 0,-0.31805 0.0206,-0.65395 0.0618,-1.00763 0,0 3.02262,-22.88372 3.02262,-22.88372"
id="path12077" />
d="m 473.30415,460.47729 c 0,0 -0.0804,4.97133 -0.0804,4.97133 0.98569,-2.87136 1.86574,-4.96674 2.64065,-6.28932 0.77288,-1.31909 1.63191,-2.24853 2.57593,-2.78936 1.01432,-0.58102 1.92593,-0.57975 2.7356,4.3e-4 0.57165,0.43409 1.07517,1.41355 1.51085,2.93619 0.44533,1.487 0.6504,3.16172 0.61612,5.02597 0,0 -0.37098,20.16552 -0.37098,20.16552 0,0 1.09632,-0.69519 1.09632,-0.69519 0.30795,-0.19527 0.52558,-0.18379 0.65312,0.0343 0.1279,0.19274 0.18732,0.5284 0.17832,1.00704 -0.009,0.4534 -0.0822,0.87365 -0.22092,1.26091 -0.13883,0.38745 -0.362,0.67967 -0.66977,0.87676 0,0 -3.48879,2.2342 -3.48879,2.2342 -0.32291,0.20678 -0.54961,0.20133 -0.67985,-0.0168 -0.13035,-0.21825 -0.19152,-0.55628 -0.18341,-1.01409 0.009,-0.48331 0.0832,-0.90811 0.22395,-1.27426 0.14113,-0.39138 0.37338,-0.68956 0.69648,-0.89444 0,0 1.09126,-0.69198 1.09126,-0.69198 0,0 0.35635,-19.67714 0.35635,-19.67714 0.0412,-2.27809 -0.26274,-4.00074 -0.9136,-5.16921 -0.65266,-1.19813 -1.55322,-1.46656 -2.70395,-0.79997 -0.87978,0.50971 -1.6529,1.39411 -2.31814,2.65394 -0.66627,1.2367 -1.63439,3.93929 -2.90635,8.11592 0,0 -0.33083,20.46711 -0.33083,20.46711 0,0 1.52554,-0.96736 1.52554,-0.96736 0.32,-0.20291 0.54652,-0.19417 0.67982,0.026 0.13361,0.19441 0.19632,0.5352 0.1882,1.02244 -0.008,0.46152 -0.0833,0.89021 -0.22665,1.28621 -0.14347,0.39619 -0.37497,0.69664 -0.69477,0.90144 0,0 -4.42215,2.83191 -4.42215,2.83191 -0.3258,0.20863 -0.55714,0.20298 -0.6938,-0.0174 -0.13675,-0.22051 -0.20159,-0.56416 -0.19444,-1.03091 0.008,-0.49277 0.0843,-0.92686 0.23029,-1.30217 0.1463,-0.40101 0.38259,-0.70494 0.70859,-0.91166 0,0 1.54286,-0.97835 1.54286,-0.97835 0,0 0.43113,-27.17649 0.43113,-27.17649 0,0 -1.15824,0.67362 -1.15824,0.67362 -0.32722,0.19033 -0.55954,0.16948 -0.69672,-0.0629 -0.13729,-0.23247 -0.20212,-0.59828 -0.19443,-1.09741 0.007,-0.47286 0.0845,-0.90805 0.23156,-1.30535 0.14701,-0.39707 0.38436,-0.6898 0.71179,-0.87815 0,0 2.52342,-1.45131 2.52342,-1.45131"
id="path6897" />
<path
inkscape:connector-curvature="0"
d="m 271.11411,457.35945 c 0,0 0,-6.42681 0,-6.42681 -3.10047,3.40822 -6.38155,3.94515 -9.83759,1.65192 -2.48679,-1.65009 -4.41727,-4.24834 -5.80096,-7.79282 -1.37793,-3.56428 -2.06474,-7.25483 -2.06474,-11.08277 0,-4.20723 0.90527,-7.30878 2.72332,-9.31282 1.82803,-2.01507 4.51481,-1.9316 8.08109,0.27619 0.96857,0.59969 2.02383,1.3936 3.16658,2.38297 1.1466,0.95764 2.39035,2.13516 3.7323,3.53459 0,0 0,-7.22352 0,-7.22352 -3e-5,-2.44323 -0.54423,-4.89656 -1.63001,-7.35412 -1.08235,-2.44961 -2.69936,-4.31509 -4.84337,-5.59616 -1.63234,-0.97525 -3.90928,-1.34198 -6.81764,-1.10525 -0.52311,0.032 -0.8578,0.004 -1.00462,-0.0848 -0.26088,-0.15719 -0.48896,-0.50248 -0.68433,-1.03576 -0.17902,-0.52313 -0.26847,-1.09611 -0.26847,-1.7192 0,-0.58839 0.0813,-1.00706 0.24405,-1.25606 0.22793,-0.3834 1.14942,-0.54477 2.77027,-0.48366 2.57013,0.061 4.52742,0.48442 5.86093,1.27225 2.66612,1.57529 4.76009,4.20783 6.27107,7.90057 1.51771,3.67383 2.27912,7.27529 2.27913,10.79204 0,0 0,29.62623 0,29.62623 0,0 2.88997,1.89115 2.88997,1.89115 0.53593,0.3507 0.91679,0.8142 1.14207,1.39054 0.22537,0.54089 0.33812,1.15113 0.33816,1.83041 -4e-5,0.64351 -0.11284,1.10539 -0.33816,1.38561 -0.22528,0.27997 -0.60614,0.24255 -1.14207,-0.11167 0,0 -5.06698,-3.34907 -5.06698,-3.34907 m 0,-22.20172 c -1.00273,-1.23099 -2.06169,-2.33664 -3.17634,-3.31716 -1.11102,-0.97729 -2.27699,-1.84752 -3.49734,-2.61108 -3.03992,-1.90193 -5.39629,-2.00244 -7.08327,-0.32077 -1.27186,1.23928 -1.90596,3.27543 -1.90596,6.11197 0,2.62903 0.47952,5.1547 1.44068,7.58233 0.98029,2.44541 2.40686,4.2853 4.28547,5.51948 1.80611,1.18656 3.48841,1.53771 5.04496,1.04694 1.58058,-0.51735 3.21096,-1.91034 4.8918,-4.18559 0,0 0,-9.82612 0,-9.82612"
id="path12079" />
d="m 502.73274,460.0514 c 0,0 -12.58078,7.66685 -12.58078,7.66685 0.13943,3.95275 0.75486,6.81973 1.84191,8.60127 1.09127,1.74028 2.46782,2.07625 4.12588,1.02077 0.91736,-0.58398 1.88324,-1.57454 2.89733,-2.9694 1.01026,-1.38958 1.83995,-2.9037 2.49094,-4.54374 0.19007,-0.48101 0.352,-0.76339 0.48584,-0.84731 0.15283,-0.0958 0.2829,-0.0209 0.39022,0.22483 0.10778,0.2211 0.15695,0.53905 0.14755,0.95388 -0.009,0.41479 -0.0948,0.86546 -0.25619,1.35225 -0.48577,1.51058 -1.32969,3.17888 -2.53523,5.00941 -1.20067,1.80791 -2.42926,3.11745 -3.68662,3.92576 -2.11999,1.36285 -3.86995,0.76072 -5.24366,-1.82965 -1.37343,-2.64104 -2.01438,-6.49315 -1.91501,-11.55003 0.0906,-4.61389 0.85108,-8.9821 2.27681,-13.08506 1.42996,-4.0921 3.13808,-6.70212 5.11668,-7.83561 2.02129,-1.15786 3.63504,-0.42605 4.84758,2.17494 1.20485,2.55883 1.735,6.46775 1.59675,11.73084 m -1.15024,-2.39108 c -0.1636,-3.27931 -0.73716,-5.69144 -1.72424,-7.23625 -0.98254,-1.55853 -2.19418,-1.92464 -3.63745,-1.08857 -1.45189,0.84113 -2.73048,2.64931 -3.83206,5.42777 -1.10528,2.78784 -1.82554,6.03803 -2.15785,9.74209 0,0 11.3516,-6.84504 11.3516,-6.84504"
id="path6899" />
<path
inkscape:connector-curvature="0"
d="m 305.27676,479.93957 c 0,0 0,-6.86189 0,-6.86189 -3.21505,3.68169 -6.65929,4.28417 -10.32564,1.85139 -2.236,-1.48368 -3.92619,-3.82619 -5.07842,-7.02675 -1.48866,-4.17529 -2.23061,-8.37816 -2.2306,-12.62199 0,0 0,-29.48895 0,-29.48895 0,0 -3.01401,-1.80791 -3.01401,-1.80791 -0.53074,-0.31833 -0.9106,-0.76254 -1.14007,-1.33286 -0.22933,-0.56981 -0.34393,-1.19694 -0.34393,-1.88171 0,-0.64863 0.11456,-1.12104 0.34393,-1.41732 0.22947,-0.29643 0.60933,-0.2875 1.14007,0.0273 0,0 5.27157,3.127 5.27157,3.127 0,0 0,34.2244 0,34.2244 0,2.98398 0.46767,5.74427 1.40491,8.28605 0.93973,2.54862 2.11799,4.29026 3.53714,5.2226 3.75734,2.46845 7.2386,1.27516 10.43505,-3.63264 0,0 0,-30.23698 0,-30.23698 0,0 -4.33901,-2.6027 -4.33901,-2.6027 -0.55605,-0.33351 -0.954,-0.79367 -1.19439,-1.38071 -0.24026,-0.58652 -0.36032,-1.23005 -0.36029,-1.93091 -3e-5,-0.66389 0.12001,-1.14576 0.36029,-1.44571 0.24039,-0.30014 0.63834,-0.28557 1.19439,0.0442 0,0 6.71277,3.9819 6.71277,3.9819 0,0 0,43.77138 0,43.77138 0,0 2.01873,1.32102 2.01873,1.32102 0.5707,0.37346 0.98027,0.86624 1.22818,1.47843 0.24802,0.57501 0.3721,1.21898 0.37212,1.93157 -2e-5,0.67508 -0.12418,1.15577 -0.37212,1.4421 -0.24791,0.28605 -0.65748,0.24015 -1.22818,-0.13705 0,0 -4.39249,-2.90326 -4.39249,-2.90326"
id="path12081" />
<path
inkscape:connector-curvature="0"
d="m 331.10608,451.86264 c 0,0 0,40.29309 0,40.29309 0,0 11.33093,7.41479 11.33093,7.41479 0.62404,0.40837 1.07195,0.93651 1.34306,1.58448 0.27124,0.60912 0.40696,1.28649 0.40699,2.03171 -3e-5,0.70599 -0.13581,1.20478 -0.40699,1.49638 -0.27111,0.2913 -0.71902,0.23036 -1.34306,-0.18211 0,0 -19.93946,-13.17917 -19.93946,-13.17917 -0.59038,-0.39022 -1.0129,-0.89763 -1.26813,-1.5226 -0.25505,-0.62448 -0.38252,-1.27858 -0.38251,-1.96267 -10e-6,-0.72207 0.12741,-1.20858 0.38251,-1.45953 0.25523,-0.28919 0.67775,-0.24091 1.26813,0.14542 0,0 6.04677,3.95692 6.04677,3.95692 0,0 0,-40.15334 0,-40.15334 0,0 -5.42587,-3.25463 -5.42587,-3.25463 -0.59138,-0.35471 -1.01459,-0.83694 -1.27026,-1.44699 -0.2555,-0.60948 -0.38317,-1.27541 -0.38317,-1.99818 0,-0.68461 0.12762,-1.17925 0.38317,-1.48397 0.25567,-0.30491 0.67888,-0.28227 1.27026,0.0685 0,0 5.42587,3.21853 5.42587,3.21853 0,0 0,-7.31632 0,-7.31632 -2e-5,-4.07098 0.86197,-7.11046 2.592,-9.12558 1.73815,-2.02447 4.05487,-2.22739 6.961,-0.59209 2.45295,1.38047 5.08868,3.29457 7.91092,5.74926 1.07167,0.91997 1.71405,1.65721 1.92494,2.20997 0.23203,0.56511 0.34813,1.20269 0.34816,1.91248 -3e-5,0.70989 -0.1266,1.22928 -0.37979,1.55791 -0.25304,0.28912 -0.59009,0.31325 -1.01094,0.0727 -0.16827,-0.0961 -0.45198,-0.31718 -0.85089,-0.66317 -3.15558,-2.70293 -5.79955,-4.65865 -7.9424,-5.87884 -2.2532,-1.28289 -3.985,-1.22414 -5.20258,0.16697 -1.19342,1.39829 -1.78867,3.42534 -1.78866,6.08452 0,0 0,7.34179 0,7.34179 0,0 12.07996,7.16563 12.07996,7.16563 0.62529,0.37097 1.07408,0.87241 1.34574,1.50461 0.27179,0.63256 0.40778,1.32201 0.40781,2.06791 -3e-5,0.70676 -0.13609,1.21428 -0.40781,1.52253 -0.27166,0.30808 -0.72045,0.27422 -1.34574,-0.10088 0,0 -12.07996,-7.246 -12.07996,-7.246"
id="path12083" />
<path
inkscape:connector-curvature="0"
d="m 381.53904,480.26145 c -4e-5,-1.19393 0.13803,-1.97639 0.41437,-2.34753 0.27648,-0.37137 0.62238,-0.43403 1.03788,-0.18762 0.439,0.26047 0.79752,0.74165 1.07534,1.44329 0.27794,0.70231 0.41702,1.69419 0.41703,2.97521 0,0 0,8.92609 0,8.92609 -10e-6,1.23978 -0.13902,2.04325 -0.41703,2.41011 -0.27782,0.36667 -0.63634,0.41516 -1.07534,0.14588 -0.39243,-0.24064 -0.72682,-0.67235 -1.00333,-1.29503 -0.25333,-0.60811 -0.40294,-1.44075 -0.44892,-2.49818 -0.13799,-2.55388 -0.85046,-5.02174 -2.13409,-7.39831 -1.87213,-3.42059 -4.3356,-6.03941 -7.37923,-7.858 -3.15377,-1.88428 -5.58541,-2.18625 -7.30824,-0.92152 -1.29812,0.94833 -1.94553,2.48638 -1.94553,4.61649 0,2.41154 0.76823,4.89373 2.30933,7.4543 1.0603,1.78482 3.07849,3.90375 6.06957,6.36723 3.94113,3.22198 6.70097,5.81863 8.2541,7.77127 2.22609,2.8303 3.88664,5.87077 4.97442,9.11605 1.11394,3.26899 1.6721,6.39758 1.67214,9.37882 -4e-5,4.43046 -1.1968,7.60368 -3.5795,9.51102 -2.36847,1.85478 -5.81509,1.27327 -10.31153,-1.7103 -4.44518,-2.94957 -8.0486,-7.3738 -10.83305,-13.26579 -10e-6,1.36395 -0.0436,2.2178 -0.13101,2.56131 -0.0874,0.34347 -0.25106,0.57633 -0.49105,0.6985 -0.21804,0.13637 -0.46864,0.11113 -0.75172,-0.076 -0.39163,-0.25884 -0.71767,-0.73428 -0.97829,-1.42646 -0.26047,-0.69164 -0.39063,-1.63687 -0.39063,-2.83609 0,0 0,-10.37303 0,-10.37303 0,-1.19919 0.11929,-1.98223 0.35807,-2.34925 0.2606,-0.35334 0.59748,-0.39824 1.01085,-0.13424 0.39201,0.25036 0.71901,0.71962 0.9808,1.40824 0.28381,0.6629 0.42578,1.41575 0.4258,2.25821 -2e-5,1.84546 0.25131,3.55252 0.75448,5.12277 0.76692,2.42665 1.98618,4.83059 3.66211,7.21589 1.70538,2.36981 3.79751,4.37105 6.28262,6.00369 3.70087,2.43135 6.47684,3.00416 8.3079,1.69647 1.83952,-1.31379 2.76254,-3.37564 2.76258,-6.18089 -4e-5,-3.21781 -0.93458,-6.38939 -2.797,-9.50367 -1.87655,-3.11405 -4.59528,-6.11381 -8.13869,-8.9908 -3.48927,-2.83712 -5.9752,-5.24246 -7.47672,-7.22927 -1.49576,-1.97906 -2.65753,-4.26856 -3.48835,-6.87006 -0.82903,-2.59583 -1.24288,-5.09307 -1.24286,-7.49587 -2e-5,-4.32499 1.1555,-7.05664 3.47704,-8.20014 2.33556,-1.19067 5.14142,-0.82407 8.42768,1.11751 3.92599,2.31968 7.14794,5.96756 9.64805,10.94971"
id="path12085" />
d="m 514.91047,422.62215 c 0,0 -1.06434,42.27288 -1.06434,42.27288 0,0 4.45362,-2.8241 4.45362,-2.8241 0.2761,-0.17507 0.46813,-0.15759 0.57629,0.0523 0.10868,0.18619 0.15712,0.50328 0.14534,0.95133 -0.0112,0.42443 -0.0782,0.81493 -0.20113,1.17164 -0.12299,0.35687 -0.32235,0.62363 -0.59831,0.80035 0,0 -10.15763,6.50487 -10.15763,6.50487 -0.27917,0.17878 -0.476,0.16246 -0.5903,-0.0494 -0.11437,-0.21191 -0.16642,-0.53506 -0.15609,-0.96944 0.0109,-0.45857 0.0801,-0.85922 0.20776,-1.20182 0.12814,-0.36656 0.33197,-0.63844 0.61129,-0.81556 0,0 4.56188,-2.89274 4.56188,-2.89274 0,0 0.97884,-39.26779 0.97884,-39.26779 0,0 -3.35907,1.85407 -3.35907,1.85407 -0.27977,0.15447 -0.48159,0.1208 -0.60529,-0.10124 -0.11445,-0.22726 -0.16609,-0.57399 -0.15489,-1.04015 0.0106,-0.44163 0.0802,-0.843 0.20889,-1.204 0.12859,-0.36073 0.33761,-0.62003 0.62686,-0.77784 0,0 4.51628,-2.46343 4.51628,-2.46343"
id="path6901" />
</g>
</g>
<g
@@ -599,7 +644,7 @@
<g
inkscape:corner7="0.22235256 : 0.05733945 : 0.532878 : 1"
inkscape:corner0="0.4922944 : 0.12449455 : 0 : 1"
inkscape:perspectiveID="#perspective3054"
inkscape:perspectiveID="#perspective5786"
id="g3195"
style="fill:#f0f0f0;fill-opacity:0.51111115;stroke:#253237;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;display:inline"
sodipodi:type="inkscape:box3d">
@@ -684,31 +729,6 @@
id="path4004"
sodipodi:type="inkscape:box3dside" />
</g>
<g
id="text4031"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
transform="matrix(0.5589128,0,0,0.5589128,174.77385,97.01703)">
<path
id="path4038"
d="m 282.79778,223.1883 c 0,0 -0.6821,34.01888 -0.6821,34.01888 0,0 18.98585,-5.00566 18.98585,-5.00566 1.2893,-0.33993 2.20833,-0.45044 2.75935,-0.33226 0.55064,0.096 0.82138,0.35348 0.81277,0.77255 -0.008,0.39705 -0.29289,0.80178 -0.85387,1.21447 -0.56196,0.41327 -1.48645,0.79167 -2.77573,1.13557 0,0 -44.72801,11.93065 -44.72801,11.93065 -1.42497,0.3801 -2.44616,0.51347 -3.06094,0.39901 -0.61559,-0.11457 -0.91968,-0.38193 -0.91159,-0.80201 0.008,-0.44338 0.3259,-0.87559 0.95192,-1.29625 0.62554,-0.44339 1.65213,-0.85314 3.07713,-1.22885 0,0 20.05366,-5.28718 20.05366,-5.28718 0,0 0.68066,-34.22837 0.68066,-34.22837 0,0 -20.05925,4.54892 -20.05925,4.54892 -1.42544,0.32329 -2.44718,0.42713 -3.0626,0.31069 -0.6158,-0.1399 -0.91975,-0.43212 -0.91119,-0.87654 0.008,-0.44433 0.32603,-0.86491 0.95227,-1.26139 0.62576,-0.41923 1.6527,-0.78845 3.07817,-1.10733 0,0 44.74122,-10.00757 44.74122,-10.00757 1.28958,-0.28842 2.20881,-0.36188 2.75993,-0.22091 0.55075,0.1187 0.82154,0.38796 0.81291,0.80788 -0.009,0.42002 -0.29367,0.82541 -0.85477,1.21646 -0.56164,0.36954 -1.48611,0.70037 -2.77567,0.99277 0,0 -18.99012,4.30647 -18.99012,4.30647"
inkscape:connector-curvature="0" />
<path
id="path4040"
d="m 333.70439,218.67102 c 0,0 -0.0587,2.72754 -0.0587,2.72754 4.31507,-3.46248 8.58164,-5.67789 12.79965,-6.66399 2.51867,-0.58878 4.7071,-0.73536 6.57013,-0.44328 1.85514,0.26995 3.39018,0.98553 4.60856,2.14501 2.14625,-1.9575 4.2924,-3.53718 6.43822,-4.74174 2.17248,-1.22772 4.32584,-2.08967 6.46016,-2.58865 3.32651,-0.77764 5.94413,-0.79259 7.86586,-0.0522 2.51331,0.93636 3.74321,2.31125 3.70162,4.12895 0,0 -0.40751,17.77352 -0.40751,17.77352 0,0 3.78154,-0.99701 3.78154,-0.99701 1.0589,-0.27918 1.81331,-0.35863 2.265,-0.23889 0.45151,0.0996 0.67268,0.33943 0.66395,0.71958 -0.008,0.36017 -0.24358,0.72101 -0.70559,1.08272 -0.46279,0.36219 -1.22275,0.68437 -2.28164,0.96681 0,0 -8.30108,2.21421 -8.30108,2.21421 0,0 0.46012,-20.18321 0.46012,-20.18321 0.0296,-1.29965 -0.64981,-2.20744 -2.04182,-2.72464 -1.39694,-0.51893 -3.02752,-0.55871 -4.89435,-0.11645 -1.69116,0.40066 -3.48972,1.18482 -5.39699,2.35517 -1.91549,1.15505 -4.1177,3.07215 -6.61075,5.75887 0,0 -0.38593,17.34484 -0.38593,17.34484 0,0 3.94466,-1.04002 3.94466,-1.04002 1.12023,-0.29535 1.91848,-0.38295 2.39656,-0.26337 0.47792,0.0988 0.71231,0.34368 0.70356,0.73459 -0.008,0.37035 -0.25674,0.74319 -0.74514,1.11873 -0.48916,0.37602 -1.29295,0.71329 -2.41317,1.01209 0,0 -8.78473,2.34322 -8.78473,2.34322 0,0 0.45491,-20.57441 0.45491,-20.57441 0.0309,-1.39962 -0.70802,-2.36557 -2.22095,-2.89919 -1.47959,-0.56565 -3.16794,-0.62501 -5.06745,-0.17502 -1.752,0.41508 -3.49828,1.13407 -5.2386,2.15872 -2.4247,1.44429 -4.99579,3.55425 -7.71548,6.33646 0,0 -0.38442,17.85802 -0.38442,17.85802 0,0 4.24187,-1.11838 4.24187,-1.11838 1.1874,-0.31306 2.03362,-0.40968 2.54064,-0.2905 0.50681,0.0978 0.75565,0.3479 0.7469,0.75024 -0.008,0.38118 -0.27082,0.76681 -0.78834,1.15733 -0.51807,0.39097 -1.3698,0.74465 -2.55719,1.06137 0,0 -13.64864,3.64061 -13.64864,3.64061 -1.22865,0.32772 -2.10857,0.43336 -2.63763,0.31598 -0.52971,-0.11749 -0.7907,-0.37136 -0.78245,-0.76153 0.009,-0.41183 0.28334,-0.80778 0.82373,-1.18753 0.54007,-0.40091 1.42551,-0.76349 2.65418,-1.08743 0,0 4.33418,-1.14272 4.33418,-1.14272 0,0 0.4806,-22.47941 0.4806,-22.47941 0,0 -4.33464,1.0317 -4.33464,1.0317 -1.2288,0.29249 -2.10883,0.37258 -2.63794,0.23946 -0.52978,-0.1332 -0.79056,-0.4061 -0.78184,-0.81857 0.008,-0.39072 0.28294,-0.77944 0.82386,-1.16588 0.54015,-0.38591 1.4257,-0.72332 2.65452,-1.01198 0,0 9.40801,-2.20977 9.40801,-2.20977"
inkscape:connector-curvature="0" />
<path
id="path4042"
d="m 431.66157,220.15121 c 0,0 0.0838,-3.4392 0.0838,-3.4392 -5.86908,4.46079 -12.19603,7.61638 -19.00283,9.44026 -5.01634,1.34413 -8.9635,1.66058 -11.80893,0.93249 -2.86592,-0.75319 -4.28108,-2.23143 -4.2297,-4.43076 0.0565,-2.41757 2.02666,-5.0136 5.88321,-7.76824 3.82039,-2.72881 9.29321,-4.96718 16.3493,-6.71054 1.8819,-0.46494 3.91395,-0.89069 6.09374,-1.27732 2.16795,-0.40343 4.49584,-0.76226 6.98064,-1.07648 0,0 0.0943,-3.86881 0.0943,-3.86881 0.0318,-1.30873 -0.94792,-2.20502 -2.94729,-2.69073 -2.0101,-0.48823 -5.06896,-0.24773 -9.20127,0.73123 -3.1937,0.75663 -7.73215,2.3834 -13.66129,4.9035 -1.08129,0.45367 -1.77483,0.7173 -2.07866,0.79 -0.54077,0.12948 -1.01175,0.12481 -1.41272,-0.0143 -0.36747,-0.14728 -0.54717,-0.39832 -0.53881,-0.75307 0.008,-0.33499 0.1838,-0.64127 0.52757,-0.91864 0.48125,-0.40757 2.39918,-1.26142 5.73331,-2.55378 5.19823,-2.03472 9.08047,-3.34807 11.68433,-3.95682 5.12395,-1.19783 9.05529,-1.36876 11.82888,-0.5292 2.75357,0.81456 4.09994,2.15371 4.05425,4.02181 0,0 -0.38517,15.72953 -0.38517,15.72953 0,0 5.19262,-1.36904 5.19262,-1.36904 0.95041,-0.25058 1.62073,-0.31597 2.01241,-0.19663 0.39163,0.10055 0.58294,0.32805 0.57423,0.68255 -0.008,0.33588 -0.21359,0.66851 -0.61574,0.99809 -0.40275,0.32996 -1.0786,0.62159 -2.02902,0.8751 0,0 -9.18117,2.44897 -9.18117,2.44897 m 0.28963,-11.88378 c -1.85188,0.1444 -3.826,0.40309 -5.9241,0.77705 -2.10961,0.37603 -4.34564,0.85922 -6.71011,1.45071 -5.99108,1.49874 -10.75526,3.45758 -14.2458,5.87477 -2.66308,1.8282 -4.02015,3.55498 -4.05808,5.1712 -0.0352,1.49786 0.93743,2.49682 2.9103,2.99513 1.99648,0.48693 4.89613,0.22483 8.67932,-0.77721 3.58353,-0.94915 6.88503,-2.2348 9.91145,-3.85407 3.03569,-1.63439 6.13916,-3.76218 9.30881,-6.377 0,0 0.12821,-5.26058 0.12821,-5.26058"
inkscape:connector-curvature="0" />
<path
id="path4044"
d="m 487.68217,186.54679 c 0,0 0.10564,-4.06721 0.10564,-4.06721 0,0 7.90801,-1.85745 7.90801,-1.85745 0.79301,-0.18623 1.35751,-0.21524 1.69464,-0.0873 0.3367,0.12786 0.50061,0.35664 0.49198,0.68643 -0.008,0.31249 -0.18616,0.61347 -0.5337,0.90306 -0.34808,0.28997 -0.91806,0.52925 -1.71109,0.71799 0,0 -4.51455,1.07452 -4.51455,1.07452 0,0 -0.57459,22.03902 -0.57459,22.03902 -0.0384,1.47001 -0.55548,2.91413 -1.55336,4.33529 -0.6668,0.94954 -1.76798,2.04674 -3.30751,3.29427 -1.54611,1.25278 -2.95556,2.23384 -4.2268,2.94103 -1.27575,0.70968 -2.98068,1.36473 -5.1209,1.96595 0,0 -10.09114,2.83466 -10.09114,2.83466 -0.86083,0.2418 -1.47625,0.30679 -1.84501,0.1943 -0.36961,-0.0944 -0.5502,-0.31403 -0.54146,-0.65872 0.009,-0.3447 0.20323,-0.67811 0.58346,-1.00002 0.37979,-0.32158 1.0007,-0.60203 1.86152,-0.84114 0,0 10.21573,-2.81129 10.21573,-2.81129 2.05634,-0.57131 3.90303,-1.41898 5.54333,-2.54169 1.66023,-1.12521 3.03533,-2.47541 4.12856,-4.05097 0.61561,-0.90119 0.93791,-1.9227 0.96764,-3.06566 0,0 0.17268,-6.6482 0.17268,-6.6482 -3.75728,4.22258 -8.58953,7.13169 -14.54094,8.71456 -4.90653,1.30498 -9.17076,1.28431 -12.76987,-0.0855 -3.60562,-1.4096 -5.38035,-3.78477 -5.29699,-7.11539 0.0834,-3.33124 2.00056,-6.62133 5.72421,-9.84613 3.71648,-3.20034 8.039,-5.36811 12.94485,-6.51501 5.95052,-1.39107 10.69758,-0.88232 14.28567,1.49047 m -0.1735,6.67977 c 0.0676,-2.60468 -1.25813,-4.46865 -3.99335,-5.59822 -2.72937,-1.14506 -6.06018,-1.2571 -10.00838,-0.32175 -3.99164,0.94566 -7.47585,2.69973 -10.43699,5.26937 -2.98394,2.57159 -4.51858,5.21107 -4.58622,7.90293 -0.0681,2.70979 1.35151,4.62821 4.24133,5.74881 2.86713,1.09352 6.30461,1.10802 10.2967,0.0587 3.94868,-1.03788 7.32661,-2.82534 10.14966,-5.35628 2.82923,-2.53633 4.26956,-5.09924 4.33725,-7.70358"
inkscape:connector-curvature="0" />
<path
id="path4046"
d="m 540.11557,181.1992 c 0,0 -31.2176,7.85302 -31.2176,7.85302 0.48573,2.63928 2.15047,4.43554 4.97687,5.38625 2.82796,0.91931 6.31992,0.8233 10.45571,-0.27212 2.27866,-0.60354 4.65697,-1.48834 7.13282,-2.65107 2.45777,-1.15424 4.45604,-2.3471 6.00292,-3.58061 0.45083,-0.36101 0.83942,-0.58385 1.16596,-0.6688 0.37271,-0.097 0.69561,-0.0757 0.96883,0.0637 0.27337,0.12295 0.40619,0.32289 0.39861,0.5999 -0.008,0.27704 -0.20081,0.59468 -0.57975,0.95322 -1.14042,1.11074 -3.16231,2.40927 -6.08171,3.90253 -2.92062,1.48339 -5.94124,2.64545 -9.0645,3.48232 -5.2951,1.41883 -9.75204,1.42909 -13.33713,0.003 -3.59795,-1.46568 -5.36582,-3.92779 -5.27448,-7.37497 0.0832,-3.13906 1.88506,-6.25108 5.37983,-9.31298 3.48579,-3.03794 7.7012,-5.12678 12.61811,-6.27626 4.99076,-1.1667 9.012,-0.99979 12.09648,0.47721 3.05557,1.44667 4.50134,3.91533 4.35903,7.41612 m -2.91605,-1.34024 c -0.52374,-2.13318 -2.02526,-3.60994 -4.51812,-4.43193 -2.48827,-0.834 -5.50996,-0.83398 -9.07894,0.0115 -3.60706,0.85456 -6.76149,2.32359 -9.44972,4.41217 -2.70894,2.10468 -4.4334,4.44604 -5.1587,7.01535 0,0 28.20548,-7.00711 28.20548,-7.00711"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(0.80256968,0,0,0.80256968,38.124381,46.818937)"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
@@ -749,7 +769,7 @@
<g
id="text4949"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
transform="matrix(0.83804272,0,0,0.83804272,31.314311,25.788578)">
transform="matrix(0.74694175,0,0,0.74694175,45.485062,44.593966)">
<path
id="path4956"
d="m 142.69979,137.10297 c 0,0 -1.02955,33.67577 -1.02955,33.67577 0,0 -1.95085,-0.57539 -1.95085,-0.57539 0,0 0.11438,-3.62641 0.11438,-3.62641 -0.83178,2.72212 -1.69018,3.94864 -2.57494,3.68641 -1.08457,-0.32145 -1.96585,-2.08912 -2.6458,-5.29794 -0.67825,-3.20078 -1.01674,-7.18681 -1.01674,-11.96409 0,-5.51039 0.38729,-9.93148 1.16353,-13.27043 0.79003,-3.34576 1.80543,-4.8788 3.04874,-4.59076 0.58877,0.13642 1.0911,0.64686 1.50651,1.53207 0.42191,0.88799 0.85328,2.3539 1.29417,4.39917 0,0 0.13239,-4.42502 0.13239,-4.42502 0,0 1.95816,0.45662 1.95816,0.45662 m -2.38162,15.3911 c 0,-2.99293 -0.21149,-5.4766 -0.63396,-7.44868 -0.42183,-1.99292 -0.96573,-3.06948 -1.63097,-3.23169 -0.72176,-0.17595 -1.32564,0.83047 -1.81241,3.01599 -0.4859,2.20539 -0.72852,4.99168 -0.72852,8.36184 0,2.94297 0.20217,5.40768 0.60697,7.39634 0.40539,1.99165 0.92751,3.07935 1.56702,3.26122 0.71103,0.20221 1.32739,-0.80489 1.84844,-3.02486 0.52203,-2.27207 0.78343,-5.04988 0.78343,-8.33016"
@@ -788,29 +808,54 @@
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(0.53155689,0,0,0.53155689,185.92425,73.057684)"
transform="matrix(0.87020295,0,0,0.87020295,36.583926,33.755817)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
id="text5440">
id="text5788">
<path
inkscape:connector-curvature="0"
d="m 282.85502,131.91713 c 0,0 0,60.1855 0,60.1855 0,0 18.99047,-3.66344 18.99047,-3.66344 1.28959,-0.24877 2.21156,-0.19199 2.76814,0.16971 0.55582,0.32211 0.83347,0.85406 0.83354,1.59612 -7e-5,0.70307 -0.27789,1.34368 -0.83354,1.92233 -0.55658,0.57941 -1.47855,0.99706 -2.76814,1.25292 0,0 -44.74121,8.87701 -44.74121,8.87701 -1.42547,0.28283 -2.44971,0.23848 -3.07009,-0.13431 -0.62119,-0.37318 -0.93211,-0.93202 -0.93207,-1.6762 -4e-5,-0.78548 0.31077,-1.46595 0.93207,-2.04091 0.62038,-0.61545 1.64462,-1.0607 3.07009,-1.33569 0,0 20.05972,-3.8697 20.05972,-3.8697 0,0 0,-60.55879 0,-60.55879 0,0 -20.05972,2.55389 -20.05972,2.55389 -1.42547,0.18155 -2.44971,0.0849 -3.07009,-0.29062 -0.62119,-0.41721 -0.93211,-1.01884 -0.93207,-1.80439 -4e-5,-0.78544 0.31077,-1.44382 0.93207,-1.97467 0.62038,-0.57129 1.64462,-0.94369 3.07009,-1.11742 0,0 44.74121,-5.45018 44.74121,-5.45018 1.28959,-0.157 2.21156,-0.0348 2.76814,0.36651 0.55582,0.36168 0.83347,0.91337 0.83354,1.65541 -7e-5,0.74214 -0.27789,1.38258 -0.83354,1.92167 -0.55658,0.50085 -1.47855,0.83337 -2.76814,0.99749 0,0 -18.99047,2.41776 -18.99047,2.41776"
id="path5447" />
d="m 292.16734,221.79451 c 0,0 0.079,32.92107 0.079,32.92107 0,0 6.83396,-1.8594 6.83396,-1.8594 0.46993,-0.12786 0.80691,-0.0884 1.01132,0.11827 0.20419,0.18473 0.30715,0.48443 0.30895,0.89923 0.002,0.39306 -0.0986,0.7486 -0.30066,1.06669 -0.20232,0.31832 -0.53842,0.54236 -1.00864,0.67204 0,0 -15.85959,4.37404 -15.85959,4.37404 -0.49118,0.13546 -0.8436,0.0983 -1.05684,-0.11192 -0.21335,-0.21022 -0.32005,-0.51707 -0.32005,-0.92043 0,-0.42568 0.10663,-0.79078 0.31991,-1.09527 0.21307,-0.32663 0.56522,-0.55672 1.05608,-0.69027 0,0 6.99856,-1.90419 6.99856,-1.90419 0,0 -0.0639,-33.01316 -0.0639,-33.01316 0,0 -6.94528,1.58452 -6.94528,1.58452 -0.48709,0.11116 -0.83656,0.0697 -1.04802,-0.12452 -0.21157,-0.21626 -0.31738,-0.53384 -0.31738,-0.95255 0,-0.41857 0.10573,-0.77281 0.31723,-1.06267 0.2113,-0.3116 0.56052,-0.52201 1.04729,-0.63134 0,0 15.72034,-3.52906 15.72034,-3.52906 0.46618,-0.1046 0.80048,-0.0507 1.00326,0.16175 0.20255,0.1909 0.30468,0.4903 0.30646,0.89834 0.002,0.40818 -0.0977,0.76414 -0.29818,1.06788 -0.2008,0.28254 -0.53427,0.47704 -1.00074,0.58343 0,0 -6.78316,1.54752 -6.78316,1.54752"
id="path5793" />
<path
inkscape:connector-curvature="0"
d="m 333.91441,137.89555 c 0,0 0,4.82145 0,4.82145 4.26231,-4.95507 8.50252,-7.71134 12.72066,-8.30086 2.51875,-0.35197 4.71531,-0.0105 6.59457,1.01943 1.8709,0.98856 3.43002,2.67958 4.6808,5.07092 2.11395,-2.88191 4.23612,-5.09366 6.36625,-6.64009 2.15634,-1.5801 4.30164,-2.51686 6.43596,-2.81516 3.32659,-0.46487 5.9579,0.22791 7.90698,2.06895 2.54851,2.35126 3.81689,5.1278 3.81694,8.34054 0,0 0,31.43173 0,31.43173 0,0 3.78169,-0.72952 3.78169,-0.72952 1.05891,-0.20428 1.81612,-0.1377 2.27337,0.19926 0.45658,0.30111 0.68473,0.78785 0.68478,1.46049 -5e-5,0.63729 -0.22831,1.21332 -0.68478,1.72849 -0.45725,0.51581 -1.21446,0.87878 -2.27337,1.08887 0,0 -8.30139,1.64706 -8.30139,1.64706 0,0 0,-35.69743 0,-35.69743 -5e-5,-2.29723 -0.70401,-4.09415 -2.11546,-5.39408 -1.41642,-1.30426 -3.05675,-1.82293 -4.92361,-1.5517 -1.6912,0.24582 -3.48172,1.14219 -5.37282,2.6937 -1.89982,1.52212 -4.07088,4.31725 -6.51735,8.39799 0,0 0,30.68038 0,30.68038 0,0 3.945,-0.76103 3.945,-0.76103 1.12031,-0.21612 1.92139,-0.15193 2.40505,0.19205 0.48304,0.30709 0.72435,0.80641 0.7244,1.49821 -5e-5,0.65545 -0.24151,1.24922 -0.7244,1.78172 -0.48366,0.53316 -1.28474,0.91091 -2.40505,1.13318 0,0 -8.78558,1.74313 -8.78558,1.74313 0,0 0,-36.39673 0,-36.39673 -6e-5,-2.4744 -0.76441,-4.39095 -2.29726,-5.75335 -1.49996,-1.40997 -3.19853,-1.9793 -5.09812,-1.70331 -1.75207,0.25466 -3.49172,1.04986 -5.21877,2.38888 -2.4059,1.89533 -4.94464,4.93136 -7.61849,9.11946 0,0 0,31.59463 0,31.59463 0,0 4.24249,-0.81841 4.24249,-0.81841 1.18757,-0.22909 2.03666,-0.16772 2.54928,0.18357 0.51194,0.31331 0.76772,0.82591 0.76772,1.53812 0,0.67475 -0.25565,1.28741 -0.76772,1.83856 -0.51262,0.5518 -1.36171,0.94553 -2.54928,1.18115 0,0 -13.65088,2.70845 -13.65088,2.70845 -1.22888,0.24381 -2.11171,0.18914 -2.64637,-0.1651 -0.53532,-0.35459 -0.80324,-0.87742 -0.80324,-1.56821 0,-0.72913 0.26779,-1.35677 0.80324,-1.8825 0.53466,-0.56337 1.41749,-0.9636 2.64637,-1.20066 0,0 4.33489,-0.83624 4.33489,-0.83624 0,0 0,-39.76731 0,-39.76731 0,0 -4.33489,0.63844 -4.33489,0.63844 -1.22888,0.18102 -2.11171,0.0812 -2.64637,-0.30039 -0.53532,-0.3819 -0.80324,-0.93762 -0.80324,-1.66681 0,-0.69073 0.26779,-1.3047 0.80324,-1.84141 0.53466,-0.53594 1.41749,-0.89098 2.64637,-1.06519 0,0 9.40839,-1.33332 9.40839,-1.33332"
id="path5449" />
d="m 310.82617,224.548 c 0,0 0.0183,2.71052 0.0183,2.71052 1.59486,-2.82856 3.1975,-4.42813 4.80917,-4.80918 0.96652,-0.22849 1.81505,-0.0602 2.54657,0.50362 0.73011,0.54196 1.34443,1.48928 1.84362,2.84195 0.81039,-1.66756 1.62919,-2.95534 2.45658,-3.86518 0.83957,-0.93171 1.68046,-1.49641 2.52294,-1.6956 1.31778,-0.31154 2.3707,0.0529 3.16143,1.09107 1.03734,1.32998 1.56558,2.9259 1.58639,4.79109 0,0 0.20434,18.33386 0.20434,18.33386 0,0 1.53013,-0.41632 1.53013,-0.41632 0.42981,-0.11694 0.739,-0.0757 0.92789,0.12381 0.18853,0.17852 0.2851,0.46568 0.2898,0.86158 0.004,0.37517 -0.0849,0.71339 -0.26782,1.01476 -0.18312,0.30159 -0.48957,0.51171 -0.91962,0.63032 0,0 -3.35086,0.92415 -3.35086,0.92415 0,0 -0.22279,-20.77656 -0.22279,-20.77656 -0.0143,-1.33018 -0.30714,-2.3628 -0.87909,-3.0991 -0.57267,-0.73709 -1.22837,-1.01732 -1.9678,-0.8398 -0.66827,0.16051 -1.37063,0.69532 -2.10748,1.60588 -0.73886,0.89188 -1.5757,2.51342 -2.51176,4.86946 0,0 0.15842,17.6379 0.15842,17.6379 0,0 1.54833,-0.42128 1.54833,-0.42128 0.44115,-0.12002 0.75819,-0.0792 0.95147,0.12232 0.19296,0.18032 0.29136,0.47108 0.29523,0.8724 0.004,0.38029 -0.0887,0.72347 -0.27704,1.02961 -0.18854,0.30636 -0.50335,0.52043 -0.94475,0.64217 0,0 -3.43946,0.94859 -3.43946,0.94859 0,0 -0.17831,-20.87173 -0.17831,-20.87173 -0.0121,-1.41164 -0.31784,-2.49778 -0.91785,-3.25983 -0.5861,-0.78757 -1.24345,-1.09429 -1.97265,-0.91922 -0.67099,0.16116 -1.3334,0.62756 -1.98734,1.40021 -0.90879,1.0908 -1.86103,2.82298 -2.85755,5.20088 0,0 0.12057,17.88402 0.12057,17.88402 0,0 1.61271,-0.43879 1.61271,-0.43879 0.45299,-0.12325 0.77823,-0.083 0.97608,0.1207 0.1976,0.18215 0.29787,0.47663 0.3009,0.88354 0.003,0.38558 -0.0926,0.73385 -0.28674,1.04496 -0.19419,0.31131 -0.51774,0.52949 -0.971,0.6545 0,0 -5.16143,1.42351 -5.16143,1.42351 -0.46029,0.12695 -0.79127,0.0881 -0.99256,-0.11674 -0.20137,-0.20491 -0.30318,-0.50235 -0.30537,-0.89222 -0.002,-0.41142 0.0958,-0.76345 0.29429,-1.05603 0.19822,-0.314 0.5275,-0.53357 0.98751,-0.65873 0,0 1.62837,-0.44305 1.62837,-0.44305 0,0 -0.14116,-22.4169 -0.14116,-22.4169 0,0 -1.62022,0.3912 -1.62022,0.3912 -0.4577,0.11052 -0.78681,0.0614 -0.98695,-0.14757 -0.20023,-0.209 -0.30151,-0.51693 -0.3038,-0.92368 -0.002,-0.38522 0.0954,-0.72992 0.29266,-1.034 0.19711,-0.30384 0.52454,-0.51011 0.98197,-0.61888 0,0 3.52575,-0.83819 3.52575,-0.83819"
id="path5795" />
<path
inkscape:connector-curvature="0"
d="m 432.47276,167.4628 c 0,0 0,-6.0828 0,-6.0828 -5.7975,6.30445 -12.08843,10.16628 -18.89488,11.53144 -5.01615,1.00608 -8.98079,0.48151 -11.86134,-1.59461 -2.90152,-2.12615 -4.36018,-5.14012 -4.36018,-9.03027 0,-4.27566 1.92089,-8.34103 5.73528,-12.16858 3.77821,-3.79124 9.22987,-6.25766 16.28577,-7.41051 1.88182,-0.30744 3.91568,-0.50406 6.09908,-0.59067 2.1711,-0.11991 4.5042,-0.11625 6.99627,0.009 0,0 0,-6.83683 0,-6.83683 -5e-5,-2.31243 -1.00752,-4.17126 -3.03041,-5.58202 -2.03364,-1.41813 -5.10423,-1.83216 -9.23645,-1.23173 -3.19365,0.46414 -7.71884,2.10172 -13.62152,4.94147 -1.07664,0.50744 -1.76786,0.78436 -2.07171,0.82982 -0.54075,0.081 -1.01453,-0.0567 -1.42103,-0.41361 -0.37302,-0.36215 -0.55967,-0.85678 -0.55965,-1.4836 -2e-5,-0.59191 0.16967,-1.08669 0.50881,-1.48409 0.4743,-0.5905 2.38272,-1.57754 5.70477,-2.95304 5.17873,-2.17952 9.05121,-3.44151 11.655,-3.80542 5.12389,-0.71605 9.07344,0.061 11.88347,2.3116 2.78957,2.201 4.1768,4.94583 4.17684,8.24643 0,0 0,27.80543 0,27.80543 0,0 5.19212,-1.00161 5.19212,-1.00161 0.9503,-0.18332 1.62332,-0.11496 2.02049,0.20469 0.39666,0.28626 0.59487,0.74275 0.59492,1.36971 -5e-5,0.59401 -0.19835,1.12807 -0.59492,1.60254 -0.39717,0.475 -1.07019,0.8068 -2.02049,0.99534 0,0 -9.18024,1.82144 -9.18024,1.82144 m 0,-21.01324 c -1.85966,-0.253 -3.83943,-0.33685 -5.94113,-0.2503 -2.11321,0.0871 -4.351,0.32956 -6.71539,0.72884 -5.99089,1.01179 -10.73667,3.1774 -14.19058,6.50681 -2.63574,2.51203 -3.96016,5.20345 -3.96016,8.06185 0,2.64923 1.0022,4.69037 2.99914,6.11798 2.02049,1.41398 4.93209,1.74663 8.71515,1.00868 3.58337,-0.69901 6.87476,-2.07305 9.88112,-4.11507 3.01516,-2.0662 6.08631,-4.98942 9.21185,-8.75869 0,0 0,-9.3001 0,-9.3001"
id="path5451" />
d="m 350.89656,241.32467 c 0,0 -0.0589,-3.6804 -0.0589,-3.6804 -2.44263,3.80778 -5.10211,6.12062 -7.98027,6.91861 -2.10441,0.58347 -3.76815,0.25666 -4.98415,-0.98555 -1.21953,-1.26623 -1.84495,-3.04991 -1.87379,-5.34667 -0.0317,-2.52154 0.73085,-4.92487 2.28129,-7.20305 1.54219,-2.26605 3.8038,-3.77126 6.77195,-4.51991 0.7964,-0.20085 1.66062,-0.33746 2.59222,-0.41005 0.92884,-0.0925 1.93136,-0.11301 3.00698,-0.0616 0,0 -0.0657,-4.10694 -0.0657,-4.10694 -0.0222,-1.38732 -0.47413,-2.48748 -1.3571,-3.30238 -0.88479,-0.81652 -2.19971,-1.01605 -3.95,-0.59577 -1.34605,0.32326 -3.2353,1.35808 -5.67763,3.11343 -0.44361,0.31258 -0.72851,0.48429 -0.85424,0.51483 -0.22367,0.0544 -0.4211,-0.0207 -0.59224,-0.22543 -0.1572,-0.2081 -0.23822,-0.49632 -0.24303,-0.86451 -0.005,-0.34763 0.0618,-0.6405 0.19913,-0.87854 0.1918,-0.35344 0.97539,-0.96079 2.34657,-1.81956 2.14879,-1.36681 3.76798,-2.17692 4.86556,-2.43642 2.17117,-0.5133 3.8675,-0.11811 5.09661,1.18044 1.22539,1.27503 1.8531,2.9031 1.88568,4.88818 0,0 0.27554,16.79617 0.27554,16.79617 0,0 2.26031,-0.61499 2.26031,-0.61499 0.41544,-0.11304 0.71203,-0.0724 0.89013,0.12173 0.17763,0.17395 0.26972,0.45203 0.27631,0.83437 0.006,0.36231 -0.0756,0.68817 -0.24525,0.97765 -0.1699,0.28969 -0.46252,0.49188 -0.87818,0.60651 0,0 -3.98778,1.09982 -3.98778,1.09982 m -0.20304,-12.6875 c -0.80507,-0.13756 -1.65804,-0.17224 -2.55931,-0.10371 -0.90358,0.0688 -1.85617,0.23114 -2.85824,0.48756 -2.52482,0.64614 -4.49945,1.96292 -5.91531,3.95406 -1.07701,1.49735 -1.60605,3.09291 -1.58411,4.78359 0.0203,1.56816 0.45251,2.77768 1.29533,3.62647 0.85525,0.84341 2.07851,1.0467 3.66561,0.61257 1.51075,-0.41325 2.89832,-1.234 4.16372,-2.45986 1.27358,-1.2449 2.56786,-3.01121 3.88202,-5.29462 0,0 -0.0897,-5.60606 -0.0897,-5.60606"
id="path5797" />
<path
inkscape:connector-curvature="0"
d="m 487.99642,123.24158 c 0,0 0,-7.18198 0,-7.18198 0,0 7.90751,-1.12062 7.90751,-1.12062 0.79296,-0.11233 1.36016,-0.009 1.70274,0.31079 0.34213,0.31914 0.51311,0.76977 0.51315,1.35205 -4e-5,0.55172 -0.1711,1.03642 -0.51315,1.45436 -0.34258,0.41847 -0.90978,0.68611 -1.70274,0.80287 0,0 -4.51418,0.66486 -4.51418,0.66486 0,0 0,38.94129 0,38.94129 -4e-5,2.59919 -0.48281,5.02085 -1.45031,7.2696 -0.64654,1.50257 -1.72664,3.14785 -3.24428,4.93949 -1.52421,1.79929 -2.91796,3.15367 -4.17969,4.05975 -1.26625,0.90926 -2.96613,1.60334 -5.1058,2.08195 0,0 -10.08857,2.25658 -10.08857,2.25658 -0.86063,0.19248 -1.47865,0.13846 -1.85284,-0.1629 -0.37458,-0.26951 -0.56202,-0.70931 -0.56199,-1.31915 -3e-5,-0.6099 0.18735,-1.14853 0.56199,-1.6156 0.37419,-0.46662 0.99221,-0.79375 1.85284,-0.98147 0,0 10.21398,-2.18055 10.21398,-2.18055 2.05581,-0.44853 3.89332,-1.44561 5.5158,-2.98788 1.64244,-1.5412 2.99182,-3.56029 4.05143,-6.05696 0.59628,-1.43064 0.89407,-3.15551 0.89411,-5.17643 0,0 0,-11.75228 0,-11.75228 -3.67199,6.46046 -8.46094,10.29476 -14.41118,11.46715 -4.90563,0.96658 -9.19852,-0.24333 -12.85592,-3.66485 -3.66449,-3.49351 -5.51038,-8.19646 -5.51038,-14.08282 0,-5.88631 1.84589,-11.19456 5.51038,-15.88982 3.6574,-4.65324 7.95029,-7.30895 12.85592,-7.99455 5.95024,-0.83153 10.73919,1.3743 14.41118,6.56705 m 0,11.79891 c -4e-5,-4.60139 -1.38279,-8.2714 -4.16442,-11.02605 -2.77587,-2.78019 -6.12983,-3.89388 -10.07779,-3.32022 -3.9914,0.58007 -7.45175,2.73284 -10.36533,6.4757 -2.93682,3.74047 -4.41401,8.00015 -4.41399,12.75663 -2e-5,4.7889 1.47717,8.58342 4.41399,11.36687 2.91358,2.72941 6.37393,3.70079 10.36533,2.93654 3.94796,-0.75589 7.30192,-2.99916 10.07779,-6.71425 2.78163,-3.72257 4.16438,-7.87377 4.16442,-12.47522"
id="path5453" />
d="m 375.34938,213.69585 c 0,0 -0.0974,-4.46393 -0.0974,-4.46393 0,0 3.68773,-0.87669 3.68773,-0.87669 0.37208,-0.0884 0.64113,-0.0368 0.8074,0.15502 0.16617,0.1917 0.25341,0.46963 0.26178,0.83387 0.008,0.34517 -0.066,0.6522 -0.22166,0.92112 -0.15581,0.26917 -0.41973,0.44869 -0.792,0.53856 0,0 -2.11132,0.50977 -2.11132,0.50977 0,0 0.54123,24.40071 0.54123,24.40071 0.0363,1.63856 -0.15744,3.16664 -0.58194,4.58541 -0.2835,0.94739 -0.76869,1.98351 -1.45663,3.10962 -0.68973,1.12896 -1.32331,1.97649 -1.90026,2.54121 -0.57809,0.56581 -1.35962,0.99328 -2.34591,1.28221 0,0 -4.61112,1.35073 -4.61112,1.35073 -0.39039,0.11434 -0.67276,0.0767 -0.84684,-0.11314 -0.17377,-0.16995 -0.26435,-0.44453 -0.27168,-0.82361 -0.007,-0.37906 0.0714,-0.71279 0.23628,-1.00117 0.16471,-0.28821 0.4423,-0.4887 0.83248,-0.60152 0,0 4.66707,-1.3197 4.66707,-1.3197 0.94729,-0.27395 1.78841,-0.89388 2.52391,-1.85846 0.74626,-0.96574 1.35024,-2.23429 1.81265,-3.80502 0.26003,-0.90063 0.37608,-1.98619 0.34838,-3.25697 0,0 -0.16086,-7.37517 -0.16086,-7.37517 -1.62758,4.07072 -3.80169,6.48925 -6.53059,7.23934 -2.23287,0.61374 -4.19888,-0.12311 -5.89159,-2.21938 -1.68617,-2.12737 -2.56457,-4.99526 -2.6305,-8.59335 -0.0658,-3.59204 0.69765,-6.85485 2.28324,-9.77979 1.5891,-2.91055 3.49618,-4.62319 5.71739,-5.14835 2.71476,-0.64182 4.95439,0.6184 6.73072,3.76863 m 0.16039,7.3538 c -0.0626,-2.87086 -0.7569,-5.1338 -2.0858,-6.79534 -1.32015,-1.66944 -2.87807,-2.29072 -4.67812,-1.8585 -1.80975,0.43462 -3.35087,1.81991 -4.62062,4.16259 -1.27628,2.33429 -1.88951,4.95932 -1.83504,7.86963 0.0549,2.93412 0.76232,5.25114 2.11916,6.94432 1.35246,1.66842 2.93958,2.25345 4.75697,1.76072 1.80761,-0.49005 3.33004,-1.90799 4.57015,-4.24741 1.2464,-2.3511 1.83598,-4.96126 1.7733,-7.83601"
id="path5799" />
<path
inkscape:connector-curvature="0"
d="m 540.62477,128.16676 c 0,0 -31.21107,5.34869 -31.21107,5.34869 0.55959,4.81556 2.2836,8.46026 5.1546,10.92445 2.872,2.40913 6.38532,3.19917 10.51985,2.39265 2.27795,-0.44435 4.64854,-1.36045 7.10966,-2.74289 2.44306,-1.3723 4.42228,-2.9394 5.94583,-4.70274 0.44396,-0.51656 0.82908,-0.80507 1.15552,-0.86603 0.37259,-0.0695 0.6983,0.0569 0.97727,0.37934 0.27866,0.2933 0.41792,0.68457 0.41796,1.174 -4e-5,0.48947 -0.18573,0.99996 -0.55739,1.53196 -1.11764,1.65734 -3.11777,3.40564 -6.01644,5.2527 -2.90027,1.82933 -5.91022,3.06093 -9.03241,3.68714 -5.29338,1.06168 -9.78084,-0.14614 -13.42879,-3.66389 -3.66146,-3.59033 -5.50683,-8.44484 -5.50683,-14.53483 0,-5.54457 1.73031,-10.56796 5.16522,-15.03667 3.42605,-4.4281 7.61147,-6.97301 12.52802,-7.66014 4.99038,-0.69739 9.04168,0.70282 12.18653,4.16823 3.11531,3.40416 4.63885,8.17864 4.59247,14.34803 m -2.97258,-3.17835 c -0.58603,-3.92674 -2.13806,-6.95772 -4.66971,-9.09992 -2.52711,-2.16203 -5.56808,-2.99195 -9.13671,-2.47342 -3.60671,0.52417 -6.74137,2.26195 -9.39035,5.22633 -2.66963,2.9875 -4.34237,6.66553 -5.00354,11.02281 0,0 28.20031,-4.6758 28.20031,-4.6758"
id="path5455" />
d="m 400.95375,215.84309 c 0,0 -15.30351,3.94188 -15.30351,3.94188 0.34391,3.04783 1.23396,5.34503 2.66637,6.88627 1.43922,1.51372 3.17433,1.99038 5.19951,1.43641 1.12095,-0.30662 2.28367,-0.91984 3.48738,-1.83766 1.19883,-0.91409 2.16489,-1.95211 2.90025,-3.11439 0.2145,-0.34084 0.40349,-0.53306 0.56706,-0.57689 0.1868,-0.05 0.35355,0.0278 0.50028,0.23369 0.14614,0.18703 0.22361,0.43961 0.23247,0.75782 0.009,0.31828 -0.0759,0.65247 -0.25418,1.00277 -0.53474,1.08992 -1.51174,2.24633 -2.93533,3.4719 -1.41926,1.20943 -2.89777,2.0288 -4.43582,2.45524 -2.59183,0.71861 -4.80714,-0.0257 -6.63604,-2.24415 -1.8247,-2.25008 -2.7858,-5.3079 -2.87757,-9.16136 -0.0834,-3.50233 0.67052,-6.70553 2.2543,-9.60045 1.58612,-2.87997 3.57782,-4.59755 5.9692,-5.16295 2.44485,-0.578 4.47658,0.20903 6.10451,2.35191 1.62144,2.1165 2.47361,5.16594 2.56112,9.15996 m -1.55297,-1.99958 c -0.36339,-2.52164 -1.19348,-4.43925 -2.49343,-5.75652 -1.29227,-1.32421 -2.81005,-1.77891 -4.55736,-1.35935 -1.75678,0.42189 -3.25581,1.59979 -4.49431,3.53879 -1.24433,1.94813 -1.99432,4.30819 -2.24605,7.0779 0,0 13.79115,-3.50082 13.79115,-3.50082"
id="path5801" />
</g>
<g
id="text6335"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
transform="translate(1.4477142e-8,-14.516129)">
<path
id="path6342"
d="m 289.7812,172.74924 c 0,0 0,30.32096 0,30.32096 0,0 5.31622,-1.09403 5.31622,-1.09403 0.36864,-0.0759 0.6328,-0.009 0.79253,0.19948 0.15968,0.18869 0.23953,0.47439 0.23955,0.85707 -2e-5,0.36257 -0.0799,0.68117 -0.23955,0.95582 -0.15973,0.27468 -0.42389,0.45007 -0.79253,0.52616 0,0 -12.20372,2.51907 -12.20372,2.51907 -0.37097,0.0766 -0.63686,0.0102 -0.79765,-0.19916 -0.16081,-0.20937 -0.24121,-0.49598 -0.24121,-0.85983 0,-0.38404 0.0804,-0.7038 0.24121,-0.95925 0.16079,-0.27564 0.42668,-0.45161 0.79765,-0.52795 0,0 5.3343,-1.09775 5.3343,-1.09775 0,0 0,-30.33259 0,-30.33259 0,0 -5.3343,1.0578 -5.3343,1.0578 -0.37097,0.0736 -0.63686,0.0152 -0.79765,-0.17532 -0.16081,-0.21064 -0.24121,-0.50801 -0.24121,-0.89209 0,-0.38402 0.0804,-0.70312 0.24121,-0.9573 0.16079,-0.2743 0.42668,-0.44812 0.79765,-0.52149 0,0 12.20372,-2.41236 12.20372,-2.41236 0.36864,-0.0728 0.6328,-0.004 0.79253,0.20591 0.15968,0.19002 0.23953,0.47636 0.23955,0.85902 -2e-5,0.38273 -0.0799,0.71076 -0.23955,0.98409 -0.15973,0.25327 -0.42389,0.41645 -0.79253,0.48952 0,0 -5.31622,1.05422 -5.31622,1.05422"
inkscape:connector-curvature="0" />
<path
id="path6344"
d="m 304.56912,176.44974 c 0,0 0,2.56275 0,2.56275 1.30843,-2.57317 2.62214,-3.99091 3.94109,-4.25437 0.79339,-0.15843 1.48888,0.0539 2.08658,0.63694 0.5975,0.56281 1.09732,1.50612 1.49954,2.82986 0.68233,-1.5411 1.37053,-2.72191 2.0646,-3.54263 0.70597,-0.84286 1.41171,-1.33466 2.11721,-1.47559 1.10637,-0.22094 1.98741,0.19403 2.64338,1.24457 0.86213,1.3493 1.29307,2.9247 1.29309,4.72665 0,0 0,17.62938 0,17.62938 0,0 1.29225,-0.26593 1.29225,-0.26593 0.36384,-0.0749 0.62457,-0.008 0.78222,0.19923 0.1576,0.18768 0.23641,0.47161 0.23643,0.8518 -2e-5,0.3602 -0.0789,0.67662 -0.23643,0.94926 -0.15765,0.27268 -0.41838,0.44656 -0.78222,0.52167 0,0 -2.82218,0.58254 -2.82218,0.58254 0,0 0,-19.91946 0,-19.91946 -2e-5,-1.28187 -0.2369,-2.29585 -0.71072,-3.04209 -0.47398,-0.74635 -1.02099,-1.0575 -1.64109,-0.93328 -0.55951,0.11212 -1.14958,0.58117 -1.77024,1.40731 -0.62086,0.80639 -1.32718,2.30204 -2.11901,4.48741 0,0 0,16.76074 0,16.76074 0,0 1.27899,-0.26321 1.27899,-0.26321 0.36526,-0.0752 0.62699,-0.009 0.78525,0.19931 0.15823,0.18797 0.23733,0.47243 0.23735,0.85335 -2e-5,0.3609 -0.0792,0.67796 -0.23735,0.95119 -0.15826,0.27327 -0.41999,0.4476 -0.78525,0.52299 0,0 -2.83314,0.58481 -2.83314,0.58481 0,0 0,-19.77746 0,-19.77746 -1e-5,-1.34457 -0.2439,-2.39933 -0.73178,-3.16444 -0.47581,-0.78777 -1.01275,-1.12183 -1.61085,-1.00201 -0.54945,0.11011 -1.09295,0.51024 -1.63047,1.20051 -0.74545,0.97331 -1.52785,2.54716 -2.34725,4.72194 0,0 0,16.79351 0,16.79351 0,0 1.30233,-0.26801 1.30233,-0.26801 0.3667,-0.0755 0.62946,-0.009 0.78832,0.19938 0.15885,0.18827 0.23827,0.47325 0.23828,0.85492 -1e-5,0.3616 -0.0794,0.6793 -0.23828,0.95314 -0.15886,0.27387 -0.42162,0.44864 -0.78832,0.52433 0,0 -4.14836,0.8563 -4.14836,0.8563 -0.36753,0.0759 -0.63097,0.01 -0.79027,-0.199 -0.15931,-0.20855 -0.23897,-0.49391 -0.23897,-0.85606 0,-0.38226 0.0796,-0.70045 0.23897,-0.95457 0.1593,-0.2742 0.42274,-0.44911 0.79027,-0.52474 0,0 1.30416,-0.26839 1.30416,-0.26839 0,0 0,-21.02253 0,-21.02253 0,0 -1.30416,0.26159 -1.30416,0.26159 -0.36753,0.0737 -0.63097,0.006 -0.79027,-0.20361 -0.15931,-0.20947 -0.23897,-0.50535 -0.23897,-0.88764 0,-0.36212 0.0796,-0.67984 0.23897,-0.95317 0.1593,-0.27324 0.42274,-0.44662 0.79027,-0.52013 0,0 2.84603,-0.56906 2.84603,-0.56906"
inkscape:connector-curvature="0" />
<path
id="path6346"
d="m 338.26689,195.60376 c 0,0 0,-3.61767 0,-3.61767 -2.20252,3.52388 -4.55814,5.54631 -7.06742,6.06489 -1.82363,0.37688 -3.24985,-0.0877 -4.27786,-1.39461 -1.02852,-1.32754 -1.54299,-3.10136 -1.54298,-5.32096 -10e-6,-2.43953 0.67785,-4.70711 2.03287,-6.80168 1.35409,-2.09312 3.3292,-3.40199 5.92348,-3.92714 0.69926,-0.14153 1.45854,-0.21543 2.27777,-0.22172 0.81887,-0.0262 1.70362,0.0239 2.65414,0.15025 0,0 0,-4.06615 0,-4.06615 -2e-5,-1.37528 -0.38498,-2.49383 -1.15511,-3.35589 -0.77046,-0.86234 -1.92668,-1.1392 -3.46933,-0.83014 -1.18192,0.23683 -2.84139,1.13844 -4.97959,2.70598 -0.38682,0.2775 -0.63466,0.4272 -0.74347,0.44903 -0.19348,0.0389 -0.36277,-0.047 -0.50789,-0.25774 -0.13305,-0.2131 -0.19957,-0.49956 -0.19957,-0.85935 0,-0.33976 0.0605,-0.6217 0.18143,-0.84583 0.1693,-0.33368 0.85246,-0.88012 2.04895,-1.63902 1.8839,-1.21542 3.30773,-1.91909 4.27248,-2.1118 1.91602,-0.38264 3.40901,0.10672 4.47992,1.46726 1.07032,1.33994 1.60526,2.99588 1.60527,4.96838 0,0 0,16.61698 0,16.61698 0,0 2.01829,-0.41534 2.01829,-0.41534 0.37219,-0.0766 0.63629,-0.0115 0.79235,0.19532 0.15601,0.18689 0.23402,0.46947 0.23404,0.84774 -2e-5,0.35837 -0.0781,0.67311 -0.23404,0.9442 -0.15606,0.27114 -0.42016,0.44511 -0.79235,0.52194 0,0 -3.55138,0.73307 -3.55138,0.73307 m 0,-12.49741 c -0.70985,-0.19458 -1.46206,-0.29097 -2.25669,-0.2891 -0.79498,0.002 -1.63244,0.0922 -2.51243,0.27083 -2.20778,0.44829 -3.93465,1.58796 -5.17941,3.41949 -0.94315,1.37125 -1.41489,2.87666 -1.41489,4.51572 0,1.51915 0.35684,2.72513 1.07033,3.61771 0.72532,0.8898 1.77657,1.19268 3.15324,0.90903 1.31539,-0.27102 2.53349,-0.95103 3.65445,-2.03968 1.13235,-1.11048 2.29417,-2.73492 3.4854,-4.87285 0,0 0,-5.53115 0,-5.53115"
inkscape:connector-curvature="0" />
<path
id="path6348"
d="m 361.03362,169.73799 c 0,0 0,-4.57811 0,-4.57811 0,0 3.51111,-0.70203 3.51111,-0.70203 0.35609,-0.0712 0.61126,-0.003 0.76556,0.20328 0.15424,0.20673 0.23137,0.49814 0.23139,0.87424 -2e-5,0.35635 -0.0772,0.66876 -0.23139,0.93722 -0.1543,0.26853 -0.40947,0.4385 -0.76556,0.50991 0,0 -2.01322,0.40381 -2.01322,0.40381 0,0 0,24.93239 0,24.93239 -2e-5,1.66412 -0.21394,3.19438 -0.64182,4.59098 -0.28533,0.93124 -0.76094,1.93198 -1.42698,3.00242 -0.66629,1.07077 -1.27327,1.8618 -1.82089,2.37289 -0.5478,0.51123 -1.2804,0.8629 -2.198,1.05498 0,0 -4.25995,0.89161 -4.25995,0.89161 -0.3584,0.075 -0.61529,0.01 -0.77062,-0.19631 -0.15536,-0.18605 -0.23304,-0.46782 -0.23304,-0.8453 0,-0.37749 0.0777,-0.70165 0.23304,-0.9725 0.15533,-0.27081 0.41222,-0.44362 0.77062,-0.51839 0,0 4.31359,-0.87039 4.31359,-0.87039 0.88183,-0.18403 1.67398,-0.72615 2.37652,-1.6262 0.71418,-0.90221 1.3032,-2.12502 1.76716,-3.66839 0.26165,-0.88672 0.39248,-1.97415 0.39248,-3.26235 0,0 0,-7.49145 0,-7.49145 -1.60613,3.99699 -3.67816,6.25834 -6.21753,6.78211 -2.06489,0.42591 -3.85102,-0.4773 -5.35762,-2.71118 -1.49577,-2.25793 -2.24408,-5.18732 -2.24408,-8.78698 0,-3.59961 0.74831,-6.82288 2.24408,-9.66819 1.5066,-2.84552 3.29273,-4.47385 5.35762,-4.88629 2.53937,-0.50714 4.6114,0.90308 6.21753,4.22817 m 0,7.52118 c 0,-2.93314 -0.60662,-5.28816 -1.82036,-7.06588 -1.20261,-1.78115 -2.6443,-2.50382 -4.3256,-2.16698 -1.68272,0.33717 -3.12789,1.64976 -4.33499,3.9386 -1.20785,2.27039 -1.81204,4.86726 -1.81204,7.78958 0,2.94224 0.60419,5.31369 1.81204,7.11356 1.2071,1.77893 2.65227,2.49487 4.33499,2.14886 1.6813,-0.34572 3.12299,-1.65368 4.3256,-3.9231 1.21374,-2.29027 1.82036,-4.90147 1.82036,-7.83464"
inkscape:connector-curvature="0" />
<path
id="path6350"
d="m 385.85186,173.58032 c 0,0 -15.13765,3.07797 -15.13765,3.07797 0.26034,3.16944 1.06482,5.60432 2.41279,7.30409 1.35885,1.67644 3.03546,2.3087 5.02902,1.89796 1.10796,-0.22828 2.26831,-0.77304 3.48095,-1.634 1.21188,-0.86041 2.19967,-1.87147 2.96371,-3.03319 0.22326,-0.34131 0.41713,-0.52883 0.58164,-0.56257 0.18794,-0.0385 0.3524,0.0557 0.49337,0.2829 0.14092,0.20743 0.21138,0.47854 0.21141,0.81334 -3e-5,0.33482 -0.094,0.67909 -0.28188,1.03285 -0.56391,1.10093 -1.56872,2.23389 -3.01514,3.39933 -1.43573,1.14415 -2.91371,1.87353 -4.43406,2.18773 -2.54834,0.52665 -4.68036,-0.42556 -6.39472,-2.85877 -1.70402,-2.4575 -2.55658,-5.67472 -2.55657,-9.65009 -10e-6,-3.61935 0.79928,-6.88542 2.39688,-9.79647 1.60812,-2.91102 3.59284,-4.60156 5.95302,-5.07297 2.42802,-0.4849 4.42362,0.44725 5.9881,2.79462 1.5632,2.32586 2.3326,5.59781 2.30913,9.81727 m -1.49798,-2.20747 c -0.29388,-2.67927 -1.06987,-4.74949 -2.32855,-6.21109 -1.24773,-1.46483 -2.73778,-2.02412 -4.4707,-1.67694 -1.73447,0.34753 -3.22825,1.49618 -4.48082,3.44663 -1.25337,1.95173 -2.03418,4.35276 -2.34185,7.20251 0,0 13.62192,-2.76111 13.62192,-2.76111"
inkscape:connector-curvature="0" />
</g>
</g>
<text
@@ -844,7 +889,7 @@
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
transform="matrix(0.81677441,0,0,0.81677441,35.330746,48.494017)"
transform="matrix(0.64605126,0,0,0.64605126,58.138831,104.45649)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium"
id="text10309">
<path
@@ -872,6 +917,134 @@
d="m 233.61915,313.32443 c 0,0 4.86427,2.31094 4.86427,2.31094 0,0 -2.7e-4,5.00485 -2.7e-4,5.00485 1.71074,-3.52308 3.64965,-4.78093 5.82081,-3.75454 2.5118,1.18756 4.48297,4.13443 5.9036,8.84914 1.23117,4.03483 1.84851,9.9569 1.84853,17.75524 0,0 0,33.90579 0,33.90579 0,0 -5.07083,-2.83374 -5.07083,-2.83374 0,0 6.2e-4,-30.6586 6.2e-4,-30.6586 9e-5,-5.40954 -0.29652,-9.29502 -0.88902,-11.65343 -0.57668,-2.38426 -1.62396,-3.94697 -3.13732,-4.68877 -1.63768,-0.80262 -2.79522,0.005 -3.4777,2.41735 -0.6666,2.37712 -0.99957,6.93792 -0.99994,13.68633 0,0 -0.001,26.14439 -0.001,26.14439 0,0 -4.86529,-2.71887 -4.86529,-2.71887 0,0 0.004,-53.76608 0.004,-53.76608"
id="path10326" />
</g>
<g
style="display:none"
inkscape:label="rwlayershort"
id="layer3"
inkscape:groupmode="layer">
<g
inkscape:corner7="0.23104367 : -0.032927705 : 0.53664065 : 1"
inkscape:corner0="0.51156871 : 0.026428054 : 0 : 1"
inkscape:perspectiveID="#perspective4014"
id="g11520"
style="fill:#24b8eb;fill-opacity:0.64251206;stroke:#253237;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="inkscape:box3d">
<path
d="M 131.92561,229.48947 254.03226,279.93524 540.96513,197.86229 411.55236,171.87435 z"
inkscape:box3dsidetype="13"
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
id="path11530"
sodipodi:type="inkscape:box3dside" />
<path
d="m 131.92561,190.22181 0,39.26766 279.62675,-57.61512 0,-28.97934 z"
inkscape:box3dsidetype="6"
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
id="path11522"
sodipodi:type="inkscape:box3dside" />
<path
d="m 411.55236,142.89501 129.41277,21.38902 0,33.57826 -129.41277,-25.98794 z"
inkscape:box3dsidetype="11"
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
id="path11532"
sodipodi:type="inkscape:box3dside" />
<path
d="M 131.92561,190.22181 254.03226,231.71944 540.96513,164.28403 411.55236,142.89501 z"
inkscape:box3dsidetype="5"
style="fill:#24b8eb;fill-opacity:0.64251206"
id="path11524"
sodipodi:type="inkscape:box3dside" />
<path
d="m 254.03226,231.71944 0,48.2158 286.93287,-82.07295 0,-33.57826 z"
inkscape:box3dsidetype="14"
style="fill:#24b8eb;fill-opacity:0.64251206"
id="path11528"
sodipodi:type="inkscape:box3dside" />
<path
d="m 131.92561,190.22181 122.10665,41.49763 0,48.2158 -122.10665,-50.44577 z"
inkscape:box3dsidetype="3"
style="fill:#24b8eb;fill-opacity:0.64251206"
id="path11526"
sodipodi:type="inkscape:box3dside" />
</g>
<g
transform="matrix(0.65426564,0,0,0.65426564,59.078784,80.39098)"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
id="text12905">
<path
inkscape:connector-curvature="0"
d="m 132.39162,196.56835 c 0,0 2.25832,0.79098 2.25832,0.79098 0,0 1.50732,28.61196 1.50732,28.61196 0,0 4.34598,-26.56183 4.34598,-26.56183 0,0 2.722,0.95339 2.722,0.95339 0,0 1.63516,29.08943 1.63516,29.08943 0,0 4.31997,-27.00363 4.31997,-27.00363 0,0 2.42221,0.84838 2.42221,0.84838 0,0 -5.66212,33.42382 -5.66212,33.42382 0,0 -2.73065,-1.12467 -2.73065,-1.12467 0,0 -1.5784,-29.68879 -1.5784,-29.68879 0,0 -4.4624,27.20079 -4.4624,27.20079 0,0 -2.67264,-1.10077 -2.67264,-1.10077 0,0 -2.10475,-35.43906 -2.10475,-35.43906"
id="path12912" />
<path
inkscape:connector-curvature="0"
d="m 164.03604,213.26939 c -0.2639,-0.42447 -0.56258,-0.78434 -0.89592,-1.0796 -0.33304,-0.29492 -0.68661,-0.50929 -1.06059,-0.64322 -1.33705,-0.47863 -2.47231,0.33686 -3.4066,2.43656 -0.92991,2.06688 -1.50465,5.07325 -1.72714,9.01466 0,0 -1.04777,17.82424 -1.04777,17.82424 0,0 -2.42011,-0.99676 -2.42011,-0.99676 0,0 1.98378,-35.17658 1.98378,-35.17658 0,0 2.47527,0.86697 2.47527,0.86697 0,0 -0.33507,5.56959 -0.33507,5.56959 0.60533,-1.89455 1.35104,-3.25595 2.23803,-4.08114 0.89961,-0.82526 1.87507,-1.05633 2.92646,-0.68969 0.27488,0.0959 0.54641,0.23479 0.81455,0.4165 0.26786,0.15981 0.53715,0.37533 0.80786,0.64667 0,0 -0.35275,5.89174 -0.35275,5.89174"
id="path12914" />
<path
inkscape:connector-curvature="0"
d="m 167.87077,194.36999 c 0,0 2.5978,0.8462 2.5978,0.8462 0,0 -0.48615,7.70745 -0.48615,7.70745 0,0 -2.58509,-0.87602 -2.58509,-0.87602 0,0 0.47344,-7.67763 0.47344,-7.67763 m -0.87992,14.31682 c 0,0 2.57415,0.9016 2.57415,0.9016 0,0 -2.30324,35.91396 -2.30324,35.91396 0,0 -2.5149,-1.0358 -2.5149,-1.0358 0,0 2.24399,-35.77976 2.24399,-35.77976"
id="path12916" />
<path
inkscape:connector-curvature="0"
d="m 183.34977,214.41656 c 0,0 -0.34194,4.75863 -0.34194,4.75863 0,0 -5.33307,-1.91046 -5.33307,-1.91046 0,0 -1.36427,19.81122 -1.36427,19.81122 -0.0441,0.73284 -0.076,1.34864 -0.0958,1.84769 -0.0198,0.49879 -0.0272,0.89218 -0.0223,1.18025 0.024,1.41732 0.22117,2.51814 0.59164,3.30404 0.38018,0.79025 0.97369,1.34835 1.78193,1.67447 0,0 2.66812,1.07661 2.66812,1.07661 0,0 -0.36838,4.94638 -0.36838,4.94638 0,0 -2.51686,-1.03661 -2.51686,-1.03661 -1.55308,-0.63966 -2.72009,-1.81877 -3.50617,-3.53794 -0.77559,-1.71295 -1.18868,-3.99849 -1.24016,-6.86324 -0.009,-0.50749 -0.005,-1.05378 0.0125,-1.63897 0.0171,-0.60759 0.0472,-1.26529 0.0905,-1.97325 0,0 1.33026,-19.73599 1.33026,-19.73599 0,0 -2.21945,-0.79507 -2.21945,-0.79507 0,0 0.32464,-4.68341 0.32464,-4.68341 0,0 2.18338,0.76473 2.18338,0.76473 0,0 0.70719,-10.54703 0.70719,-10.54703 0,0 2.66503,0.88587 2.66503,0.88587 0,0 -0.71095,10.59328 -0.71095,10.59328 0,0 5.36413,1.8788 5.36413,1.8788"
id="path12918" />
<path
inkscape:connector-curvature="0"
d="m 199.13849,236.70883 c 0,0 -1.72385,21.2125 -1.72385,21.2125 0,0 -2.77523,-1.14302 -2.77523,-1.14302 0,0 0.45537,-5.5694 0.45537,-5.5694 -0.79039,1.93977 -1.69787,3.25939 -2.72178,3.963 -1.00998,0.68226 -2.14049,0.76306 -3.39088,0.2461 -1.4019,-0.5796 -2.56171,-2.02483 -3.48324,-4.3353 -0.91085,-2.32565 -1.3871,-5.01869 -1.42975,-8.08698 -0.0612,-4.40249 0.65095,-7.60298 2.1444,-9.6005 1.51381,-2.0078 3.64053,-2.5073 6.39035,-1.48111 0,0 3.88091,1.44834 3.88091,1.44834 0,0 0.13737,-1.64241 0.13737,-1.64241 0.0187,-0.17753 0.0322,-0.36859 0.0405,-0.57316 0.008,-0.22771 0.0101,-0.57318 0.006,-1.03646 -0.0184,-2.06353 -0.40494,-3.80038 -1.15864,-5.20652 -0.74267,-1.42355 -1.7772,-2.37178 -3.10017,-2.84471 -0.90567,-0.32369 -1.83075,-0.39003 -2.77476,-0.20023 -0.93078,0.19278 -1.88487,0.63805 -2.86168,1.33418 0,0 0.40119,-5.68296 0.40119,-5.68296 1.0224,-0.5343 2.0267,-0.84843 3.0124,-0.94098 0.99899,-0.11252 1.96874,-0.005 2.90868,0.32235 2.01064,0.70123 3.55659,2.24252 4.62956,4.62368 1.08518,2.38922 1.64359,5.50025 1.67366,9.32128 0.006,0.76751 -0.0125,1.66447 -0.0556,2.69043 -0.0433,1.00181 -0.11156,2.06254 -0.20482,3.18188 m -3.01967,1.47698 c 0,0 -2.78542,-1.06163 -2.78542,-1.06163 -2.2624,-0.86226 -3.92041,-0.80292 -4.98268,0.16995 -1.04789,0.94964 -1.55167,2.85777 -1.51494,5.72282 0.0254,1.98149 0.31466,3.64088 0.8682,4.98133 0.56384,1.34561 1.32816,2.21415 2.29484,2.60564 1.48548,0.60158 2.77591,-0.0812 3.87044,-2.05855 1.10034,-2.01109 1.81516,-5.00707 2.14096,-8.99265 0,0 0.1086,-1.36691 0.1086,-1.36691"
id="path12920" />
<path
inkscape:connector-curvature="0"
d="m 217.64994,242.08214 c -0.003,-3.45467 -0.36941,-6.29845 -1.09988,-8.52314 -0.71911,-2.21914 -1.712,-3.55453 -2.9753,-4.006 -0.9147,-0.32682 -1.77169,-0.13384 -2.57095,0.57649 -0.7861,0.6882 -1.46696,1.86026 -2.04305,3.51377 -0.60552,1.7306 -1.08098,3.81943 -1.42712,6.2652 -0.33468,2.41877 -0.49538,4.89667 -0.48288,7.43549 0.0158,3.20708 0.36798,5.85818 1.05704,7.96044 0.69992,2.08483 1.65443,3.37263 2.86659,3.86366 0.92007,0.37271 1.77251,0.25313 2.55721,-0.36105 0.78714,-0.63948 1.47963,-1.76427 2.07706,-3.37684 0.61006,-1.68425 1.10315,-3.73887 1.47858,-6.16534 0.37661,-2.43421 0.56447,-4.82931 0.5627,-7.18268 m -9.23169,-12.84717 c 0.71257,-1.9212 1.61108,-3.31025 2.69696,-4.16424 1.10132,-0.8778 2.25765,-1.10762 3.46876,-0.68529 1.8688,0.65177 3.36054,2.56955 4.46812,5.75349 1.11991,3.19191 1.67936,7.16826 1.67728,11.91278 -0.002,3.86886 -0.33149,7.48101 -0.9869,10.83305 -0.64142,3.34015 -1.55578,6.15428 -2.74017,8.44433 -0.7715,1.50955 -1.65836,2.54577 -2.65987,3.1114 -0.99765,0.5634 -2.04044,0.61881 -3.12849,0.16897 -1.14744,-0.4744 -2.14129,-1.46065 -2.98356,-2.95812 -0.84085,-1.4949 -1.52693,-3.4884 -2.05939,-5.98273 0,0 -0.48266,5.66038 -0.48266,5.66038 0,0 -2.84889,-1.17336 -2.84889,-1.17336 0,0 4.44431,-52.94734 4.44431,-52.94734 0,0 2.95322,0.96198 2.95322,0.96198 0,0 -1.81872,21.0647 -1.81872,21.0647"
id="path12922" />
<path
inkscape:connector-curvature="0"
d="m 228.71944,214.19071 c 0,0 3.15615,1.02808 3.15615,1.02808 0,0 -5.33605,54.69811 -5.33605,54.69811 0,0 -3.03879,-1.25157 -3.03879,-1.25157 0,0 5.21869,-54.47462 5.21869,-54.47462"
id="path12924" />
<path
inkscape:connector-curvature="0"
d="m 249.07211,254.74636 c 0.0404,-0.38368 0.0691,-0.78443 0.0859,-1.20226 0.0288,-0.41348 0.0457,-0.83161 0.0506,-1.25434 0.0353,-3.03778 -0.36798,-5.60275 -1.20915,-7.68768 -0.82831,-2.07819 -1.97429,-3.37815 -3.43389,-3.89992 -1.61834,-0.57843 -3.05045,-0.009 -4.29713,1.70059 -1.23987,1.67549 -2.18445,4.34652 -2.83626,8.00619 0,0 11.63988,4.33748 11.63988,4.33748 m 2.81056,6.45167 c 0,0 -15.09094,-5.79069 -15.09094,-5.79069 -0.0752,0.89703 -0.126,1.60789 -0.15253,2.13298 -0.0265,0.52486 -0.0411,0.98119 -0.0437,1.36905 -0.0225,3.36482 0.44677,6.15468 1.40888,8.37881 0.97504,2.23208 2.36307,3.71384 4.1703,4.44572 1.39681,0.56568 2.72662,0.77468 3.98908,0.62476 1.26781,-0.15056 2.45566,-0.64338 3.56302,-1.48066 0,0 -0.70189,6.42657 -0.70189,6.42657 -1.18125,0.49488 -2.39603,0.72794 -3.64426,0.70088 -1.23153,-0.0222 -2.4791,-0.29519 -3.74285,-0.81767 -2.68557,-1.11031 -4.73074,-3.28927 -6.14928,-6.53818 -1.40393,-3.26112 -2.09137,-7.34961 -2.06451,-12.28511 0.023,-4.22844 0.39788,-8.03395 1.12728,-11.41867 0.74471,-3.42191 1.82516,-6.33485 3.24539,-8.73744 0.92003,-1.50587 2.01004,-2.53659 3.27144,-3.08937 1.27888,-0.55109 2.63589,-0.57813 4.0712,-0.0776 2.26618,0.79035 4.06153,2.85633 5.37632,6.19826 1.32912,3.35217 1.96352,7.4395 1.9016,12.24399 -0.0148,1.14841 -0.0669,2.36942 -0.15622,3.66262 -0.0889,1.26675 -0.21507,2.6175 -0.37835,4.05176"
id="path12926" />
</g>
<g
id="text14746"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
transform="matrix(1.1734694,0,0,1.1734694,-48.893189,-48.489991)">
<path
id="path14753"
d="m 292.56742,237.4772 c 0,0 0,-1.59047 0,-1.59047 -1e-5,-0.5391 0.0453,-0.93633 0.13582,-1.19161 0.0987,-0.25714 0.22627,-0.40435 0.38255,-0.44167 0.1562,-0.0372 0.27949,0.0501 0.36989,0.26184 0.0986,0.20984 0.14786,0.58398 0.14787,1.12245 0,0 0,6.27362 0,6.27362 -10e-6,0.55648 -0.0493,0.96364 -0.14787,1.22152 -0.0904,0.25592 -0.21369,0.40336 -0.36989,0.44226 -0.13983,0.0349 -0.25912,-0.0432 -0.35786,-0.23424 -0.0906,-0.1931 -0.14406,-0.53022 -0.16051,-1.01139 -0.0412,-1.49945 -0.41597,-2.74678 -1.12524,-3.74312 -0.95853,-1.37023 -2.0518,-1.9091 -3.28082,-1.61375 -0.80737,0.19408 -1.57032,0.76646 -2.2886,1.71804 -0.5353,0.69109 -0.96233,1.48343 -1.28077,2.37687 -0.55364,1.55049 -0.99453,3.22917 -1.32232,5.0356 -0.2355,1.33038 -0.35329,2.79525 -0.35329,4.3941 0,0 0,4.00625 0,4.00625 0,3.41577 0.57185,6.23436 1.71333,8.4515 1.13855,2.19332 2.4576,3.08294 3.95555,2.67411 0.89633,-0.24464 1.69568,-0.88624 2.39858,-1.92393 0.71,-1.03826 1.39417,-2.49958 2.05261,-4.38314 0.13978,-0.41447 0.29596,-0.64466 0.46853,-0.69065 0.14784,-0.0394 0.26691,0.0276 0.35722,0.20089 0.0903,0.17329 0.13541,0.41244 0.13543,0.71743 -2e-5,0.41269 -0.17649,1.08812 -0.52962,2.02685 -0.67425,1.83488 -1.43607,3.29166 -2.28591,4.36978 -0.84324,1.0599 -1.70051,1.71048 -2.57191,1.95056 -0.75663,0.20846 -1.52704,0.10426 -2.31133,-0.31343 -0.60168,-0.3239 -1.09951,-0.75841 -1.49315,-1.30354 -0.394,-0.54561 -0.88069,-1.51132 -1.46037,-2.89811 -0.57203,-1.40902 -0.96363,-2.74066 -1.1743,-3.99402 -0.21078,-1.27211 -0.3162,-2.69969 -0.3162,-4.28229 0,0 0,-4.6659 0,-4.6659 0,-2.25562 0.27827,-4.62592 0.83428,-7.1086 0.56373,-2.49973 1.32824,-4.49134 2.29251,-5.97481 0.97053,-1.50028 2.01815,-2.3831 3.14231,-2.65042 1.72644,-0.41045 3.20678,0.51535 4.44348,2.77142"
inkscape:connector-curvature="0" />
<path
id="path14755"
d="m 308.66695,250.09217 c -10e-6,3.3873 -0.5478,6.4277 -1.64547,9.12638 -1.09249,2.70338 -2.41593,4.27147 -3.97244,4.7003 -1.57825,0.43483 -2.92347,-0.40609 -4.03348,-2.528 -1.11284,-2.14518 -1.67032,-4.92676 -1.67032,-8.34065 0,-3.43174 0.55748,-6.50462 1.67032,-9.21347 1.11001,-2.71971 2.45523,-4.27243 4.03348,-4.66229 1.55651,-0.38443 2.87995,0.49215 3.97244,2.62466 1.09767,2.12517 1.64546,4.88816 1.64547,8.29307 m -1.01277,0.2646 c -10e-6,-2.7907 -0.44957,-5.05158 -1.35007,-6.78534 -0.89442,-1.73935 -1.98297,-2.45048 -3.26712,-2.12996 -1.28798,0.32151 -2.38981,1.59368 -3.30406,3.8193 -0.90806,2.21042 -1.3628,4.71879 -1.36279,7.52165 -10e-6,2.78505 0.45473,5.0558 1.36279,6.80955 0.91425,1.7479 2.01608,2.44432 3.30406,2.09279 1.28415,-0.35048 2.3727,-1.63042 3.26712,-3.83716 0.9005,-2.22197 1.35006,-4.71775 1.35007,-7.49083"
inkscape:connector-curvature="0" />
<path
id="path14757"
d="m 314.42401,237.15342 c 0,0 0,3.33838 0,3.33838 0.68834,-1.73173 1.30925,-2.96305 1.86301,-3.69535 0.55304,-0.7313 1.17532,-1.18207 1.86656,-1.35283 0.74434,-0.18383 1.42164,0.006 2.03224,0.56853 0.43228,0.41464 0.82174,1.18719 1.16849,2.31729 0.35414,1.10991 0.53111,2.29857 0.53112,3.56668 0,0 0,13.7844 0,13.7844 0,0 0.81847,-0.22256 0.81847,-0.22256 0.23026,-0.0626 0.39521,-0.003 0.49492,0.17762 0.0997,0.16363 0.14951,0.41019 0.14952,0.73967 -1e-5,0.31216 -0.0499,0.58594 -0.14952,0.82137 -0.0997,0.23549 -0.26466,0.38485 -0.49492,0.44805 0,0 -2.59918,0.71347 -2.59918,0.71347 -0.23955,0.0658 -0.40963,0.008 -0.51015,-0.17349 -0.10057,-0.18148 -0.15085,-0.42903 -0.15085,-0.74263 0,-0.331 0.0503,-0.60603 0.15085,-0.82505 0.10052,-0.23636 0.2706,-0.3871 0.51015,-0.45224 0,0 0.81034,-0.22035 0.81034,-0.22035 0,0 0,-13.43494 0,-13.43494 -10e-6,-1.54782 -0.25067,-2.78882 -0.75241,-3.72384 -0.50236,-0.9535 -1.17565,-1.32537 -2.02071,-1.11445 -0.64462,0.16091 -1.20459,0.59773 -1.67958,1.31084 -0.47553,0.69646 -1.15466,2.32016 -2.03835,4.87447 0,0 0,13.85296 0,13.85296 0,0 1.1141,-0.30294 1.1141,-0.30294 0.23417,-0.0637 0.40192,-0.004 0.50332,0.17797 0.10137,0.16478 0.15204,0.4133 0.15205,0.74557 -1e-5,0.31479 -0.0507,0.59099 -0.15205,0.82865 -0.1014,0.23771 -0.26915,0.38871 -0.50332,0.45299 0,0 -3.22119,0.88421 -3.22119,0.88421 -0.23607,0.0648 -0.40534,0.006 -0.50771,-0.17703 -0.10241,-0.18288 -0.15362,-0.43257 -0.15362,-0.74903 0,-0.33403 0.0512,-0.61171 0.15362,-0.83298 0.10237,-0.23878 0.27164,-0.39025 0.50771,-0.45445 0,0 1.11958,-0.30443 1.11958,-0.30443 0,0 0,-18.34278 0,-18.34278 0,0 -0.83646,0.20956 -0.83646,0.20956 -0.23592,0.0591 -0.40507,-0.004 -0.50738,-0.18919 -0.10234,-0.18526 -0.15352,-0.4449 -0.15351,-0.77884 -10e-6,-0.31633 0.0512,-0.59268 0.15351,-0.829 0.10231,-0.23622 0.27146,-0.38357 0.50738,-0.44208 0,0 1.82397,-0.4522 1.82397,-0.4522"
inkscape:connector-curvature="0" />
<path
id="path14759"
d="m 329.72799,233.35924 c 0,0 5.13345,-1.27269 5.13345,-1.27269 0.22371,-0.0554 0.38397,0.007 0.48085,0.18852 0.0968,0.18111 0.14525,0.43402 0.14526,0.75877 -10e-6,0.30771 -0.0485,0.57622 -0.14526,0.80555 -0.0969,0.22944 -0.25714,0.37217 -0.48085,0.4282 0,0 -5.13345,1.28608 -5.13345,1.28608 0,0 0,14.43158 0,14.43158 -10e-6,1.25643 0.21891,2.24711 0.65643,2.97148 0.44458,0.72157 1.09178,0.96605 1.94066,0.73436 0.6374,-0.17396 1.32621,-0.5761 2.06616,-1.20576 0.73864,-0.64564 1.31224,-1.29704 1.72148,-1.95454 0.1487,-0.2622 0.27135,-0.40633 0.36797,-0.43241 0.11885,-0.0321 0.22284,0.0507 0.31196,0.24856 0.0891,0.18071 0.13361,0.41608 0.13362,0.70616 -10e-6,0.25597 -0.0483,0.50799 -0.14476,0.75609 -0.23768,0.62804 -0.81757,1.40124 -1.74108,2.32087 -0.91812,0.90249 -1.8008,1.47097 -2.64781,1.70434 -1.10446,0.30428 -1.98559,-0.0463 -2.64198,-1.05341 -0.65743,-1.00874 -0.98654,-2.52169 -0.98653,-4.53773 0,0 0,-14.44811 0,-14.44811 0,0 -1.76335,0.44177 -1.76335,0.44177 -0.22807,0.0572 -0.39159,-0.006 -0.4905,-0.18811 -0.0989,-0.18257 -0.1484,-0.43805 -0.14839,-0.7664 -1e-5,-0.31102 0.0494,-0.58251 0.14839,-0.81445 0.0989,-0.23183 0.26243,-0.37601 0.4905,-0.43258 0,0 1.76335,-0.43717 1.76335,-0.43717 0,0 0,-6.4099 0,-6.4099 -1e-5,-0.51689 0.0454,-0.89822 0.13621,-1.14394 0.0908,-0.24561 0.20423,-0.38466 0.34033,-0.41716 0.14361,-0.0342 0.26073,0.0498 0.35139,0.25184 0.0906,0.20213 0.13594,0.56133 0.13595,1.07763 0,0 0,6.40256 0,6.40256"
inkscape:connector-curvature="0" />
<path
id="path14761"
d="m 347.92414,250.72178 c 0,0 0,-3.05626 0,-3.05626 -1.32486,2.95612 -2.74493,4.64604 -4.26117,5.06378 -1.10424,0.30423 -1.9692,-0.10219 -2.59338,-1.22112 -0.62513,-1.1376 -0.93805,-2.65046 -0.93805,-4.53728 0,-2.07378 0.41226,-3.99242 1.23557,-5.75329 0.82167,-1.75736 2.01824,-2.83768 3.58648,-3.24242 0.42203,-0.10891 0.87997,-0.15956 1.37368,-0.15206 0.49311,-0.009 1.02545,0.0469 1.59687,0.16843 0,0 0,-3.43514 0,-3.43514 -1e-5,-1.16186 -0.23137,-2.11384 -0.69447,-2.85657 -0.46365,-0.7435 -1.16008,-0.99968 -2.09048,-0.76745 -0.71376,0.17817 -1.7173,0.9112 -3.01271,2.20186 -0.23464,0.22862 -0.38501,0.35128 -0.45105,0.36788 -0.11743,0.0296 -0.22021,-0.0464 -0.30832,-0.22792 -0.0808,-0.18338 -0.12119,-0.42787 -0.12118,-0.73345 -10e-6,-0.28856 0.0367,-0.52691 0.11017,-0.715 0.10279,-0.2802 0.51741,-0.73128 1.24291,-1.35247 1.14063,-0.994 2.00133,-1.56201 2.58384,-1.70592 1.1553,-0.28533 2.05404,0.15837 2.69792,1.32913 0.64285,1.15216 0.9639,2.56014 0.96391,4.22531 0,0 0,14.02795 0,14.02795 0,0 1.20981,-0.32897 1.20981,-0.32897 0.22283,-0.0606 0.38091,-0.003 0.4743,0.17316 0.0933,0.15921 0.14002,0.39824 0.14004,0.7171 -2e-5,0.3021 -0.0467,0.56663 -0.14004,0.79361 -0.0934,0.22705 -0.25147,0.37117 -0.4743,0.43233 0,0 -2.13035,0.58478 -2.13035,0.58478 m 0,-10.558 c -0.42669,-0.17475 -0.87915,-0.26722 -1.35749,-0.27728 -0.47891,-0.0101 -0.9838,0.054 -1.51479,0.19244 -1.33413,0.34776 -2.37964,1.28966 -3.13434,2.82696 -0.57244,1.15204 -0.85896,2.42481 -0.85896,3.81711 0,1.29044 0.21674,2.31854 0.64989,3.0837 0.44002,0.76238 1.07722,1.02935 1.9107,0.80187 0.79534,-0.21708 1.53095,-0.78111 2.20715,-1.69129 0.68232,-0.92751 1.38163,-2.28814 2.09784,-4.08071 0,0 0,-4.6728 0,-4.6728"
inkscape:connector-curvature="0" />
<path
id="path14763"
d="m 358.9208,215.38083 c 0,0 0,5.40783 0,5.40783 0,0 -1.31083,0.31638 -1.31083,0.31638 0,0 0,-5.41657 0,-5.41657 0,0 1.31083,-0.30764 1.31083,-0.30764 m 0.0317,10.73306 c 0,0 0,19.48737 0,19.48737 0,0 3.46775,-0.94294 3.46775,-0.94294 0.21618,-0.0588 0.36953,-0.001 0.46013,0.17246 0.0906,0.15719 0.13584,0.39281 0.13585,0.70687 -1e-5,0.29756 -0.0453,0.5579 -0.13585,0.7811 -0.0906,0.22326 -0.24395,0.36455 -0.46013,0.42389 0,0 -7.86049,2.15769 -7.86049,2.15769 -0.21341,0.0586 -0.36643,3.5e-4 -0.45897,-0.17483 -0.0926,-0.1752 -0.13887,-0.41325 -0.13887,-0.71413 0,-0.31759 0.0463,-0.58094 0.13887,-0.79001 0.0925,-0.22573 0.24556,-0.36759 0.45897,-0.42562 0,0 3.50529,-0.95316 3.50529,-0.95316 0,0 0,-17.38816 0,-17.38816 0,0 -2.59952,0.65125 -2.59952,0.65125 -0.21294,0.0534 -0.36917,-0.008 -0.46862,-0.1831 -0.0924,-0.17722 -0.13856,-0.41614 -0.13855,-0.71671 -1e-5,-0.31722 0.0462,-0.58749 0.13855,-0.81081 0.0924,-0.22321 0.24857,-0.36209 0.46862,-0.41667 0,0 3.48697,-0.86449 3.48697,-0.86449"
inkscape:connector-curvature="0" />
<path
id="path14765"
d="m 368.46442,223.75567 c 0,0 0,3.12776 0,3.12776 0.60425,-1.6123 1.14936,-2.75688 1.63557,-3.43494 0.4856,-0.67719 1.03206,-1.09054 1.63914,-1.24051 0.65376,-0.16146 1.24872,0.0263 1.78514,0.56245 0.37979,0.39496 0.72197,1.12482 1.02665,2.18925 0.31119,1.04566 0.4667,2.16256 0.46671,3.35132 0,0 0,12.92183 0,12.92183 0,0 0.71929,-0.19559 0.71929,-0.19559 0.20237,-0.055 0.34735,0.003 0.43499,0.17441 0.0876,0.155 0.13141,0.38695 0.13142,0.69584 -1e-5,0.29266 -0.0438,0.54854 -0.13142,0.76765 -0.0876,0.21918 -0.23262,0.35655 -0.43499,0.4121 0,0 -2.28391,0.62693 -2.28391,0.62693 -0.21044,0.0578 -0.35985,8.6e-4 -0.44816,-0.17084 -0.0883,-0.17172 -0.13252,-0.40454 -0.13251,-0.69846 -1e-5,-0.31023 0.0442,-0.56721 0.13251,-0.77087 0.0883,-0.21993 0.23772,-0.3585 0.44816,-0.41572 0,0 0.71195,-0.19359 0.71195,-0.19359 0,0 0,-12.59334 0,-12.59334 0,-1.45086 -0.22023,-2.61784 -0.66105,-3.50168 -0.44133,-0.90112 -1.03277,-1.25955 -1.77501,-1.0743 -0.56613,0.14133 -1.05787,0.54243 -1.47496,1.20365 -0.41753,0.64556 -1.01377,2.15684 -1.78952,4.5368 0,0 0,12.97896 0,12.97896 0,0 0.97803,-0.26595 0.97803,-0.26595 0.20559,-0.0559 0.35287,0.002 0.4419,0.17485 0.089,0.15603 0.1335,0.38972 0.1335,0.70106 0,0.29497 -0.0445,0.55297 -0.1335,0.77401 -0.089,0.2211 -0.23631,0.35987 -0.4419,0.41631 0,0 -2.82735,0.7761 -2.82735,0.7761 -0.20715,0.0569 -0.35568,-0.001 -0.44551,-0.17409 -0.0899,-0.17297 -0.13479,-0.40769 -0.13479,-0.70413 0,-0.31289 0.0449,-0.57216 0.13479,-0.77778 0.0898,-0.22202 0.23836,-0.36119 0.44551,-0.41752 0,0 0.98254,-0.26717 0.98254,-0.26717 0,0 0,-17.18426 0,-17.18426 0,0 -0.73409,0.18391 -0.73409,0.18391 -0.20703,0.0519 -0.35546,-0.01 -0.44524,-0.18475 -0.0898,-0.17506 -0.13471,-0.41902 -0.13471,-0.73184 0,-0.29632 0.0449,-0.55442 0.13471,-0.7743 0.0898,-0.21977 0.23821,-0.35532 0.44524,-0.40667 0,0 1.60087,-0.39689 1.60087,-0.39689"
inkscape:connector-curvature="0" />
<path
id="path14767"
d="m 388.11235,229.76789 c 0,0 -8.48758,2.22224 -8.48758,2.22224 0.14697,2.60006 0.60091,4.60711 1.36077,6.01981 0.76503,1.39207 1.70765,1.93407 2.82657,1.62868 0.62097,-0.16949 1.27063,-0.59601 1.94883,-1.27892 0.67702,-0.6817 1.22829,-1.48892 1.65434,-2.42175 0.12444,-0.27395 0.23249,-0.42323 0.32414,-0.44789 0.10471,-0.0282 0.19631,0.0513 0.27482,0.23843 0.0785,0.17107 0.11771,0.39273 0.11772,0.665 -10e-6,0.27228 -0.0523,0.55072 -0.15697,0.83539 -0.31413,0.88653 -0.87429,1.79282 -1.68153,2.71981 -0.80235,0.91103 -1.62941,1.48439 -2.48135,1.71911 -1.43066,0.39416 -2.63019,-0.41452 -3.59644,-2.43084 -0.96193,-2.03924 -1.44377,-4.68961 -1.44377,-7.94738 0,-2.96601 0.45175,-5.62524 1.35369,-7.97367 0.90655,-2.34471 2.02355,-3.67918 3.34919,-4.00664 1.36076,-0.33608 2.47689,0.47235 3.35047,2.42115 0.87162,1.92849 1.30016,4.60654 1.2871,8.03747 m -0.83466,-1.82578 c -0.16388,-2.18666 -0.59682,-3.88887 -1.29971,-5.10755 -0.69758,-1.2225 -1.5317,-1.71355 -2.5032,-1.47106 -0.97392,0.24311 -1.81394,1.14718 -2.51921,2.71386 -0.70654,1.5695 -1.1471,3.51858 -1.32078,5.8459 0,0 7.6429,-1.98115 7.6429,-1.98115"
inkscape:connector-curvature="0" />
<path
id="path14769"
d="m 394.65863,217.26158 c 0,0 0,5.05071 0,5.05071 1.05317,-2.61538 1.83796,-4.31797 2.35603,-5.11227 0.52374,-0.81061 1.00534,-1.26991 1.44497,-1.37865 0.47726,-0.11799 0.91902,0.17532 1.32537,0.87929 0.41225,0.68589 0.61821,1.23352 0.61822,1.64339 -10e-6,0.29956 -0.0412,0.56219 -0.12356,0.78788 -0.0761,0.20844 -0.17434,0.32787 -0.29482,0.35828 -0.0634,0.016 -0.11736,0.006 -0.16176,-0.0302 -0.0444,-0.0519 -0.12694,-0.21251 -0.24755,-0.48199 -0.2223,-0.49656 -0.41611,-0.82689 -0.58139,-0.99082 -0.16538,-0.16396 -0.32763,-0.22611 -0.48676,-0.18636 -0.35034,0.0875 -0.77435,0.54152 -1.27228,1.36266 -0.49218,0.82062 -1.35019,2.74163 -2.57647,5.76941 0,0 0,10.95911 0,10.95911 0,0 3.57169,-0.97122 3.57169,-0.97122 0.19745,-0.0537 0.33753,0.003 0.42029,0.17013 0.0827,0.15127 0.12408,0.37699 0.12409,0.67715 -10e-6,0.28439 -0.0414,0.53269 -0.12409,0.74496 -0.0828,0.21232 -0.22284,0.34558 -0.42029,0.39978 0,0 -6.34991,1.74303 -6.34991,1.74303 -0.19434,0.0533 -0.33368,0.004 -0.41796,-0.14841 -0.0843,-0.16829 -0.12645,-0.396 -0.12645,-0.68312 0,-0.27115 0.0389,-0.50507 0.11673,-0.70172 0.0843,-0.21431 0.22686,-0.34878 0.42768,-0.40341 0,0 1.96714,-0.53508 1.96714,-0.53508 0,0 0,-16.69431 0,-16.69431 0,0 -1.5011,0.37607 -1.5011,0.37607 -0.19412,0.0486 -0.33329,-0.0121 -0.41746,-0.18232 -0.0842,-0.17019 -0.1263,-0.40677 -0.1263,-0.70967 0,-0.28692 0.0389,-0.53569 0.11658,-0.7463 0.0842,-0.21212 0.22659,-0.34304 0.42718,-0.3928 0,0 2.31218,-0.57324 2.31218,-0.57324"
inkscape:connector-curvature="0" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer6"
@@ -922,64 +1095,7 @@
d="m 133.59629,56.078359 119.50583,10.663536 0,64.052605 -119.50583,-22.31404 z" />
</g>
<g
id="text5935"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;text-align:center;line-height:88.99999857%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
transform="matrix(0.82611672,0,0,0.82611672,33.620121,15.579543)">
<path
id="path5944"
d="m 153.83888,67.902732 c 0,0 -8.49364,12.847003 -8.49364,12.847003 0,0 -2.61139,-8.338168 -2.61139,-8.338168 0,0 -4.57259,7.39592 -4.57259,7.39592 0,0 -4.56493,-14.065601 -4.56493,-14.065601 0,0 3.1018,0.33111 3.1018,0.33111 0,0 2.23127,7.74856 2.23127,7.74856 0,0 4.57156,-7.36476 4.57156,-7.36476 0,0 2.48012,8.212597 2.48012,8.212597 0,0 4.3089,-7.145498 4.3089,-7.145498 0,0 3.5489,0.378837 3.5489,0.378837"
inkscape:connector-curvature="0" />
<path
id="path5946"
d="m 159.48544,68.50549 c 0,0 -0.14506,1.081269 -0.14506,1.081269 1.08487,-0.840755 2.18357,-1.203434 3.29625,-1.085323 0.97953,0.104001 1.8738,0.531365 2.68199,1.28339 0,0 -2.07994,2.256579 -2.07994,2.256579 -0.59715,-0.539033 -1.19307,-0.84117 -1.78775,-0.907144 -0.40876,-0.04533 -0.76837,-0.0083 -1.07903,0.110906 -0.31032,0.110074 -0.58159,0.314687 -0.81388,0.613752 -0.22246,0.290909 -0.41092,0.680177 -0.56546,1.167777 -0.14482,0.48847 -0.26061,1.079247 -0.34742,1.772359 0,0 -0.83785,6.248278 -0.83785,6.248278 0,0 -3.17048,-0.408479 -3.17048,-0.408479 0,0 1.65969,-12.473776 1.65969,-12.473776 0,0 3.18894,0.340412 3.18894,0.340412"
inkscape:connector-curvature="0" />
<path
id="path5948"
d="m 172.11804,63.653761 c -1e-5,0.442892 -0.17671,0.808538 -0.52981,1.096682 -0.35269,0.287833 -0.77536,0.407208 -1.2677,0.358444 -0.49153,-0.04865 -0.91718,-0.256105 -1.27725,-0.622096 -0.34966,-0.382881 -0.52433,-0.798829 -0.52434,-1.248191 0,-0.449323 0.16967,-0.813819 0.50932,-1.093731 0.35004,-0.288441 0.76564,-0.410358 1.24707,-0.365433 0.49226,0.04598 0.9199,0.256324 1.28263,0.631329 0.37326,0.367241 0.56007,0.781688 0.56008,1.242996 m -1.04355,6.088833 c 0,0 -1.74605,12.789101 -1.74605,12.789101 0,0 -3.29826,-0.42494 -3.29826,-0.42494 0,0 1.72648,-12.718331 1.72648,-12.718331 0,0 3.31783,0.35417 3.31783,0.35417"
inkscape:connector-curvature="0" />
<path
id="path5950"
d="m 179.01592,73.460646 c 0,0 -1.40778,10.137791 -1.40778,10.137791 0,0 -3.39162,-0.436971 -3.39162,-0.436971 0,0 1.39178,-10.080958 1.39178,-10.080958 0,0 -1.91023,-0.213095 -1.91023,-0.213095 0,0 0.38104,-2.804082 0.38104,-2.804082 0,0 1.91269,0.204175 1.91269,0.204175 0,0 0.83006,-6.00759 0.83006,-6.00759 0,0 3.4216,0.330185 3.4216,0.330185 0,0 -0.83963,6.041632 -0.83963,6.041632 0,0 3.18456,0.339944 3.18456,0.339944 0,0 -0.39206,2.843759 -0.39206,2.843759 0,0 -3.18041,-0.35479 -3.18041,-0.35479"
inkscape:connector-curvature="0" />
<path
id="path5952"
d="m 200.09628,72.840604 c 0,0 -1.92201,13.407533 -1.92201,13.407533 0,0 -3.62916,-0.467574 -3.62916,-0.467574 0,0 0.21229,-1.438465 0.21229,-1.438465 -1.54259,0.989936 -3.13133,1.376921 -4.76545,1.165541 -1.99844,-0.258505 -3.61848,-1.068102 -4.86609,-2.425845 -1.24247,-1.352149 -1.8618,-2.975618 -1.86182,-4.874587 -2e-5,-2.19038 0.70861,-3.906541 2.1309,-5.152891 1.45025,-1.249951 3.31827,-1.756081 5.61179,-1.512503 1.08847,0.115618 2.01837,0.372012 2.78823,0.769622 0.78266,0.399806 1.58371,1.032558 2.40329,1.899222 0,0 0.24627,-1.759869 0.24627,-1.759869 0,0 3.65176,0.389816 3.65176,0.389816 m -4.43914,5.916099 c -2e-5,-1.199313 -0.393,-2.217808 -1.17742,-3.05388 -0.78244,-0.843484 -1.79012,-1.332653 -3.0208,-1.468712 -1.33304,-0.147352 -2.44657,0.189847 -3.34298,1.009297 -0.89377,0.826514 -1.33967,1.910207 -1.33965,3.252913 0,1.172514 0.37155,2.177587 1.11602,3.016769 0.74629,0.841254 1.7085,1.336241 2.8887,1.483838 1.3143,0.164372 2.45544,-0.165971 3.42144,-0.99352 0.96902,-0.84934 1.45469,-1.932246 1.45469,-3.246705"
inkscape:connector-curvature="0" />
<path
id="path5954"
d="m 210.59369,62.948857 c 0,0 -1.76559,12.102809 -1.76559,12.102809 0.99306,-0.529993 1.85742,-0.864422 2.59199,-1.002271 0.77082,-0.144321 1.60707,-0.168814 2.50926,-0.07301 2.23174,0.237044 4.08602,1.090293 5.55608,2.56358 1.47683,1.470144 2.21784,3.222946 2.21788,5.253295 1e-5,2.230397 -0.8416,3.981762 -2.51819,5.249095 -1.67957,1.279068 -3.71714,1.760708 -6.10579,1.451727 -2.21017,-0.285894 -4.13141,-1.259787 -5.76887,-2.916662 0,0 -0.27205,1.812753 -0.27205,1.812753 0,0 -3.734,-0.481081 -3.734,-0.481081 0,0 3.51282,-24.297211 3.51282,-24.297211 0,0 3.77646,0.336974 3.77646,0.336974 m 7.18134,18.458814 c -3e-5,-1.252477 -0.4394,-2.326274 -1.31629,-3.219543 -0.8745,-0.890788 -2.00772,-1.412305 -3.39688,-1.565883 -1.49808,-0.165597 -2.73151,0.1696 -3.70334,1.003067 -0.96885,0.811323 -1.45213,1.945103 -1.45212,3.403219 2e-5,1.223263 0.41506,2.257404 1.24678,3.10411 0.83392,0.8686 1.92249,1.387638 3.26835,1.55592 1.49058,0.186383 2.74974,-0.136303 3.77469,-0.970743 1.05167,-0.834302 1.57881,-1.938376 1.57881,-3.310147"
inkscape:connector-curvature="0" />
<path
id="path5956"
d="m 232.93555,64.942427 c 0,0 -3.79346,25.295545 -3.79346,25.295545 0,0 -4.00189,-0.515597 -4.00189,-0.515597 0,0 3.76476,-25.139598 3.76476,-25.139598 0,0 4.03059,0.35965 4.03059,0.35965"
inkscape:connector-curvature="0" />
<path
id="path5958"
d="m 239.07676,85.477198 c 1e-5,1.068436 0.45116,2.002121 1.35531,2.802708 0.91923,0.804368 2.09404,1.296834 3.52714,1.476294 1.97588,0.247435 3.50087,-0.165051 4.56866,-1.241156 0,0 3.20459,1.821904 3.20459,1.821904 -1.11699,1.073416 -2.26255,1.773857 -3.43638,2.10314 -1.18258,0.336864 -2.65489,0.390514 -4.41308,0.162756 -2.77115,-0.358979 -4.96266,-1.305345 -6.58587,-2.835657 -1.61521,-1.522765 -2.41984,-3.383769 -2.41987,-5.588642 -3e-5,-2.306935 0.88512,-4.137105 2.66268,-5.496037 1.77472,-1.357381 4.03193,-1.893987 6.78151,-1.60249 2.68277,0.284445 4.81243,1.219511 6.37815,2.809048 1.59911,1.610417 2.40156,3.625163 2.40163,6.038461 -3e-5,0.251826 -0.0196,0.658706 -0.0588,1.220604 0,0 -13.9657,-1.670933 -13.9657,-1.670933 m 9.66373,-1.627103 c -0.45104,-2.323059 -1.99908,-3.629393 -4.62888,-3.919627 -2.4703,-0.272608 -4.06924,0.672373 -4.8094,2.829777 0,0 9.43828,1.08985 9.43828,1.08985"
inkscape:connector-curvature="0" />
<path
id="path5960"
d="m 159.44201,83.06886 c 0,0 -2.98737,22.36088 -2.98737,22.36088 0,0 -3.15565,-0.54145 -3.15565,-0.54145 0,0 2.96891,-22.238329 2.96891,-22.238329 0,0 3.17411,0.418899 3.17411,0.418899"
inkscape:connector-curvature="0" />
<path
id="path5962"
d="m 176.52978,95.739649 c 0,0 -1.77849,12.829461 -1.77849,12.829461 0,0 -3.35926,-0.57638 -3.35926,-0.57638 0,0 0.19654,-1.37669 0.19654,-1.37669 -1.4283,0.89866 -2.89961,1.2156 -4.41324,0.95511 -1.85149,-0.31864 -3.35276,-1.15466 -4.5091,-2.50553 -1.15176,-1.3455 -1.72593,-2.93049 -1.72594,-4.75897 -2e-5,-2.109076 0.65694,-3.736288 1.97537,-4.885562 1.3441,-1.151542 3.07504,-1.57194 5.19969,-1.255482 1.00813,0.150176 1.86927,0.430138 2.58214,0.840229 0.72466,0.412634 1.46626,1.050011 2.22494,1.913032 0,0 0.22797,-1.684407 0.22797,-1.684407 0,0 3.37938,0.505189 3.37938,0.505189 m -4.10825,5.533921 c -2e-5,-1.15392 -0.36381,-2.14778 -1.09003,-2.980058 -0.72446,-0.839417 -1.65756,-1.345968 -2.79733,-1.520697 -1.23475,-0.189261 -2.26634,0.09566 -3.09688,0.852554 -0.8282,0.763868 -1.24141,1.791281 -1.24139,3.083861 0,1.12875 0.34431,2.10939 1.03417,2.94341 0.69147,0.836 1.58293,1.34622 2.67619,1.52967 1.2173,0.20427 2.27406,-0.0736 3.16851,-0.83603 0.89715,-0.78318 1.34676,-1.80802 1.34676,-3.07271"
inkscape:connector-curvature="0" />
<path
id="path5964"
d="m 195.82123,98.623555 c 0,0 -13.67153,18.801495 -13.67153,18.801495 0,0 -3.92324,-0.72275 -3.92324,-0.72275 0,0 5.91998,-8.17342 5.91998,-8.17342 0,0 -5.26986,-12.438405 -5.26986,-12.438405 0,0 3.68066,0.550227 3.68066,0.550227 0,0 3.67874,9.080848 3.67874,9.080848 0,0 5.46568,-7.713835 5.46568,-7.713835 0,0 4.11957,0.61584 4.11957,0.61584"
inkscape:connector-curvature="0" />
<path
id="path5966"
d="m 200.49583,107.30031 c 10e-6,1.00571 0.39972,1.89861 1.20069,2.68021 0.8142,0.7855 1.85458,1.28526 3.1234,1.49839 1.74884,0.29375 3.09819,-0.0472 4.04278,-1.02632 0,0 2.83375,1.81217 2.83375,1.81217 -0.98755,0.97496 -2.00057,1.5985 -3.0388,1.87223 -1.04617,0.28064 -2.34899,0.28605 -3.9052,0.0179 -2.45382,-0.42276 -4.39522,-1.38083 -5.83367,-2.87148 -1.43178,-1.48374 -2.14519,-3.26113 -2.14521,-5.33734 -2e-5,-2.17231 0.78478,-3.86759 2.36043,-5.09052 1.57263,-1.221165 3.5721,-1.654065 6.00661,-1.29191 2.37422,0.353213 4.25813,1.30051 5.6427,2.84497 1.41372,1.56471 2.12298,3.48409 2.12303,5.75287 -2e-5,0.23675 -0.0173,0.61866 -0.0519,1.14569 0,0 -12.35857,-2.0069 -12.35857,-2.0069 m 8.55495,-1.22843 c -0.39896,-2.19902 -1.76849,-3.47665 -4.09592,-3.833 -2.18726,-0.33486 -3.60353,0.50381 -4.25927,2.51108 0,0 8.35519,1.32192 8.35519,1.32192"
inkscape:connector-curvature="0" />
<path
id="path5968"
d="m 222.18466,102.56466 c 0,0 -0.17825,1.18915 -0.17825,1.18915 1.3334,-0.86103 2.68436,-1.19131 4.05308,-0.98751 1.20542,0.1795 2.30628,0.71229 3.30152,1.59991 0,0 -2.56067,2.36656 -2.56067,2.36656 -0.7348,-0.63744 -1.46792,-1.01191 -2.19936,-1.12432 -0.50266,-0.0772 -0.94483,-0.0599 -1.32674,0.0518 -0.38147,0.10156 -0.71487,0.31051 -1.00037,0.62671 -0.27337,0.30779 -0.50495,0.72683 -0.69483,1.25708 -0.17792,0.53184 -0.32018,1.17898 -0.42683,1.94144 0,0 -1.02913,6.86861 -1.02913,6.86861 0,0 -3.89147,-0.66771 -3.89147,-0.66771 0,0 2.03647,-13.70721 2.03647,-13.70721 0,0 3.91658,0.58549 3.91658,0.58549"
inkscape:connector-curvature="0" />
</g>
<g
transform="matrix(0.70185341,0,0,0.70185341,118.30543,27.168909)"
transform="matrix(0.70185341,0,0,0.70185341,103.7893,28.378586)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
id="text6476">
<path
@@ -1000,7 +1116,7 @@
id="path6489" />
<path
inkscape:connector-curvature="0"
d="m 426.78356,107.09258 c 0,0 0,-1.88162 0,-1.88162 -1.29426,1.23241 -2.72793,2.21052 -4.30255,2.93345 -1.58097,0.75218 -3.02296,1.21187 -4.32438,1.37727 -2.84033,0.36091 -5.16206,-0.50088 -6.95591,-2.59442 -1.80197,-2.1297 -2.706,-4.61561 -2.706,-7.450523 0,-3.449995 1.14945,-6.766286 3.43846,-9.93519 2.29325,-3.179053 5.43363,-4.95254 9.40099,-5.331327 1.57921,-0.150749 3.39679,-0.06225 5.44939,0.26374 0,0 0,-1.920817 0,-1.920817 -1e-5,-1.202127 -0.33577,-2.151503 -1.00813,-2.849026 -0.6567,-0.700183 -1.92263,-0.967515 -3.80372,-0.800477 -1.5489,0.137578 -3.56646,0.792207 -6.05983,1.968997 -0.9326,0.429384 -1.65947,0.668141 -2.17946,0.715577 -0.71179,0.06498 -1.32039,-0.265367 -1.82538,-0.991816 -0.48819,-0.755544 -0.7325,-1.746725 -0.7325,-2.972869 0,-0.693 0.0873,-1.300079 0.26176,-1.821128 0.17441,-0.520739 0.41846,-0.940499 0.73202,-1.259265 0.31331,-0.345082 0.96525,-0.770689 1.95416,-1.276103 1.31474,-0.663016 2.65095,-1.206818 4.00842,-1.631975 1.3528,-0.449995 2.5732,-0.717309 3.66242,-0.802899 3.23272,-0.253864 5.71949,0.634365 7.47424,2.656278 1.76343,1.985514 2.64219,4.831201 2.64221,8.543807 0,0 0,16.434219 0,16.434219 0,0 0.8685,-0.09997 0.8685,-0.09997 1.22086,-0.140526 2.0847,0.135063 2.5939,0.825754 0.52488,0.662055 0.78706,1.586611 0.78708,2.774351 -2e-5,1.16192 -0.2622,2.14952 -0.78708,2.96365 -0.5092,0.78731 -1.37304,1.2577 -2.5939,1.41076 0,0 -5.99471,0.75157 -5.99471,0.75157 m 0,-14.386544 c -2.06948,-0.40743 -3.98883,-0.518817 -5.75577,-0.331915 -2.13431,0.225806 -3.97905,1.227956 -5.53012,3.010736 -0.96819,1.140564 -1.45318,2.243056 -1.45316,3.305406 -2e-5,0.770223 0.23388,1.367567 0.70129,1.791657 0.86409,0.77522 2.04484,1.07465 3.53944,0.90007 1.26684,-0.14798 2.69144,-0.69613 4.27211,-1.641973 1.59121,-0.943971 2.9993,-2.138927 4.22621,-3.584347 0,0 0,-3.449634 0,-3.449634"
d="m 426.78356,107.09258 c 0,0 0,-1.88162 0,-1.88162 -1.29426,1.23241 -2.72793,2.21052 -4.30255,2.93345 -1.58097,0.75218 -3.02296,1.21187 -4.32438,1.37727 -2.84033,0.36091 -5.16206,-0.50088 -6.95591,-2.59442 -1.80197,-2.1297 -2.706,-4.61561 -2.706,-7.450523 0,-3.449995 1.14945,-6.766286 3.43846,-9.93519 2.29325,-3.179053 5.43363,-4.95254 9.40099,-5.331327 1.57921,-0.150749 3.39679,-0.06225 5.44939,0.26374 0,0 0,-1.920817 0,-1.920817 -1e-5,-1.202127 -0.33577,-2.151503 -1.00813,-2.849026 -0.6567,-0.700183 -1.92263,-0.967515 -3.80372,-0.800477 -1.5489,0.137578 -3.56646,0.792207 -6.05983,1.968997 -0.9326,0.429384 -1.65947,0.668141 -2.17946,0.715577 -0.71179,0.06498 -1.32039,-0.265367 -1.82538,-0.991816 -0.48819,-0.755544 -0.7325,-1.746725 -0.7325,-2.972869 0,-0.693 0.0873,-1.300079 0.26176,-1.821128 0.17441,-0.520739 0.41846,-0.940499 0.73202,-1.259265 0.31331,-0.345082 0.96525,-0.770689 1.95416,-1.276103 1.31474,-0.663016 2.65095,-1.206818 4.00842,-1.631975 1.3528,-0.449995 2.5732,-0.717309 3.66242,-0.802899 3.23272,-0.253864 5.71949,0.634365 7.47424,2.656278 1.76343,1.985514 2.64219,4.831201 2.64221,8.543807 0,0 0,16.434219 0,16.434219 0,0 0.8685,-0.09997 0.8685,-0.09997 1.22086,-0.140526 2.0847,0.135063 2.5939,0.825754 0.52488,0.662055 0.78706,1.586613 0.78708,2.774353 -2e-5,1.16192 -0.2622,2.14952 -0.78708,2.96365 -0.5092,0.78731 -1.37304,1.2577 -2.5939,1.41076 0,0 -5.99471,0.75157 -5.99471,0.75157 m 0,-14.386546 c -2.06948,-0.40743 -3.98883,-0.518817 -5.75577,-0.331915 -2.13431,0.225806 -3.97905,1.227956 -5.53012,3.010736 -0.96819,1.140564 -1.45318,2.243056 -1.45316,3.305406 -2e-5,0.770223 0.23388,1.367569 0.70129,1.791659 0.86409,0.77522 2.04484,1.07465 3.53944,0.90007 1.26684,-0.14798 2.69144,-0.69613 4.27211,-1.641975 1.59121,-0.943971 2.9993,-2.138927 4.22621,-3.584347 0,0 0,-3.449634 0,-3.449634"
id="path6491" />
<path
inkscape:connector-curvature="0"
@@ -1019,54 +1135,127 @@
d="m 529.26714,63.310804 c 0,0 0,4.360627 0,4.360627 1.63097,-2.247844 2.90878,-3.756252 3.83736,-4.531717 0.93851,-0.774258 1.81212,-1.192426 2.62133,-1.256017 1.24109,-0.09744 2.44062,0.637677 3.59899,2.201052 0.78636,1.052813 1.17886,2.159045 1.17888,3.320496 -2e-5,0.982826 -0.19008,1.837577 -0.5705,2.564837 -0.36861,0.704643 -0.8176,1.081739 -1.34729,1.13078 -0.46884,0.04344 -0.96305,-0.337016 -1.48272,-1.142328 -0.52052,-0.806521 -0.98594,-1.192073 -1.39602,-1.155672 -0.53514,0.04754 -1.33941,0.727598 -2.41476,2.043211 -1.06624,1.318692 -2.40692,3.27905 -4.02527,5.887282 0,0 0,10.526834 0,10.526834 0,0 5.50612,-0.63378 5.50612,-0.63378 0.92146,-0.106064 1.57368,0.14475 1.95822,0.751703 0.39645,0.582377 0.59451,1.389478 0.59453,2.421834 -2e-5,1.009903 -0.19808,1.864635 -0.59453,2.564818 -0.38454,0.676972 -1.03676,1.073391 -1.95822,1.188916 0,0 -11.77989,1.476871 -11.77989,1.476871 -0.95657,0.119927 -1.64331,-0.115635 -2.05861,-0.707472 -0.40281,-0.617169 -0.60438,-1.455248 -0.60438,-2.513711 0,-1.035437 0.20157,-1.898985 0.60438,-2.590038 0.4153,-0.714702 1.10204,-1.126896 2.05861,-1.237002 0,0 2.35416,-0.270974 2.35416,-0.270974 0,0 0,-17.063345 0,-17.063345 0,0 -1.426,0.128571 -1.426,0.128571 -0.95398,0.08605 -1.63887,-0.173426 -2.05304,-0.779149 -0.40171,-0.630509 -0.60275,-1.474561 -0.60274,-2.531606 -10e-6,-1.034031 0.20103,-1.889297 0.60274,-2.565222 0.41417,-0.699049 1.09906,-1.086463 2.05304,-1.162716 0,0 5.34561,-0.427083 5.34561,-0.427083"
id="path6499" />
</g>
<g
transform="matrix(0.86745158,0,0,0.86745158,24.966041,10.718461)"
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
id="text10906">
<path
inkscape:connector-curvature="0"
d="m 153.83888,80.580698 c 0,0 -8.49369,30.064162 -8.49369,30.064162 0,0 -2.61138,-18.595363 -2.61138,-18.595363 0,0 -4.57263,17.271913 -4.57263,17.271913 0,0 -4.56489,-31.350308 -4.56489,-31.350308 0,0 3.1018,0.399872 3.1018,0.399872 0,0 2.23125,17.302482 2.23125,17.302482 0,0 4.5716,-17.201161 4.5716,-17.201161 0,0 2.48011,18.325657 2.48011,18.325657 0,0 4.30892,-16.674766 4.30892,-16.674766 0,0 3.54891,0.457512 3.54891,0.457512"
id="path10913" />
<path
inkscape:connector-curvature="0"
d="m 159.48545,81.308632 c 0,0 -0.14506,2.466001 -0.14506,2.466001 1.08487,-2.027243 2.18358,-2.972954 3.29626,-2.831021 0.97953,0.125009 1.8738,0.992223 2.68199,2.604674 0,0 -2.07993,5.347173 -2.07993,5.347173 -0.59716,-1.153753 -1.19308,-1.770955 -1.78777,-1.853275 -0.40876,-0.05653 -0.76837,0.06793 -1.07902,0.373103 -0.31033,0.284418 -0.58159,0.778602 -0.81389,1.482374 -0.22246,0.684173 -0.41092,1.58735 -0.56546,2.709458 -0.14482,1.12299 -0.26061,2.474469 -0.34742,4.054536 0,0 -0.83785,14.250185 -0.83785,14.250185 0,0 -3.1705,-0.5674 -3.1705,-0.5674 0,0 1.65971,-28.446914 1.65971,-28.446914 0,0 3.18894,0.411106 3.18894,0.411106"
id="path10915" />
<path
inkscape:connector-curvature="0"
d="m 172.11805,68.890531 c 0,1.003379 -0.1767,1.8517 -0.5298,2.544356 -0.35269,0.691923 -0.77536,1.010087 -1.2677,0.955217 -0.49153,-0.05472 -0.91719,-0.476639 -1.27726,-1.265141 -0.34966,-0.827922 -0.52433,-1.750538 -0.52433,-2.768572 -1e-5,-1.017937 0.16966,-1.862856 0.50931,-2.535355 0.35004,-0.692993 0.76564,-1.016131 1.24707,-0.968719 0.49226,0.04858 0.9199,0.476836 1.28263,1.285447 0.37326,0.789837 0.56007,1.707665 0.56008,2.752767 m -1.04353,13.912119 c 0,0 -1.74602,29.17105 -1.74602,29.17105 0,0 -3.29827,-0.59027 -3.29827,-0.59027 0,0 1.72646,-29.008502 1.72646,-29.008502 0,0 3.31783,0.427722 3.31783,0.427722"
id="path10917" />
<path
inkscape:connector-curvature="0"
d="m 179.01598,90.329159 c 0,0 -1.40773,23.126301 -1.40773,23.126301 0,0 -3.39164,-0.60698 -3.39164,-0.60698 0,0 1.39174,-22.995732 1.39174,-22.995732 0,0 -1.91023,-0.267064 -1.91023,-0.267064 0,0 0.38103,-6.395689 0.38103,-6.395689 0,0 1.91269,0.246577 1.91269,0.246577 0,0 0.83004,-13.70396 0.83004,-13.70396 0,0 3.4216,0.361663 3.4216,0.361663 0,0 -0.8396,13.782164 -0.8396,13.782164 0,0 3.18457,0.410542 3.18457,0.410542 0,0 -0.39205,6.486823 -0.39205,6.486823 0,0 -3.18042,-0.444645 -3.18042,-0.444645"
id="path10919" />
<path
inkscape:connector-curvature="0"
d="m 200.09638,86.544035 c 0,0 -1.9219,30.592005 -1.9219,30.592005 0,0 -3.62917,-0.64949 -3.62917,-0.64949 0,0 0.21227,-3.28285 0.21227,-3.28285 -1.54259,2.41691 -3.13133,3.47304 -4.76546,3.17868 -1.99844,-0.35998 -3.6185,-2.0112 -4.86612,-4.94632 -1.24249,-2.92301 -1.86183,-6.53106 -1.86186,-10.83321 -3e-5,-4.962328 0.70859,-8.930336 2.13088,-11.914549 1.45024,-2.995545 3.31826,-4.353123 5.61178,-4.060287 1.08848,0.139025 2.01838,0.614876 2.78825,1.428732 0.78266,0.817394 1.58372,2.160431 2.4033,4.031318 0,0 0.24627,-4.0148 0.24627,-4.0148 0,0 3.65176,0.470771 3.65176,0.470771 m -4.43909,13.904255 c -4e-5,-2.717054 -0.39303,-4.980086 -1.17745,-6.785644 -0.78246,-1.822565 -1.79014,-2.81699 -3.02082,-2.98627 -1.33305,-0.183291 -2.44658,0.70638 -3.34298,2.664066 -0.89378,1.973413 -1.33967,4.478873 -1.33964,7.520788 1e-5,2.65635 0.37157,4.89141 1.11605,6.70853 0.74629,1.8216 1.70851,2.83435 2.88872,3.03545 1.31431,0.22398 2.45545,-0.65327 3.42144,-2.63719 0.96902,-2.03362 1.45468,-4.54179 1.45468,-7.51973"
id="path10921" />
<path
inkscape:connector-curvature="0"
d="m 210.59369,62.948857 c 0,0 -1.76545,27.618349 -1.76545,27.618349 0.99306,-1.312846 1.85741,-2.168093 2.59198,-2.563345 0.77082,-0.414004 1.60707,-0.563925 2.50926,-0.448755 2.23175,0.285016 4.08604,2.008664 5.55612,5.180407 1.47685,3.163873 2.21788,7.051196 2.21795,11.650967 4e-5,5.05301 -0.84154,9.11579 -2.51812,12.17628 -1.67956,3.08741 -3.71714,4.40866 -6.1058,3.97839 -2.21018,-0.39812 -4.13144,-2.38754 -5.76892,-5.95632 0,0 -0.27204,4.13756 -0.27204,4.13756 0,0 -3.73402,-0.66825 -3.73402,-0.66825 0,0 3.51259,-55.442257 3.51259,-55.442257 0,0 3.77645,0.336974 3.77645,0.336974 m 7.18157,41.007653 c -5e-5,-2.83751 -0.43943,-5.220592 -1.31634,-7.145285 -0.87451,-1.919338 -2.00774,-2.97287 -3.3969,-3.163946 -1.49809,-0.205986 -2.73151,0.692689 -3.70333,2.690649 -0.96885,1.947466 -1.45212,4.570632 -1.45209,7.874012 3e-5,2.77133 0.41508,5.06732 1.24682,6.89164 0.83393,1.87364 1.9225,2.92662 3.26838,3.15588 1.49058,0.25395 2.74975,-0.61929 3.77469,-2.62548 1.05165,-2.00888 1.57878,-4.5697 1.57877,-7.67747"
id="path10923" />
<path
inkscape:connector-curvature="0"
d="m 232.93555,64.942427 c 0,0 -3.79307,57.735703 -3.79307,57.735703 0,0 -4.00192,-0.71619 -4.00192,-0.71619 0,0 3.76441,-57.379163 3.76441,-57.379163 0,0 4.03058,0.35965 4.03058,0.35965"
id="path10925" />
<path
inkscape:connector-curvature="0"
d="m 239.0771,110.77066 c 3e-5,2.42055 0.4512,4.48489 1.35536,6.19654 0.91925,1.71851 2.09407,2.70154 3.52717,2.94627 1.9759,0.33746 3.50088,-0.76924 4.56866,-3.32776 0,0 3.20464,3.76569 3.20464,3.76569 -1.11698,2.55798 -2.26253,4.27421 -3.43636,5.15274 -1.18257,0.89672 -2.65489,1.18453 -4.41309,0.86707 -2.77117,-0.50035 -4.9627,-2.39688 -6.58594,-5.68055 -1.61524,-3.26745 -2.41991,-7.39273 -2.41997,-12.38791 -7e-5,-5.2264 0.88505,-9.472622 2.6626,-12.752021 1.77469,-3.27557 4.03189,-4.746141 6.78148,-4.39624 2.68278,0.341472 4.81246,2.219379 6.37821,5.643695 1.59914,3.467846 2.40165,7.941666 2.40175,13.409026 -1e-5,0.57052 -0.0196,1.49453 -0.0587,2.77194 0,0 -13.96577,-2.20849 -13.96577,-2.20849 m 9.66372,-4.77749 c -0.45108,-5.21198 -1.99914,-7.996687 -4.62896,-8.357264 -2.4703,-0.338637 -4.06923,1.982786 -4.80935,6.953984 0,0 9.43831,1.40328 9.43831,1.40328"
id="path10927" />
</g>
</g>
<g
id="text7027"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
transform="matrix(0.71864924,0,0,0.71864924,121.45753,79.73219)">
<path
id="path7034"
d="m 257.77651,339.30723 c 0,0 -0.0126,-47.29911 -0.0126,-47.29911 0,0 -1.07548,0.31593 -1.07548,0.31593 -1.66284,0.48854 -2.85746,0.28792 -3.58019,-0.6041 -0.70114,-0.93919 -1.05207,-2.31685 -1.05207,-4.13168 0,-1.81444 0.35082,-3.37328 1.05164,-4.67526 0.72225,-1.34546 1.91609,-2.25144 3.57799,-2.71834 0,0 16.97387,-4.76807 16.97387,-4.76807 3.96095,-1.11259 7.12511,-0.0323 9.50921,3.22201 2.37256,3.20077 3.55893,7.47543 3.56767,12.83748 0.004,2.54895 -0.26558,5.03047 -0.80964,7.44667 -0.54488,2.41969 -1.37616,4.76094 -2.49546,7.02568 2.05523,1.5616 3.5872,3.66333 4.601,6.30634 1.03267,2.59309 1.55152,5.7504 1.5581,9.47676 0.005,2.96688 -0.35657,5.85099 -1.08626,8.65561 -0.5429,2.13369 -1.21349,3.9137 -2.01229,5.33981 -1.07439,1.98467 -2.39566,3.77328 -3.96594,5.36629 -1.57592,1.56019 -3.5546,2.76646 -5.94107,3.61797 0,0 -19.88366,7.09459 -19.88366,7.09459 -1.66745,0.59496 -2.8654,0.46776 -3.59015,-0.3841 -0.7031,-0.90081 -1.05501,-2.26426 -1.05501,-4.08924 0,-1.78498 0.36314,-3.35858 1.08856,-4.71936 0.72421,-1.39809 1.91002,-2.37974 3.55397,-2.94517 0,0 1.07785,-0.37071 1.07785,-0.37071 m 6.82963,-31.88447 c 0,0 7.39137,-2.30892 7.39137,-2.30892 2.62158,-0.8189 4.78642,-2.6695 6.50056,-5.5468 1.1532,-1.92898 1.72713,-4.06042 1.72408,-6.3978 -0.003,-2.06859 -0.54939,-3.7066 -1.64172,-4.9163 -1.09485,-1.25071 -2.83681,-1.52649 -5.23332,-0.82255 0,0 -8.7512,2.57075 -8.7512,2.57075 0,0 0.0102,17.42162 0.0102,17.42162 m 0.0173,29.5295 c 0,0 11.59226,-3.98707 11.59226,-3.98707 2.6872,-0.92424 4.5687,-2.28259 5.65417,-4.07576 0.82819,-1.3569 1.24028,-3.03056 1.23742,-5.02267 -0.003,-2.37465 -0.82491,-4.43936 -2.46842,-6.19896 -1.6491,-1.76544 -4.02284,-2.14729 -7.13269,-1.13597 0,0 -8.89303,2.89208 -8.89303,2.89208 0,0 0.0103,17.52835 0.0103,17.52835"
inkscape:connector-curvature="0" />
<path
id="path7036"
d="m 315.63395,330.78832 c 0,0 -0.008,-2.66312 -0.008,-2.66312 -1.5205,2.05858 -3.20684,3.79158 -5.06081,5.19796 -1.86182,1.44967 -3.56117,2.45156 -5.09604,3.00252 -3.35058,1.20262 -6.09378,0.54663 -8.21773,-1.98311 -2.1334,-2.5787 -3.20755,-5.87974 -3.21543,-9.8935 -0.01,-4.88257 1.33706,-9.85215 4.02708,-14.88639 2.69328,-5.04641 6.38764,-8.30943 11.05913,-9.80146 1.85895,-0.5937 3.99917,-0.90711 6.4167,-0.94198 0,0 -0.008,-2.71047 -0.008,-2.71047 -0.005,-1.69597 -0.40413,-2.95433 -1.19822,-3.7763 -0.77565,-0.82947 -2.26653,-0.90179 -4.47994,-0.2133 -1.82287,0.56707 -4.19603,1.97667 -7.12852,4.23834 -1.09717,0.83095 -1.95272,1.34329 -2.56522,1.53566 -0.83846,0.26342 -1.55663,-0.0562 -2.15389,-0.96001 -0.57751,-0.94891 -0.86835,-2.28914 -0.872,-4.01969 -0.002,-0.97796 0.0989,-1.85561 0.30293,-2.6328 0.20389,-0.77667 0.49009,-1.42758 0.85846,-1.95271 0.36795,-0.56215 1.13444,-1.3193 2.29738,-2.26995 1.54584,-1.25105 3.11705,-2.33895 4.71339,-3.2645 1.59048,-0.95927 3.02556,-1.62913 4.30677,-2.01132 3.80176,-1.13384 6.73,-0.47944 8.80217,1.94792 2.08246,2.37423 3.12878,6.17396 3.14584,11.40899 0,0 0.0755,23.20429 0.0755,23.20429 0,0 1.02221,-0.35158 1.02221,-0.35158 1.43677,-0.49417 2.45508,-0.3138 3.05789,0.53908 0.62114,0.80865 0.93435,2.052 0.94024,3.73109 0.006,1.64284 -0.29817,3.103 -0.91229,4.38174 -0.5959,1.23719 -1.61113,2.11228 -3.0486,2.62518 0,0 -7.06105,2.51942 -7.06105,2.51942 m -0.0605,-20.34496 c -2.43905,-0.0753 -4.70041,0.23148 -6.78144,0.92294 -2.51422,0.83547 -4.68502,2.69856 -6.5076,5.59502 -1.13795,1.84779 -1.70634,3.52499 -1.70292,5.02807 0.002,1.0899 0.28029,1.87848 0.83301,2.36524 1.0218,0.88744 2.41549,1.02464 4.17755,0.41484 1.49329,-0.5168 3.1709,-1.63797 5.03058,-3.3593 1.87161,-1.72078 3.52592,-3.75158 4.9653,-6.09198 0,0 -0.0145,-4.87483 -0.0145,-4.87483"
inkscape:connector-curvature="0" />
<path
id="path7038"
d="m 351.45961,282.46833 c -0.91452,-0.81047 -1.87521,-1.32503 -2.88241,-1.54283 -1.00973,-0.2537 -2.06646,-0.2094 -3.17058,0.13403 -2.19836,0.68386 -3.94926,1.92675 -5.24728,3.73026 -0.5762,0.79085 -0.86315,1.54528 -0.8602,2.26251 0.003,0.82494 0.39908,1.5073 1.18614,2.04629 0.59861,0.38285 1.93021,0.51244 3.98804,0.38963 3.75668,-0.20875 6.35384,-0.0517 7.81225,0.46829 1.90678,0.68882 3.37659,2.14965 4.41397,4.38104 1.03506,2.22658 1.55882,4.7606 1.57299,7.60629 0.0192,3.8658 -0.83398,7.40347 -2.56521,10.62256 -2.494,4.67157 -5.77005,7.74446 -9.84541,9.20702 -1.64484,0.59029 -3.1764,0.85271 -4.59341,0.78534 -1.40277,-0.0383 -2.69857,-0.38697 -3.88635,-1.04728 -0.28039,0.56921 -0.58022,1.03726 -0.89956,1.40403 -0.31959,0.36694 -0.64935,0.61132 -0.9893,0.73259 -0.90789,0.32388 -1.6396,0.0228 -2.1942,-0.90467 -0.5364,-0.97147 -0.80986,-2.79935 -0.81995,-5.48228 0,0 -0.0141,-3.75135 -0.0141,-3.75135 -0.0101,-2.68128 0.24884,-4.67325 0.77628,-5.97507 0.54553,-1.34257 1.25338,-2.15911 2.12282,-2.4506 0.69806,-0.23398 1.28355,-0.0514 1.75697,0.54708 0.47278,0.56188 0.84401,1.69794 1.114,3.40803 0.88673,1.1377 1.94787,1.87097 3.18209,2.20069 1.2306,0.29303 2.64142,0.16353 4.23059,-0.38634 2.59273,-0.89712 4.59185,-2.37089 6.00541,-4.42001 0.6686,-1.00942 1.00048,-1.93805 0.99651,-2.78707 -0.007,-1.41485 -0.49308,-2.41976 -1.46078,-3.01586 -0.96983,-0.59733 -2.9752,-0.70841 -6.03069,-0.33021 -4.58673,0.59585 -7.6827,-0.17688 -9.25518,-2.32843 -1.57769,-2.12264 -2.37589,-5.11935 -2.39063,-8.9837 -0.0152,-3.97117 0.8521,-7.54395 2.5961,-10.70925 2.35076,-4.30605 5.42069,-7.0163 9.19499,-8.14207 1.30582,-0.38941 2.55386,-0.51306 3.74464,-0.37241 1.20554,0.0997 2.35451,0.48017 3.44739,1.14045 0.34168,-0.59723 0.65654,-1.06254 0.94466,-1.39612 0.30594,-0.33858 0.58518,-0.54582 0.83779,-0.62164 0.75685,-0.22696 1.38927,0.14621 1.89787,1.11843 0.50782,0.93618 0.76793,2.70208 0.78072,5.29897 0,0 0.013,2.63267 0.013,2.63267 0.0115,2.35245 -0.12411,3.99567 -0.4071,4.9298 -0.56706,1.80018 -1.34596,2.85977 -2.33781,3.17733 -0.6686,0.21411 -1.25866,-0.004 -1.76979,-0.6537 -0.51177,-0.6508 -0.84365,-1.62508 -0.99522,-2.92244"
inkscape:connector-curvature="0" />
<path
id="path7040"
d="m 391.08767,286.09973 c 0,0 -21.40037,7.16598 -21.40037,7.16598 0.57216,2.58305 1.56606,4.48187 2.97874,5.69565 1.42536,1.20392 3.33049,1.3912 5.70856,0.56836 1.94011,-0.6713 4.49918,-2.39426 7.66518,-5.15474 1.2993,-1.12534 2.19719,-1.77197 2.69637,-1.94256 0.68118,-0.23272 1.25664,0.0618 1.72693,0.88273 0.46973,0.82008 0.70926,1.97252 0.71896,3.45813 0.009,1.35076 -0.23184,2.58617 -0.72232,3.70718 -0.65513,1.48575 -2.26858,3.26333 -4.85199,5.34083 -2.60048,2.05693 -5.11941,3.52549 -7.55489,4.39953 -4.22378,1.51581 -7.65099,0.33127 -10.26023,-3.58227 -2.60677,-3.94222 -3.93431,-9.46384 -3.97137,-16.54436 -0.0394,-7.52874 1.32903,-14.07941 4.09047,-19.62629 2.75903,-5.5472 5.92505,-8.84107 9.48957,-9.90426 2.12737,-0.63445 4.07097,-0.46394 5.83355,0.50605 1.77201,0.96099 3.08675,2.17372 3.94852,3.63907 1.21416,2.13157 2.22166,4.91277 3.02403,8.34384 0.54592,2.39326 0.82964,5.27426 0.85162,8.64573 0,0 0.0287,4.4014 0.0287,4.4014 m -5.73214,-8.54412 c -0.80672,-2.7354 -1.85391,-4.63367 -3.14346,-5.69374 -1.29366,-1.0973 -2.833,-1.37003 -4.62091,-0.81389 -1.77862,0.55329 -3.31967,1.79032 -4.62063,3.71406 -1.30548,1.89566 -2.36785,4.49783 -3.18525,7.80742 0,0 15.57025,-5.01385 15.57025,-5.01385"
inkscape:connector-curvature="0" />
<path
id="path7042"
d="m 438.50105,238.91477 c 0,0 0.33366,38.11886 0.33366,38.11886 0,0 4.5189,-1.55424 4.5189,-1.55424 1.06904,-0.36769 1.8298,-0.17153 2.28417,0.58709 0.46789,0.72139 0.70825,1.80481 0.72144,3.25104 0.0129,1.41496 -0.20635,2.65984 -0.65806,3.73554 -0.43823,1.04046 -1.19112,1.75156 -2.26052,2.13313 0,0 -13.68028,4.8812 -13.68028,4.8812 -1.1116,0.39663 -1.91344,0.23005 -2.40353,-0.50122 -0.47582,-0.76976 -0.72,-1.89742 -0.73214,-3.38218 -0.0119,-1.45226 0.21273,-2.71134 0.67337,-3.77635 0.47483,-1.10101 1.26883,-1.84247 2.38003,-2.22466 0,0 4.62789,-1.59173 4.62789,-1.59173 0,0 -0.3275,-38.34793 -0.3275,-38.34793 0,0 -4.6215,1.35761 -4.6215,1.35761 -1.10965,0.32602 -1.91007,0.11077 -2.39927,-0.64712 -0.47496,-0.79518 -0.71868,-1.93224 -0.73077,-3.41027 -0.0121,-1.47774 0.21202,-2.73263 0.67186,-3.76384 0.47403,-1.06604 1.26664,-1.75469 2.37589,-2.06634 0,0 13.65257,-3.78793 13.65257,-3.78793 1.06727,-0.29982 1.82661,-0.0734 2.27992,0.67815 0.4671,0.74675 0.70703,1.83959 0.72016,3.27935 0.0131,1.44004 -0.20565,2.68084 -0.65663,3.72319 -0.43753,1.00825 -1.18918,1.66931 -2.25681,1.98288 0,0 -4.51285,1.3257 -4.51285,1.3257"
inkscape:connector-curvature="0" />
<path
id="path7044"
d="m 455.88348,238.41146 c 0,0 0.0257,2.69003 0.0257,2.69003 0.68312,-1.72546 1.29991,-2.94833 1.85075,-3.67036 0.56356,-0.75579 1.21217,-1.24275 1.94542,-1.46144 0.62141,-0.18526 1.23821,-0.0305 1.85047,0.46347 0.61126,0.49329 1.21121,1.3268 1.79992,2.49991 0.71137,-1.56555 1.43158,-2.77864 2.16064,-3.64047 0.7408,-0.89447 1.49699,-1.45627 2.26852,-1.68643 1.53816,-0.45872 2.79097,0.0945 3.76153,1.65542 1.28104,2.03781 1.94044,5.01712 1.98128,8.9439 0,0 0.21643,20.82129 0.21643,20.82129 0.85204,-0.29305 1.48772,-0.0721 1.90821,0.66181 0.42,0.73316 0.63698,1.77834 0.65128,3.13628 0.0143,1.35811 -0.17928,2.54755 -0.58098,3.56911 -0.40256,0.99258 -1.09593,1.66483 -2.08175,2.01658 0,0 -3.92315,1.3998 -3.92315,1.3998 0,0 -0.30125,-29.5317 -0.30125,-29.5317 -0.0146,-1.42806 -0.13917,-2.37963 -0.37387,-2.85506 -0.23487,-0.47561 -0.58859,-0.64006 -1.06152,-0.49297 -0.46004,0.14313 -0.88398,0.55012 -1.27173,1.2214 -0.49476,0.91973 -1.09234,2.54691 -1.79337,4.88434 0,0 0.1894,18.96164 0.1894,18.96164 0.8724,-0.30006 1.52302,-0.079 1.95307,0.662 0.42956,0.74027 0.65113,1.79714 0.66503,3.17137 0.0139,1.37439 -0.18487,2.57895 -0.59663,3.61451 -0.4126,1.00623 -1.12276,1.68951 -2.13218,2.04968 0,0 -4.01729,1.43339 -4.01729,1.43339 0,0 -0.29261,-29.88883 -0.29261,-29.88883 -0.0139,-1.41455 -0.14767,-2.35965 -0.40153,-2.83564 -0.24053,-0.51127 -0.60278,-0.69179 -1.08713,-0.54115 -0.49887,0.15521 -0.98803,0.66317 -1.46747,1.52462 -0.4804,0.8318 -1.05239,2.39108 -1.71646,4.68046 0,0 0.18368,19.19395 0.18368,19.19395 0.89368,-0.30737 1.55989,-0.0863 1.99991,0.66201 0.45342,0.74274 0.68669,1.80921 0.70018,3.2002 0.0135,1.39115 -0.19765,2.61376 -0.6338,3.6687 -0.42312,1.02036 -1.1508,1.7151 -2.18483,2.08405 0,0 -3.90344,1.39277 -3.90344,1.39277 -1.04783,0.37387 -1.79708,0.20173 -2.24591,-0.51779 -0.46384,-0.74661 -0.70262,-1.84073 -0.71594,-3.28161 -0.013,-1.40935 0.19719,-2.62896 0.63021,-3.65799 0.43218,-1.05897 1.10915,-1.74654 2.02961,-2.06313 0,0 -0.21801,-23.27593 -0.21801,-23.27593 -0.91971,0.2877 -1.60455,0.0483 -2.05317,-0.71937 -0.44909,-0.76843 -0.68033,-1.85564 -0.69331,-3.26087 -0.013,-1.40499 0.20412,-2.61343 0.65085,-3.62449 0.43169,-1.03656 1.17158,-1.71162 2.21788,-2.0255 0,0 4.10732,-1.23196 4.10732,-1.23196"
inkscape:connector-curvature="0" />
<path
id="path7046"
d="m 490.87185,268.26248 c 0,0 -0.0238,-2.12947 -0.0238,-2.12947 -0.96684,1.56112 -2.04221,2.85176 -3.22705,3.87118 -1.18857,1.05267 -2.27482,1.75638 -3.25773,2.1092 -2.1433,0.7693 -3.90736,0.0916 -5.28616,-2.04226 -1.38398,-2.17145 -2.09463,-4.85752 -2.12832,-8.05178 -0.041,-3.88602 0.78508,-7.77051 2.47177,-11.63982 1.69085,-3.8838 4.03967,-6.29946 7.03403,-7.25585 1.19331,-0.3811 2.57099,-0.52435 4.13102,-0.43103 0,0 -0.0243,-2.16861 -0.0243,-2.16861 -0.0152,-1.35698 -0.28175,-2.38328 -0.80016,-3.07972 -0.50639,-0.70131 -1.46852,-0.83189 -2.89014,-0.3897 -1.16973,0.36389 -2.6864,1.37311 -4.5546,3.03337 -0.69844,0.60846 -1.2438,0.97457 -1.63533,1.09754 -0.5358,0.16833 -0.99846,-0.12206 -1.38767,-0.87192 -0.37678,-0.78462 -0.57264,-1.86678 -0.58731,-3.24582 -0.008,-0.77933 0.0501,-1.47376 0.17529,-2.08321 0.1251,-0.60911 0.30385,-1.1141 0.53618,-1.51496 0.23184,-0.43046 0.71786,-0.99743 1.45701,-1.70003 0.98321,-0.92446 1.98458,-1.71816 3.00395,-2.38162 1.01611,-0.69116 1.93495,-1.15887 2.7573,-1.40418 2.44294,-0.72858 4.33815,-0.0679 5.69456,1.97299 1.36388,2.00056 2.06787,5.09484 2.11563,9.28942 0,0 0.21151,18.5876 0.21151,18.5876 0,0 0.65945,-0.22681 0.65945,-0.22681 0.92741,-0.31897 1.58879,-0.11998 1.98565,0.5958 0.40854,0.68149 0.62043,1.69497 0.63598,3.04114 0.0152,1.31705 -0.17178,2.47066 -0.56118,3.4616 -0.37775,0.95836 -1.02971,1.60314 -1.95738,1.93413 0,0 -4.54817,1.62282 -4.54817,1.62282 m -0.18218,-16.27076 c -1.57456,-0.18741 -3.03025,-0.0602 -4.36568,0.38353 -1.61175,0.53558 -2.9938,1.90828 -4.14364,4.12194 -0.71713,1.41252 -1.06983,2.71889 -1.05695,3.91694 0.009,0.8687 0.19313,1.51219 0.55118,1.93012 0.66205,0.76298 1.55791,0.94835 2.68579,0.55802 0.95654,-0.33103 2.02809,-1.13477 3.2135,-2.40861 1.19412,-1.27383 2.24686,-2.80822 3.15946,-4.60277 0,0 -0.0437,-3.89917 -0.0437,-3.89917"
inkscape:connector-curvature="0" />
<path
id="path7048"
d="m 513.83107,223.64708 c 0,0 -0.0321,-2.60694 -0.0321,-2.60694 0,0 4.24921,-1.27452 4.24921,-1.27452 0.86692,-0.25998 1.48579,-0.0345 1.85799,0.67552 0.38309,0.67764 0.58268,1.66515 0.59908,2.9632 0.016,1.27005 -0.15729,2.37215 -0.52017,3.30702 -0.35202,0.90414 -0.96092,1.49191 -1.82805,1.76307 0,0 -0.61656,0.19283 -0.61656,0.19283 0,0 0.3963,31.78092 0.3963,31.78092 0.0383,3.07233 -0.1991,5.84676 -0.71289,8.32595 -0.50258,2.50775 -1.30016,4.80111 -2.39487,6.88205 -1.09848,2.08802 -2.35446,3.40535 -3.76947,3.94832 0,0 -4.20721,1.61434 -4.20721,1.61434 -0.90127,0.34581 -1.55322,0.17312 -1.95437,-0.5193 -0.389,-0.66876 -0.59138,-1.65732 -0.60684,-2.96502 -0.0158,-1.33662 0.16113,-2.49707 0.53047,-3.48063 0.38146,-0.95795 1.02342,-1.60387 1.92446,-1.93799 0,0 4.09797,-1.51959 4.09797,-1.51959 1.12773,-0.41818 1.99206,-1.47339 2.59485,-3.16418 0.6016,-1.68753 0.88825,-3.64562 0.86083,-5.87641 0,0 -0.0527,-4.28868 -0.0527,-4.28868 -0.79402,1.54526 -1.61175,2.78547 -2.45334,3.71951 -0.83173,0.93214 -1.69344,1.55874 -2.58528,1.87869 -2.53138,0.90814 -4.68912,-0.3421 -6.46539,-3.76745 -1.78479,-3.47022 -2.71501,-8.19944 -2.78452,-14.17311 -0.0698,-5.99942 0.74291,-11.29294 2.43134,-15.86475 1.6791,-4.57629 3.78635,-7.2342 6.31459,-7.98783 0.93884,-0.27979 1.83117,-0.21544 2.67743,0.19177 0.8558,0.37421 1.67211,1.10227 2.44924,2.18321 m 0.18895,16.81679 c -0.0397,-3.22458 -0.57346,-5.86075 -1.60346,-7.91342 -1.02083,-2.06186 -2.23403,-2.87672 -3.64183,-2.43909 -1.41359,0.43948 -2.61815,2.01503 -3.61171,4.73172 -0.98452,2.72148 -1.4586,5.72173 -1.41993,8.9951 0.039,3.30339 0.58054,5.9872 1.62246,8.04652 1.05092,2.02074 2.28478,2.78371 3.69937,2.29449 1.4088,-0.48717 2.59406,-2.07774 3.55781,-4.76688 0.97229,-2.71336 1.4373,-5.6943 1.39729,-8.94844"
inkscape:connector-curvature="0" />
<path
id="path7050"
d="m 540.11181,236.19855 c 0,0 -14.17571,4.74678 -14.17571,4.74678 0.39598,2.12039 1.06655,3.70874 2.0101,4.76439 0.95245,1.04897 2.21683,1.29937 3.78949,0.75521 1.28429,-0.44438 2.97443,-1.71113 5.06396,-3.7914 0.85848,-0.84849 1.45291,-1.3286 1.78475,-1.44201 0.45294,-0.15474 0.83898,0.11397 1.1584,0.80553 0.3191,0.69101 0.48673,1.64075 0.5031,2.84977 0.0149,1.09925 -0.1376,2.09168 -0.45762,2.9779 -0.4274,1.17397 -1.49195,2.53431 -3.19995,4.08586 -1.71744,1.53209 -3.38257,2.58934 -4.99438,3.16779 -2.79108,1.00165 -5.0682,-0.14146 -6.81995,-3.44725 -1.74841,-3.32527 -2.66198,-7.85839 -2.73457,-13.58545 -0.0772,-6.09039 0.78143,-11.32407 2.56808,-15.68474 1.78745,-4.3669 3.86227,-6.89434 6.21974,-7.59751 1.4088,-0.42014 2.70212,-0.19498 3.88143,0.67196 1.18643,0.86072 2.07063,1.90611 2.65495,3.13691 0.82406,1.78934 1.51493,4.09853 2.07343,6.92778 0.38048,1.97331 0.58916,4.3313 0.62629,7.07581 0,0 0.0485,3.58267 0.0485,3.58267 m -3.88051,-7.22718 c -0.55565,-2.26143 -1.2656,-3.85327 -2.13087,-4.7749 -0.86777,-0.95155 -1.89277,-1.24457 -3.07652,-0.87637 -1.17666,0.36604 -2.19027,1.29725 -3.03946,2.79568 -0.85185,1.47453 -1.5375,3.53206 -2.05595,6.17324 0,0 10.3028,-3.31765 10.3028,-3.31765"
inkscape:connector-curvature="0" />
style="display:none"
inkscape:label="Base Image"
id="layer10"
inkscape:groupmode="layer">
<g
id="text7027"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
transform="matrix(0.71864924,0,0,0.71864924,102.10269,88.99025)">
<path
id="path7034"
d="m 257.77651,339.30723 c 0,0 -0.0126,-47.29911 -0.0126,-47.29911 0,0 -1.07548,0.31593 -1.07548,0.31593 -1.66284,0.48854 -2.85746,0.28792 -3.58019,-0.6041 -0.70114,-0.93919 -1.05207,-2.31685 -1.05207,-4.13168 0,-1.81444 0.35082,-3.37328 1.05164,-4.67526 0.72225,-1.34546 1.91609,-2.25144 3.57799,-2.71834 0,0 16.97387,-4.76807 16.97387,-4.76807 3.96095,-1.11259 7.12511,-0.0323 9.50921,3.22201 2.37256,3.20077 3.55893,7.47543 3.56767,12.83748 0.004,2.54895 -0.26558,5.03047 -0.80964,7.44667 -0.54488,2.41969 -1.37616,4.76094 -2.49546,7.02568 2.05523,1.5616 3.5872,3.66333 4.601,6.30634 1.03267,2.59309 1.55152,5.7504 1.5581,9.47676 0.005,2.96688 -0.35657,5.85099 -1.08626,8.65561 -0.5429,2.13369 -1.21349,3.9137 -2.01229,5.33981 -1.07439,1.98467 -2.39566,3.77328 -3.96594,5.36629 -1.57592,1.56019 -3.5546,2.76646 -5.94107,3.61797 0,0 -19.88366,7.09459 -19.88366,7.09459 -1.66745,0.59496 -2.8654,0.46776 -3.59015,-0.3841 -0.7031,-0.90081 -1.05501,-2.26426 -1.05501,-4.08924 0,-1.78498 0.36314,-3.35858 1.08856,-4.71936 0.72421,-1.39809 1.91002,-2.37974 3.55397,-2.94517 0,0 1.07785,-0.37071 1.07785,-0.37071 m 6.82963,-31.88447 c 0,0 7.39137,-2.30892 7.39137,-2.30892 2.62158,-0.8189 4.78642,-2.6695 6.50056,-5.5468 1.1532,-1.92898 1.72713,-4.06042 1.72408,-6.3978 -0.003,-2.06859 -0.54939,-3.7066 -1.64172,-4.9163 -1.09485,-1.25071 -2.83681,-1.52649 -5.23332,-0.82255 0,0 -8.7512,2.57075 -8.7512,2.57075 0,0 0.0102,17.42162 0.0102,17.42162 m 0.0173,29.5295 c 0,0 11.59226,-3.98707 11.59226,-3.98707 2.6872,-0.92424 4.5687,-2.28259 5.65417,-4.07576 0.82819,-1.3569 1.24028,-3.03056 1.23742,-5.02267 -0.003,-2.37465 -0.82491,-4.43936 -2.46842,-6.19896 -1.6491,-1.76544 -4.02284,-2.14729 -7.13269,-1.13597 0,0 -8.89303,2.89208 -8.89303,2.89208 0,0 0.0103,17.52835 0.0103,17.52835"
inkscape:connector-curvature="0" />
<path
id="path7036"
d="m 315.63395,330.78832 c 0,0 -0.008,-2.66312 -0.008,-2.66312 -1.5205,2.05858 -3.20684,3.79158 -5.06081,5.19796 -1.86182,1.44967 -3.56117,2.45156 -5.09604,3.00252 -3.35058,1.20262 -6.09378,0.54663 -8.21773,-1.98311 -2.1334,-2.5787 -3.20755,-5.87974 -3.21543,-9.8935 -0.01,-4.88257 1.33706,-9.85215 4.02708,-14.88639 2.69328,-5.04641 6.38764,-8.30943 11.05913,-9.80146 1.85895,-0.5937 3.99917,-0.90711 6.4167,-0.94198 0,0 -0.008,-2.71047 -0.008,-2.71047 -0.005,-1.69597 -0.40413,-2.95433 -1.19822,-3.7763 -0.77565,-0.82947 -2.26653,-0.90179 -4.47994,-0.2133 -1.82287,0.56707 -4.19603,1.97667 -7.12852,4.23834 -1.09717,0.83095 -1.95272,1.34329 -2.56522,1.53566 -0.83846,0.26342 -1.55663,-0.0562 -2.15389,-0.96001 -0.57751,-0.94891 -0.86835,-2.28914 -0.872,-4.01969 -0.002,-0.97796 0.0989,-1.85561 0.30293,-2.6328 0.20389,-0.77667 0.49009,-1.42758 0.85846,-1.95271 0.36795,-0.56215 1.13444,-1.3193 2.29738,-2.26995 1.54584,-1.25105 3.11705,-2.33895 4.71339,-3.2645 1.59048,-0.95927 3.02556,-1.62913 4.30677,-2.01132 3.80176,-1.13384 6.73,-0.47944 8.80217,1.94792 2.08246,2.37423 3.12878,6.17396 3.14584,11.40899 0,0 0.0755,23.20429 0.0755,23.20429 0,0 1.02221,-0.35158 1.02221,-0.35158 1.43677,-0.49417 2.45508,-0.3138 3.05789,0.53908 0.62114,0.80865 0.93435,2.052 0.94024,3.73109 0.006,1.64284 -0.29817,3.103 -0.91229,4.38174 -0.5959,1.23719 -1.61113,2.11228 -3.0486,2.62518 0,0 -7.06105,2.51942 -7.06105,2.51942 m -0.0605,-20.34496 c -2.43905,-0.0753 -4.70041,0.23148 -6.78144,0.92294 -2.51422,0.83547 -4.68502,2.69856 -6.5076,5.59502 -1.13795,1.84779 -1.70634,3.52499 -1.70292,5.02807 0.002,1.0899 0.28029,1.87848 0.83301,2.36524 1.0218,0.88744 2.41549,1.02464 4.17755,0.41484 1.49329,-0.5168 3.1709,-1.63797 5.03058,-3.3593 1.87161,-1.72078 3.52592,-3.75158 4.9653,-6.09198 0,0 -0.0145,-4.87483 -0.0145,-4.87483"
inkscape:connector-curvature="0" />
<path
id="path7038"
d="m 351.45961,282.46833 c -0.91452,-0.81047 -1.87521,-1.32503 -2.88241,-1.54283 -1.00973,-0.2537 -2.06646,-0.2094 -3.17058,0.13403 -2.19836,0.68386 -3.94926,1.92675 -5.24728,3.73026 -0.5762,0.79085 -0.86315,1.54528 -0.8602,2.26251 0.003,0.82494 0.39908,1.5073 1.18614,2.04629 0.59861,0.38285 1.93021,0.51244 3.98804,0.38963 3.75668,-0.20875 6.35384,-0.0517 7.81225,0.46829 1.90678,0.68882 3.37659,2.14965 4.41397,4.38104 1.03506,2.22658 1.55882,4.7606 1.57299,7.60629 0.0192,3.8658 -0.83398,7.40347 -2.56521,10.62256 -2.494,4.67157 -5.77005,7.74446 -9.84541,9.20702 -1.64484,0.59029 -3.1764,0.85271 -4.59341,0.78534 -1.40277,-0.0383 -2.69857,-0.38697 -3.88635,-1.04728 -0.28039,0.56921 -0.58022,1.03726 -0.89956,1.40403 -0.31959,0.36694 -0.64935,0.61132 -0.9893,0.73259 -0.90789,0.32388 -1.6396,0.0228 -2.1942,-0.90467 -0.5364,-0.97147 -0.80986,-2.79935 -0.81995,-5.48228 0,0 -0.0141,-3.75135 -0.0141,-3.75135 -0.0101,-2.68128 0.24884,-4.67325 0.77628,-5.97507 0.54553,-1.34257 1.25338,-2.15911 2.12282,-2.4506 0.69806,-0.23398 1.28355,-0.0514 1.75697,0.54708 0.47278,0.56188 0.84401,1.69794 1.114,3.40803 0.88673,1.1377 1.94787,1.87097 3.18209,2.20069 1.2306,0.29303 2.64142,0.16353 4.23059,-0.38634 2.59273,-0.89712 4.59185,-2.37089 6.00541,-4.42001 0.6686,-1.00942 1.00048,-1.93805 0.99651,-2.78707 -0.007,-1.41485 -0.49308,-2.41976 -1.46078,-3.01586 -0.96983,-0.59733 -2.9752,-0.70841 -6.03069,-0.33021 -4.58673,0.59585 -7.6827,-0.17688 -9.25518,-2.32843 -1.57769,-2.12264 -2.37589,-5.11935 -2.39063,-8.9837 -0.0152,-3.97117 0.8521,-7.54395 2.5961,-10.70925 2.35076,-4.30605 5.42069,-7.0163 9.19499,-8.14207 1.30582,-0.38941 2.55386,-0.51306 3.74464,-0.37241 1.20554,0.0997 2.35451,0.48017 3.44739,1.14045 0.34168,-0.59723 0.65654,-1.06254 0.94466,-1.39612 0.30594,-0.33858 0.58518,-0.54582 0.83779,-0.62164 0.75685,-0.22696 1.38927,0.14621 1.89787,1.11843 0.50782,0.93618 0.76793,2.70208 0.78072,5.29897 0,0 0.013,2.63267 0.013,2.63267 0.0115,2.35245 -0.12411,3.99567 -0.4071,4.9298 -0.56706,1.80018 -1.34596,2.85977 -2.33781,3.17733 -0.6686,0.21411 -1.25866,-0.004 -1.76979,-0.6537 -0.51177,-0.6508 -0.84365,-1.62508 -0.99522,-2.92244"
inkscape:connector-curvature="0" />
<path
id="path7040"
d="m 391.08767,286.09973 c 0,0 -21.40037,7.16598 -21.40037,7.16598 0.57216,2.58305 1.56606,4.48187 2.97874,5.69565 1.42536,1.20392 3.33049,1.3912 5.70856,0.56836 1.94011,-0.6713 4.49918,-2.39426 7.66518,-5.15474 1.2993,-1.12534 2.19719,-1.77197 2.69637,-1.94256 0.68118,-0.23272 1.25664,0.0618 1.72693,0.88273 0.46973,0.82008 0.70926,1.97252 0.71896,3.45813 0.009,1.35076 -0.23184,2.58617 -0.72232,3.70718 -0.65513,1.48575 -2.26858,3.26333 -4.85199,5.34083 -2.60048,2.05693 -5.11941,3.52549 -7.55489,4.39953 -4.22378,1.51581 -7.65099,0.33127 -10.26023,-3.58227 -2.60677,-3.94222 -3.93431,-9.46384 -3.97137,-16.54436 -0.0394,-7.52874 1.32903,-14.07941 4.09047,-19.62629 2.75903,-5.5472 5.92505,-8.84107 9.48957,-9.90426 2.12737,-0.63445 4.07097,-0.46394 5.83355,0.50605 1.77201,0.96099 3.08675,2.17372 3.94852,3.63907 1.21416,2.13157 2.22166,4.91277 3.02403,8.34384 0.54592,2.39326 0.82964,5.27426 0.85162,8.64573 0,0 0.0287,4.4014 0.0287,4.4014 m -5.73214,-8.54412 c -0.80672,-2.7354 -1.85391,-4.63367 -3.14346,-5.69374 -1.29366,-1.0973 -2.833,-1.37003 -4.62091,-0.81389 -1.77862,0.55329 -3.31967,1.79032 -4.62063,3.71406 -1.30548,1.89566 -2.36785,4.49783 -3.18525,7.80742 0,0 15.57025,-5.01385 15.57025,-5.01385"
inkscape:connector-curvature="0" />
<path
id="path7042"
d="m 438.50105,238.91477 c 0,0 0.33366,38.11886 0.33366,38.11886 0,0 4.5189,-1.55424 4.5189,-1.55424 1.06904,-0.36769 1.8298,-0.17153 2.28417,0.58709 0.46789,0.72139 0.70825,1.80481 0.72144,3.25104 0.0129,1.41496 -0.20635,2.65984 -0.65806,3.73554 -0.43823,1.04046 -1.19112,1.75156 -2.26052,2.13313 0,0 -13.68028,4.8812 -13.68028,4.8812 -1.1116,0.39663 -1.91344,0.23005 -2.40353,-0.50122 -0.47582,-0.76976 -0.72,-1.89742 -0.73214,-3.38218 -0.0119,-1.45226 0.21273,-2.71134 0.67337,-3.77635 0.47483,-1.10101 1.26883,-1.84247 2.38003,-2.22466 0,0 4.62789,-1.59173 4.62789,-1.59173 0,0 -0.3275,-38.34793 -0.3275,-38.34793 0,0 -4.6215,1.35761 -4.6215,1.35761 -1.10965,0.32602 -1.91007,0.11077 -2.39927,-0.64712 -0.47496,-0.79518 -0.71868,-1.93224 -0.73077,-3.41027 -0.0121,-1.47774 0.21202,-2.73263 0.67186,-3.76384 0.47403,-1.06604 1.26664,-1.75469 2.37589,-2.06634 0,0 13.65257,-3.78793 13.65257,-3.78793 1.06727,-0.29982 1.82661,-0.0734 2.27992,0.67815 0.4671,0.74675 0.70703,1.83959 0.72016,3.27935 0.0131,1.44004 -0.20565,2.68084 -0.65663,3.72319 -0.43753,1.00825 -1.18918,1.66931 -2.25681,1.98288 0,0 -4.51285,1.3257 -4.51285,1.3257"
inkscape:connector-curvature="0" />
<path
id="path7044"
d="m 455.88348,238.41146 c 0,0 0.0257,2.69003 0.0257,2.69003 0.68312,-1.72546 1.29991,-2.94833 1.85075,-3.67036 0.56356,-0.75579 1.21217,-1.24275 1.94542,-1.46144 0.62141,-0.18526 1.23821,-0.0305 1.85047,0.46347 0.61126,0.49329 1.21121,1.3268 1.79992,2.49991 0.71137,-1.56555 1.43158,-2.77864 2.16064,-3.64047 0.7408,-0.89447 1.49699,-1.45627 2.26852,-1.68643 1.53816,-0.45872 2.79097,0.0945 3.76153,1.65542 1.28104,2.03781 1.94044,5.01712 1.98128,8.9439 0,0 0.21643,20.82129 0.21643,20.82129 0.85204,-0.29305 1.48772,-0.0721 1.90821,0.66181 0.42,0.73316 0.63698,1.77834 0.65128,3.13628 0.0143,1.35811 -0.17928,2.54755 -0.58098,3.56911 -0.40256,0.99258 -1.09593,1.66483 -2.08175,2.01658 0,0 -3.92315,1.3998 -3.92315,1.3998 0,0 -0.30125,-29.5317 -0.30125,-29.5317 -0.0146,-1.42806 -0.13917,-2.37963 -0.37387,-2.85506 -0.23487,-0.47561 -0.58859,-0.64006 -1.06152,-0.49297 -0.46004,0.14313 -0.88398,0.55012 -1.27173,1.2214 -0.49476,0.91973 -1.09234,2.54691 -1.79337,4.88434 0,0 0.1894,18.96164 0.1894,18.96164 0.8724,-0.30006 1.52302,-0.079 1.95307,0.662 0.42956,0.74027 0.65113,1.79714 0.66503,3.17137 0.0139,1.37439 -0.18487,2.57895 -0.59663,3.61451 -0.4126,1.00623 -1.12276,1.68951 -2.13218,2.04968 0,0 -4.01729,1.43339 -4.01729,1.43339 0,0 -0.29261,-29.88883 -0.29261,-29.88883 -0.0139,-1.41455 -0.14767,-2.35965 -0.40153,-2.83564 -0.24053,-0.51127 -0.60278,-0.69179 -1.08713,-0.54115 -0.49887,0.15521 -0.98803,0.66317 -1.46747,1.52462 -0.4804,0.8318 -1.05239,2.39108 -1.71646,4.68046 0,0 0.18368,19.19395 0.18368,19.19395 0.89368,-0.30737 1.55989,-0.0863 1.99991,0.66201 0.45342,0.74274 0.68669,1.80921 0.70018,3.2002 0.0135,1.39115 -0.19765,2.61376 -0.6338,3.6687 -0.42312,1.02036 -1.1508,1.7151 -2.18483,2.08405 0,0 -3.90344,1.39277 -3.90344,1.39277 -1.04783,0.37387 -1.79708,0.20173 -2.24591,-0.51779 -0.46384,-0.74661 -0.70262,-1.84073 -0.71594,-3.28161 -0.013,-1.40935 0.19719,-2.62896 0.63021,-3.65799 0.43218,-1.05897 1.10915,-1.74654 2.02961,-2.06313 0,0 -0.21801,-23.27593 -0.21801,-23.27593 -0.91971,0.2877 -1.60455,0.0483 -2.05317,-0.71937 -0.44909,-0.76843 -0.68033,-1.85564 -0.69331,-3.26087 -0.013,-1.40499 0.20412,-2.61343 0.65085,-3.62449 0.43169,-1.03656 1.17158,-1.71162 2.21788,-2.0255 0,0 4.10732,-1.23196 4.10732,-1.23196"
inkscape:connector-curvature="0" />
<path
id="path7046"
d="m 490.87185,268.26248 c 0,0 -0.0238,-2.12947 -0.0238,-2.12947 -0.96684,1.56112 -2.04221,2.85176 -3.22705,3.87118 -1.18857,1.05267 -2.27482,1.75638 -3.25773,2.1092 -2.1433,0.7693 -3.90736,0.0916 -5.28616,-2.04226 -1.38398,-2.17145 -2.09463,-4.85752 -2.12832,-8.05178 -0.041,-3.88602 0.78508,-7.77051 2.47177,-11.63982 1.69085,-3.8838 4.03967,-6.29946 7.03403,-7.25585 1.19331,-0.3811 2.57099,-0.52435 4.13102,-0.43103 0,0 -0.0243,-2.16861 -0.0243,-2.16861 -0.0152,-1.35698 -0.28175,-2.38328 -0.80016,-3.07972 -0.50639,-0.70131 -1.46852,-0.83189 -2.89014,-0.3897 -1.16973,0.36389 -2.6864,1.37311 -4.5546,3.03337 -0.69844,0.60846 -1.2438,0.97457 -1.63533,1.09754 -0.5358,0.16833 -0.99846,-0.12206 -1.38767,-0.87192 -0.37678,-0.78462 -0.57264,-1.86678 -0.58731,-3.24582 -0.008,-0.77933 0.0501,-1.47376 0.17529,-2.08321 0.1251,-0.60911 0.30385,-1.1141 0.53618,-1.51496 0.23184,-0.43046 0.71786,-0.99743 1.45701,-1.70003 0.98321,-0.92446 1.98458,-1.71816 3.00395,-2.38162 1.01611,-0.69116 1.93495,-1.15887 2.7573,-1.40418 2.44294,-0.72858 4.33815,-0.0679 5.69456,1.97299 1.36388,2.00056 2.06787,5.09484 2.11563,9.28942 0,0 0.21151,18.5876 0.21151,18.5876 0,0 0.65945,-0.22681 0.65945,-0.22681 0.92741,-0.31897 1.58879,-0.11998 1.98565,0.5958 0.40854,0.68149 0.62043,1.69497 0.63598,3.04114 0.0152,1.31705 -0.17178,2.47066 -0.56118,3.4616 -0.37775,0.95836 -1.02971,1.60314 -1.95738,1.93413 0,0 -4.54817,1.62282 -4.54817,1.62282 m -0.18218,-16.27076 c -1.57456,-0.18741 -3.03025,-0.0602 -4.36568,0.38353 -1.61175,0.53558 -2.9938,1.90828 -4.14364,4.12194 -0.71713,1.41252 -1.06983,2.71889 -1.05695,3.91694 0.009,0.8687 0.19313,1.51219 0.55118,1.93012 0.66205,0.76298 1.55791,0.94835 2.68579,0.55802 0.95654,-0.33103 2.02809,-1.13477 3.2135,-2.40861 1.19412,-1.27383 2.24686,-2.80822 3.15946,-4.60277 0,0 -0.0437,-3.89917 -0.0437,-3.89917"
inkscape:connector-curvature="0" />
<path
id="path7048"
d="m 513.83107,223.64708 c 0,0 -0.0321,-2.60694 -0.0321,-2.60694 0,0 4.24921,-1.27452 4.24921,-1.27452 0.86692,-0.25998 1.48579,-0.0345 1.85799,0.67552 0.38309,0.67764 0.58268,1.66515 0.59908,2.9632 0.016,1.27005 -0.15729,2.37215 -0.52017,3.30702 -0.35202,0.90414 -0.96092,1.49191 -1.82805,1.76307 0,0 -0.61656,0.19283 -0.61656,0.19283 0,0 0.3963,31.78092 0.3963,31.78092 0.0383,3.07233 -0.1991,5.84676 -0.71289,8.32595 -0.50258,2.50775 -1.30016,4.80111 -2.39487,6.88205 -1.09848,2.08802 -2.35446,3.40535 -3.76947,3.94832 0,0 -4.20721,1.61434 -4.20721,1.61434 -0.90127,0.34581 -1.55322,0.17312 -1.95437,-0.5193 -0.389,-0.66876 -0.59138,-1.65732 -0.60684,-2.96502 -0.0158,-1.33662 0.16113,-2.49707 0.53047,-3.48063 0.38146,-0.95795 1.02342,-1.60387 1.92446,-1.93799 0,0 4.09797,-1.51959 4.09797,-1.51959 1.12773,-0.41818 1.99206,-1.47339 2.59485,-3.16418 0.6016,-1.68753 0.88825,-3.64562 0.86083,-5.87641 0,0 -0.0527,-4.28868 -0.0527,-4.28868 -0.79402,1.54526 -1.61175,2.78547 -2.45334,3.71951 -0.83173,0.93214 -1.69344,1.55874 -2.58528,1.87869 -2.53138,0.90814 -4.68912,-0.3421 -6.46539,-3.76745 -1.78479,-3.47022 -2.71501,-8.19944 -2.78452,-14.17311 -0.0698,-5.99942 0.74291,-11.29294 2.43134,-15.86475 1.6791,-4.57629 3.78635,-7.2342 6.31459,-7.98783 0.93884,-0.27979 1.83117,-0.21544 2.67743,0.19177 0.8558,0.37421 1.67211,1.10227 2.44924,2.18321 m 0.18895,16.81679 c -0.0397,-3.22458 -0.57346,-5.86075 -1.60346,-7.91342 -1.02083,-2.06186 -2.23403,-2.87672 -3.64183,-2.43909 -1.41359,0.43948 -2.61815,2.01503 -3.61171,4.73172 -0.98452,2.72148 -1.4586,5.72173 -1.41993,8.9951 0.039,3.30339 0.58054,5.9872 1.62246,8.04652 1.05092,2.02074 2.28478,2.78371 3.69937,2.29449 1.4088,-0.48717 2.59406,-2.07774 3.55781,-4.76688 0.97229,-2.71336 1.4373,-5.6943 1.39729,-8.94844"
inkscape:connector-curvature="0" />
<path
id="path7050"
d="m 540.11181,236.19855 c 0,0 -14.17571,4.74678 -14.17571,4.74678 0.39598,2.12039 1.06655,3.70874 2.0101,4.76439 0.95245,1.04897 2.21683,1.29937 3.78949,0.75521 1.28429,-0.44438 2.97443,-1.71113 5.06396,-3.7914 0.85848,-0.84849 1.45291,-1.3286 1.78475,-1.44201 0.45294,-0.15474 0.83898,0.11397 1.1584,0.80553 0.3191,0.69101 0.48673,1.64075 0.5031,2.84977 0.0149,1.09925 -0.1376,2.09168 -0.45762,2.9779 -0.4274,1.17397 -1.49195,2.53431 -3.19995,4.08586 -1.71744,1.53209 -3.38257,2.58934 -4.99438,3.16779 -2.79108,1.00165 -5.0682,-0.14146 -6.81995,-3.44725 -1.74841,-3.32527 -2.66198,-7.85839 -2.73457,-13.58545 -0.0772,-6.09039 0.78143,-11.32407 2.56808,-15.68474 1.78745,-4.3669 3.86227,-6.89434 6.21974,-7.59751 1.4088,-0.42014 2.70212,-0.19498 3.88143,0.67196 1.18643,0.86072 2.07063,1.90611 2.65495,3.13691 0.82406,1.78934 1.51493,4.09853 2.07343,6.92778 0.38048,1.97331 0.58916,4.3313 0.62629,7.07581 0,0 0.0485,3.58267 0.0485,3.58267 m -3.88051,-7.22718 c -0.55565,-2.26143 -1.2656,-3.85327 -2.13087,-4.7749 -0.86777,-0.95155 -1.89277,-1.24457 -3.07652,-0.87637 -1.17666,0.36604 -2.19027,1.29725 -3.03946,2.79568 -0.85185,1.47453 -1.5375,3.53206 -2.05595,6.17324 0,0 10.3028,-3.31765 10.3028,-3.31765"
inkscape:connector-curvature="0" />
</g>
</g>
<g
style="display:none"
inkscape:label="Image (name)"
id="layer11"
inkscape:groupmode="layer">
<g
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
id="text14133">
<path
inkscape:connector-curvature="0"
d="m 290.77223,304.74825 c 0,0 0,32.31662 0,32.31662 0,0 5.87857,-2.13185 5.87857,-2.13185 0.40465,-0.14674 0.69438,-0.12402 0.86947,0.0681 0.17497,0.17071 0.26242,0.45829 0.26244,0.86282 -2e-5,0.38327 -0.0874,0.73459 -0.26244,1.05416 -0.17509,0.31972 -0.46482,0.5537 -0.86947,0.70197 0,0 -13.61665,4.98933 -13.61665,4.98933 -0.42075,0.15417 -0.72258,0.13428 -0.9052,-0.06 -0.18272,-0.19433 -0.27412,-0.48744 -0.27411,-0.87928 -1e-5,-0.41357 0.0914,-0.77331 0.27411,-1.07911 0.18262,-0.32736 0.48445,-0.56735 0.9052,-0.71994 0,0 6.0052,-2.17777 6.0052,-2.17777 0,0 0,-32.39447 0,-32.39447 0,0 -6.0052,1.90797 -6.0052,1.90797 -0.42075,0.13372 -0.72258,0.10996 -0.9052,-0.0714 -0.18272,-0.20317 -0.27412,-0.51163 -0.27411,-0.92526 -1e-5,-0.41355 0.0914,-0.76884 0.27411,-1.06575 0.18262,-0.31845 0.48445,-0.54373 0.9052,-0.67588 0,0 13.61665,-4.27499 13.61665,-4.27499 0.40465,-0.127 0.69438,-0.0902 0.86947,0.11043 0.17497,0.17924 0.26242,0.47109 0.26244,0.87558 -2e-5,0.40459 -0.0874,0.76232 -0.26244,1.07333 -0.17509,0.28993 -0.46482,0.49917 -0.86947,0.6277 0,0 -5.87857,1.86774 -5.87857,1.86774"
id="path14140" />
<path
inkscape:connector-curvature="0"
d="m 306.92675,306.55175 c 0,0 0,2.67986 0,2.67986 1.40003,-2.87625 2.80101,-4.53947 4.20289,-4.99685 0.84101,-0.27434 1.57685,-0.14959 2.20819,0.37302 0.63018,0.50092 1.1566,1.40903 1.57974,2.72378 0.71685,-1.69138 1.43861,-3.00815 2.16526,-3.95142 0.7378,-0.96608 1.47405,-1.5684 2.20876,-1.80813 1.14953,-0.37499 2.06265,-0.0655 2.74123,0.9259 0.89011,1.26835 1.33432,2.825 1.33433,4.6724 0,0 0,18.0741 0,18.0741 0,0 1.32918,-0.48202 1.32918,-0.48202 0.37346,-0.13543 0.64087,-0.10964 0.80249,0.0773 0.16149,0.1664 0.24221,0.4439 0.24224,0.83254 -3e-5,0.36823 -0.0808,0.70459 -0.24224,1.00917 -0.16162,0.30475 -0.42903,0.52553 -0.80249,0.66237 0,0 -2.90839,1.06568 -2.90839,1.06568 0,0 0,-20.46113 0,-20.46113 -2e-5,-1.31673 -0.24507,-2.32553 -0.73568,-3.02713 -0.49135,-0.70254 -1.05913,-0.94797 -1.70374,-0.73524 -0.58247,0.19227 -1.19764,0.75726 -1.8457,1.69604 -0.6493,0.9199 -1.38919,2.56622 -2.22024,4.94195 0,0 0,17.3523 0,17.3523 0,0 1.3415,-0.48649 1.3415,-0.48649 0.38232,-0.13865 0.65607,-0.11371 0.8215,0.0747 0.16532,0.16767 0.24796,0.44807 0.24797,0.8413 -1e-5,0.37255 -0.0826,0.71319 -0.24797,1.02208 -0.16543,0.30904 -0.43918,0.53359 -0.8215,0.67367 0,0 -2.97744,1.09098 -2.97744,1.09098 0,0 0,-20.5158 0,-20.5158 -10e-6,-1.39476 -0.25733,-2.45395 -0.77253,-3.1784 -0.50307,-0.7506 -1.0715,-1.02182 -1.70561,-0.81257 -0.58338,0.19258 -1.16121,0.68673 -1.7335,1.4832 -0.79496,1.12309 -1.63094,2.88106 -2.50825,5.27652 0,0 0,17.56098 0,17.56098 0,0 1.39351,-0.50535 1.39351,-0.50535 0.39153,-0.14199 0.67186,-0.11795 0.84127,0.072 0.16931,0.16894 0.25394,0.45233 0.25395,0.85026 -10e-6,0.377 -0.0846,0.72208 -0.25395,1.0354 -0.16941,0.31346 -0.44974,0.54191 -0.84127,0.68538 0,0 -4.455,1.63237 -4.455,1.63237 -0.39697,0.14545 -0.68175,0.12306 -0.85404,-0.0675 -0.17239,-0.19062 -0.25861,-0.47625 -0.25861,-0.85683 0,-0.40172 0.0862,-0.75019 0.25861,-1.04538 0.17229,-0.31613 0.45707,-0.54619 0.85404,-0.69015 0,0 1.40566,-0.50976 1.40566,-0.50976 0,0 0,-22.02661 0,-22.02661 0,0 -1.40566,0.46583 -1.40566,0.46583 -0.39697,0.13157 -0.68175,0.0992 -0.85404,-0.0974 -0.17239,-0.19662 -0.25861,-0.49584 -0.25861,-0.8976 0,-0.38054 0.0862,-0.72601 0.25861,-1.03629 0.17229,-0.31008 0.45707,-0.53015 0.85404,-0.66022 0,0 3.06149,-1.00289 3.06149,-1.00289"
id="path14142" />
<path
inkscape:connector-curvature="0"
d="m 341.55437,321.16678 c 0,0 0,-3.62699 0,-3.62699 -2.17583,3.87291 -4.51596,6.27757 -7.0237,7.20015 -1.83227,0.67408 -3.27105,0.43232 -4.31124,-0.73067 -1.0434,-1.1869 -1.56629,-2.91222 -1.56629,-5.17318 0,-2.48503 0.68882,-4.89489 2.06231,-7.22253 1.36795,-2.31825 3.35505,-3.9208 5.95041,-4.80953 0.69672,-0.23856 1.45188,-0.41679 2.26509,-0.53489 0.81121,-0.13772 1.68585,-0.20766 2.62342,-0.20985 0,0 0,-4.07662 0,-4.07662 -2e-5,-1.37882 -0.37947,-2.45115 -1.13965,-3.21827 -0.76194,-0.7688 -1.90808,-0.90154 -3.44237,-0.39518 -1.17945,0.38931 -2.84126,1.51364 -4.99257,3.38085 -0.3904,0.3327 -0.64074,0.51747 -0.7507,0.55406 -0.19558,0.0652 -0.3668,3.9e-4 -0.51363,-0.19445 -0.13465,-0.19895 -0.202,-0.48128 -0.20199,-0.84695 -1e-5,-0.3453 0.0612,-0.63975 0.18363,-0.88328 0.17131,-0.36105 0.86176,-1.00434 2.06822,-1.92757 1.89239,-1.46888 3.31682,-2.35756 4.27913,-2.67154 1.90441,-0.62126 3.38216,-0.31269 4.43882,0.92018 1.05329,1.20909 1.5787,2.79915 1.57872,4.773 0,0 0,16.62862 0,16.62862 0,0 1.97614,-0.71664 1.97614,-0.71664 0.36334,-0.13177 0.62098,-0.10607 0.77314,0.077 0.15205,0.16316 0.22807,0.43326 0.22809,0.81038 -2e-5,0.35731 -0.0761,0.68284 -0.22809,0.97668 -0.15216,0.294 -0.4098,0.50756 -0.77314,0.64069 0,0 -3.48375,1.2765 -3.48375,1.2765 m 0,-12.52962 c -0.69996,-0.0967 -1.44303,-0.0891 -2.22949,0.0233 -0.78834,0.11262 -1.62047,0.32041 -2.49673,0.62375 -2.20674,0.76397 -3.94122,2.16401 -5.19605,4.20202 -0.95337,1.53165 -1.43106,3.1323 -1.43105,4.79877 -1e-5,1.54453 0.36138,2.71501 1.08302,3.51015 0.73228,0.78902 1.7913,0.93038 3.17399,0.42691 1.31676,-0.47947 2.5323,-1.35466 3.64772,-2.62381 1.12362,-1.28931 2.27325,-3.09547 3.44859,-5.41563 0,0 0,-5.54541 0,-5.54541"
id="path14144" />
<path
inkscape:connector-curvature="0"
d="m 363.37657,292.52517 c 0,0 0,-4.46549 0,-4.46549 0,0 3.26058,-1.06811 3.26058,-1.06811 0.32917,-0.10781 0.56487,-0.0698 0.70734,0.11412 0.14235,0.1838 0.21351,0.45813 0.21353,0.82302 -2e-5,0.34574 -0.0711,0.65733 -0.21353,0.93491 -0.14247,0.27777 -0.37817,0.47117 -0.70734,0.58025 0,0 -1.86625,0.61846 -1.86625,0.61846 0,0 0,24.27579 0,24.27579 -2e-5,1.62032 -0.19884,3.14134 -0.59683,4.56437 -0.26563,0.94969 -0.7088,1.99622 -1.33026,3.14072 -0.62268,1.14668 -1.19079,2.01258 -1.70405,2.59672 -0.51409,0.58507 -1.20267,1.04343 -2.06685,1.37504 0,0 -4.03689,1.54904 -4.03689,1.54904 -0.34152,0.13104 -0.58649,0.1075 -0.73469,-0.0709 -0.14829,-0.15886 -0.22246,-0.42461 -0.22245,-0.79717 -1e-5,-0.37258 0.0741,-0.70475 0.22245,-0.99644 0.1482,-0.29158 0.39317,-0.50222 0.73469,-0.63197 0,0 4.08746,-1.52372 4.08746,-1.52372 0.83042,-0.31553 1.57488,-0.96721 2.23397,-1.95413 0.66885,-0.98911 1.21963,-2.27103 1.65294,-3.84567 0.24415,-0.9032 0.36616,-1.98282 0.36618,-3.23934 0,0 0,-7.30717 0,-7.30717 -1.50064,4.12055 -3.44508,6.62347 -5.84129,7.49922 -1.95926,0.71605 -3.66187,0.0829 -5.10374,-1.90912 -1.43671,-2.02462 -2.15742,-4.82517 -2.15742,-8.39501 0,-3.56981 0.72071,-6.859 2.15742,-9.85774 1.44187,-2.98939 3.14448,-4.80022 5.10374,-5.43943 2.39621,-0.78171 4.34065,0.36653 5.84129,3.42973 m 0,7.33618 c -2e-5,-2.86099 -0.5661,-5.08622 -1.70124,-6.6799 -1.12797,-1.60294 -2.48445,-2.14543 -4.0723,-1.62139 -1.59565,0.52668 -2.97118,1.98968 -4.12378,4.39343 -1.15668,2.39261 -1.73656,5.03846 -1.73655,7.93123 -1e-5,2.91249 0.57987,5.17691 1.73655,6.78901 1.1526,1.58686 2.52813,2.0886 4.12378,1.51152 1.58785,-0.57426 2.94433,-2.05505 4.0723,-4.43824 1.13514,-2.39819 1.70122,-5.02464 1.70124,-7.88566"
id="path14146" />
<path
inkscape:connector-curvature="0"
d="m 385.85611,293.37466 c 0,0 -13.55496,4.71571 -13.55496,4.71571 0.2372,3.02382 0.96927,5.26873 2.19279,6.73218 1.2295,1.435 2.74111,1.82321 4.53079,1.17154 0.99106,-0.36087 2.02623,-1.02925 3.10508,-2.00348 1.07513,-0.97087 1.94922,-2.05434 2.62395,-3.25093 0.19693,-0.351 0.36786,-0.55242 0.51284,-0.60437 0.16557,-0.0593 0.31039,0.01 0.43448,0.20823 0.12401,0.17941 0.18601,0.42768 0.18602,0.74485 -10e-6,0.31721 -0.0827,0.65493 -0.24805,1.01332 -0.49671,1.11372 -1.38342,2.31505 -2.66343,3.60658 -1.27482,1.27424 -2.59161,2.16252 -3.95089,2.66259 -2.28921,0.84219 -4.21494,0.2119 -5.77044,-1.90319 -1.55233,-2.14839 -2.33133,-5.14665 -2.33133,-8.98687 0,-3.4963 0.73037,-6.7413 2.18612,-9.72476 1.45984,-2.97335 3.25394,-4.80294 5.37664,-5.49548 2.17154,-0.70841 3.94716,-0.0213 5.33343,2.05084 1.38014,2.04439 2.0576,5.06314 2.03696,9.06324 m -1.32018,-1.9248 c -0.25953,-2.51086 -0.94567,-4.39376 -2.06125,-5.65048 -1.10911,-1.26462 -2.43784,-1.64358 -3.98896,-1.13166 -1.55879,0.51451 -2.90637,1.77483 -4.03999,3.78444 -1.13768,2.01684 -1.8481,4.41869 -2.1284,7.20193 0,0 12.2186,-4.20423 12.2186,-4.20423"
id="path14148" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="busybox"
style="display:none">
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
@@ -1154,7 +1343,7 @@
style="display:inline">
<g
sodipodi:type="inkscape:box3d"
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
id="g4222"
inkscape:perspectiveID="#perspective3054"
inkscape:corner0="0.22429094 : 0.11834566 : 0 : 1"
@@ -1162,81 +1351,40 @@
<path
sodipodi:type="inkscape:box3dside"
id="path4232"
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="13"
d="M 252.05613,280.2201 384.72319,334.81304 666.79274,224.25249 541.87079,199.19901 z" />
<path
sodipodi:type="inkscape:box3dside"
id="path4224"
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="6"
d="m 252.05613,231.66533 0,48.55477 289.81466,-81.02109 0,-33.71629 z" />
<path
sodipodi:type="inkscape:box3dside"
id="path4234"
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="11"
d="m 541.87079,165.48272 124.92195,20.6172 0,38.15257 -124.92195,-25.05348 z" />
<path
sodipodi:type="inkscape:box3dside"
id="path4226"
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="5"
d="m 252.05613,231.66533 132.66706,44.8271 282.06955,-90.39251 -124.92195,-20.6172 z" />
<path
sodipodi:type="inkscape:box3dside"
id="path4230"
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="14"
d="m 384.72319,276.49243 0,58.32061 282.06955,-110.56055 0,-38.15257 z" />
<path
sodipodi:type="inkscape:box3dside"
id="path4228"
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
inkscape:box3dsidetype="3"
d="m 252.05613,231.66533 132.66706,44.8271 0,58.32061 -132.66706,-54.59294 z" />
</g>
<g
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
id="text7405"
transform="matrix(0.86928132,0,0,0.86928132,68.726388,34.325549)">
<path
d="m 417.72187,271.67771 c 0.45964,-0.87898 0.95501,-1.58682 1.48596,-2.12375 0.55424,-0.54392 1.14379,-0.91726 1.7685,-1.12036 1.07876,-0.35057 1.95161,-0.2027 2.61991,0.44206 0.69087,0.63597 1.03586,1.98145 1.03589,4.03727 0,0 0,7.25115 0,7.25115 -3e-5,2.05593 -0.34502,3.64783 -1.03589,4.77721 -0.6683,1.09532 -1.54115,1.83155 -2.61991,2.20805 -0.98557,0.34403 -1.78059,0.29979 -2.38395,-0.13385 -0.60435,-0.43424 -1.05214,-1.48442 -1.34284,-3.15097 -0.16979,-1.1199 -0.50935,-1.91599 -1.01928,-2.38829 -0.9976,-0.92643 -2.40092,-1.46608 -4.21428,-1.61771 -1.79715,-0.16049 -3.61486,0.0653 -5.45337,0.67999 -2.29773,0.76835 -4.41987,2.04969 -6.36352,3.84723 -1.95316,1.80642 -3.68595,4.26332 -5.19549,7.37284 -1.51522,3.12131 -2.27496,6.47967 -2.27496,10.06631 0,0 0,5.77048 0,5.77048 0,4.28088 1.37679,7.34109 4.11635,9.17127 2.74635,1.8082 6.51717,1.79213 11.2834,-0.0225 2.81766,-1.07278 5.1872,-2.41185 7.11649,-4.017 1.11898,-0.92957 2.30747,-2.37459 3.56482,-4.33233 0.77171,-1.18439 1.37356,-1.98235 1.80635,-2.39529 0.43226,-0.44034 0.924,-0.76308 1.47501,-0.96835 0.98018,-0.36512 1.83884,-0.25397 2.57676,0.33193 0.73643,0.58484 1.10414,1.4594 1.10418,2.62451 -4e-5,1.16516 -0.49832,2.60348 -1.49676,4.31825 -1.4548,2.5064 -3.33495,4.76638 -5.64662,6.78184 -3.12807,2.73423 -6.61268,4.85827 -10.46302,6.36663 -4.53994,1.7785 -8.67566,2.32306 -12.39372,1.61343 -3.03035,-0.56053 -5.62935,-2.30057 -7.78841,-5.22863 -2.17061,-2.97285 -3.26028,-6.69992 -3.26028,-11.16928 0,0 0,-6.09058 0,-6.09058 0,-4.6738 0.97164,-9.36038 2.90802,-14.04301 1.95316,-4.69804 4.63314,-8.68963 8.02553,-11.97092 3.36399,-3.25375 6.90127,-5.47379 10.60692,-6.67212 2.21183,-0.71517 4.26347,-1.08158 6.15737,-1.10215 1.9092,-0.0564 3.67553,0.23986 5.30084,0.88669"
id="path7412"
inkscape:connector-curvature="0" />
<path
d="m 466.70409,284.11603 c -4e-5,3.10053 -0.70271,6.37256 -2.11204,9.826 -1.39335,3.43214 -3.49325,6.5661 -6.31177,9.40829 -2.81823,2.82872 -5.79051,4.86062 -8.92029,6.08721 -3.13367,1.22811 -6.1576,1.54546 -9.06886,0.9409 -2.93374,-0.63654 -5.18367,-2.17957 -6.73746,-4.63284 -1.56014,-2.46323 -2.3426,-5.36517 -2.34258,-8.69833 -2e-5,-3.3882 0.7941,-6.99172 2.37743,-10.79875 1.5768,-3.81873 3.82638,-7.15944 6.73687,-10.01746 2.91098,-2.84395 5.92341,-4.78983 9.0346,-5.84739 3.10768,-1.05629 6.06917,-1.12915 8.88765,-0.23026 2.81875,0.85825 4.92959,2.59617 6.34441,5.21111 1.40933,2.57869 2.112,5.4934 2.11204,8.75152 m -6.60014,2.45977 c -3e-5,-2.62464 -0.76966,-4.76021 -2.31368,-6.41189 -2.11994,-2.23039 -4.9249,-2.73963 -8.43028,-1.50955 -3.11119,1.09182 -5.72735,3.2159 -7.83793,6.37866 -2.1224,3.18051 -3.18806,6.37399 -3.18806,9.56707 0,2.61999 1.0771,4.674 3.22219,6.15574 2.13302,1.44634 4.73755,1.57892 7.8038,0.41099 3.06347,-1.16686 5.61932,-3.24823 7.67767,-6.23879 2.04698,-3.0006 3.06626,-5.78055 3.06629,-8.35223"
id="path7414"
inkscape:connector-curvature="0" />
<path
d="m 481.95196,260.34743 c 0,0 0,2.66299 0,2.66299 1.14044,-1.62655 2.38873,-2.97832 3.74374,-4.05613 1.36996,-1.0805 2.84485,-1.88838 4.42335,-2.42497 3.60997,-1.22702 6.4403,-0.76492 8.50935,1.36751 1.63094,1.69239 2.44358,4.36389 2.44362,8.02036 0,0 0,14.31302 0,14.31302 1.25392,-0.47538 2.17704,-0.46334 2.77196,0.0342 0.59383,0.47182 0.89038,1.28043 0.89041,2.42644 -3e-5,1.12112 -0.30615,2.16157 -0.91919,3.12262 -0.59495,0.93031 -1.60482,1.67385 -3.0332,2.23111 0,0 -5.40899,2.11024 -5.40899,2.11024 -1.45658,0.56826 -2.50348,0.62196 -3.13706,0.15871 -0.6149,-0.49714 -0.92274,-1.3301 -0.92273,-2.49824 -10e-6,-1.14273 0.30783,-2.18711 0.92273,-3.13192 0.61379,-0.96849 1.56213,-1.69544 2.8423,-2.18079 0,0 0,-14.66303 0,-14.66303 -3e-5,-1.69234 -0.35406,-2.80465 -1.06319,-3.33774 -0.92799,-0.68555 -2.32454,-0.70208 -4.19518,-0.0457 -1.41952,0.49817 -2.67379,1.29592 -3.76103,2.39428 -1.07036,1.069 -2.43819,3.04122 -4.10689,5.92428 0,0 0,14.70435 0,14.70435 1.60779,-0.60954 2.64191,-0.80934 3.10733,-0.60165 0.98946,0.39156 1.48317,1.32831 1.48319,2.81107 -2e-5,1.15043 -0.32236,2.22127 -0.96792,3.21388 -0.62652,0.9609 -1.69006,1.73454 -3.1945,2.32147 0,0 -7.19176,2.80576 -7.19176,2.80576 -1.54125,0.6013 -2.64914,0.6686 -3.31968,0.19933 -0.65079,-0.50439 -0.97661,-1.35781 -0.97661,-2.55958 0,-1.46302 0.50438,-2.79167 1.51105,-3.98347 0.50229,-0.58163 1.57779,-1.18477 3.22143,-1.80792 0,0 0,-19.38913 0,-19.38913 -1.35182,0.47637 -2.35332,0.45169 -3.00159,-0.0761 -0.64944,-0.52865 -0.97458,-1.38057 -0.97458,-2.55503 0,-1.17439 0.32514,-2.2388 0.97458,-3.19197 0.66916,-0.98457 1.77475,-1.73955 3.31283,-2.26462 0,0 6.01623,-2.05369 6.01623,-2.05369"
id="path7416"
inkscape:connector-curvature="0" />
<path
d="m 521.96757,254.15887 c 0,0 0,14.97869 0,14.97869 -2e-5,1.60357 0.24544,2.56759 0.73584,2.89169 0.76139,0.51136 2.1168,0.39509 4.05911,-0.34473 2.80364,-1.06789 5.37237,-2.84804 7.7113,-5.33397 0.89251,-0.95596 1.59086,-1.52809 2.09628,-1.71808 0.6958,-0.26155 1.29479,-0.1308 1.79747,0.39123 0.51917,0.51473 0.77845,1.28093 0.77848,2.2992 -3e-5,0.94726 -0.27662,1.87049 -0.83044,2.77083 -0.84992,1.44318 -2.53882,3.13186 -5.07954,5.07434 -2.54256,1.92649 -4.70294,3.24084 -6.47355,3.93476 -3.44262,1.34919 -6.0523,1.37395 -7.8094,0.0588 -1.74779,-1.35347 -2.62505,-3.50271 -2.62503,-6.44251 0,0 0,-16.5731 0,-16.5731 0,0 -2.05882,0.72547 -2.05882,0.72547 -1.37945,0.48611 -2.37084,0.49025 -2.97081,0.0103 -0.58222,-0.51196 -0.87369,-1.33661 -0.87369,-2.47329 0,-1.1119 0.29147,-2.11405 0.87369,-3.00531 0.59997,-0.92076 1.59136,-1.6167 2.97081,-2.08763 0,0 2.05882,-0.70279 2.05882,-0.70279 0,0 0,-6.79827 0,-6.79827 -2e-5,-1.81283 0.25877,-3.18359 0.77578,-4.11122 0.53464,-0.95657 1.22474,-1.57143 2.06939,-1.84519 0.82422,-0.26705 1.49131,-0.0937 2.00219,0.51875 0.52827,0.58142 0.7921,1.77073 0.79212,3.56862 0,0 0,6.74223 0,6.74223 0,0 10.18499,-3.47674 10.18499,-3.47674 1.30327,-0.44485 2.22483,-0.41358 2.76783,0.0919 0.55951,0.47491 0.83894,1.2595 0.83897,2.35437 -3e-5,1.07114 -0.27946,2.04959 -0.83897,2.93643 -0.543,0.8584 -1.46456,1.51706 -2.76783,1.97627 0,0 -10.18499,3.58889 -10.18499,3.58889"
id="path7418"
inkscape:connector-curvature="0" />
<path
d="m 559.66457,265.0724 c 0,0 0,-1.65213 0,-1.65213 -1.25166,1.42773 -2.63904,2.6702 -4.16386,3.72696 -1.5321,1.08495 -2.93048,1.87615 -4.19336,2.37115 -2.75884,1.08136 -5.01666,0.94734 -6.76281,-0.41439 -1.75549,-1.39258 -2.63677,-3.34151 -2.63676,-5.84124 -10e-6,-3.04209 1.12043,-6.27245 3.34992,-9.67368 2.23124,-3.40766 5.28286,-5.79805 9.13173,-7.17622 1.53009,-0.54785 3.28974,-0.94775 5.27514,-1.20046 0,0 0,-1.68655 0,-1.68655 -10e-6,-1.0555 -0.32465,-1.80122 -0.97488,-2.23783 -0.63528,-0.44317 -1.86051,-0.34677 -3.6824,0.29254 -1.50137,0.52689 -3.45863,1.632 -5.87999,3.32289 -0.90638,0.62348 -1.61309,1.02515 -2.1188,1.20392 -0.69244,0.24484 -1.28471,0.11428 -1.77624,-0.39265 -0.47531,-0.53707 -0.71321,-1.34616 -0.71321,-2.42667 0,-0.61067 0.085,-1.16859 0.2549,-1.67355 0.16981,-0.50463 0.4074,-0.93853 0.71264,-1.30164 0.30494,-0.38615 0.93933,-0.93193 1.90127,-1.63603 1.27817,-0.92773 2.57642,-1.75559 3.89452,-2.4841 1.31272,-0.74868 2.49627,-1.30178 3.55203,-1.66067 3.1303,-1.06398 5.53509,-0.93017 7.23033,0.38846 1.70225,1.28338 2.54998,3.55047 2.55001,6.8064 0,0 0,14.41279 0,14.41279 0,0 0.83751,-0.31753 0.83751,-0.31753 1.17673,-0.44611 2.00896,-0.43296 2.49936,0.0377 0.50538,0.4413 0.75778,1.18199 0.7578,2.2226 -2e-5,1.01802 -0.25242,1.95288 -0.7578,2.80559 -0.4904,0.82527 -1.32263,1.46729 -2.49936,1.92637 0,0 -5.78769,2.25798 -5.78769,2.25798 m 0,-12.63193 c -2.00172,0.18907 -3.85997,0.59879 -5.57212,1.23078 -2.06997,0.76411 -3.86077,2.13531 -5.36767,4.11681 -0.94116,1.26201 -1.41277,2.36215 -1.41276,3.29768 -10e-6,0.67828 0.22746,1.14181 0.68191,1.39034 0.83991,0.45156 1.98707,0.39956 3.43827,-0.15328 1.22924,-0.46827 2.61072,-1.33019 4.14246,-2.5826 1.54083,-1.25266 2.9034,-2.67625 4.08991,-4.27082 0,0 0,-3.02891 0,-3.02891"
id="path7420"
inkscape:connector-curvature="0" />
<path
d="m 585.74071,212.074 c 0,0 0,7.16504 0,7.16504 0,0 -5.51333,1.83108 -5.51333,1.83108 0,0 0,-7.22931 0,-7.22931 0,0 5.51333,-1.76681 5.51333,-1.76681 m 0.6264,12.63042 c 0,0 0,23.18845 0,23.18845 0,0 5.44909,-2.06588 5.44909,-2.06588 1.08113,-0.40987 1.84584,-0.38472 2.29649,0.0738 0.46445,0.43068 0.69642,1.14459 0.69644,2.14221 -2e-5,0.97595 -0.23199,1.86831 -0.69644,2.67799 -0.45065,0.78354 -1.21536,1.38608 -2.29649,1.80787 0,0 -15.69674,6.12386 -15.69674,6.12386 -1.14176,0.44544 -1.96206,0.45149 -2.45838,0.0164 -0.48157,-0.46425 -0.72262,-1.21347 -0.72262,-2.24714 0,-1.01118 0.24105,-1.92338 0.72262,-2.73565 0.49632,-0.83932 1.31662,-1.47551 2.45838,-1.90839 0,0 5.63166,-2.13509 5.63166,-2.13509 0,0 0,-16.55001 0,-16.55001 0,0 -3.76605,1.32704 -3.76605,1.32704 -1.11956,0.39453 -1.92723,0.3661 -2.42053,-0.0869 -0.4941,-0.47605 -0.74144,-1.22966 -0.74144,-2.26024 0,-1.00813 0.23961,-1.90826 0.71829,-2.69949 0.49335,-0.81758 1.30874,-1.42015 2.44368,-1.8076 0,0 8.38204,-2.86128 8.38204,-2.86128"
id="path7422"
inkscape:connector-curvature="0" />
<path
d="m 606.24115,217.92025 c 0,0 0,2.2023 0,2.2023 0.7802,-1.28921 1.63467,-2.3465 2.56278,-3.17247 0.93895,-0.82801 1.95053,-1.42568 3.03396,-1.79398 2.48087,-0.84324 4.42899,-0.32348 5.85479,1.54706 1.12491,1.48534 1.68574,3.74481 1.68578,6.78271 0,0 0,11.89164 0,11.89164 0.86581,-0.32825 1.50354,-0.26909 1.91468,0.17625 0.41052,0.42401 0.61557,1.11228 0.61559,2.06526 -2e-5,0.93228 -0.21169,1.78086 -0.63547,2.54657 -0.41117,0.74092 -1.10881,1.30366 -2.09499,1.6884 0,0 -3.72827,1.45454 -3.72827,1.45454 -1.00232,0.39104 -1.7223,0.37778 -2.15784,-0.0412 -0.42258,-0.44595 -0.63409,-1.15329 -0.63408,-2.12152 -1e-5,-0.94718 0.2115,-1.79617 0.63408,-2.54619 0.42194,-0.76993 1.0741,-1.32183 1.95495,-1.65578 0,0 0,-12.1648 0,-12.1648 -2e-5,-1.40401 -0.24368,-2.34454 -0.73159,-2.82219 -0.63824,-0.61483 -1.5982,-0.69805 -2.88303,-0.2472 -0.97422,0.34189 -1.83446,0.93988 -2.57973,1.79473 -0.73331,0.83097 -1.66987,2.39371 -2.81161,4.6933 0,0 0,12.16052 0,12.16052 1.10005,-0.41704 1.80804,-0.52636 2.12679,-0.32927 0.6779,0.37779 1.01628,1.18016 1.01629,2.40776 -10e-6,0.95246 -0.22094,1.82122 -0.6633,2.60717 -0.42918,0.76053 -1.15744,1.34151 -2.18696,1.74316 0,0 -4.91118,1.91603 -4.91118,1.91603 -1.0503,0.40976 -1.80479,0.403 -2.26125,-0.0218 -0.44287,-0.45256 -0.66454,-1.17471 -0.66454,-2.16594 0,-1.2067 0.34317,-2.27482 1.02834,-3.20276 0.342,-0.45242 1.07456,-0.8914 2.19484,-1.31613 0,0 0,-16.01045 0,-16.01045 -0.92144,0.32472 -1.60371,0.25352 -2.04516,-0.21486 -0.44212,-0.46902 -0.66341,-1.18822 -0.66341,-2.1571 0,-0.96882 0.22129,-1.83077 0.66341,-2.58503 0.45568,-0.77943 1.20889,-1.34815 2.25739,-1.7061 0,0 4.10874,-1.40255 4.10874,-1.40255"
id="path7424"
inkscape:connector-curvature="0" />
<path
d="m 644.42407,221.55153 c 0,0 -15.84858,5.88512 -15.84858,5.88512 0.41318,1.48367 1.14126,2.52944 2.18182,3.13726 1.04954,0.60078 2.45777,0.56327 4.21934,-0.10771 1.43657,-0.54718 3.33446,-1.76325 5.68431,-3.63848 0.96403,-0.76487 1.62951,-1.21599 1.99855,-1.3552 0.50353,-0.18992 0.92654,-0.0603 1.26941,0.38809 0.3424,0.44789 0.51345,1.10965 0.51347,1.98568 -2e-5,0.79642 -0.18329,1.54398 -0.55019,2.24339 -0.48998,0.92735 -1.68791,2.10137 -3.60292,3.52816 -1.92823,1.41649 -3.79437,2.47996 -5.59703,3.18644 -3.12825,1.22598 -5.65843,0.79547 -7.57412,-1.31227 -1.91553,-2.12687 -2.8781,-5.28997 -2.8781,-9.47861 0,-4.45685 1.04101,-8.44454 3.11177,-11.94407 2.06878,-3.49923 4.4295,-5.69213 7.07474,-6.5913 1.57787,-0.5363 3.01551,-0.58142 4.315,-0.13915 1.30587,0.43603 2.27203,1.05539 2.90198,1.85821 0.88687,1.17037 1.61767,2.74022 2.19361,4.70929 0.39141,1.37395 0.58692,3.05573 0.58694,5.04679 0,0 0,2.59836 0,2.59836 m -4.19058,-4.61262 c -0.58342,-1.55695 -1.34865,-2.60079 -2.29717,-3.13041 -0.95176,-0.55153 -2.0893,-0.59624 -3.41485,-0.13111 -1.31911,0.46293 -2.4656,1.31304 -3.43736,2.55189 -0.97511,1.22272 -1.77306,2.84546 -2.39235,4.86837 0,0 11.54173,-4.15874 11.54173,-4.15874"
id="path7426"
inkscape:connector-curvature="0" />
<path
d="m 656.45255,200.78016 c 0,0 0,3.74016 0,3.74016 1.50412,-2.33039 2.68177,-3.93837 3.53714,-4.83147 0.86415,-0.89415 1.66822,-1.46695 2.41272,-1.72004 1.14134,-0.38792 2.24384,-0.0528 3.30795,1.00108 0.72205,0.70786 1.08236,1.5579 1.08238,2.55158 -2e-5,0.84085 -0.17449,1.61893 -0.52373,2.33493 -0.33846,0.69384 -0.7508,1.12733 -1.23737,1.30005 -0.43076,0.15294 -0.88492,-0.0507 -1.36261,-0.6119 -0.47857,-0.56214 -0.90658,-0.77747 -1.28377,-0.64513 -0.49233,0.17279 -1.23248,0.95394 -2.22251,2.34704 -0.98213,1.39417 -2.21771,3.40728 -3.7102,6.0464 0,0 0,9.029 0,9.029 0,0 5.07344,-1.92346 5.07344,-1.92346 0.84781,-0.32142 1.44769,-0.26977 1.8013,0.15376 0.36448,0.39943 0.54656,1.04086 0.54657,1.92471 -1e-5,0.86465 -0.18209,1.64615 -0.54657,2.3452 -0.35361,0.67633 -0.95349,1.17981 -1.8013,1.51057 0,0 -10.8696,4.24062 -10.8696,4.24062 -0.88519,0.34534 -1.52093,0.31698 -1.90547,-0.0864 -0.37306,-0.42833 -0.55977,-1.09756 -0.55977,-2.00725 0,-0.88991 0.18671,-1.683 0.55977,-2.37855 0.38454,-0.71891 1.02028,-1.24619 1.90547,-1.58179 0,0 2.17687,-0.82531 2.17687,-0.82531 0,0 0,-14.64841 0,-14.64841 0,0 -1.31833,0.46454 -1.31833,0.46454 -0.88243,0.31097 -1.51618,0.25832 -1.89952,-0.15911 -0.37188,-0.4419 -0.55801,-1.11722 -0.55801,-2.02551 0,-0.88849 0.18613,-1.67319 0.55801,-2.35341 0.38334,-0.70305 1.01709,-1.2052 1.89952,-1.50645 0,0 4.93762,-1.6855 4.93762,-1.6855"
id="path7428"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 384.72319,334.81304 0,-58.32061 282.06955,-90.39251 0,38.15257 z"
@@ -1280,36 +1428,83 @@
inkscape:connector-curvature="0" />
</g>
<g
id="text7126"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
transform="matrix(0.57476281,0,0,0.57476281,223.85115,141.75209)">
id="text9181"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
transform="translate(0,-6)">
<path
id="path7133"
d="m 424.21557,335.98998 c 0,0 0,55.19399 0,55.19399 0,0 13.47722,-6.53014 13.47722,-6.53014 3.14312,-1.52293 5.35743,-1.94671 6.65892,-1.28244 1.33868,0.59704 2.00626,1.9199 2.00632,3.97014 -6e-5,2.00575 -0.66764,3.98769 -2.00632,5.95105 -1.30149,1.90451 -3.5158,3.6444 -6.65892,5.22447 0,0 -41.77049,20.99836 -41.77049,20.99836 -3.52678,1.77294 -6.07175,2.38156 -7.61614,1.81257 -1.50171,-0.64346 -2.25469,-2.0732 -2.25465,-4.28748 -4e-5,-2.1661 0.75294,-4.2911 2.25465,-6.36916 1.54439,-2.1417 4.08936,-4.06954 7.61614,-5.77839 0,0 14.46852,-7.01045 14.46852,-7.01045 0,0 0,-56.17707 0,-56.17707 0,0 -14.46852,5.9816 -14.46852,5.9816 -3.52678,1.45812 -6.07175,1.8395 -7.61614,1.13255 -1.50171,-0.77747 -2.25469,-2.27444 -2.25465,-4.4888 -4e-5,-2.21416 0.75294,-4.29593 2.25465,-6.23985 1.54439,-2.0036 4.08936,-3.70398 7.61614,-5.0977 0,0 41.77049,-16.43825 41.77049,-16.43825 3.14312,-1.24222 5.35743,-1.49068 6.65892,-0.75493 1.33868,0.71676 2.00626,2.09928 2.00632,4.14946 -6e-5,2.05039 -0.66764,3.99501 -2.00632,5.83877 -1.30149,1.78837 -3.5158,3.33055 -6.65892,4.62992 0,0 -13.47722,5.57177 -13.47722,5.57177"
id="path9188"
d="m 419.10683,281.89145 c 0,0 0,-2.03714 0,-2.03714 -3e-5,-0.69051 0.0779,-1.21057 0.23359,-1.56003 0.16977,-0.35378 0.38897,-0.57387 0.65748,-0.66032 0.26827,-0.0863 0.47992,-0.005 0.63507,0.24347 0.16913,0.24399 0.25367,0.71031 0.2537,1.39901 0,0 0,8.02408 0,8.02408 -3e-5,0.71176 -0.0846,1.24546 -0.2537,1.6012 -0.15515,0.3512 -0.3668,0.57235 -0.63507,0.66333 -0.24024,0.0815 -0.44526,0.0131 -0.61501,-0.20548 -0.15572,-0.22341 -0.24776,-0.64111 -0.27606,-1.25309 -0.0708,-1.90988 -0.71598,-3.41113 -1.93866,-4.50643 -1.6562,-1.51414 -3.55054,-1.92872 -5.68694,-1.23502 -1.40743,0.45705 -2.7403,1.39227 -3.99772,2.80806 -0.93873,1.03358 -1.68859,2.17121 -2.24836,3.41229 -0.97438,2.15669 -1.75138,4.45228 -2.32971,6.88527 -0.4158,1.79161 -0.62389,3.72591 -0.62389,5.80133 0,0 0,5.20043 0,5.20043 0,4.43391 1.00955,7.91984 3.01993,10.44682 1.99887,2.48909 4.30676,3.23169 6.91744,2.24404 1.55697,-0.58902 2.94224,-1.65714 4.15785,-3.20225 1.2255,-1.54498 2.40414,-3.62131 3.53637,-6.22666 0.24009,-0.57118 0.50825,-0.91111 0.80442,-1.02002 0.25361,-0.0933 0.45778,-0.0421 0.61262,0.1533 0.15472,0.19535 0.23206,0.48794 0.23209,0.87783 -3e-5,0.52756 -0.30247,1.44272 -0.90815,2.74722 -1.15807,2.54873 -2.46912,4.64404 -3.9349,6.28471 -1.45779,1.61908 -2.94333,2.71978 -4.45696,3.29882 -1.31723,0.50391 -2.6613,0.60967 -4.03252,0.31496 -1.05399,-0.23099 -1.9274,-0.63787 -2.61886,-1.22095 -0.69284,-0.58423 -1.54974,-1.68494 -2.57189,-3.30482 -1.01027,-1.65369 -1.7028,-3.26411 -2.07569,-4.82896 -0.37329,-1.59011 -0.56008,-3.4145 -0.56008,-5.47187 0,0 0,-6.06566 0,-6.06566 0,-2.93231 0.49291,-6.09055 1.47668,-9.46765 0.99585,-3.39605 2.34392,-6.18065 4.04011,-8.35311 1.70261,-2.18997 3.53533,-3.5965 5.49604,-4.22491 2.99933,-0.96119 5.55976,-0.14235 7.69078,2.4382"
inkscape:connector-curvature="0" />
<path
id="path7135"
d="m 474.35548,321.63415 c 0,0 0,3.73374 0,3.73374 1.92733,-2.9209 3.65321,-5.08391 5.18045,-6.49616 1.55867,-1.46461 3.33722,-2.61502 5.33231,-3.45245 1.68521,-0.70725 3.34395,-0.94038 4.97648,-0.70268 1.62504,0.23673 3.20599,0.94782 4.74343,2.13018 1.93051,-2.65596 3.86859,-4.82797 5.81403,-6.51986 1.97032,-1.73866 3.96513,-3.02996 5.98397,-3.87753 4.00255,-1.68024 7.21652,-1.79129 9.66328,-0.35535 3.21252,1.855 4.80754,5.38685 4.80759,10.60859 0,0 0,27.6555 0,27.6555 2.1599,-1.04652 3.75414,-1.23977 4.79061,-0.58622 1.03318,0.65163 1.54863,1.87201 1.54868,3.66267 -5e-5,1.79071 -0.5155,3.52001 -1.54868,5.19171 -1.03647,1.63695 -2.79895,3.08221 -5.29884,4.33892 0,0 -10.06477,5.05964 -10.06477,5.05964 0,0 0,-39.58935 0,-39.58935 -6e-5,-1.91719 -0.297,-3.11211 -0.89158,-3.58537 -0.59574,-0.47394 -1.50874,-0.44198 -2.74155,0.0979 -1.20189,0.52645 -2.3191,1.38607 -3.35078,2.58013 -1.3208,1.61273 -2.93391,4.26901 -4.84334,7.97938 0,0 0,25.7042 0,25.7042 2.30443,-1.11656 4.00503,-1.34235 5.11047,-0.68443 1.10187,0.6559 1.65151,1.90764 1.65157,3.75675 -6e-5,1.84918 -0.5497,3.64359 -1.65157,5.38738 -1.10544,1.70812 -2.98552,3.23082 -5.65277,4.57166 0,0 -10.74506,5.40164 -10.74506,5.40164 0,0 0,-40.91537 0,-40.91537 -3e-5,-1.93926 -0.33584,-3.14035 -1.00844,-3.60389 -0.63643,-0.52301 -1.61196,-0.49718 -2.92936,0.0798 -1.36017,0.59578 -2.70648,1.67478 -4.03875,3.23966 -1.33726,1.52808 -2.94849,4.14396 -4.83738,7.8579 0,0 0,26.58677 0,26.58677 2.46515,-1.19443 4.28396,-1.45709 5.46607,-0.79567 1.21615,0.64074 1.82269,1.91622 1.82272,3.82806 -3e-5,1.91187 -0.60657,3.7862 -1.82272,5.62767 -1.18211,1.78589 -3.1929,3.39402 -6.04626,4.82843 0,0 -10.90353,5.48129 -10.90353,5.48129 -2.9631,1.48957 -5.07979,1.93911 -6.33531,1.33808 -1.30051,-0.6268 -1.95246,-1.95499 -1.95246,-3.98291 0,-1.98383 0.63159,-3.90163 1.8916,-5.74874 1.25573,-1.88473 3.19176,-3.45934 5.79746,-4.7219 0,0 0,-32.59212 0,-32.59212 -2.6057,1.14753 -4.54173,1.36358 -5.79746,0.64022 -1.26001,-0.7257 -1.8916,-2.08142 -1.8916,-4.06531 0,-1.98377 0.65195,-3.87089 1.95246,-5.65667 1.25552,-1.80622 3.37221,-3.33638 6.33531,-4.58745 0,0 11.48372,-4.84843 11.48372,-4.84843"
id="path9190"
d="m 446.20148,293.70621 c -2e-5,4.24459 -0.90262,8.20511 -2.71524,11.89678 -1.80943,3.70706 -4.00854,6.06196 -6.60502,7.05524 -2.64397,1.01145 -4.90651,0.34117 -6.7797,-2.02677 -1.88367,-2.40388 -2.82947,-5.7829 -2.82946,-10.12702 -1e-5,-4.36681 0.94579,-8.42515 2.82946,-12.15934 1.87319,-3.73593 4.13573,-6.04253 6.7797,-6.93007 2.59648,-0.87152 4.79559,-0.0961 6.60502,2.31138 1.81262,2.38984 2.71522,5.71315 2.71524,9.9798 m -1.66979,0.59968 c -1e-5,-3.50178 -0.74267,-6.22333 -2.23301,-8.17124 -1.48384,-1.96123 -3.2946,-2.58265 -5.43761,-1.85412 -2.1569,0.73328 -4.00807,2.62575 -5.54831,5.68434 -1.53361,3.04527 -2.30304,6.35392 -2.30304,9.91552 0,3.53895 0.76943,6.29496 2.30304,8.26131 1.54024,1.9523 3.39141,2.51514 5.54831,1.69916 2.14301,-0.81073 3.95377,-2.73277 5.43761,-5.75981 1.49034,-3.04055 2.233,-6.29551 2.23301,-9.77516"
inkscape:connector-curvature="0" />
<path
id="path7137"
d="m 562.43254,335.80937 c 0,0 0,-2.71514 0,-2.71514 -2.30606,2.70118 -4.87114,5.1449 -7.70127,7.33086 -2.8552,2.24364 -5.47141,3.96922 -7.84251,5.16834 -5.20777,2.63369 -9.49858,3.09887 -12.83492,1.35082 -3.37011,-1.8053 -5.06796,-4.81824 -5.06796,-9.0251 0,-5.11964 2.15792,-10.86811 6.43245,-17.18435 4.25226,-6.28955 10.02684,-11.0544 17.24316,-14.30015 2.84824,-1.28103 6.10956,-2.36863 9.77105,-3.26347 0,0 0,-2.7717 0,-2.7717 -2e-5,-1.73462 -0.5974,-2.88455 -1.79549,-3.45139 -1.17251,-0.58209 -3.43943,-0.13856 -6.82404,1.3438 -2.80151,1.22705 -6.47056,3.52887 -11.03627,6.93278 -1.71671,1.26407 -3.05812,2.11073 -4.01962,2.53599 -1.3186,0.58329 -2.4484,0.51384 -3.38742,-0.21163 -0.9092,-0.78105 -1.36471,-2.07838 -1.36471,-3.89039 0,-1.02411 0.16274,-1.9804 0.48805,-2.86825 0.32494,-0.88687 0.77935,-1.67105 1.36269,-2.35229 0.5823,-0.71918 1.79217,-1.78262 3.62279,-3.18545 2.42508,-1.8453 4.8798,-3.52261 7.36327,-5.03345 2.46472,-1.53781 4.67946,-2.71773 6.6492,-3.54469 5.80784,-2.43811 10.23696,-2.73568 13.34237,-0.93866 3.10431,1.72985 4.6451,5.24645 4.64515,10.56249 0,0 0,23.53209 0,23.53209 0,0 1.51884,-0.73593 1.51884,-0.73593 2.12842,-1.03128 3.62972,-1.22407 4.51288,-0.58501 0.90892,0.5867 1.36241,1.72437 1.36247,3.4143 -6e-5,1.65327 -0.45355,3.23865 -1.36247,4.75951 -0.88316,1.47417 -2.38446,2.74508 -4.51288,3.81506 0,0 -10.56481,5.31101 -10.56481,5.31101 m 0,-20.75947 c -3.69168,0.82545 -7.13631,1.98253 -10.32525,3.47506 -3.87486,1.81361 -7.24447,4.57256 -10.09242,8.28457 -1.7846,2.36681 -2.68052,4.33654 -2.68052,5.89954 0,1.13321 0.43227,1.84245 1.29513,2.12718 1.59189,0.51241 3.7604,0.0971 6.49405,-1.2357 2.30727,-1.12489 4.89129,-2.94044 7.74527,-5.43602 2.85919,-2.48828 5.37788,-5.20012 7.56374,-8.13688 0,0 0,-4.97775 0,-4.97775"
id="path9192"
d="m 455.60751,276.10974 c 0,0 0,4.15113 0,4.15113 1.11495,-2.3191 2.11892,-3.99679 3.01293,-5.03692 0.89151,-1.03717 1.89309,-1.74157 3.00371,-2.11441 1.19364,-0.40064 2.27776,-0.32355 3.25343,0.22887 0.68978,0.41072 1.31055,1.27219 1.86271,2.58332 0.56341,1.28329 0.84476,2.70473 0.84478,4.26601 0,0 0,16.97118 0,16.97118 0,0 1.29949,-0.48945 1.29949,-0.48945 0.36507,-0.1375 0.62647,-0.10806 0.78443,0.0883 0.15785,0.17489 0.23676,0.46473 0.23678,0.86961 -2e-5,0.38358 -0.079,0.73322 -0.23678,1.04899 -0.15796,0.31594 -0.41936,0.54343 -0.78443,0.68248 0,0 -4.13649,1.57553 -4.13649,1.57553 -0.38266,0.14575 -0.6545,0.1203 -0.81523,-0.0767 -0.16083,-0.19703 -0.24127,-0.48927 -0.24126,-0.8766 -10e-6,-0.40886 0.0804,-0.76201 0.24126,-1.05937 0.16073,-0.31869 0.43257,-0.5501 0.81523,-0.69423 0,0 1.29268,-0.48689 1.29268,-0.48689 0,0 0,-16.56218 0,-16.56218 -2e-5,-1.9081 -0.39958,-3.37817 -1.20018,-4.41215 -0.80264,-1.05804 -1.88008,-1.35848 -3.23511,-0.89784 -1.03568,0.35211 -1.93681,1.02658 -2.70223,2.02432 -0.76727,0.97846 -1.86472,3.15928 -3.29572,6.55195 0,0 0,17.22555 0,17.22555 0,0 1.80355,-0.67931 1.80355,-0.67931 0.3784,-0.14252 0.64933,-0.11436 0.81305,0.0844 0.16361,0.17695 0.24539,0.47148 0.2454,0.88368 -1e-5,0.39049 -0.0818,0.74701 -0.2454,1.06957 -0.16372,0.32276 -0.43465,0.55619 -0.81305,0.70032 0,0 -5.22933,1.99177 -5.22933,1.99177 -0.38503,0.14665 -0.66124,0.12033 -0.82837,-0.0793 -0.16721,-0.19969 -0.25085,-0.49706 -0.25084,-0.89202 -1e-5,-0.4169 0.0836,-0.77761 0.25084,-1.08204 0.16713,-0.32618 0.44334,-0.56178 0.82837,-0.7068 0,0 1.82264,-0.68649 1.82264,-0.68649 0,0 0,-22.83855 0,-22.83855 0,0 -1.36122,0.46482 -1.36122,0.46482 -0.38448,0.13131 -0.6603,0.094 -0.82719,-0.11207 -0.16697,-0.20614 -0.2505,-0.51757 -0.25049,-0.93421 -1e-5,-0.39465 0.0835,-0.75178 0.25049,-1.07132 0.16689,-0.31929 0.44271,-0.54376 0.82719,-0.67343 0,0 2.96436,-0.99954 2.96436,-0.99954"
inkscape:connector-curvature="0" />
<path
id="path7139"
d="m 614.59063,265.59533 c 0,0 0,-3.16839 0,-3.16839 0,0 8.92,-3.76602 8.92,-3.76602 1.79996,-0.75989 3.07019,-0.80436 3.81764,-0.13827 0.76945,0.6204 1.15341,1.70749 1.15345,3.26251 -4e-5,1.52133 -0.384,2.93962 -1.15345,4.25756 -0.74745,1.27705 -2.01768,2.31128 -3.81764,3.10391 0,0 -1.28387,0.56539 -1.28387,0.56539 0,0 0,38.24265 0,38.24265 -4e-5,3.691 -0.5643,7.19606 -1.6961,10.52494 -1.11156,3.36323 -2.83663,6.66786 -5.18616,9.92382 -2.36864,3.28232 -5.0627,5.74584 -8.09096,7.38311 0,0 -9.11465,4.9279 -9.11465,4.9279 -1.97442,1.06746 -3.39649,1.31721 -4.25833,0.74277 -0.83728,-0.55472 -1.2568,-1.64096 -1.25677,-3.2576 -3e-5,-1.65259 0.41949,-3.22074 1.25677,-4.70139 0.86184,-1.45486 2.28391,-2.69907 4.25833,-3.73065 0,0 8.88239,-4.64088 8.88239,-4.64088 2.41674,-1.26271 4.28005,-3.1242 5.60022,-5.58388 1.31418,-2.44866 1.96909,-5.01935 1.96913,-7.72028 0,0 0,-5.19407 0,-5.19407 -1.71598,2.38202 -3.4802,4.41407 -5.29344,6.09337 -1.79872,1.67668 -3.66026,3.00312 -5.58571,3.97635 -5.50613,2.78311 -10.19527,2.66011 -14.02683,-0.43675 -3.88027,-3.17252 -5.83896,-8.5095 -5.83896,-15.98064 0,-7.50753 1.95869,-14.65634 5.83896,-21.38216 3.83156,-6.6772 8.5207,-11.15558 14.02683,-13.46567 2.02917,-0.85127 3.94159,-1.25068 5.73937,-1.20278 1.81231,0.002 3.52501,0.45844 5.13978,1.36515 m -0.0377,20.43011 c -4e-5,-3.91307 -1.05883,-6.83031 -3.18794,-8.76215 -2.11904,-1.95711 -4.6924,-2.28085 -7.7318,-0.95049 -3.07071,1.34414 -5.7337,3.98774 -7.9777,7.94239 -2.23376,3.97214 -3.35686,8.0001 -3.35684,12.06182 -2e-5,4.09774 1.12308,7.10481 3.35684,9.01068 2.244,1.84339 4.90699,2.00617 7.9777,0.51014 3.0394,-1.48077 5.61276,-4.16715 7.7318,-8.04946 2.12911,-3.90122 3.1879,-7.81515 3.18794,-11.76293"
id="path9194"
d="m 479.92231,267.91115 c 0,0 7.93929,-2.67701 7.93929,-2.67701 0.34358,-0.11582 0.58957,-0.0747 0.73824,0.12332 0.14856,0.19796 0.22283,0.49327 0.22285,0.88604 -2e-5,0.37214 -0.0743,0.70755 -0.22285,1.00626 -0.14867,0.29894 -0.39466,0.50704 -0.73824,0.62435 0,0 -7.93929,2.71107 -7.93929,2.71107 0,0 0,17.5856 0,17.5856 -10e-6,1.53103 0.34075,2.68285 1.02117,3.45423 0.69061,0.76528 1.69453,0.8979 3.00873,0.40072 0.98487,-0.37258 2.04735,-1.03413 3.18661,-1.9829 1.13503,-0.96594 2.01495,-1.89616 2.64195,-2.79193 0.22765,-0.35338 0.41536,-0.55761 0.56319,-0.61282 0.1818,-0.0679 0.3408,0.007 0.47704,0.22365 0.13614,0.1963 0.20421,0.46949 0.20422,0.81966 -10e-6,0.30901 -0.0738,0.62518 -0.22124,0.94859 -0.36343,0.81742 -1.25108,1.8964 -2.66748,3.24084 -1.41148,1.32553 -2.77168,2.23999 -4.07986,2.74044 -1.71013,0.65421 -3.07802,0.45516 -4.09907,-0.60245 -1.02442,-1.06109 -1.53788,-2.82281 -1.53788,-5.28253 0,0 0,-17.628 0,-17.628 0,0 -2.75879,0.94206 -2.75879,0.94206 -0.35775,0.12218 -0.61439,0.083 -0.76967,-0.11774 -0.15535,-0.20078 -0.23305,-0.50216 -0.23305,-0.90403 0,-0.38067 0.0777,-0.72418 0.23305,-1.03047 0.15528,-0.30606 0.41192,-0.51941 0.76967,-0.64007 0,0 2.75879,-0.93022 2.75879,-0.93022 0,0 0,-7.82065 0,-7.82065 0,-0.63066 0.0709,-1.10555 0.21258,-1.42455 0.14162,-0.31879 0.31857,-0.51233 0.53079,-0.58066 0.22384,-0.072 0.40634,0.006 0.54755,0.23289 0.14114,0.22719 0.21169,0.65532 0.2117,1.28446 0,0 0,7.80185 0,7.80185"
inkscape:connector-curvature="0" />
<path
id="path7141"
d="m 666.74676,266.8091 c 0,0 -27.70776,13.06906 -27.70776,13.06906 0.73837,2.30281 2.03731,3.81645 3.88909,4.54184 1.86216,0.70963 4.35196,0.30059 7.45241,-1.21076 2.51697,-1.22691 5.82649,-3.62825 9.89955,-7.1722 1.66319,-1.44005 2.80865,-2.30969 3.44295,-2.61502 0.86438,-0.41605 1.5896,-0.30651 2.17677,0.32658 0.58582,0.63176 0.87828,1.64102 0.87831,3.02886 -3e-5,1.26171 -0.31339,2.48919 -0.94115,3.68452 -0.8394,1.58764 -2.89644,3.74108 -6.19931,6.48162 -3.34379,2.74229 -6.59732,4.91806 -9.75663,6.51552 -5.52112,2.79166 -10.02299,2.76518 -13.45335,-0.14815 -3.449,-2.96066 -5.18937,-7.86937 -5.18937,-14.69893 0,-7.26688 1.88196,-13.999 5.60883,-20.13533 3.70116,-6.09897 7.89786,-10.11107 12.56687,-12.0712 2.7683,-1.1621 5.27977,-1.50678 7.54111,-1.04568 2.26409,0.44825 3.93385,1.25121 5.02007,2.40819 1.526,1.68907 2.78058,4.0385 3.76749,7.04712 0.66979,2.09858 1.00409,4.72307 1.00412,7.87745 0,0 0,4.11651 0,4.11651 m -7.20565,-6.43207 c -1.00994,-2.36059 -2.33715,-3.86869 -3.98626,-4.52066 -1.65921,-0.68816 -3.64816,-0.52771 -5.974,0.49093 -2.32324,1.01757 -4.34961,2.62703 -6.07233,4.83214 -1.73349,2.1859 -3.15565,4.98628 -4.26166,8.401 0,0 20.29425,-9.20341 20.29425,-9.20341"
id="path9196"
d="m 507.59418,284.6149 c 0,0 0,-3.63759 0,-3.63759 -1.97126,3.83544 -4.09162,6.19491 -6.36413,7.06425 -1.66058,0.63526 -2.96464,0.36062 -3.90749,-0.82933 -0.94581,-1.21408 -1.41981,-2.9567 -1.41981,-5.22501 0,-2.49306 0.62441,-4.89516 1.86942,-7.19916 1.2399,-2.29455 3.04084,-3.85692 5.3928,-4.68926 0.63133,-0.22341 1.31558,-0.38496 2.05241,-0.48487 0.73499,-0.11963 1.52741,-0.16982 2.3768,-0.15063 0,0 0,-4.08853 0,-4.08853 -10e-6,-1.38285 -0.34377,-2.46702 -1.03247,-3.25387 -0.69032,-0.78861 -1.72878,-0.94811 -3.11901,-0.47551 -1.06879,0.36336 -2.57478,1.45299 -4.52455,3.2767 -0.35386,0.32479 -0.58075,0.50443 -0.68042,0.53862 -0.17727,0.0609 -0.33247,-0.008 -0.46556,-0.20685 -0.12205,-0.20267 -0.1831,-0.48744 -0.18309,-0.85428 -1e-5,-0.34641 0.0555,-0.64039 0.16645,-0.88189 0.15527,-0.35826 0.7811,-0.98775 1.87459,-1.88616 1.71506,-1.42987 3.00589,-2.28846 3.8779,-2.5812 1.72557,-0.5792 3.06445,-0.23562 4.02174,1.02522 0.95419,1.23685 1.43016,2.84357 1.43017,4.82313 0,0 0,16.67655 0,16.67655 0,0 1.79004,-0.67421 1.79004,-0.67421 0.32911,-0.12395 0.56246,-0.0924 0.70028,0.0947 0.13772,0.16703 0.20657,0.43961 0.20659,0.8178 -2e-5,0.35829 -0.0689,0.68305 -0.20659,0.9743 -0.13782,0.29141 -0.37117,0.49978 -0.70028,0.62513 0,0 -3.15579,1.202 -3.15579,1.202 m 0,-12.56621 c -0.63412,-0.11291 -1.30734,-0.12215 -2.01989,-0.0274 -0.71427,0.095 -1.46826,0.28452 -2.26226,0.56886 -1.99974,0.71618 -3.57168,2.08121 -4.70901,4.09722 -0.86414,1.51494 -1.29713,3.10995 -1.29712,4.78174 -1e-5,1.54949 0.32757,2.73182 0.98167,3.54568 0.66373,0.80794 1.62356,0.97347 2.87668,0.4994 1.19328,-0.45143 2.29477,-1.30203 3.30546,-2.54998 1.01808,-1.26789 2.05966,-3.05352 3.12447,-5.35395 0,0 0,-5.5616 0,-5.5616"
inkscape:connector-curvature="0" />
<path
id="path9198"
d="m 523.702,240.54258 c 0,0 0,6.34723 0,6.34723 0,0 -1.89662,0.61903 -1.89662,0.61903 0,0 0,-6.36799 0,-6.36799 0,0 1.89662,-0.59827 1.89662,-0.59827 m 0.0457,12.59128 c 0,0 0,22.8716 0,22.8716 0,0 4.98692,-1.8783 4.98692,-1.8783 0.30944,-0.11656 0.52886,-0.0834 0.65845,0.0995 0.1295,0.16349 0.19423,0.42857 0.19424,0.79531 -10e-6,0.34743 -0.0648,0.66158 -0.19424,0.94246 -0.12959,0.28103 -0.34901,0.48047 -0.65845,0.59834 0,0 -11.367,4.32951 -11.367,4.32951 -0.31177,0.11876 -0.53541,0.0856 -0.67072,-0.0998 -0.13538,-0.1854 -0.20308,-0.45583 -0.20308,-0.81118 0,-0.37512 0.0677,-0.69681 0.20308,-0.96503 0.13531,-0.28782 0.35895,-0.49043 0.67072,-0.60786 0,0 5.09683,-1.9197 5.09683,-1.9197 0,0 0,-20.43068 0,-20.43068 0,0 -3.77547,1.28922 -3.77547,1.28922 -0.31037,0.106 -0.53819,0.0657 -0.68325,-0.12114 -0.13477,-0.19038 -0.20218,-0.46292 -0.20217,-0.81751 -10e-6,-0.37425 0.0674,-0.70236 0.20217,-0.98427 0.1347,-0.28172 0.36252,-0.47665 0.68325,-0.58482 0,0 5.05872,-1.70573 5.05872,-1.70573"
inkscape:connector-curvature="0" />
<path
id="path9200"
d="m 537.32375,248.55623 c 0,0 0,3.62744 0,3.62744 0.85157,-1.98473 1.61868,-3.41372 2.30203,-4.28987 0.68168,-0.87397 1.4478,-1.45313 2.29768,-1.73844 0.91383,-0.30672 1.74417,-0.19946 2.49175,0.31998 0.5287,0.38502 1.00462,1.16228 1.42804,2.33096 0.43214,1.14498 0.64797,2.40056 0.64799,3.76807 0,0 0,14.86484 0,14.86484 0,0 0.99719,-0.37559 0.99719,-0.37559 0.28024,-0.10556 0.48092,-0.0691 0.6022,0.1094 0.1212,0.15971 0.18179,0.41693 0.18181,0.77172 -2e-5,0.33612 -0.0606,0.63926 -0.18181,0.90944 -0.12128,0.27032 -0.32196,0.45885 -0.6022,0.56559 0,0 -3.17247,1.20835 -3.17247,1.20835 -0.29322,0.11168 -0.5015,0.0781 -0.62464,-0.10097 -0.1232,-0.17913 -0.18482,-0.43824 -0.18481,-0.77724 -1e-5,-0.35784 0.0616,-0.66361 0.18481,-0.91724 0.12314,-0.27233 0.33142,-0.46371 0.62464,-0.57415 0,0 0.99087,-0.37321 0.99087,-0.37321 0,0 0,-14.50223 0,-14.50223 -2e-5,-1.67078 -0.30634,-2.97304 -0.91998,-3.90831 -0.61502,-0.95611 -1.44029,-1.25912 -2.47769,-0.90646 -0.79254,0.26945 -1.48185,0.82573 -2.06717,1.66956 -0.58655,0.82666 -1.42522,2.69155 -2.51824,5.6018 0,0 0,15.05244 0,15.05244 0,0 1.37768,-0.5189 1.37768,-0.5189 0.28918,-0.10892 0.49624,-0.0731 0.62138,0.10749 0.12507,0.16149 0.18759,0.4224 0.18759,0.7828 0,0.34142 -0.0626,0.64972 -0.18759,0.9249 -0.12514,0.27533 -0.3322,0.46807 -0.62138,0.57821 0,0 -3.99187,1.52045 -3.99187,1.52045 -0.2936,0.11182 -0.50419,0.0772 -0.6316,-0.10415 -0.12747,-0.18138 -0.19123,-0.44453 -0.19122,-0.78936 -1e-5,-0.36399 0.0637,-0.67542 0.19122,-0.93422 0.12741,-0.27783 0.338,-0.47202 0.6316,-0.5826 0,0 1.39041,-0.52369 1.39041,-0.52369 0,0 0,-19.9511 0,-19.9511 0,0 -1.03851,0.35462 -1.03851,0.35462 -0.29323,0.10015 -0.50356,0.0572 -0.63081,-0.1291 -0.12731,-0.18629 -0.19099,-0.46138 -0.19098,-0.82516 -1e-5,-0.3446 0.0636,-0.6533 0.19098,-0.92606 0.12725,-0.27258 0.33758,-0.4583 0.63081,-0.5572 0,0 2.26229,-0.76281 2.26229,-0.76281"
inkscape:connector-curvature="0" />
<path
id="path9202"
d="m 564.37221,251.7564 c 0,0 -11.52429,4.14925 -11.52429,4.14925 0.20161,2.94498 0.82381,5.14921 1.86378,6.61012 1.04511,1.43359 2.33011,1.85933 3.85161,1.28373 0.8426,-0.31877 1.72276,-0.93491 2.64009,-1.84687 0.91423,-0.90885 1.65753,-1.93361 2.23132,-3.07472 0.16748,-0.33476 0.31285,-0.525 0.43614,-0.57085 0.14082,-0.0524 0.26398,0.0197 0.36951,0.21624 0.10547,0.17832 0.15819,0.42155 0.1582,0.72977 -10e-6,0.30823 -0.0703,0.63376 -0.21096,0.97672 -0.42243,1.06628 -1.1765,2.20515 -2.26499,3.41901 -1.08401,1.1971 -2.20364,2.01781 -3.35931,2.45991 -1.94615,0.7445 -3.58314,0.0702 -4.90528,-2.03457 -1.31936,-2.13686 -1.98142,-5.07429 -1.98141,-8.80462 -10e-6,-3.39624 0.62072,-6.52518 1.85798,-9.37715 1.24083,-2.84225 2.7659,-4.56294 4.57045,-5.16871 1.84627,-0.61971 3.35606,0.10399 4.53489,2.16125 1.17368,2.03023 1.74983,4.98512 1.73227,8.87149 m -1.12272,-1.91239 c -0.22071,-2.44805 -0.8042,-4.29941 -1.75284,-5.55586 -0.94308,-1.26387 -2.07284,-1.67412 -3.3916,-1.2258 -1.32518,0.45052 -2.47072,1.63227 -3.43432,3.54863 -0.96701,1.92314 -1.57083,4.23377 -1.80906,6.92855 0,0 10.38782,-3.69552 10.38782,-3.69552"
inkscape:connector-curvature="0" />
<path
id="path9204"
d="m 573.09946,236.49319 c 0,0 0,5.67252 0,5.67252 1.39118,-3.11706 2.42557,-5.15863 3.10733,-6.13505 0.68836,-0.9944 1.32057,-1.58768 1.89705,-1.78148 0.62514,-0.2101 1.20313,0.0452 1.73426,0.76436 0.5383,0.69735 0.80705,1.27409 0.80706,1.73125 -1e-5,0.33412 -0.0538,0.63396 -0.16121,0.89952 -0.0993,0.24531 -0.22754,0.39508 -0.38483,0.4493 -0.0829,0.0286 -0.15328,0.0265 -0.21128,-0.006 -0.0581,-0.0505 -0.16584,-0.21587 -0.32347,-0.49644 -0.29063,-0.51722 -0.54416,-0.85379 -0.76045,-1.00936 -0.21651,-0.15563 -0.42901,-0.19806 -0.6375,-0.12711 -0.4593,0.15634 -1.01569,0.73516 -1.66979,1.73811 -0.64734,1.00259 -1.77765,3.30323 -3.39717,6.91661 0,0 0,12.30832 0,12.30832 0,0 4.70377,-1.77166 4.70377,-1.77166 0.25887,-0.0975 0.44243,-0.0607 0.55085,0.11042 0.10835,0.15336 0.16252,0.39774 0.16253,0.73321 -10e-6,0.3178 -0.0542,0.60323 -0.16253,0.85632 -0.10842,0.25321 -0.29198,0.42911 -0.55085,0.52771 0,0 -8.39069,3.19589 -8.39069,3.19589 -0.25883,0.0986 -0.44449,0.0704 -0.55681,-0.0846 -0.11237,-0.17308 -0.16857,-0.42152 -0.16857,-0.74529 0,-0.30576 0.0519,-0.57716 0.15561,-0.81415 0.11232,-0.25813 0.3023,-0.43758 0.56977,-0.53836 0,0 2.61311,-0.98462 2.61311,-0.98462 0,0 0,-18.76796 0,-18.76796 0,0 -1.99291,0.68053 -1.99291,0.68053 -0.25825,0.0882 -0.44347,0.0437 -0.55552,-0.13359 -0.11211,-0.17732 -0.16818,-0.43671 -0.16818,-0.77807 0,-0.32336 0.0517,-0.61034 0.15524,-0.8609 0.11207,-0.25331 0.3016,-0.42495 0.56846,-0.51496 0,0 3.06672,-1.03405 3.06672,-1.03405"
inkscape:connector-curvature="0" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer12"
inkscape:label="Image (name)#1"
style="display:inline">
<g
transform="translate(-12.096774,4.8387096)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
id="text8052">
<path
inkscape:connector-curvature="0"
d="m 423.74041,363.69642 c 0,0 0,46.13338 0,46.13338 0,0 6.60461,-3.25288 6.60461,-3.25288 0.45439,-0.22379 0.77972,-0.20169 0.97632,0.0662 0.19645,0.2373 0.29465,0.64448 0.29467,1.22164 -2e-5,0.54682 -0.0983,1.05125 -0.29467,1.51342 -0.1966,0.46245 -0.52193,0.80673 -0.97632,1.03282 0,0 -15.30796,7.61688 -15.30796,7.61688 -0.47355,0.23563 -0.81328,0.21827 -1.01883,-0.0526 -0.20568,-0.27092 -0.30855,-0.68631 -0.30855,-1.24607 0,-0.59083 0.10283,-1.10805 0.30855,-1.55154 0.20555,-0.47431 0.54528,-0.8281 1.01883,-1.06133 0,0 6.75525,-3.32706 6.75525,-3.32706 0,0 0,-46.25099 0,-46.25099 0,0 -6.75525,2.91925 -6.75525,2.91925 -0.47355,0.20469 -0.81328,0.18057 -1.01883,-0.0726 -0.20568,-0.2843 -0.30855,-0.72199 -0.30855,-1.31286 0,-0.59081 0.10283,-1.1013 0.30855,-1.53138 0.20555,-0.46081 0.54528,-0.79235 1.01883,-0.99466 0,0 15.30796,-6.53778 15.30796,-6.53778 0.45439,-0.19399 0.77972,-0.15067 0.97632,0.13006 0.19645,0.25021 0.29465,0.66381 0.29467,1.24095 -2e-5,0.57722 -0.0983,1.09044 -0.29467,1.53969 -0.1966,0.41925 -0.52193,0.72704 -0.97632,0.92336 0,0 -6.60461,2.85414 -6.60461,2.85414"
id="path8059" />
<path
inkscape:connector-curvature="0"
d="m 441.87507,365.74833 c 0,0 0,3.82064 0,3.82064 1.56942,-4.14583 3.13954,-6.56174 4.71033,-7.25855 0.94216,-0.41791 1.76641,-0.26368 2.47352,0.46081 0.70573,0.69355 1.29521,1.97053 1.76901,3.83012 0.80259,-2.43288 1.61058,-4.33197 2.42395,-5.69892 0.82577,-1.39965 1.64969,-2.28097 2.47179,-2.64567 1.28608,-0.57047 2.30749,-0.15871 3.06643,1.23159 0.99542,1.77766 1.49212,3.97984 1.49215,6.61017 0,0 0,25.73386 0,25.73386 0,0 1.48605,-0.73191 1.48605,-0.73191 0.41748,-0.20562 0.71641,-0.17807 0.89705,0.0826 0.18051,0.23133 0.27074,0.62358 0.27077,1.17682 -3e-5,0.52419 -0.0903,1.00579 -0.27077,1.44493 -0.18064,0.43941 -0.47957,0.76299 -0.89705,0.97072 0,0 -3.25208,1.61816 -3.25208,1.61816 0,0 0,-29.13622 0,-29.13622 -2e-5,-1.87499 -0.27409,-3.30363 -0.82284,-4.287 -0.54964,-0.98475 -1.18481,-1.31612 -1.90601,-0.99255 -0.65174,0.29248 -1.34015,1.11693 -2.06542,2.47501 -0.72674,1.33131 -1.55495,3.70059 -2.48533,7.11235 0,0 0,24.72225 0,24.72225 0,0 1.50177,-0.73965 1.50177,-0.73965 0.42794,-0.21077 0.73434,-0.18473 0.9195,0.078 0.18502,0.23308 0.27752,0.62963 0.27753,1.18976 -1e-5,0.53068 -0.0926,1.01883 -0.27753,1.46455 -0.18516,0.446 -0.49156,0.77547 -0.9195,0.9884 0,0 -3.33363,1.65874 -3.33363,1.65874 0,0 0,-29.23324 0,-29.23324 -2e-5,-1.9874 -0.2882,-3.4883 -0.86521,-4.50391 -0.56348,-1.05333 -1.20023,-1.42148 -1.91062,-1.10276 -0.65361,0.29333 -1.30108,1.01634 -1.94239,2.17018 -0.89094,1.6268 -1.82798,4.16023 -2.81147,7.60421 0,0 0,25.03641 0,25.03641 0,0 1.56211,-0.76936 1.56211,-0.76936 0.43885,-0.21614 0.75303,-0.1917 0.94289,0.0732 0.18975,0.23484 0.28458,0.63583 0.28459,1.20303 -1e-5,0.53738 -0.0948,1.03223 -0.28459,1.48482 -0.18986,0.45281 -0.50404,0.78839 -0.94289,1.00674 0,0 -4.99523,2.48551 -4.99523,2.48551 -0.44529,0.22157 -0.76474,0.19977 -0.95802,-0.0659 -0.19339,-0.26571 -0.29012,-0.67 -0.29011,-1.21278 -1e-5,-0.57291 0.0967,-1.07295 0.29011,-1.5 0.19328,-0.45695 0.51273,-0.7951 0.95802,-1.01441 0,0 1.5765,-0.77645 1.5765,-0.77645 0,0 0,-31.40719 0,-31.40719 0,0 -1.5765,0.71024 -1.5765,0.71024 -0.44529,0.20064 -0.76474,0.16379 -0.95802,-0.11096 -0.19339,-0.27476 -0.29012,-0.69868 -0.29011,-1.27164 -1e-5,-0.54273 0.0967,-1.03824 0.29011,-1.48635 0.19328,-0.44782 0.51273,-0.77089 0.95802,-0.96927 0,0 3.43312,-1.52911 3.43312,-1.52911"
id="path8061" />
<path
inkscape:connector-curvature="0"
d="m 480.58851,385.41099 c 0,0 0,-5.15657 0,-5.15657 -2.4262,5.5798 -5.03657,9.079 -7.835,10.47699 -2.04539,1.02181 -3.65191,0.72721 -4.81363,-0.89204 -1.16547,-1.65345 -1.74963,-4.09108 -1.74963,-7.30887 0,-3.53667 0.76951,-6.98913 2.30362,-10.34663 1.52759,-3.34322 3.746,-5.68753 6.64239,-7.03536 0.77733,-0.36171 1.61976,-0.63945 2.52684,-0.83351 0.90473,-0.2221 1.88006,-0.34939 2.92541,-0.38255 0,0 0,-5.7958 0,-5.7958 -10e-6,-1.96032 -0.42307,-3.47297 -1.27068,-4.53986 -0.84967,-1.0694 -2.12799,-1.22244 -3.8396,-0.45447 -1.31604,0.59057 -3.17073,2.24198 -5.57246,4.96625 -0.43594,0.48573 -0.71549,0.75657 -0.83828,0.81214 -0.21842,0.0989 -0.40964,0.0122 -0.57362,-0.26044 -0.15038,-0.27883 -0.22559,-0.67845 -0.22559,-1.19879 0,-0.49136 0.0684,-0.91228 0.20509,-1.26267 0.19131,-0.51914 0.96238,-1.45616 2.30947,-2.80749 2.11245,-2.14861 3.70209,-3.45689 4.77581,-3.9332 2.12442,-0.94235 3.77243,-0.54918 4.95058,1.17099 1.17422,1.68619 1.75986,3.93017 1.75988,6.73612 0,0 0,23.63827 0,23.63827 0,0 2.20228,-1.08466 2.20228,-1.08466 0.40486,-0.19939 0.6919,-0.17146 0.86143,0.0837 0.1694,0.2268 0.25409,0.60813 0.25411,1.1441 -2e-5,0.5078 -0.0847,0.973 -0.25411,1.39571 -0.16953,0.42296 -0.45657,0.73515 -0.86143,0.9366 0,0 -3.88288,1.93203 -3.88288,1.93203 m 0,-17.81357 c -0.78041,-0.11482 -1.60899,-0.0799 -2.48605,0.10525 -0.87928,0.18568 -1.80752,0.50815 -2.78512,0.968 -2.46256,1.15841 -4.39871,3.20675 -5.7998,6.14762 -1.06467,2.21091 -1.5982,4.50451 -1.59819,6.87592 -1e-5,2.19789 0.40363,3.85127 1.20954,4.95824 0.81771,1.09778 2.0001,1.26287 3.54357,0.49962 1.46955,-0.72669 2.82587,-2.01263 4.07022,-3.85519 1.2533,-1.87118 2.53536,-4.47776 3.84583,-7.81547 0,0 0,-7.88399 0,-7.88399"
id="path8063" />
<path
inkscape:connector-curvature="0"
d="m 504.87507,344.02572 c 0,0 0,-6.33756 0,-6.33756 0,0 3.62149,-1.61301 3.62149,-1.61301 0.3655,-0.16275 0.62721,-0.11582 0.78538,0.14085 0.15805,0.25653 0.23705,0.64362 0.23708,1.1613 -3e-5,0.49052 -0.0791,0.93476 -0.23708,1.33282 -0.15817,0.39836 -0.41988,0.67984 -0.78538,0.84448 0,0 -2.07259,0.93375 -2.07259,0.93375 0,0 0,34.44897 0,34.44897 -2e-5,2.29935 -0.22086,4.46439 -0.66296,6.49712 -0.29508,1.35662 -0.78741,2.85674 -1.47785,4.50202 -0.69188,1.64858 -1.32318,2.89693 -1.89359,3.74358 -0.57137,0.84805 -1.33675,1.52227 -2.29743,2.02265 0,0 -4.48946,2.33825 -4.48946,2.33825 -0.37994,0.19787 -0.65249,0.17289 -0.81737,-0.0754 -0.16499,-0.22051 -0.24751,-0.5954 -0.2475,-1.12453 -10e-6,-0.52918 0.0825,-1.0035 0.2475,-1.42286 0.16488,-0.41919 0.43743,-0.72673 0.81737,-0.92267 0,0 4.54567,-2.30289 4.54567,-2.30289 0.92315,-0.47614 1.75064,-1.42648 2.48315,-2.84967 0.74328,-1.42651 1.3553,-3.26448 1.83674,-5.51382 0.27125,-1.28999 0.40681,-2.82626 0.40683,-4.60956 0,0 0,-10.37051 0,-10.37051 -1.66739,5.89686 -3.82848,9.5134 -6.49259,10.83562 -2.17909,1.08151 -4.07329,0.23861 -5.67781,-2.54346 -1.59915,-2.82914 -2.40148,-6.78447 -2.40147,-11.85622 -1e-5,-5.07169 0.80232,-9.76707 2.40147,-14.07131 1.60452,-4.29012 3.49872,-6.9134 5.67781,-7.88005 2.66411,-1.18176 4.8252,0.38981 6.49259,4.69207 m 0,10.41166 c -2e-5,-4.06038 -0.62896,-7.20112 -1.89031,-9.42839 -1.2536,-2.24103 -2.76147,-2.97007 -4.52696,-2.17791 -1.77459,0.79633 -3.30477,2.91596 -4.5872,6.36538 -1.28721,3.43436 -1.9326,7.21098 -1.9326,11.32033 0,4.13734 0.64539,7.33529 1.9326,9.58763 1.28243,2.21618 2.81261,2.88369 4.5872,2.01202 1.76549,-0.86719 3.27336,-3.01347 4.52696,-6.43279 1.26135,-3.44025 1.89029,-7.18583 1.89031,-11.24627"
id="path8065" />
<path
inkscape:connector-curvature="0"
d="m 529.8044,344.5465 c 0,0 -15.0214,7.10051 -15.0214,7.10051 0.26314,4.28098 1.07521,7.44153 2.43223,9.47797 1.36338,1.99553 3.03922,2.49762 5.02283,1.51672 1.09819,-0.54306 2.24508,-1.52324 3.44017,-2.93807 1.19075,-1.4097 2.1587,-2.97236 2.90578,-4.68889 0.21804,-0.50344 0.40728,-0.79413 0.56779,-0.87226 0.1833,-0.0892 0.34362,0.005 0.48099,0.28146 0.13728,0.25029 0.2059,0.60007 0.20592,1.0494 -2e-5,0.44938 -0.0915,0.9304 -0.27459,1.44334 -0.5499,1.59345 -1.53164,3.3235 -2.9491,5.19415 -1.412,1.84634 -2.87079,3.14741 -4.37696,3.89984 -2.53736,1.26758 -4.67257,0.436 -6.39774,-2.51332 -1.72209,-2.9974 -2.58645,-7.22532 -2.58645,-12.67216 0,-4.95904 0.81041,-9.58368 2.42538,-13.8585 1.61912,-4.25962 3.60849,-6.90642 5.96144,-7.9502 2.40629,-1.06738 4.37322,-0.14533 5.90848,2.75024 1.52811,2.85581 2.27809,7.11232 2.25523,12.77977 m -1.46157,-2.68694 c -0.28736,-3.54969 -1.04714,-6.19709 -2.28263,-7.94479 -1.22853,-1.7594 -2.70063,-2.2574 -4.41951,-1.48616 -1.72781,0.77534 -3.22184,2.60204 -4.47892,5.48524 -1.26182,2.8941 -2.04987,6.32176 -2.36082,10.27751 0,0 13.54188,-6.3318 13.54188,-6.3318"
id="path8067" />
</g>
</g>
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
transform="matrix(0.83545525,0,0,0.83545525,52.49863,66.133437)"
transform="matrix(0.71809444,0,0,0.71809444,82.080142,116.02377)"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium"
id="text10963">
<path

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 272 KiB

View File

@@ -1,11 +1,11 @@
:title: Terms
:title: Glossary
:description: Definitions of terms used in Docker documentation
:keywords: concepts, documentation, docker, containers
Terms
=====
Glossary
========
Definitions of terms used in Docker documentation.
@@ -14,5 +14,9 @@ Contents:
.. toctree::
:maxdepth: 1
fundamentals
filesystem
layer
image
container

View File

@@ -0,0 +1,40 @@
:title: Layers
:description: Organizing the Docker Root File System
:keywords: containers, lxc, concepts, explanation, image, container
Layers
======
In a traditional Linux boot, the kernel first mounts the root
:ref:`filesystem_def` as read-only, checks its integrity, and then
switches the whole rootfs volume to read-write mode.
.. _layer_def:
Layer
.....
When Docker mounts the rootfs, it starts read-only, as in a tradtional
Linux boot, but then, instead of changing the file system to
read-write mode, it takes advantage of a `union mount
<http://en.wikipedia.org/wiki/Union_mount>`_ to add a read-write file
system *over* the read-only file system. In fact there may be multiple
read-only file systems stacked on top of each other. We think of each
one of these file systems as a **layer**.
.. image:: images/docker-filesystems-multilayer.png
At first, the top read-write layer has nothing in it, but any time a
process creates a file, this happens in the top layer. And if
something needs to update an existing file in a lower layer, then the
file gets copied to the upper layer and changes go into the copy. The
version of the file on the lower layer cannot be seen by the
applications anymore, but it is there, unchanged.
.. _ufs_def:
Union File System
.................
We call the union of the read-write layer and all the read-only layers
a **union file system**.

View File

@@ -17,7 +17,8 @@ This documentation has the following resources:
commandline/index
contributing/index
api/index
faq
terms/index
faq
.. image:: concepts/images/lego_docker.jpg

View File

@@ -51,7 +51,7 @@ For example:
.. code-block:: bash
# Run docker in daemon mode
sudo <path to>/docker -H 0.0.0.0:5555 &
sudo <path to>/docker -H 0.0.0.0:5555 -d &
# Download a base image
docker -H :5555 pull base
@@ -61,7 +61,7 @@ on both tcp and a unix socket
.. code-block:: bash
# Run docker in daemon mode
sudo <path to>/docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock
sudo <path to>/docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock -d &
# Download a base image
docker pull base
# OR

View File

@@ -1,25 +1,27 @@
:title: Docker Builder
:description: Docker Builder specifes a simple DSL which allows you to automate the steps you would normally manually take to create an image.
:keywords: builder, docker, Docker Builder, automation, image creation
:title: Dockerfiles for Images
:description: Dockerfiles use a simple DSL which allows you to automate the steps you would normally manually take to create an image.
:keywords: builder, docker, Dockerfile, automation, image creation
==============
Docker Builder
==============
==================
Dockerfile Builder
==================
**Docker can act as a builder** and read instructions from a text
Dockerfile to automate the steps you would otherwise make manually to
create an image. Executing ``docker build`` will run your steps and
commit them along the way, giving you a final image.
.. contents:: Table of Contents
Docker Builder specifes a simple DSL which allows you to automate the steps you
would normally manually take to create an image. Docker Build will run your
steps and commit them along the way, giving you a final image.
1. Usage
========
To build an image from a source repository, create a description file called `Dockerfile`
at the root of your repository. This file will describe the steps to assemble
the image.
To build an image from a source repository, create a description file
called ``Dockerfile`` at the root of your repository. This file will
describe the steps to assemble the image.
Then call `docker build` with the path of your source repository as argument:
Then call ``docker build`` with the path of your source repository as
argument:
``docker build .``
@@ -28,7 +30,7 @@ build succeeds:
``docker build -t shykes/myapp .``
Docker will run your steps one-by-one, committing the result if necessary,
Docker will run your steps one-by-one, committing the result if necessary,
before finally outputting the ID of your new image.
2. Format
@@ -36,124 +38,172 @@ before finally outputting the ID of your new image.
The Dockerfile format is quite simple:
``instruction arguments``
::
The Instruction is not case-sensitive, however convention is for them to be
# Comment
INSTRUCTION arguments
The Instruction is not case-sensitive, however convention is for them to be
UPPERCASE in order to distinguish them from arguments more easily.
Dockerfiles are evaluated in order, therefore the first instruction must be
`FROM` in order to specify the base image from which you are building.
Docker evaluates the instructions in a Dockerfile in order. **The first
instruction must be `FROM`** in order to specify the base image from
which you are building.
Docker will ignore lines in Dockerfiles prefixed with "`#`", so you may add
comment lines. A comment marker in the rest of the line will be treated as an
argument.
Docker will ignore **comment lines** *beginning* with ``#``. A comment
marker anywhere in the rest of the line will be treated as an argument.
2. Instructions
3. Instructions
===============
Docker builder comes with a set of instructions, described below.
Here is the set of instructions you can use in a ``Dockerfile`` for
building images.
2.1 FROM
3.1 FROM
--------
``FROM <image>``
The `FROM` instruction sets the base image for subsequent instructions. As such,
a valid Dockerfile must have it as its first instruction.
The ``FROM`` instruction sets the :ref:`base_image_def` for subsequent
instructions. As such, a valid Dockerfile must have ``FROM`` as its
first instruction.
`FROM` can be included multiple times within a single Dockerfile in order to
create multiple images. Simply make a note of the last image id output by the
commit before each new `FROM` command.
``FROM`` must be the first non-comment instruction in the
``Dockerfile``.
2.2 MAINTAINER
``FROM`` can appear multiple times within a single Dockerfile in order
to create multiple images. Simply make a note of the last image id
output by the commit before each new ``FROM`` command.
3.2 MAINTAINER
--------------
``MAINTAINER <name>``
The `MAINTAINER` instruction allows you to set the Author field of the generated
images.
The ``MAINTAINER`` instruction allows you to set the *Author* field of
the generated images.
2.3 RUN
3.3 RUN
-------
``RUN <command>``
The `RUN` instruction will execute any commands on the current image and commit
the results. The resulting committed image will be used for the next step in the
Dockerfile.
The ``RUN`` instruction will execute any commands on the current image
and commit the results. The resulting committed image will be used for
the next step in the Dockerfile.
Layering `RUN` instructions and generating commits conforms to the
core concepts of Docker where commits are cheap and containers can be created
from any point in an image's history, much like source control.
Layering ``RUN`` instructions and generating commits conforms to the
core concepts of Docker where commits are cheap and containers can be
created from any point in an image's history, much like source
control.
2.4 CMD
3.4 CMD
-------
``CMD <command>``
The `CMD` instruction sets the command to be executed when running the image.
This is functionally equivalent to running
`docker commit -run '{"Cmd": <command>}'` outside the builder.
The ``CMD`` instruction sets the command to be executed when running
the image. This is functionally equivalent to running ``docker commit
-run '{"Cmd": <command>}'`` outside the builder.
.. note::
Don't confuse `RUN` with `CMD`. `RUN` actually runs a command and commits
the result; `CMD` does not execute anything at build time, but specifies the
intended command for the image.
Don't confuse `RUN` with `CMD`. `RUN` actually runs a
command and commits the result; `CMD` does not execute anything at
build time, but specifies the intended command for the image.
2.5 EXPOSE
3.5 EXPOSE
----------
``EXPOSE <port> [<port>...]``
The `EXPOSE` instruction sets ports to be publicly exposed when running the
image. This is functionally equivalent to running
`docker commit -run '{"PortSpecs": ["<port>", "<port2>"]}'` outside the builder.
The ``EXPOSE`` instruction sets ports to be publicly exposed when
running the image. This is functionally equivalent to running ``docker
commit -run '{"PortSpecs": ["<port>", "<port2>"]}'`` outside the
builder.
2.6 ENV
3.6 ENV
-------
``ENV <key> <value>``
The `ENV` instruction sets the environment variable `<key>` to the value
`<value>`. This value will be passed to all future ``RUN`` instructions. This is
functionally equivalent to prefixing the command with `<key>=<value>`
The ``ENV`` instruction sets the environment variable ``<key>`` to the
value ``<value>``. This value will be passed to all future ``RUN``
instructions. This is functionally equivalent to prefixing the command
with ``<key>=<value>``
.. note::
The environment variables will persist when a container is run from the resulting image.
The environment variables will persist when a container is run
from the resulting image.
2.7 ADD
3.7 ADD
-------
``ADD <src> <dest>``
The `ADD` instruction will copy new files from <src> and add them to the container's filesystem at path `<dest>`.
The ``ADD`` instruction will copy new files from <src> and add them to
the container's filesystem at path ``<dest>``.
`<src>` must be the path to a file or directory relative to the source directory being built (also called the
context of the build) or a remote file URL.
``<src>`` must be the path to a file or directory relative to the
source directory being built (also called the *context* of the build) or
a remote file URL.
`<dest>` is the path at which the source will be copied in the destination container.
``<dest>`` is the path at which the source will be copied in the
destination container.
The copy obeys the following rules:
If `<src>` is a directory, the entire directory is copied, including filesystem metadata.
* If ``<src>`` is a URL and ``<dest>`` does not end with a trailing slash,
then a file is downloaded from the URL and copied to ``<dest>``.
* If ``<src>`` is a URL and ``<dest>`` does end with a trailing slash,
then the filename is inferred from the URL and the file is downloaded to
``<dest>/<filename>``. For instance, ``ADD http://example.com/foobar /``
would create the file ``/foobar``. The URL must have a nontrivial path
so that an appropriate filename can be discovered in this case
(``http://example.com`` will not work).
* If ``<src>`` is a directory, the entire directory is copied,
including filesystem metadata.
* If ``<src>``` is a tar archive in a recognized compression format
(identity, gzip, bzip2 or xz), it is unpacked as a directory.
If `<src>` is a tar archive in a recognized compression format (identity, gzip, bzip2 or xz), it
is unpacked as a directory.
When a directory is copied or unpacked, it has the same behavior as
``tar -x``: the result is the union of
When a directory is copied or unpacked, it has the same behavior as 'tar -x': the result is the union of
a) whatever existed at the destination path and b) the contents of the source tree, with conflicts resolved
in favor of b on a file-by-file basis.
1. whatever existed at the destination path and
2. the contents of the source tree,
If `<src>` is any other kind of file, it is copied individually along with its metadata. In this case,
if `<dst>` ends with a trailing slash '/', it will be considered a directory and the contents of `<src>`
will be written at `<dst>/base(<src>)`.
If `<dst>` does not end with a trailing slash, it will be considered a regular file and the contents
of `<src>` will be written at `<dst>`.
with conflicts resolved in favor of 2) on a file-by-file basis.
If `<dest>` doesn't exist, it is created along with all missing directories in its path. All new
files and directories are created with mode 0700, uid and gid 0.
* If ``<src>`` is any other kind of file, it is copied individually
along with its metadata. In this case, if ``<dst>`` ends with a
trailing slash ``/``, it will be considered a directory and the
contents of ``<src>`` will be written at ``<dst>/base(<src>)``.
* If ``<dst>`` does not end with a trailing slash, it will be
considered a regular file and the contents of ``<src>`` will be
written at ``<dst>``.
* If ``<dest>`` doesn't exist, it is created along with all missing
directories in its path. All new files and directories are created
with mode 0700, uid and gid 0.
3. Dockerfile Examples
3.8 ENTRYPOINT
--------------
``ENTRYPOINT ["/bin/echo"]``
The ``ENTRYPOINT`` instruction adds an entry command that will not be
overwritten when arguments are passed to docker run, unlike the
behavior of ``CMD``. This allows arguments to be passed to the
entrypoint. i.e. ``docker run <image> -d`` will pass the "-d" argument
to the entrypoint.
3.9 VOLUME
----------
``VOLUME ["/data"]``
The ``VOLUME`` instruction will add one or more new volumes to any
container created from the image.
4. Dockerfile Examples
======================
.. code-block:: bash
@@ -161,14 +211,14 @@ files and directories are created with mode 0700, uid and gid 0.
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
MAINTAINER Guillaume J. Charmes "guillaume@dotcloud.com"
# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y inotify-tools nginx apache2 openssh-server
.. code-block:: bash
@@ -176,12 +226,12 @@ files and directories are created with mode 0700, uid and gid 0.
# Firefox over VNC
#
# VERSION 0.3
FROM ubuntu
# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get install -y x11vnc xvfb firefox
RUN mkdir /.vnc
@@ -189,7 +239,7 @@ files and directories are created with mode 0700, uid and gid 0.
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'
EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]

View File

@@ -1,27 +1,75 @@
:title: Working With Repositories
:description: Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind Docker, and user repositories.
:description: Repositories allow users to share images.
:keywords: repo, repositiores, usage, pull image, push image, image, documentation
.. _working_with_the_repository:
Working with the Repository
===========================
Working with Repositories
=========================
A *repository* is a hosted collection of tagged :ref:`images
<image_def>` that together create the file system for a container. The
repository's name is a tag that indicates the provenance of the
repository, i.e. who created it and where the original copy is
located.
Top-level repositories and user repositories
--------------------------------------------
You can find one or more repositories hosted on a *registry*. There
can be an implicit or explicit host name as part of the repository
tag. The implicit registry is located at ``index.docker.io``, the home
of "top-level" repositories and the Central Index. This registry may
also include public "user" repositories.
Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind
Docker, and user repositories.
So Docker is not only a tool for creating and managing your own
:ref:`containers <container_def>` -- **Docker is also a tool for
sharing**. The Docker project provides a Central Registry to host
public repositories, namespaced by user, and a Central Index which
provides user authentication and search over all the public
repositories. You can host your own Registry too! Docker acts as a
client for these services via ``docker search, pull, login`` and
``push``.
* Top-level repositories can easily be recognized by not having a ``/`` (slash) in their name. These repositories can
generally be trusted.
* User repositories always come in the form of ``<username>/<repo_name>``. This is what your published images will look like.
* User images are not checked, it is therefore up to you whether or not you trust the creator of this image.
Top-level, User, and Your Own Repositories
------------------------------------------
There are two types of public repositories: *top-level* repositories
which are controlled by the Docker team, and *user* repositories
created by individual contributors.
Find public images available on the index
-----------------------------------------
* Top-level repositories can easily be recognized by **not** having a
``/`` (slash) in their name. These repositories can generally be
trusted.
* User repositories always come in the form of
``<username>/<repo_name>``. This is what your published images will
look like if you push to the public Central Registry.
* Only the authenticated user can push to their *username* namespace
on the Central Registry.
* User images are not checked, it is therefore up to you whether or
not you trust the creator of this image.
Right now (version 0.5), private repositories are only possible by
hosting `your own registry
<https://github.com/dotcloud/docker-registry>`_. To push or pull to a
repository on your own registry, you must prefix the tag with the
address of the registry's host, like this:
.. code-block:: bash
# Tag to create a repository with the full registry location.
# The location (e.g. localhost.localdomain:5000) becomes
# a permanent part of the repository name
docker tag 0u812deadbeef localhost.localdomain:5000/repo_name
# Push the new repository to its home location on localhost
docker push localhost.localdomain:5000/repo_name
Once a repository has your registry's host name as part of the tag,
you can push and pull it like any other repository, but it will
**not** be searchable (or indexed at all) in the Central Index, and
there will be no user name checking performed. Your registry will
function completely independently from the Central Index.
Find public images available on the Central Index
-------------------------------------------------
Seach by name, namespace or description
@@ -37,68 +85,48 @@ Download them simply by their name
docker pull <value>
Very similarly you can search for and browse the index online on https://index.docker.io
Very similarly you can search for and browse the index online on
https://index.docker.io
Connecting to the repository
----------------------------
Connecting to the Central Registry
----------------------------------
You can create a user on the central docker repository online, or by running
You can create a user on the central Docker Index online, or by running
.. code-block:: bash
docker login
This will prompt you for a username, which will become a public
namespace for your public repositories.
If your username does not exist it will prompt you to also enter a password and your e-mail address. It will then
automatically log you in.
If your username does not exist it will prompt you to also enter a
password and your e-mail address. It will then automatically log you
in.
Committing a container to a named image
---------------------------------------
In order to commit to the repository it is required to have committed your container to an image with your namespace.
In order to commit to the repository it is required to have committed
your container to an image within your username namespace.
.. code-block:: bash
# for example docker commit $CONTAINER_ID dhrp/kickassapp
docker commit <container_id> <your username>/<some_name>
docker commit <container_id> <username>/<repo_name>
Pushing a container to the repository
-----------------------------------------
Pushing a container to its repository
-------------------------------------
In order to push an image to the repository you need to have committed your container to a named image (see above)
In order to push an image to its repository you need to have committed
your container to a named image (see above)
Now you can commit this image to the repository
.. code-block:: bash
# for example docker push dhrp/kickassapp
docker push <image-name>
Changing the server to connect to
----------------------------------
When you are running your own index and/or registry, You can change the server the docker client will connect to.
Variable
^^^^^^^^
.. code-block:: sh
DOCKER_INDEX_URL
Setting this environment variable on the docker server will change the URL docker index.
This address is used in commands such as ``docker login``, ``docker push`` and ``docker pull``.
The docker daemon doesn't need to be restarted for this parameter to take effect.
Example
^^^^^^^
.. code-block:: sh
docker -d &
export DOCKER_INDEX_URL="https://index.docker.io"
docker push <username>/<repo_name>

View File

@@ -1 +1 @@
Thatcher Penskens <thatcher@dotcloud.com>
Thatcher Peskens <thatcher@dotcloud.com>

View File

@@ -68,19 +68,18 @@
<div style="float: right" class="pull-right">
<ul class="nav">
<li id="nav-introduction"><a href="http://www.docker.io/">Introduction</a></li>
<li id="nav-introduction"><a href="http://www.docker.io/" title="Docker Homepage">Home</a></li>
<li id="nav-about"><a href="http://www.docker.io/about/" title="About">About</a></li>
<li id="nav-community"><a href="http://www.docker.io/community/" title="Community">Community</a></li>
<li id="nav-gettingstarted"><a href="http://www.docker.io/gettingstarted/">Getting started</a></li>
<li id="nav-documentation" class="active"><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
<li id="nav-blog"><a href="http://blog.docker.io/" title="Docker Blog">Blog</a></li>
<li id="nav-index"><a href="http://index.docker.io/" title="Docker Image Index, find images here">INDEX <img class="inline-icon" src="{{ pathto('_static/img/external-link-icon.png', 1) }}" title="external link"> </a></li>
</ul>
<!--<div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">-->
<!--<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>-->
<!--<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>-->
<!--</div>-->
</div>
<div style="margin-left: -12px; float: left;">
<a href="http://www.docker.io"><img style="margin-top: 12px; height: 38px" src="{{ pathto('_static/img/docker-letters-logo.gif', 1) }}"></a>
<a href="http://www.docker.io" title="Docker Homepage"><img style="margin-top: 0px; height: 60px; margin-left: 10px;" src="{{ pathto('_static/img/docker-top-logo.png', 1) }}"></a>
</div>
</div>
@@ -96,7 +95,7 @@
<div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
<a href="http://github.com/dotcloud/docker/"><img src="{{ pathto('_static/img/fork-us.png', 1) }}"> Fork us on Github</a>
</div>
<h1 class="pageheader">DOCUMENTATION</h1>
<h1 class="pageheader"><a href="http://docs.docker.io/en/latest/" title="Documentation" style="color: white;">DOCUMENTATION</a></h1>
</div>
</div>

View File

@@ -34,12 +34,12 @@ h4 {
.navbar .nav li a {
padding: 22px 15px 22px;
}
.navbar .brand {
padding: 13px 10px 13px 28px ;
}
.navbar-dotcloud .container {
border-bottom: 2px #000000 solid;
}
.inline-icon {
margin-bottom: 6px;
}
/*
* Responsive YouTube, Vimeo, Embed, and HTML5 Videos with CSS
* http://www.jonsuh.com
@@ -82,7 +82,7 @@ h4 {
.btn-custom {
background-color: #292929 !important;
background-repeat: repeat-x;
filter: progid:dximagetransform.microsoft.gradient(startColorstr="#515151", endColorstr="#282828");
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#515151", endColorstr="#282828");
background-image: -khtml-gradient(linear, left top, left bottom, from(#515151), to(#282828));
background-image: -moz-linear-gradient(top, #515151, #282828);
background-image: -ms-linear-gradient(top, #515151, #282828);
@@ -301,7 +301,7 @@ section.header {
height: 28px;
line-height: 28px;
background-color: #43484c;
filter: progid:dximagetransform.microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #747474), color-stop(100%, #43484c));
background-image: -webkit-linear-gradient(top, #747474 0%, #43484c 100%);
background-image: -moz-linear-gradient(top, #747474 0%, #43484c 100%);

View File

@@ -53,13 +53,6 @@ h1, h2, h3, h4 {
padding: 22px 15px 22px;
}
}
.brand {
padding: 13px 10px 13px 28px ;
// padding-left: 30px;
}
background-color: white;
}
@@ -67,6 +60,9 @@ h1, h2, h3, h4 {
border-bottom: 2px @black solid;
}
.inline-icon {
margin-bottom: 6px;
}
/*
* Responsive YouTube, Vimeo, Embed, and HTML5 Videos with CSS

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1 +0,0 @@
Thatcher Penskens <thatcher@dotcloud.com>

View File

@@ -1,2 +0,0 @@
www:
type: static

View File

@@ -1,220 +0,0 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Docker - the Linux container runtime</title>
<meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
<meta name="viewport" content="width=device-width">
<!-- twitter bootstrap -->
<link rel="stylesheet" href="../static/css/bootstrap.min.css">
<link rel="stylesheet" href="../static/css/bootstrap-responsive.min.css">
<!-- main style file -->
<link rel="stylesheet" href="../static/css/main.css">
<!-- vendor scripts -->
<script src="../static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
<script src="../static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-dotcloud">
<div class="container" style="text-align: center;">
<div style="float: right" class="pull-right">
<ul class="nav">
<li id="nav-introduction"><a href="../">Introduction</a></li>
<li id="nav-gettingstarted" class="active"><a href="">Getting started</a></li>
<li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
</ul>
</div>
<div style="margin-left: -12px; float: left;">
<a href="../index.html"><img style="margin-top: 12px; height: 38px" src="../static/img/docker-letters-logo.gif"></a>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span12 titlebar">
<div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
<a href="http://github.com/dotcloud/docker/"><img src="../static/img/fork-us.png"> Fork us on Github</a>
</div>
<h1 class="pageheader"> GETTING STARTED</h1>
</div>
</div>
</div>
<div class="container">
<div class="alert alert-info" style="margin-bottom: 0;">
<strong>Docker is still under heavy development.</strong> It should not yet be used in production. Check <a href="http://github.com/dotcloud/docker">the repo</a> for recent progress.
</div>
<div class="row">
<div class="span6">
<section class="contentblock">
<h2>
<a name="installing-on-ubuntu-1204-and-1210" class="anchor" href="#installing-on-ubuntu-1204-and-1210"><span class="mini-icon mini-icon-link"></span>
</a>Installing on Ubuntu</h2>
<p><strong>Requirements</strong></p>
<ul>
<li>Ubuntu 12.04 (LTS) (64-bit)</li>
<li> or Ubuntu 12.10 (quantal) (64-bit)</li>
<li>The 3.8 Linux Kernel</li>
</ul>
<ol>
<li>
<p><strong>Install dependencies</strong></p>
The linux-image-extra package is only needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module.
<pre>sudo apt-get install linux-image-extra-`uname -r`</pre>
</li>
<li>
<p><strong>Install Docker</strong></p>
<p>Add the Ubuntu PPA (Personal Package Archive) sources to your apt sources list, update and install.</p>
<p>This may import a new GPG key (key 63561DC6: public key "Launchpad PPA for dotcloud team" imported).</p>
<div class="highlight">
<pre>sudo apt-get install software-properties-common</pre>
<pre>sudo add-apt-repository ppa:dotcloud/lxc-docker</pre>
<pre>sudo apt-get update</pre>
<pre>sudo apt-get install lxc-docker</pre>
</div>
</li>
<li>
<p><strong>Run!</strong></p>
<div class="highlight">
<pre>docker run -i -t ubuntu /bin/bash</pre>
</div>
</li>
Continue with the <a href="http://docs.docker.io/en/latest/examples/hello_world/">Hello world</a> example.<br>
Or check <a href="http://docs.docker.io/en/latest/installation/ubuntulinux/">more detailed installation instructions</a>
</ol>
</section>
<section class="contentblock">
<h2>Contributing to Docker</h2>
<p>Want to hack on Docker? Awesome! We have some <a href="http://docs.docker.io/en/latest/contributing/contributing/">instructions to get you started</a>. They are probably not perfect, please let us know if anything feels wrong or incomplete.</p>
</section>
</div>
<div class="span6">
<section class="contentblock">
<h2>Quick install on other operating systems</h2>
<p><strong>For other operating systems we recommend and provide a streamlined install with virtualbox,
vagrant and an Ubuntu virtual machine.</strong></p>
<ul>
<li><a href="http://docs.docker.io/en/latest/installation/vagrant/">Mac OS X and other linuxes</a></li>
<li><a href="http://docs.docker.io/en/latest/installation/windows/">Windows</a></li>
</ul>
</section>
<section class="contentblock">
<h2>Questions? Want to get in touch?</h2>
<p>There are several ways to get in touch:</p>
<p><strong>Join the discussion on IRC.</strong> We can be found in the <a href="irc://chat.freenode.net#docker">#docker</a> channel on chat.freenode.net</p>
<p><strong>Discussions</strong> happen on our google group: <a href="https://groups.google.com/d/forum/docker-club">docker-club at googlegroups.com</a></p>
<p>All our <strong>development and decisions</strong> are made out in the open on Github <a href="http://www.github.com/dotcloud/docker">github.com/dotcloud/docker</a></p>
<p><strong>Get help on using Docker</strong> by asking on <a href="http://stackoverflow.com/tags/docker/">Stackoverflow</a></p>
<p>And of course, <strong>tweet</strong> your tweets to <a href="http://twitter.com/getdocker/">twitter.com/getdocker</a></p>
</section>
<section class="contentblock">
<div id="wufoo-z7x3p3">
Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
</div>
<script type="text/javascript">var z7x3p3;(function(d, t) {
var s = d.createElement(t), options = {
'userName':'dotclouddocker',
'formHash':'z7x3p3',
'autoResize':true,
'height':'577',
'async':true,
'header':'show'};
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
s.onload = s.onreadystatechange = function() {
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
})(document, 'script');</script>
</section>
</div>
</div>
</div>
<div class="container">
<footer id="footer" class="footer">
<div class="row">
<div class="span12 social">
<div class="tbox textright forceleftmargin social links pull-right">
<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
</div>
Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
</div>
</div>
<div class="row">
<div class="emptyspace" style="height: 40px">
</div>
</div>
</footer>
</div>
<!-- bootstrap javascipts -->
<script src="../static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
<!-- Google analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-6096819-11']);
_gaq.push(['_setDomainName', 'docker.io']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

View File

@@ -1,359 +0,0 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="google-site-verification" content="UxV66EKuPe87dgnH1sbrldrx6VsoWMrx5NjwkgUFxXI" />
<title>Docker - the Linux container engine</title>
<meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
<meta name="viewport" content="width=device-width">
<!-- twitter bootstrap -->
<link rel="stylesheet" href="static/css/bootstrap.min.css">
<link rel="stylesheet" href="static/css/bootstrap-responsive.min.css">
<!-- main style file -->
<link rel="stylesheet" href="static/css/main.css">
<!-- vendor scripts -->
<script src="static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
<script src="static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
<style>
.indexlabel {
float: left;
width: 150px;
display: block;
padding: 10px 20px 10px;
font-size: 20px;
font-weight: 200;
background-color: #a30000;
color: white;
height: 22px;
}
.searchbutton {
font-size: 20px;
height: 40px;
}
.debug {
border: 1px red dotted;
}
.twitterblock {
min-height: 75px;
}
.twitterblock img {
float: left;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-dotcloud">
<div class="container" style="text-align: center;">
<div class="pull-left" id="fork-us" style="margin-top: 16px;">
<a href="http://github.com/dotcloud/docker/"><img src="static/img/fork-us.png" alt="fork-icon"> Fork us on Github</a>
</div>
<div class="pull-right" >
<ul class="nav">
<li id="nav-introduction" class="active"><a href="/">Introduction</a></li>
<li id="nav-gettingstarted"><a href="gettingstarted">Getting started</a></li>
<li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container" style="margin-top: 30px;">
<div class="row">
<div class="span12">
<section class="contentblock header">
<div class="span5" style="margin-bottom: 15px;">
<div style="text-align: center;" >
<img src="static/img/docker_letters_500px.png" alt="docker letters">
<h2>The Linux container engine</h2>
</div>
<div style="display: block; text-align: center; margin-top: 20px;">
<h5>
Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers which are independent of hardware, language, framework, packaging system and hosting provider.
</h5>
</div>
<div style="display: block; text-align: center; margin-top: 30px;">
<a class="btn btn-custom btn-large" href="gettingstarted/">Let's get started</a>
</div>
</div>
<div class="span6" >
<div class="js-video" >
<iframe width="600" height="360" src="http://www.youtube.com/embed/wW9CAH9nSLs?feature=player_detailpage&rel=0&modestbranding=1&start=11" frameborder="0" allowfullscreen></iframe>
</div>
</div>
<br style="clear: both"/>
</section>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span6">
<section class="contentblock">
<h4>Heterogeneous payloads</h4>
<p>Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.</p>
<h4>Any server</h4>
<p>Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.</p>
<h4>Isolation</h4>
<p>Docker isolates processes from each other and from the underlying host, using lightweight containers.</p>
<h4>Repeatability</h4>
<p>Because each container is isolated in its own filesystem, they behave the same regardless of where, when, and alongside what they run.</p>
</section>
<section class="contentblock">
<div class="container">
<div class="span2" style="margin-left: 0" >
<a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description"><img src="static/img/hiring_graphic.png" alt="we're hiring" width="140" style="margin-top: 25px"></a>
</div>
<div class="span4" style="margin-left: 0">
<h4>Do you think it is cool to hack on docker? Join us!</h4>
<ul>
<li>Work on open source</li>
<li>Program in Go</li>
</ul>
<a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description">read more</a>
</div>
</div>
</section>
</div>
<div class="span6">
<section class="contentblock">
<h1>New! Docker Index</h1>
On the Docker Index you can find and explore pre-made container images. It allows you to share your images and download them.
<br><br>
<a href="https://index.docker.io" target="_blank">
<div class="indexlabel">
DOCKER index
</div>
</a>
&nbsp;
<input type="button" class="searchbutton" value="Search images"
onClick="window.open('https://index.docker.io')" />
</section>
<section class="contentblock">
<div id="wufoo-z7x3p3">
Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
</div>
<script type="text/javascript">var z7x3p3;(function(d, t) {
var s = d.createElement(t), options = {
'userName':'dotclouddocker',
'formHash':'z7x3p3',
'autoResize':true,
'height':'577',
'async':true,
'header':'show'};
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
s.onload = s.onreadystatechange = function() {
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
})(document, 'script');</script>
</section>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/2707460527/252a64411a339184ff375a96fb68dcb0_bigger.png">
<em>Mitchell Hashimoto @mitchellh:</em> Docker launched today. It is incredible. Theyre also working RIGHT NOW on a Vagrant provider. LXC is COMING!!
</section>
</div>
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/1108290260/Adam_Jacob-114x150_original_bigger.jpg">
<em>Adam Jacob @adamhjk:</em> Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think.
</section>
</div>
</div>
<div class="row">
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/14872832/twitter_pic_bigger.jpg">
<em>Matt Townsend @mtownsend:</em> I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego.
</section>
</div>
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/1312352395/rupert-259x300_bigger.jpg">
<em>Rob Harrop @robertharrop:</em> Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter.
</section>
</div>
</div>
<div class="row">
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://twimg0-a.akamaihd.net/profile_images/2491994496/rbevyyq6ykp6bnoby2je_bigger.jpeg">
<em>John Willis @botchagalupe:</em> IMHO docker is to paas what chef was to Iaas 4 years ago
</section>
</div>
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://twimg0-a.akamaihd.net/profile_images/3348427561/9d7f08f1e103a16c8debd169301b9944_bigger.jpeg">
<em>John Feminella @superninjarobot:</em> So, @getdocker is pure excellence. If you've ever wished for arbitrary, PaaS-agnostic, lxc/aufs Linux containers, this is your jam!
</section>
</div>
</div>
<div class="row">
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/3408403010/4496ccdd14e9b7285eca04c31a740207_bigger.jpeg">
<em>David Romulan @destructuring:</em> I haven't had this much fun since AWS
</section>
</div>
<div class="span6">
<section class="contentblock twitterblock">
<img src="https://si0.twimg.com/profile_images/780893320/My_Avatar_bigger.jpg">
<em>Ricardo Gladwell @rgladwell:</em> wow @getdocker is either amazing or totally stupid
</section>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span6">
<section class="contentblock">
<h2>Notable features</h2>
<ul>
<li>Filesystem isolation: each process container runs in a completely separate root filesystem.</li>
<li>Resource isolation: system resources like cpu and memory can be allocated differently to each process container, using cgroups.</li>
<li>Network isolation: each process container runs in its own network namespace, with a virtual interface and IP address of its own.</li>
<li>Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremely fast, memory-cheap and disk-cheap.</li>
<li>Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval.</li>
<li>Change management: changes to a container's filesystem can be committed into a new image and re-used to create more containers. No templating or manual configuration required.</li>
<li>Interactive shell: docker can allocate a pseudo-tty and attach to the standard input of any container, for example to run a throwaway interactive shell.</li>
</ul>
<h2>Under the hood</h2>
<p>Under the hood, Docker is built on the following components:</p>
<ul>
<li>The <a href="http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c">cgroup</a> and <a href="http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part">namespacing</a> capabilities of the Linux kernel;</li>
<li><a href="http://aufs.sourceforge.net/aufs.html">AUFS</a>, a powerful union filesystem with copy-on-write capabilities;</li>
<li>The <a href="http://golang.org">Go</a> programming language;</li>
<li><a href="http://lxc.sourceforge.net/">lxc</a>, a set of convenience scripts to simplify the creation of linux containers.</li>
</ul>
<h2>Who started it</h2>
<p>
Docker is an open-source implementation of the deployment engine which powers <a href="http://dotcloud.com">dotCloud</a>, a popular Platform-as-a-Service.</p>
<p>It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
of applications and databases.
</p>
</section>
</div>
<div class="span6">
<section class="contentblock">
<h3 id="twitter">Twitter</h3>
<a class="twitter-timeline" href="https://twitter.com/getdocker" data-widget-id="312730839718957056">Tweets by @getdocker</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</section>
</div>
</div>
</div> <!-- end container -->
<div class="container">
<footer id="footer" class="footer">
<div class="row">
<div class="span12">
<div class="tbox textright forceleftmargin social links pull-right">
<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
</div>
Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
</div>
</div>
<div class="row">
<div class="emptyspace" style="height: 40px">
</div>
</div>
</footer>
</div>
<!-- bootstrap javascipts -->
<script src="static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
<!-- Google analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-6096819-11']);
_gaq.push(['_setDomainName', 'docker.io']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

View File

@@ -1,6 +0,0 @@
# rule to redirect original links created when hosted on github pages
rewrite ^/documentation/(.*).html http://docs.docker.io/en/latest/$1/ permanent;
# rewrite the stuff which was on the current page
rewrite ^/gettingstarted.html$ /gettingstarted/ permanent;

View File

@@ -1 +0,0 @@
../theme/docker/static

View File

@@ -162,7 +162,7 @@ func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
// The archive is stored on disk and will be automatically deleted as soon as has been read.
// If output is not nil, a human-readable progress bar will be written to it.
// FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
func (graph *Graph) TempLayerArchive(id string, compression Compression, output io.Writer) (*TempArchive, error) {
func (graph *Graph) TempLayerArchive(id string, compression Compression, sf *utils.StreamFormatter, output io.Writer) (*TempArchive, error) {
image, err := graph.Get(id)
if err != nil {
return nil, err
@@ -175,7 +175,6 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output
if err != nil {
return nil, err
}
sf := utils.NewStreamFormatter(false)
return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, sf.FormatProgress("Buffering to disk", "%v/%v (%v)"), sf), tmp.Root)
}

133
hack/RELEASE.md Normal file
View File

@@ -0,0 +1,133 @@
## A maintainer's guide to releasing Docker
So you're in charge of a docker release? Cool. Here's what to do.
If your experience deviates from this document, please document the changes to keep it
up-to-date.
### 1. Pull from master and create a release branch
```bash
$ git checkout master
$ git pull
$ git checkout -b bump_$VERSION
```
### 2. Update CHANGELOG.md
You can run this command for reference:
```bash
LAST_VERSION=$(git tag | grep -E "v[0-9\.]+$" | sort -nr | head -n 1)
git log $LAST_VERSION..HEAD
```
Each change should be formatted as ```BULLET CATEGORY: DESCRIPTION```
* BULLET is either ```-```, ```+``` or ```*```, to indicate a bugfix,
new feature or upgrade, respectively.
* CATEGORY should describe which part of the project is affected.
Valid categories are:
* Builder
* Documentation
* Hack
* Packaging
* Remote API
* Runtime
* DESCRIPTION: a concise description of the change that is relevant to the end-user,
using the present tense.
Changes should be described in terms of how they affect the user, for example "new feature
X which allows Y", "fixed bug which caused X", "increased performance of Y".
EXAMPLES:
```
+ Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.
* Runtime: improve detection of kernel version
- Remote API: fix a bug in the optional unix socket transport
```
### 3. Change VERSION in commands.go
### 4. Run all tests
```bash
$ make test
```
### 5. Commit and create a pull request
```bash
$ git add commands.go CHANGELOG.md
$ git commit -m "Bump version to $VERSION"
$ git push origin bump_$VERSION
```
### 6. Get 2 other maintainers to validate the pull request
### 7. Merge the pull request and apply tags
```bash
$ git checkout master
$ git merge bump_$VERSION
$ git tag -a v$VERSION # Don't forget the v!
$ git tag -f -a latest
$ git push
$ git push --tags
```
### 8. Publish binaries
To run this you will need access to the release credentials.
Get them from [the infrastructure maintainers](https://github.com/dotcloud/docker/blob/master/hack/infrastructure/MAINTAINERS).
```bash
$ RELEASE_IMAGE=image_provided_by_infrastructure_maintainers
$ BUILD=$(docker run -d -e RELEASE_PPA=0 $RELEASE_IMAGE)
```
This will do 2 things:
* It will build and upload the binaries on http://get.docker.io
* It will *test* the release on our Ubuntu PPA (a PPA is a community repository for ubuntu packages)
Wait for the build to complete.
```bash
$ docker wait $BUILD # This should print 0. If it doesn't, your build failed.
```
Check that the output looks OK. Here's an example of a correct output:
```bash
$ docker logs 2>&1 b4e7c8299d73 | grep -e 'Public URL' -e 'Successfully uploaded'
Public URL of the object is: http://get.docker.io.s3.amazonaws.com/builds/Linux/x86_64/docker-v0.4.7.tgz
Public URL of the object is: http://get.docker.io.s3.amazonaws.com/builds/Linux/x86_64/docker-latest.tgz
Successfully uploaded packages.
```
If you don't see 3 lines similar to this, something might be wrong. Check the full logs and try again.
### 9. Publish Ubuntu packages
If everything went well in the previous step, you can finalize the release by submitting the Ubuntu
packages.
```bash
$ RELEASE_IMAGE=image_provided_by_infrastructure_maintainers
$ docker run -e RELEASE_PPA=1 $RELEASE_IMAGE
```
If that goes well, Ubuntu Precise package is in its way. It will take anywhere from 0.5 to 30 hours
for the builders to complete their job depending on builder demand at this time. At this point, Quantal
and Raring packages need to be created using the Launchpad interface:
https://launchpad.net/~dotcloud/+archive/lxc-docker/+packages
Notify [the packager maintainers](https://github.com/dotcloud/docker/blob/master/packaging/MAINTAINERS)
who will ensure PPA is ready.
Congratulations! You're done

91
hack/bootcamp/README.md Normal file
View File

@@ -0,0 +1,91 @@
# Docker maintainer bootcamp
## Introduction: we need more maintainers
Docker is growing incredibly fast. At the time of writing, it has received over 200 contributions from 90 people,
and its API is used by dozens of 3rd-party tools. Over 1,000 issues have been opened. As the first production deployments
start going live, the growth will only accelerate.
Also at the time of writing, Docker has 3 full-time maintainers, and 7 part-time subsystem maintainers. If docker
is going to live up to the expectations, we need more than that.
This document describes a *bootcamp* to guide and train volunteers interested in helping the project, either with individual
contributions, maintainer work, or both.
This bootcamp is an experiment. If you decide to go through it, consider yourself an alpha-tester. You should expect quirks,
and report them to us as you encounter them to help us smooth out the process.
## How it works
The maintainer bootcamp is a 12-step program - one step for each of the maintainer's responsibilities. The aspiring maintainer must
validate all 12 steps by 1) studying it, 2) practicing it, and 3) getting endorsed for it.
Steps are all equally important and can be validated in any order. Validating all 12 steps is a pre-requisite for becoming a core
maintainer, but even 1 step will make you a better contributor!
### List of steps
#### 1) Be a power user
Use docker daily, build cool things with it, know its quirks inside and out.
#### 2) Help users
Answer questions on irc, twitter, email, in person.
#### 3) Manage the bug tracker
Help triage tickets - ask the right questions, find duplicates, reference relevant resources, know when to close a ticket when necessary, take the time to go over older tickets.
#### 4) Improve the documentation
Follow the documentation from scratch regularly and make sure it is still up-to-date. Find and fix inconsistencies. Remove stale information. Find a frequently asked question that is not documented. Simplify the content and the form.
#### 5) Evangelize the principles of docker
Understand what the underlying goals and principle of docker are. Explain design decisions based on what docker is, and what it is not. When someone is not using docker, find how docker can be valuable to them. If they are using docker, find how they can use it better.
#### 6) Fix bugs
Self-explanatory. Contribute improvements to docker which solve defects. Bugfixes should be well-tested, and prioritized by impact to the user.
#### 7) Improve the testing infrastructure
Automated testing is complicated and should be perpetually improved. Invest time to improve the current tooling. Refactor existing tests, create new ones, make testing more accessible to developers, add new testing capabilities (integration tests, mocking, stress test...), improve integration between tests and documentation...
#### 8) Contribute features
Improve docker to do more things, or get better at doing the same things. Features should be well-tested, not break existing APIs, respect the project goals. They should make the user's life measurably better. Features should be discussed ahead of time to avoid wasting time and duplicating effort.
#### 9) Refactor internals
Improve docker to repay technical debt. Simplify code layout, improve performance, add missing comments, reduce the number of files and functions, rename functions and variables to be more readable, go over FIXMEs, etc.
#### 10) Review and merge contributions
Review pull requests in a timely manner, review code in detail and offer feedback. Keep a high bar without being pedantic. Share the load of testing and merging pull requests.
#### 11) Release
Manage a release of docker from beginning to end. Tests, final review, tags, builds, upload to mirrors, distro packaging, etc.
#### 12) Train other maintainers
Contribute to training other maintainers. Give advice, delegate work, help organize the bootcamp. This also means contribute to the maintainer's manual, look for ways to improve the project organization etc.
### How to study a step
### How to practice a step
### How to get endorsed for a step

View File

@@ -5,8 +5,11 @@
# AUTHOR Solomon Hykes <solomon@dotcloud.com>
# Daniel Mizyrycki <daniel@dotcloud.net>
# BUILD_CMD docker build -t dockerbuilder .
# RUN_CMD docker run -e AWS_ID="$AWS_ID" -e AWS_KEY="$AWS_KEY" -e GPG_KEY="$GPG_KEY" dockerbuilder
# RUN_CMD docker run -e AWS_ID="$AWS_ID" -e AWS_KEY="$AWS_KEY" -e GPG_KEY="$GPG_KEY" -e PUBLISH_PPA="$PUBLISH_PPA" dockerbuilder
#
# ENV_VARIABLES AWS_ID, AWS_KEY: S3 credentials for uploading Docker binary and tarball
# GPG_KEY: Signing key for docker package
# PUBLISH_PPA: 0 for staging release, 1 for production release
#
from ubuntu:12.04
maintainer Solomon Hykes <solomon@dotcloud.com>

View File

@@ -68,7 +68,7 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
}
// Store the layer
layer := layerPath(root)
if err := os.MkdirAll(layer, 0700); err != nil {
if err := os.MkdirAll(layer, 0755); err != nil {
return err
}
@@ -94,9 +94,12 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
}
// If layerData is not nil, unpack it into the new layer
if layerData != nil {
start := time.Now()
utils.Debugf("Start untar layer")
if err := Untar(layerData, layer); err != nil {
return err
}
utils.Debugf("Untar time: %vs\n", time.Now().Sub(start).Seconds())
}
return StoreSize(img, root)

View File

@@ -13,6 +13,10 @@ lxc.utsname = {{.Id}}
{{end}}
#lxc.aa_profile = unconfined
{{if .Config.NetworkDisabled}}
# network is disabled (-n=false)
lxc.network.type = empty
{{else}}
# network configuration
lxc.network.type = veth
lxc.network.flags = up
@@ -20,6 +24,7 @@ lxc.network.link = {{.NetworkSettings.Bridge}}
lxc.network.name = eth0
lxc.network.mtu = 1500
lxc.network.ipv4 = {{.NetworkSettings.IPAddress}}/{{.NetworkSettings.IPPrefixLen}}
{{end}}
# root filesystem
{{$ROOTFS := .RootfsPath}}

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"log"
"net"
"os/exec"
@@ -18,6 +17,7 @@ var NetworkBridgeIface string
const (
DefaultNetworkBridge = "docker0"
DisableNetworkBridge = "none"
portRangeStart = 49153
portRangeEnd = 65535
)
@@ -112,10 +112,29 @@ func checkRouteOverlaps(dockerNetwork *net.IPNet) error {
return nil
}
// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
// If it can't find an address which doesn't conflict, it will return an error.
func CreateBridgeIface(ifaceName string) error {
// FIXME: try more IP ranges
// FIXME: try bigger ranges! /24 is too small.
addrs := []string{"172.16.42.1/24", "10.0.42.1/24", "192.168.42.1/24"}
addrs := []string{
// Here we don't follow the convention of using the 1st IP of the range for the gateway.
// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
// on the internal addressing or other stupid things like that.
// The shouldn't, but hey, let's not break them unless we really have to.
"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
"10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
"10.1.42.1/16",
"10.42.42.1/16",
"172.16.42.1/24",
"172.16.43.1/24",
"172.16.44.1/24",
"10.0.42.1/24",
"10.0.43.1/24",
"192.168.42.1/24",
"192.168.43.1/24",
"192.168.44.1/24",
}
var ifaceAddr string
for _, addr := range addrs {
@@ -183,8 +202,10 @@ func getIfaceAddr(name string) (net.Addr, error) {
// up iptables rules.
// It keeps track of all mappings and is able to unmap at will
type PortMapper struct {
mapping map[int]net.TCPAddr
proxies map[int]net.Listener
tcpMapping map[int]*net.TCPAddr
tcpProxies map[int]Proxy
udpMapping map[int]*net.UDPAddr
udpProxies map[int]Proxy
}
func (mapper *PortMapper) cleanup() error {
@@ -197,8 +218,10 @@ func (mapper *PortMapper) cleanup() error {
iptables("-t", "nat", "-D", "OUTPUT", "-j", "DOCKER")
iptables("-t", "nat", "-F", "DOCKER")
iptables("-t", "nat", "-X", "DOCKER")
mapper.mapping = make(map[int]net.TCPAddr)
mapper.proxies = make(map[int]net.Listener)
mapper.tcpMapping = make(map[int]*net.TCPAddr)
mapper.tcpProxies = make(map[int]Proxy)
mapper.udpMapping = make(map[int]*net.UDPAddr)
mapper.udpProxies = make(map[int]Proxy)
return nil
}
@@ -215,76 +238,72 @@ func (mapper *PortMapper) setup() error {
return nil
}
func (mapper *PortMapper) iptablesForward(rule string, port int, dest net.TCPAddr) error {
return iptables("-t", "nat", rule, "DOCKER", "-p", "tcp", "--dport", strconv.Itoa(port),
"-j", "DNAT", "--to-destination", net.JoinHostPort(dest.IP.String(), strconv.Itoa(dest.Port)))
func (mapper *PortMapper) iptablesForward(rule string, port int, proto string, dest_addr string, dest_port int) error {
return iptables("-t", "nat", rule, "DOCKER", "-p", proto, "--dport", strconv.Itoa(port),
"-j", "DNAT", "--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port)))
}
func (mapper *PortMapper) Map(port int, dest net.TCPAddr) error {
if err := mapper.iptablesForward("-A", port, dest); err != nil {
return err
func (mapper *PortMapper) Map(port int, backendAddr net.Addr) error {
if _, isTCP := backendAddr.(*net.TCPAddr); isTCP {
backendPort := backendAddr.(*net.TCPAddr).Port
backendIP := backendAddr.(*net.TCPAddr).IP
if err := mapper.iptablesForward("-A", port, "tcp", backendIP.String(), backendPort); err != nil {
return err
}
mapper.tcpMapping[port] = backendAddr.(*net.TCPAddr)
proxy, err := NewProxy(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}, backendAddr)
if err != nil {
mapper.Unmap(port, "tcp")
return err
}
mapper.tcpProxies[port] = proxy
go proxy.Run()
} else {
backendPort := backendAddr.(*net.UDPAddr).Port
backendIP := backendAddr.(*net.UDPAddr).IP
if err := mapper.iptablesForward("-A", port, "udp", backendIP.String(), backendPort); err != nil {
return err
}
mapper.udpMapping[port] = backendAddr.(*net.UDPAddr)
proxy, err := NewProxy(&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}, backendAddr)
if err != nil {
mapper.Unmap(port, "udp")
return err
}
mapper.udpProxies[port] = proxy
go proxy.Run()
}
mapper.mapping[port] = dest
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
mapper.Unmap(port)
return err
}
mapper.proxies[port] = listener
go proxy(listener, "tcp", dest.String())
return nil
}
// proxy listens for socket connections on `listener`, and forwards them unmodified
// to `proto:address`
func proxy(listener net.Listener, proto, address string) error {
utils.Debugf("proxying to %s:%s", proto, address)
defer utils.Debugf("Done proxying to %s:%s", proto, address)
for {
utils.Debugf("Listening on %s", listener)
src, err := listener.Accept()
if err != nil {
func (mapper *PortMapper) Unmap(port int, proto string) error {
if proto == "tcp" {
backendAddr, ok := mapper.tcpMapping[port]
if !ok {
return fmt.Errorf("Port tcp/%v is not mapped", port)
}
if proxy, exists := mapper.tcpProxies[port]; exists {
proxy.Close()
delete(mapper.tcpProxies, port)
}
if err := mapper.iptablesForward("-D", port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
return err
}
utils.Debugf("Connecting to %s:%s", proto, address)
dst, err := net.Dial(proto, address)
if err != nil {
log.Printf("Error connecting to %s:%s: %s", proto, address, err)
src.Close()
continue
delete(mapper.tcpMapping, port)
} else {
backendAddr, ok := mapper.udpMapping[port]
if !ok {
return fmt.Errorf("Port udp/%v is not mapped", port)
}
utils.Debugf("Connected to backend, splicing")
splice(src, dst)
if proxy, exists := mapper.udpProxies[port]; exists {
proxy.Close()
delete(mapper.udpProxies, port)
}
if err := mapper.iptablesForward("-D", port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
return err
}
delete(mapper.udpMapping, port)
}
}
func halfSplice(dst, src net.Conn) error {
_, err := io.Copy(dst, src)
// FIXME: on EOF from a tcp connection, pass WriteClose()
dst.Close()
src.Close()
return err
}
func splice(a, b net.Conn) {
go halfSplice(a, b)
go halfSplice(b, a)
}
func (mapper *PortMapper) Unmap(port int) error {
dest, ok := mapper.mapping[port]
if !ok {
return errors.New("Port is not mapped")
}
if proxy, exists := mapper.proxies[port]; exists {
proxy.Close()
delete(mapper.proxies, port)
}
if err := mapper.iptablesForward("-D", port, dest); err != nil {
return err
}
delete(mapper.mapping, port)
return nil
}
@@ -301,9 +320,9 @@ func newPortMapper() (*PortMapper, error) {
// Port allocator: Atomatically allocate and release networking ports
type PortAllocator struct {
sync.Mutex
inUse map[int]struct{}
fountain chan (int)
lock sync.Mutex
}
func (alloc *PortAllocator) runFountain() {
@@ -317,9 +336,9 @@ func (alloc *PortAllocator) runFountain() {
// FIXME: Release can no longer fail, change its prototype to reflect that.
func (alloc *PortAllocator) Release(port int) error {
utils.Debugf("Releasing %d", port)
alloc.lock.Lock()
alloc.Lock()
delete(alloc.inUse, port)
alloc.lock.Unlock()
alloc.Unlock()
return nil
}
@@ -334,8 +353,8 @@ func (alloc *PortAllocator) Acquire(port int) (int, error) {
}
return -1, fmt.Errorf("Port generator ended unexpectedly")
}
alloc.lock.Lock()
defer alloc.lock.Unlock()
alloc.Lock()
defer alloc.Unlock()
if _, inUse := alloc.inUse[port]; inUse {
return -1, fmt.Errorf("Port already in use: %d", port)
}
@@ -453,26 +472,47 @@ type NetworkInterface struct {
Gateway net.IP
manager *NetworkManager
extPorts []int
extPorts []*Nat
disabled bool
}
// Allocate an external TCP port and map it to the interface
func (iface *NetworkInterface) AllocatePort(spec string) (*Nat, error) {
if iface.disabled {
return nil, fmt.Errorf("Trying to allocate port for interface %v, which is disabled", iface) // FIXME
}
nat, err := parseNat(spec)
if err != nil {
return nil, err
}
// Allocate a random port if Frontend==0
extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend)
if err != nil {
return nil, err
if nat.Proto == "tcp" {
extPort, err := iface.manager.tcpPortAllocator.Acquire(nat.Frontend)
if err != nil {
return nil, err
}
backend := &net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}
if err := iface.manager.portMapper.Map(extPort, backend); err != nil {
iface.manager.tcpPortAllocator.Release(extPort)
return nil, err
}
nat.Frontend = extPort
} else {
extPort, err := iface.manager.udpPortAllocator.Acquire(nat.Frontend)
if err != nil {
return nil, err
}
backend := &net.UDPAddr{IP: iface.IPNet.IP, Port: nat.Backend}
if err := iface.manager.portMapper.Map(extPort, backend); err != nil {
iface.manager.udpPortAllocator.Release(extPort)
return nil, err
}
nat.Frontend = extPort
}
nat.Frontend = extPort
if err := iface.manager.portMapper.Map(nat.Frontend, net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}); err != nil {
iface.manager.portAllocator.Release(nat.Frontend)
return nil, err
}
iface.extPorts = append(iface.extPorts, nat.Frontend)
iface.extPorts = append(iface.extPorts, nat)
return nat, nil
}
@@ -485,6 +525,21 @@ type Nat struct {
func parseNat(spec string) (*Nat, error) {
var nat Nat
if strings.Contains(spec, "/") {
specParts := strings.Split(spec, "/")
if len(specParts) != 2 {
return nil, fmt.Errorf("Invalid port format.")
}
proto := specParts[1]
spec = specParts[0]
if proto != "tcp" && proto != "udp" {
return nil, fmt.Errorf("Invalid port format: unknown protocol %v.", proto)
}
nat.Proto = proto
} else {
nat.Proto = "tcp"
}
if strings.Contains(spec, ":") {
specParts := strings.Split(spec, ":")
if len(specParts) != 2 {
@@ -517,20 +572,29 @@ func parseNat(spec string) (*Nat, error) {
}
nat.Backend = int(port)
}
nat.Proto = "tcp"
return &nat, nil
}
// Release: Network cleanup - release all resources
func (iface *NetworkInterface) Release() {
for _, port := range iface.extPorts {
if err := iface.manager.portMapper.Unmap(port); err != nil {
log.Printf("Unable to unmap port %v: %v", port, err)
}
if err := iface.manager.portAllocator.Release(port); err != nil {
log.Printf("Unable to release port %v: %v", port, err)
}
if iface.disabled {
return
}
for _, nat := range iface.extPorts {
utils.Debugf("Unmaping %v/%v", nat.Proto, nat.Frontend)
if err := iface.manager.portMapper.Unmap(nat.Frontend, nat.Proto); err != nil {
log.Printf("Unable to unmap port %v/%v: %v", nat.Proto, nat.Frontend, err)
}
if nat.Proto == "tcp" {
if err := iface.manager.tcpPortAllocator.Release(nat.Frontend); err != nil {
log.Printf("Unable to release port tcp/%v: %v", nat.Frontend, err)
}
} else if err := iface.manager.udpPortAllocator.Release(nat.Frontend); err != nil {
log.Printf("Unable to release port udp/%v: %v", nat.Frontend, err)
}
}
iface.manager.ipAllocator.Release(iface.IPNet.IP)
@@ -542,13 +606,21 @@ type NetworkManager struct {
bridgeIface string
bridgeNetwork *net.IPNet
ipAllocator *IPAllocator
portAllocator *PortAllocator
portMapper *PortMapper
ipAllocator *IPAllocator
tcpPortAllocator *PortAllocator
udpPortAllocator *PortAllocator
portMapper *PortMapper
disabled bool
}
// Allocate a network interface
func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
if manager.disabled {
return &NetworkInterface{disabled: true}, nil
}
ip, err := manager.ipAllocator.Acquire()
if err != nil {
return nil, err
@@ -562,6 +634,14 @@ func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
}
func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
if bridgeIface == DisableNetworkBridge {
manager := &NetworkManager{
disabled: true,
}
return manager, nil
}
addr, err := getIfaceAddr(bridgeIface)
if err != nil {
// If the iface is not found, try to create it
@@ -577,7 +657,11 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
ipAllocator := newIPAllocator(network)
portAllocator, err := newPortAllocator()
tcpPortAllocator, err := newPortAllocator()
if err != nil {
return nil, err
}
udpPortAllocator, err := newPortAllocator()
if err != nil {
return nil, err
}
@@ -588,11 +672,12 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
}
manager := &NetworkManager{
bridgeIface: bridgeIface,
bridgeNetwork: network,
ipAllocator: ipAllocator,
portAllocator: portAllocator,
portMapper: portMapper,
bridgeIface: bridgeIface,
bridgeNetwork: network,
ipAllocator: ipAllocator,
tcpPortAllocator: tcpPortAllocator,
udpPortAllocator: udpPortAllocator,
portMapper: portMapper,
}
return manager, nil
}

258
network_proxy.go Normal file
View File

@@ -0,0 +1,258 @@
package docker
import (
"encoding/binary"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"log"
"net"
"sync"
"syscall"
"time"
)
const (
UDPConnTrackTimeout = 90 * time.Second
UDPBufSize = 2048
)
type Proxy interface {
// Start forwarding traffic back and forth the front and back-end
// addresses.
Run()
// Stop forwarding traffic and close both ends of the Proxy.
Close()
// Return the address on which the proxy is listening.
FrontendAddr() net.Addr
// Return the proxied address.
BackendAddr() net.Addr
}
type TCPProxy struct {
listener *net.TCPListener
frontendAddr *net.TCPAddr
backendAddr *net.TCPAddr
}
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
listener, err := net.ListenTCP("tcp", frontendAddr)
if err != nil {
return nil, err
}
// If the port in frontendAddr was 0 then ListenTCP will have a picked
// a port to listen on, hence the call to Addr to get that actual port:
return &TCPProxy{
listener: listener,
frontendAddr: listener.Addr().(*net.TCPAddr),
backendAddr: backendAddr,
}, nil
}
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
if err != nil {
log.Printf("Can't forward traffic to backend tcp/%v: %v\n", proxy.backendAddr, err.Error())
client.Close()
return
}
event := make(chan int64)
var broker = func(to, from *net.TCPConn) {
written, err := io.Copy(to, from)
if err != nil {
err, ok := err.(*net.OpError)
// If the socket we are writing to is shutdown with
// SHUT_WR, forward it to the other end of the pipe:
if ok && err.Err == syscall.EPIPE {
from.CloseWrite()
}
}
to.CloseRead()
event <- written
}
utils.Debugf("Forwarding traffic between tcp/%v and tcp/%v", client.RemoteAddr(), backend.RemoteAddr())
go broker(client, backend)
go broker(backend, client)
var transferred int64 = 0
for i := 0; i < 2; i++ {
select {
case written := <-event:
transferred += written
case <-quit:
// Interrupt the two brokers and "join" them.
client.Close()
backend.Close()
for ; i < 2; i++ {
transferred += <-event
}
goto done
}
}
client.Close()
backend.Close()
done:
utils.Debugf("%v bytes transferred between tcp/%v and tcp/%v", transferred, client.RemoteAddr(), backend.RemoteAddr())
}
func (proxy *TCPProxy) Run() {
quit := make(chan bool)
defer close(quit)
utils.Debugf("Starting proxy on tcp/%v for tcp/%v", proxy.frontendAddr, proxy.backendAddr)
for {
client, err := proxy.listener.Accept()
if err != nil {
utils.Debugf("Stopping proxy on tcp/%v for tcp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error())
return
}
go proxy.clientLoop(client.(*net.TCPConn), quit)
}
}
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
// A net.Addr where the IP is split into two fields so you can use it as a key
// in a map:
type connTrackKey struct {
IPHigh uint64
IPLow uint64
Port int
}
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
if len(addr.IP) == net.IPv4len {
return &connTrackKey{
IPHigh: 0,
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
Port: addr.Port,
}
}
return &connTrackKey{
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
Port: addr.Port,
}
}
type connTrackMap map[connTrackKey]*net.UDPConn
type UDPProxy struct {
listener *net.UDPConn
frontendAddr *net.UDPAddr
backendAddr *net.UDPAddr
connTrackTable connTrackMap
connTrackLock sync.Mutex
}
func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
listener, err := net.ListenUDP("udp", frontendAddr)
if err != nil {
return nil, err
}
return &UDPProxy{
listener: listener,
frontendAddr: listener.LocalAddr().(*net.UDPAddr),
backendAddr: backendAddr,
connTrackTable: make(connTrackMap),
}, nil
}
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
defer func() {
proxy.connTrackLock.Lock()
delete(proxy.connTrackTable, *clientKey)
proxy.connTrackLock.Unlock()
utils.Debugf("Done proxying between udp/%v and udp/%v", clientAddr.String(), proxy.backendAddr.String())
proxyConn.Close()
}()
readBuf := make([]byte, UDPBufSize)
for {
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
again:
read, err := proxyConn.Read(readBuf)
if err != nil {
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
// This will happen if the last write failed
// (e.g: nothing is actually listening on the
// proxied port on the container), ignore it
// and continue until UDPConnTrackTimeout
// expires:
goto again
}
return
}
for i := 0; i != read; {
written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
if err != nil {
return
}
i += written
utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, clientAddr.String())
}
}
}
func (proxy *UDPProxy) Run() {
readBuf := make([]byte, UDPBufSize)
utils.Debugf("Starting proxy on udp/%v for udp/%v", proxy.frontendAddr, proxy.backendAddr)
for {
read, from, err := proxy.listener.ReadFromUDP(readBuf)
if err != nil {
// NOTE: Apparently ReadFrom doesn't return
// ECONNREFUSED like Read do (see comment in
// UDPProxy.replyLoop)
utils.Debugf("Stopping proxy on udp/%v for udp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error())
break
}
fromKey := newConnTrackKey(from)
proxy.connTrackLock.Lock()
proxyConn, hit := proxy.connTrackTable[*fromKey]
if !hit {
proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
if err != nil {
log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err)
continue
}
proxy.connTrackTable[*fromKey] = proxyConn
go proxy.replyLoop(proxyConn, from, fromKey)
}
proxy.connTrackLock.Unlock()
for i := 0; i != read; {
written, err := proxyConn.Write(readBuf[i:read])
if err != nil {
log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err)
break
}
i += written
utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, proxy.backendAddr.String())
}
}
}
func (proxy *UDPProxy) Close() {
proxy.listener.Close()
proxy.connTrackLock.Lock()
defer proxy.connTrackLock.Unlock()
for _, conn := range proxy.connTrackTable {
conn.Close()
}
}
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
switch frontendAddr.(type) {
case *net.UDPAddr:
return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
case *net.TCPAddr:
return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
default:
panic(fmt.Errorf("Unsupported protocol"))
}
}

221
network_proxy_test.go Normal file
View File

@@ -0,0 +1,221 @@
package docker
import (
"bytes"
"fmt"
"io"
"net"
"strings"
"testing"
"time"
)
var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
var testBufSize = len(testBuf)
type EchoServer interface {
Run()
Close()
LocalAddr() net.Addr
}
type TCPEchoServer struct {
listener net.Listener
testCtx *testing.T
}
type UDPEchoServer struct {
conn net.PacketConn
testCtx *testing.T
}
func NewEchoServer(t *testing.T, proto, address string) EchoServer {
var server EchoServer
if strings.HasPrefix(proto, "tcp") {
listener, err := net.Listen(proto, address)
if err != nil {
t.Fatal(err)
}
server = &TCPEchoServer{listener: listener, testCtx: t}
} else {
socket, err := net.ListenPacket(proto, address)
if err != nil {
t.Fatal(err)
}
server = &UDPEchoServer{conn: socket, testCtx: t}
}
t.Logf("EchoServer listening on %v/%v\n", proto, server.LocalAddr().String())
return server
}
func (server *TCPEchoServer) Run() {
go func() {
for {
client, err := server.listener.Accept()
if err != nil {
return
}
go func(client net.Conn) {
server.testCtx.Logf("TCP client accepted on the EchoServer\n")
written, err := io.Copy(client, client)
server.testCtx.Logf("%v bytes echoed back to the client\n", written)
if err != nil {
server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
}
client.Close()
}(client)
}
}()
}
func (server *TCPEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
func (server *TCPEchoServer) Close() { server.listener.Addr() }
func (server *UDPEchoServer) Run() {
go func() {
readBuf := make([]byte, 1024)
for {
read, from, err := server.conn.ReadFrom(readBuf)
if err != nil {
return
}
server.testCtx.Logf("Writing UDP datagram back")
for i := 0; i != read; {
written, err := server.conn.WriteTo(readBuf[i:read], from)
if err != nil {
break
}
i += written
}
}
}()
}
func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
func (server *UDPEchoServer) Close() { server.conn.Close() }
func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
defer proxy.Close()
go proxy.Run()
client, err := net.Dial(proto, addr)
if err != nil {
t.Fatalf("Can't connect to the proxy: %v", err)
}
defer client.Close()
client.SetDeadline(time.Now().Add(10 * time.Second))
if _, err = client.Write(testBuf); err != nil {
t.Fatal(err)
}
recvBuf := make([]byte, testBufSize)
if _, err = client.Read(recvBuf); err != nil {
t.Fatal(err)
}
if !bytes.Equal(testBuf, recvBuf) {
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
}
}
func testProxy(t *testing.T, proto string, proxy Proxy) {
testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
}
func TestTCP4Proxy(t *testing.T) {
backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
defer backend.Close()
backend.Run()
frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
if err != nil {
t.Fatal(err)
}
testProxy(t, "tcp", proxy)
}
func TestTCP6Proxy(t *testing.T) {
backend := NewEchoServer(t, "tcp", "[::1]:0")
defer backend.Close()
backend.Run()
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
if err != nil {
t.Fatal(err)
}
testProxy(t, "tcp", proxy)
}
func TestTCPDualStackProxy(t *testing.T) {
// If I understand `godoc -src net favoriteAddrFamily` (used by the
// net.Listen* functions) correctly this should work, but it doesn't.
t.Skip("No support for dual stack yet")
backend := NewEchoServer(t, "tcp", "[::1]:0")
defer backend.Close()
backend.Run()
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
if err != nil {
t.Fatal(err)
}
ipv4ProxyAddr := &net.TCPAddr{
IP: net.IPv4(127, 0, 0, 1),
Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
}
testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
}
func TestUDP4Proxy(t *testing.T) {
backend := NewEchoServer(t, "udp", "127.0.0.1:0")
defer backend.Close()
backend.Run()
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
if err != nil {
t.Fatal(err)
}
testProxy(t, "udp", proxy)
}
func TestUDP6Proxy(t *testing.T) {
backend := NewEchoServer(t, "udp", "[::1]:0")
defer backend.Close()
backend.Run()
frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
if err != nil {
t.Fatal(err)
}
testProxy(t, "udp", proxy)
}
func TestUDPWriteError(t *testing.T) {
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
// Hopefully, this port will be free: */
backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
proxy, err := NewProxy(frontendAddr, backendAddr)
if err != nil {
t.Fatal(err)
}
defer proxy.Close()
go proxy.Run()
client, err := net.Dial("udp", "127.0.0.1:25587")
if err != nil {
t.Fatalf("Can't connect to the proxy: %v", err)
}
defer client.Close()
// Make sure the proxy doesn't stop when there is no actual backend:
client.Write(testBuf)
client.Write(testBuf)
backend := NewEchoServer(t, "udp", "127.0.0.1:25587")
defer backend.Close()
backend.Run()
client.SetDeadline(time.Now().Add(10 * time.Second))
if _, err = client.Write(testBuf); err != nil {
t.Fatal(err)
}
recvBuf := make([]byte, testBufSize)
if _, err = client.Read(recvBuf); err != nil {
t.Fatal(err)
}
if !bytes.Equal(testBuf, recvBuf) {
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
}
}

View File

@@ -20,28 +20,97 @@ func TestIptables(t *testing.T) {
func TestParseNat(t *testing.T) {
if nat, err := parseNat("4500"); err == nil {
if nat.Frontend != 0 || nat.Backend != 4500 {
t.Errorf("-p 4500 should produce 0->4500, got %d->%d", nat.Frontend, nat.Backend)
if nat.Frontend != 0 || nat.Backend != 4500 || nat.Proto != "tcp" {
t.Errorf("-p 4500 should produce 0->4500/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat(":4501"); err == nil {
if nat.Frontend != 4501 || nat.Backend != 4501 {
t.Errorf("-p :4501 should produce 4501->4501, got %d->%d", nat.Frontend, nat.Backend)
if nat.Frontend != 4501 || nat.Backend != 4501 || nat.Proto != "tcp" {
t.Errorf("-p :4501 should produce 4501->4501/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat("4502:4503"); err == nil {
if nat.Frontend != 4502 || nat.Backend != 4503 {
t.Errorf("-p 4502:4503 should produce 4502->4503, got %d->%d", nat.Frontend, nat.Backend)
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "tcp" {
t.Errorf("-p 4502:4503 should produce 4502->4503/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat("4502:4503/tcp"); err == nil {
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "tcp" {
t.Errorf("-p 4502:4503/tcp should produce 4502->4503/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat("4502:4503/udp"); err == nil {
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "udp" {
t.Errorf("-p 4502:4503/udp should produce 4502->4503/udp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat(":4503/udp"); err == nil {
if nat.Frontend != 4503 || nat.Backend != 4503 || nat.Proto != "udp" {
t.Errorf("-p :4503/udp should produce 4503->4503/udp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat(":4503/tcp"); err == nil {
if nat.Frontend != 4503 || nat.Backend != 4503 || nat.Proto != "tcp" {
t.Errorf("-p :4503/tcp should produce 4503->4503/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat("4503/tcp"); err == nil {
if nat.Frontend != 0 || nat.Backend != 4503 || nat.Proto != "tcp" {
t.Errorf("-p 4503/tcp should produce 0->4503/tcp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if nat, err := parseNat("4503/udp"); err == nil {
if nat.Frontend != 0 || nat.Backend != 4503 || nat.Proto != "udp" {
t.Errorf("-p 4503/udp should produce 0->4503/udp, got %d->%d/%s",
nat.Frontend, nat.Backend, nat.Proto)
}
} else {
t.Fatal(err)
}
if _, err := parseNat("4503/tcpgarbage"); err == nil {
t.Fatal(err)
}
if _, err := parseNat("4503/tcp/udp"); err == nil {
t.Fatal(err)
}
if _, err := parseNat("4503/"); err == nil {
t.Fatal(err)
}
}
func TestPortAllocation(t *testing.T) {

View File

@@ -13,8 +13,8 @@ PKG_NAME=lxc-docker
ROOT_PATH=$(shell git rev-parse --show-toplevel)
GITHUB_PATH=github.com/dotcloud/docker
BUILD_SRC=build_src
VERSION_TAG?=v$(shell sed -E 's/.+\((.+)-.+\).+/\1/;q' changelog)
VERSION=$(shell echo ${VERSION_TAG} | cut -c2-)
VERSION=$(shell sed -En '0,/^\#\# /{s/^\#\# ([^ ]+).+/\1/p}' ../../CHANGELOG.md)
VERSION_TAG?=v${VERSION}
DOCKER_VERSION=${PKG_NAME}_${VERSION}
all:
@@ -28,7 +28,6 @@ install:
mkdir -p $(DESTDIR)/usr/share/doc/lxc-docker
install -m 0755 src/${GITHUB_PATH}/docker/docker $(DESTDIR)/usr/bin/lxc-docker
cp debian/lxc-docker.1 $(DESTDIR)/usr/share/man/man1
cp debian/CHANGELOG.md $(DESTDIR)/usr/share/doc/lxc-docker/changelog
debian:
# Prepare docker source from revision ${VERSION_TAG}
@@ -41,6 +40,7 @@ debian:
cp -r `ls | grep -v ${BUILD_SRC}` ${BUILD_SRC}/debian
cp ${ROOT_PATH}/README.md ${BUILD_SRC}
cp ${ROOT_PATH}/CHANGELOG.md ${BUILD_SRC}/debian
./parse_changelog.py < ../../CHANGELOG.md > ${BUILD_SRC}/debian/changelog
# Cleanup
rm -rf `find . -name '.git*'`
rm -f ${DOCKER_VERSION}*

View File

@@ -13,6 +13,9 @@ Vagrant::Config.run do |config|
# Install debian packaging dependencies and create debian packages
pkg_cmd = "apt-get -qq update; DEBIAN_FRONTEND=noninteractive apt-get install -qq -y #{PKG_DEP}; " \
"curl -s -o /go.tar.gz https://go.googlecode.com/files/go1.1.1.linux-amd64.tar.gz; " \
"tar -C /usr/local -xzf /go.tar.gz; rm /usr/bin/go; " \
"ln -s /usr/local/go/bin/go /usr/bin; "\
"export GPG_KEY='#{ENV['GPG_KEY']}'; cd /data/docker/packaging/debian; make debian"
config.vm.provision :shell, :inline => pkg_cmd
end

View File

@@ -923,6 +923,12 @@ List images
Usage: docker import [OPTIONS] URL|\- [REPOSITORY [TAG]]
.sp
Create a new filesystem image from the contents of a tarball
At this time, the URL must start with ``http`` and point to a single file archive
(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
containing a root filesystem. If you would like to import from a local directory or archive,
you can use the ``-`` parameter to take the data from standard in.
.SS info
.sp
.nf

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python
'Parse main CHANGELOG.md from stdin outputing on stdout the debian changelog'
import sys,re, datetime
on_block=False
for line in sys.stdin.readlines():
line = line.strip()
if line.startswith('# ') or len(line) == 0:
continue
if line.startswith('## '):
if on_block:
print '\n -- dotCloud <ops@dotcloud.com> {0}\n'.format(date)
version, date = line[3:].split()
date = datetime.datetime.strptime(date, '(%Y-%m-%d)').strftime(
'%a, %d %b %Y 00:00:00 -0700')
on_block = True
print 'lxc-docker ({0}-1) precise; urgency=low'.format(version)
continue
if on_block:
print ' ' + line
print '\n -- dotCloud <ops@dotcloud.com> {0}'.format(date)

View File

@@ -1,9 +1,8 @@
description "Run docker"
start on runlevel [2345]
stop on starting rc RUNLEVEL=[016]
start on filesystem or runlevel [2345]
stop on runlevel [!2345]
respawn
script
/usr/bin/docker -d
end script
exec /usr/bin/docker -d

View File

@@ -1,4 +1,4 @@
#!/bin/sh
# Stop docker
/sbin/stop docker
if [ "`pgrep -f '/usr/bin/docker -d'`" != "" ]; then /sbin/stop docker; fi

View File

@@ -12,39 +12,140 @@ import (
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strconv"
"strings"
)
var ErrAlreadyExists = errors.New("Image already exists")
var ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
func UrlScheme() string {
u, err := url.Parse(auth.IndexServerAddress())
if err != nil {
return "https"
func pingRegistryEndpoint(endpoint string) error {
if endpoint == auth.IndexServerAddress() {
// Skip the check, we now this one is valid
// (and we never want to fallback to http in case of error)
return nil
}
return u.Scheme
resp, err := http.Get(endpoint + "_ping")
if err != nil {
return err
}
if resp.Header.Get("X-Docker-Registry-Version") == "" {
return errors.New("This does not look like a Registry server (\"X-Docker-Registry-Version\" header not found in the response)")
}
return nil
}
func validateRepositoryName(repositoryName string) error {
var (
namespace string
name string
)
nameParts := strings.SplitN(repositoryName, "/", 2)
if len(nameParts) < 2 {
namespace = "library"
name = nameParts[0]
} else {
namespace = nameParts[0]
name = nameParts[1]
}
validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
if !validNamespace.MatchString(namespace) {
return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", namespace)
}
validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
if !validRepo.MatchString(name) {
return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", name)
}
return nil
}
// Resolves a repository name to a endpoint + name
func ResolveRepositoryName(reposName string) (string, string, error) {
if strings.Contains(reposName, "://") {
// It cannot contain a scheme!
return "", "", ErrInvalidRepositoryName
}
nameParts := strings.SplitN(reposName, "/", 2)
if !strings.Contains(nameParts[0], ".") && !strings.Contains(nameParts[0], ":") {
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
err := validateRepositoryName(reposName)
return auth.IndexServerAddress(), reposName, err
}
if len(nameParts) < 2 {
// There is a dot in repos name (and no registry address)
// Is it a Registry address without repos name?
return "", "", ErrInvalidRepositoryName
}
hostname := nameParts[0]
reposName = nameParts[1]
if strings.Contains(hostname, "index.docker.io") {
return "", "", fmt.Errorf("Invalid repository name, try \"%s\" instead", reposName)
}
if err := validateRepositoryName(reposName); err != nil {
return "", "", err
}
endpoint := fmt.Sprintf("https://%s/v1/", hostname)
if err := pingRegistryEndpoint(endpoint); err != nil {
utils.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err)
endpoint = fmt.Sprintf("http://%s/v1/", hostname)
if err = pingRegistryEndpoint(endpoint); err != nil {
//TODO: triggering highland build can be done there without "failing"
return "", "", errors.New("Invalid Registry endpoint: " + err.Error())
}
}
err := validateRepositoryName(reposName)
return endpoint, reposName, err
}
// VersionInfo is used to model entities which has a version.
// It is basically a tupple with name and version.
type VersionInfo interface {
Name() string
Version() string
}
func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
for _, cookie := range c.Jar.Cookies(req.URL) {
req.AddCookie(cookie)
}
return c.Do(req)
res, err := c.Do(req)
if err != nil {
return nil, err
}
if len(res.Cookies()) > 0 {
c.Jar.SetCookies(req.URL, res.Cookies())
}
return res, err
}
// Set the user agent field in the header based on the versions provided
// in NewRegistry() and extra.
func (r *Registry) setUserAgent(req *http.Request, extra ...VersionInfo) {
if len(r.baseVersions)+len(extra) == 0 {
return
}
if len(extra) == 0 {
req.Header.Set("User-Agent", r.baseVersionsStr)
} else {
req.Header.Set("User-Agent", appendVersions(r.baseVersionsStr, extra...))
}
return
}
// Retrieve the history of a given image from the Registry.
// Return a list of the parent's json (requested image included)
func (r *Registry) GetRemoteHistory(imgId, registry string, token []string) ([]string, error) {
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/ancestry", nil)
func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]string, error) {
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/ancestry", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
res, err := r.client.Do(req)
r.setUserAgent(req)
res, err := doWithCookies(r.client, req)
if err != nil || res.StatusCode != 200 {
if res != nil {
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgId)
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID)
}
return nil, err
}
@@ -64,10 +165,10 @@ func (r *Registry) GetRemoteHistory(imgId, registry string, token []string) ([]s
}
// Check if an image exists in the Registry
func (r *Registry) LookupRemoteImage(imgId, registry string, token []string) bool {
func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) bool {
rt := &http.Transport{Proxy: http.ProxyFromEnvironment}
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
if err != nil {
return false
}
@@ -79,49 +180,16 @@ func (r *Registry) LookupRemoteImage(imgId, registry string, token []string) boo
return res.StatusCode == 200
}
func (r *Registry) getImagesInRepository(repository string, authConfig *auth.AuthConfig) ([]map[string]string, error) {
u := auth.IndexServerAddress() + "/repositories/" + repository + "/images"
req, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
if authConfig != nil && len(authConfig.Username) > 0 {
req.SetBasicAuth(authConfig.Username, authConfig.Password)
}
res, err := r.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
// Repository doesn't exist yet
if res.StatusCode == 404 {
return nil, nil
}
jsonData, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
imageList := []map[string]string{}
if err := json.Unmarshal(jsonData, &imageList); err != nil {
utils.Debugf("Body: %s (%s)\n", res.Body, u)
return nil, err
}
return imageList, nil
}
// Retrieve an image from the Registry.
func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, int, error) {
func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([]byte, int, error) {
// Get the JSON
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
if err != nil {
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
}
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
res, err := r.client.Do(req)
r.setUserAgent(req)
res, err := doWithCookies(r.client, req)
if err != nil {
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
}
@@ -142,13 +210,14 @@ func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([
return jsonString, imageSize, nil
}
func (r *Registry) GetRemoteImageLayer(imgId, registry string, token []string) (io.ReadCloser, error) {
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/layer", nil)
func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) (io.ReadCloser, error) {
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/layer", nil)
if err != nil {
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
}
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
res, err := r.client.Do(req)
r.setUserAgent(req)
res, err := doWithCookies(r.client, req)
if err != nil {
return nil, err
}
@@ -162,16 +231,14 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
repository = "library/" + repository
}
for _, host := range registries {
endpoint := fmt.Sprintf("%s/v1/repositories/%s/tags", host, repository)
if !(strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://")) {
endpoint = fmt.Sprintf("%s://%s", UrlScheme(), endpoint)
}
endpoint := fmt.Sprintf("%srepositories/%s/tags", host, repository)
req, err := r.opaqueRequest("GET", endpoint, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
res, err := r.client.Do(req)
r.setUserAgent(req)
res, err := doWithCookies(r.client, req)
if err != nil {
return nil, err
}
@@ -198,8 +265,8 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
return nil, fmt.Errorf("Could not reach any registry endpoint")
}
func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
repositoryTarget := auth.IndexServerAddress() + "/repositories/" + remote + "/images"
func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, error) {
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", indexEp, remote)
req, err := r.opaqueRequest("GET", repositoryTarget, nil)
if err != nil {
@@ -209,6 +276,7 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
}
req.Header.Set("X-Docker-Token", "true")
r.setUserAgent(req)
res, err := r.client.Do(req)
if err != nil {
@@ -230,8 +298,12 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
}
var endpoints []string
var urlScheme = indexEp[:strings.Index(indexEp, ":")]
if res.Header.Get("X-Docker-Endpoints") != "" {
endpoints = res.Header["X-Docker-Endpoints"]
// The Registry's URL scheme has to match the Index'
for _, ep := range res.Header["X-Docker-Endpoints"] {
endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", urlScheme, ep))
}
} else {
return nil, fmt.Errorf("Index response didn't contain any endpoints")
}
@@ -260,15 +332,15 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
// Push a local image to the registry
func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
registry = registry + "/v1"
// FIXME: try json with UTF8
req, err := http.NewRequest("PUT", registry+"/images/"+imgData.ID+"/json", strings.NewReader(string(jsonRaw)))
req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", bytes.NewReader(jsonRaw))
if err != nil {
return err
}
req.Header.Add("Content-type", "application/json")
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
req.Header.Set("X-Docker-Checksum", imgData.Checksum)
r.setUserAgent(req)
utils.Debugf("Setting checksum for %s: %s", imgData.ID, imgData.Checksum)
res, err := doWithCookies(r.client, req)
@@ -276,9 +348,6 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
return fmt.Errorf("Failed to upload metadata: %s", err)
}
defer res.Body.Close()
if len(res.Cookies()) > 0 {
r.client.Jar.SetCookies(req.URL, res.Cookies())
}
if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
@@ -295,15 +364,15 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
return nil
}
func (r *Registry) PushImageLayerRegistry(imgId string, layer io.Reader, registry string, token []string) error {
registry = registry + "/v1"
req, err := http.NewRequest("PUT", registry+"/images/"+imgId+"/layer", layer)
func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registry string, token []string) error {
req, err := http.NewRequest("PUT", registry+"images/"+imgID+"/layer", layer)
if err != nil {
return err
}
req.ContentLength = -1
req.TransferEncoding = []string{"chunked"}
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
r.setUserAgent(req)
res, err := doWithCookies(r.client, req)
if err != nil {
return fmt.Errorf("Failed to upload layer: %s", err)
@@ -334,14 +403,14 @@ func (r *Registry) opaqueRequest(method, urlStr string, body io.Reader) (*http.R
func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token []string) error {
// "jsonify" the string
revision = "\"" + revision + "\""
registry = registry + "/v1"
req, err := r.opaqueRequest("PUT", registry+"/repositories/"+remote+"/tags/"+tag, strings.NewReader(revision))
req, err := r.opaqueRequest("PUT", registry+"repositories/"+remote+"/tags/"+tag, strings.NewReader(revision))
if err != nil {
return err
}
req.Header.Add("Content-type", "application/json")
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
r.setUserAgent(req)
req.ContentLength = int64(len(revision))
res, err := doWithCookies(r.client, req)
if err != nil {
@@ -354,7 +423,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
return nil
}
func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
imgListJSON, err := json.Marshal(imgList)
if err != nil {
return nil, err
@@ -364,15 +433,17 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
suffix = "images"
}
u := fmt.Sprintf("%srepositories/%s/%s", indexEp, remote, suffix)
utils.Debugf("PUT %s", u)
utils.Debugf("Image list pushed to index:\n%s\n", imgListJSON)
req, err := r.opaqueRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON))
req, err := r.opaqueRequest("PUT", u, bytes.NewReader(imgListJSON))
if err != nil {
return nil, err
}
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true")
r.setUserAgent(req)
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
@@ -393,6 +464,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true")
r.setUserAgent(req)
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
@@ -404,6 +476,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
}
var tokens, endpoints []string
var urlScheme = indexEp[:strings.Index(indexEp, ":")]
if !validate {
if res.StatusCode != 200 && res.StatusCode != 201 {
errBody, err := ioutil.ReadAll(res.Body)
@@ -420,7 +493,10 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
}
if res.Header.Get("X-Docker-Endpoints") != "" {
endpoints = res.Header["X-Docker-Endpoints"]
// The Registry's URL scheme has to match the Index'
for _, ep := range res.Header["X-Docker-Endpoints"] {
endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", urlScheme, ep))
}
} else {
return nil, fmt.Errorf("Index response didn't contain any endpoints")
}
@@ -442,7 +518,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
}
func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
u := auth.IndexServerAddress() + "/search?q=" + url.QueryEscape(term)
u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
@@ -495,11 +571,52 @@ type ImgData struct {
}
type Registry struct {
client *http.Client
authConfig *auth.AuthConfig
client *http.Client
authConfig *auth.AuthConfig
baseVersions []VersionInfo
baseVersionsStr string
}
func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err error) {
func validVersion(version VersionInfo) bool {
stopChars := " \t\r\n/"
if strings.ContainsAny(version.Name(), stopChars) {
return false
}
if strings.ContainsAny(version.Version(), stopChars) {
return false
}
return true
}
// Convert versions to a string and append the string to the string base.
//
// Each VersionInfo will be converted to a string in the format of
// "product/version", where the "product" is get from the Name() method, while
// version is get from the Version() method. Several pieces of verson information
// will be concatinated and separated by space.
func appendVersions(base string, versions ...VersionInfo) string {
if len(versions) == 0 {
return base
}
var buf bytes.Buffer
if len(base) > 0 {
buf.Write([]byte(base))
}
for _, v := range versions {
if !validVersion(v) {
continue
}
buf.Write([]byte(v.Name()))
buf.Write([]byte("/"))
buf.Write([]byte(v.Version()))
buf.Write([]byte(" "))
}
return buf.String()
}
func NewRegistry(root string, authConfig *auth.AuthConfig, baseVersions ...VersionInfo) (r *Registry, err error) {
httpTransport := &http.Transport{
DisableKeepAlives: true,
Proxy: http.ProxyFromEnvironment,
@@ -512,5 +629,10 @@ func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err err
},
}
r.client.Jar, err = cookiejar.New(nil)
return r, err
if err != nil {
return nil, err
}
r.baseVersions = baseVersions
r.baseVersionsStr = appendVersions("", baseVersions...)
return r, nil
}

View File

@@ -108,9 +108,6 @@ func (runtime *Runtime) Register(container *Container) error {
// init the wait lock
container.waitLock = make(chan struct{})
// Even if not running, we init the lock (prevents races in start/stop/kill)
container.State.initLock()
container.runtime = runtime
// Attach to stdout and stderr
@@ -144,7 +141,6 @@ func (runtime *Runtime) Register(container *Container) error {
utils.Debugf("Restarting")
container.State.Ghost = false
container.State.setStopped(0)
// assume empty host config
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
return err
@@ -171,12 +167,12 @@ func (runtime *Runtime) Register(container *Container) error {
return nil
}
func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst string) error {
func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return err
}
src.AddWriter(log)
src.AddWriter(log, stream)
return nil
}

View File

@@ -1,13 +1,14 @@
package docker
import (
"bytes"
"fmt"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"log"
"net"
"os"
"runtime"
"strconv"
"strings"
"sync"
@@ -17,14 +18,19 @@ import (
)
const (
unitTestImageName = "docker-unit-tests"
unitTestImageId = "e9aa60c60128cad1"
unitTestStoreBase = "/var/lib/docker/unit-tests"
testDaemonAddr = "127.0.0.1:4270"
testDaemonProto = "tcp"
unitTestImageName = "docker-test-image"
unitTestImageID = "83599e29c455eb719f77d799bc7c51521b9551972f5a850d7ad265bc1b5292f6" // 1.0
unitTestNetworkBridge = "testdockbr0"
unitTestStoreBase = "/var/lib/docker/unit-tests"
testDaemonAddr = "127.0.0.1:4270"
testDaemonProto = "tcp"
)
var globalRuntime *Runtime
var (
globalRuntime *Runtime
startFds int
startGoroutines int
)
func nuke(runtime *Runtime) error {
var wg sync.WaitGroup
@@ -49,7 +55,7 @@ func cleanup(runtime *Runtime) error {
return err
}
for _, image := range images {
if image.ID != unitTestImageId {
if image.ID != unitTestImageID {
runtime.graph.Delete(image.ID)
}
}
@@ -73,31 +79,32 @@ func init() {
}
if uid := syscall.Geteuid(); uid != 0 {
log.Fatal("docker tests needs to be run as root")
log.Fatal("docker tests need to be run as root")
}
NetworkBridgeIface = "testdockbr0"
NetworkBridgeIface = unitTestNetworkBridge
// Make it our Store root
runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false)
if err != nil {
if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil {
panic(err)
} else {
globalRuntime = runtime
}
globalRuntime = runtime
// Create the "Server"
srv := &Server{
runtime: runtime,
runtime: globalRuntime,
enableCors: false,
lock: &sync.Mutex{},
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
// Retrieve the Image
if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
panic(err)
// If the unit test is not found, try to download it.
if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
// Retrieve the Image
if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
panic(err)
}
}
// Spawn a Daemon
go func() {
if err := ListenAndServe(testDaemonProto, testDaemonAddr, srv, os.Getenv("DEBUG") != ""); err != nil {
@@ -107,48 +114,27 @@ func init() {
// Give some time to ListenAndServer to actually start
time.Sleep(time.Second)
startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
}
// FIXME: test that ImagePull(json=true) send correct json output
func newTestRuntime() (*Runtime, error) {
root, err := ioutil.TempDir("", "docker-test")
if err != nil {
return nil, err
}
if err := os.Remove(root); err != nil {
return nil, err
}
if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
return nil, err
}
runtime, err := NewRuntimeFromDirectory(root, false)
if err != nil {
return nil, err
}
runtime.UpdateCapabilities(true)
return runtime, nil
}
func GetTestImage(runtime *Runtime) *Image {
imgs, err := runtime.graph.All()
if err != nil {
panic(err)
}
for i := range imgs {
if imgs[i].ID == unitTestImageId {
if imgs[i].ID == unitTestImageID {
return imgs[i]
}
}
panic(fmt.Errorf("Test image %v not found", unitTestImageId))
panic(fmt.Errorf("Test image %v not found", unitTestImageID))
}
func TestRuntimeCreate(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
// Make sure we start we 0 containers
@@ -220,10 +206,7 @@ func TestRuntimeCreate(t *testing.T) {
}
func TestDestroy(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
container, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
@@ -267,42 +250,16 @@ func TestDestroy(t *testing.T) {
}
func TestGet(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
builder := NewBuilder(runtime)
container1, err := builder.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "-al"},
},
)
if err != nil {
t.Fatal(err)
}
container1, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
defer runtime.Destroy(container1)
container2, err := builder.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "-al"},
},
)
if err != nil {
t.Fatal(err)
}
container2, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
defer runtime.Destroy(container2)
container3, err := builder.Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ls", "-al"},
},
)
if err != nil {
t.Fatal(err)
}
container3, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
defer runtime.Destroy(container3)
if runtime.Get(container1.ID) != container1 {
@@ -319,125 +276,152 @@ func TestGet(t *testing.T) {
}
func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
strPort := strconv.Itoa(port)
container, err := NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", "echo well hello there | nc -l -p " + strPort},
PortSpecs: []string{strPort},
},
)
if err != nil {
return nil, err
}
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
if strings.Contains(err.Error(), "address already in use") {
return nil, nil
}
return nil, err
}
return container, nil
}
// Run a container with a TCP port allocated, and test that it can receive connections on localhost
func TestAllocatePortLocalhost(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container, string) {
var err error
runtime := mkRuntime(t)
port := 5554
var container *Container
var strPort string
for {
port += 1
log.Println("Trying port", port)
t.Log("Trying port", port)
container, err = findAvailalblePort(runtime, port)
strPort = strconv.Itoa(port)
var cmd string
if proto == "tcp" {
cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat"
} else if proto == "udp" {
cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat"
} else {
t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
}
t.Log("Trying port", strPort)
container, err = NewBuilder(runtime).Create(&Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"sh", "-c", cmd},
PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
})
if container != nil {
break
}
if err != nil {
nuke(runtime)
t.Fatal(err)
}
log.Println("Port", port, "already in use")
t.Log("Port", port, "already in use")
t.Logf("Port %v already in use", strPort)
}
defer container.Kill()
hostConfig := &HostConfig{}
if err := container.Start(hostConfig); err != nil {
nuke(runtime)
t.Fatal(err)
}
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
for {
if container.State.Running {
break
}
for !container.State.Running {
time.Sleep(10 * time.Millisecond)
}
})
conn, err := net.Dial("tcp",
fmt.Sprintf(
"localhost:%s", container.NetworkSettings.PortMapping[strconv.Itoa(port)],
),
)
// Even if the state is running, lets give some time to lxc to spawn the process
container.WaitTimeout(500 * time.Millisecond)
strPort = container.NetworkSettings.PortMapping[strings.Title(proto)][strPort]
return runtime, container, strPort
}
// Run a container with a TCP port allocated, and test that it can receive connections on localhost
func TestAllocateTCPPortLocalhost(t *testing.T) {
runtime, container, port := startEchoServerContainer(t, "tcp")
defer nuke(runtime)
defer container.Kill()
for i := 0; i != 10; i++ {
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", port))
if err != nil {
t.Fatal(err)
}
defer conn.Close()
input := bytes.NewBufferString("well hello there\n")
_, err = conn.Write(input.Bytes())
if err != nil {
t.Fatal(err)
}
buf := make([]byte, 16)
read := 0
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
read, err = conn.Read(buf)
if err != nil {
if err, ok := err.(*net.OpError); ok {
if err.Err == syscall.ECONNRESET {
t.Logf("Connection reset by the proxy, socat is probably not listening yet, trying again in a sec")
conn.Close()
time.Sleep(time.Second)
continue
}
if err.Timeout() {
t.Log("Timeout, trying again")
conn.Close()
continue
}
}
t.Fatal(err)
}
output := string(buf[:read])
if !strings.Contains(output, "well hello there") {
t.Fatal(fmt.Errorf("[%v] doesn't contain [well hello there]", output))
} else {
return
}
}
t.Fatal("No reply from the container")
}
// Run a container with an UDP port allocated, and test that it can receive connections on localhost
func TestAllocateUDPPortLocalhost(t *testing.T) {
runtime, container, port := startEchoServerContainer(t, "udp")
defer nuke(runtime)
defer container.Kill()
conn, err := net.Dial("udp", fmt.Sprintf("localhost:%v", port))
if err != nil {
t.Fatal(err)
}
defer conn.Close()
output, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
input := bytes.NewBufferString("well hello there\n")
buf := make([]byte, 16)
// Try for a minute, for some reason the select in socat may take ages
// to return even though everything on the path seems fine (i.e: the
// UDPProxy forwards the traffic correctly and you can see the packets
// on the interface from within the container).
for i := 0; i != 120; i++ {
_, err := conn.Write(input.Bytes())
if err != nil {
t.Fatal(err)
}
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
read, err := conn.Read(buf)
if err == nil {
output := string(buf[:read])
if strings.Contains(output, "well hello there") {
return
}
}
}
if string(output) != "well hello there\n" {
t.Fatalf("Received wrong output from network connection: should be '%s', not '%s'",
"well hello there\n",
string(output),
)
}
container.Wait()
t.Fatal("No reply from the container")
}
func TestRestore(t *testing.T) {
root, err := ioutil.TempDir("", "docker-test")
if err != nil {
t.Fatal(err)
}
if err := os.Remove(root); err != nil {
t.Fatal(err)
}
if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
t.Fatal(err)
}
runtime1, err := NewRuntimeFromDirectory(root, false)
if err != nil {
t.Fatal(err)
}
builder := NewBuilder(runtime1)
runtime1 := mkRuntime(t)
defer nuke(runtime1)
// Create a container with one instance of docker
container1, err := builder.Create(&Config{
Image: GetTestImage(runtime1).ID,
Cmd: []string{"ls", "-al"},
},
)
if err != nil {
t.Fatal(err)
}
container1, _, _ := mkContainer(runtime1, []string{"_", "ls", "-al"}, t)
defer runtime1.Destroy(container1)
// Create a second container meant to be killed
container2, err := builder.Create(&Config{
Image: GetTestImage(runtime1).ID,
Cmd: []string{"/bin/cat"},
OpenStdin: true,
},
)
if err != nil {
t.Fatal(err)
}
container2, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
defer runtime1.Destroy(container2)
// Start the container non blocking
@@ -472,7 +456,7 @@ func TestRestore(t *testing.T) {
// Here are are simulating a docker restart - that is, reloading all containers
// from scratch
runtime2, err := NewRuntimeFromDirectory(root, false)
runtime2, err := NewRuntimeFromDirectory(runtime1.root, false)
if err != nil {
t.Fatal(err)
}

447
server.go
View File

@@ -1,6 +1,8 @@
package docker
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"github.com/dotcloud/docker/auth"
@@ -12,10 +14,12 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"path"
"runtime"
"strings"
"sync"
"time"
)
func (srv *Server) DockerVersion() APIVersion {
@@ -26,11 +30,53 @@ func (srv *Server) DockerVersion() APIVersion {
}
}
// simpleVersionInfo is a simple implementation of
// the interface VersionInfo, which is used
// to provide version information for some product,
// component, etc. It stores the product name and the version
// in string and returns them on calls to Name() and Version().
type simpleVersionInfo struct {
name string
version string
}
func (v *simpleVersionInfo) Name() string {
return v.name
}
func (v *simpleVersionInfo) Version() string {
return v.version
}
// versionCheckers() returns version informations of:
// docker, go, git-commit (of the docker) and the host's kernel.
//
// Such information will be used on call to NewRegistry().
func (srv *Server) versionInfos() []registry.VersionInfo {
v := srv.DockerVersion()
ret := make([]registry.VersionInfo, 0, 4)
ret = append(ret, &simpleVersionInfo{"docker", v.Version})
if len(v.GoVersion) > 0 {
ret = append(ret, &simpleVersionInfo{"go", v.GoVersion})
}
if len(v.GitCommit) > 0 {
ret = append(ret, &simpleVersionInfo{"git-commit", v.GitCommit})
}
kernelVersion, err := utils.GetKernelVersion()
if err == nil {
ret = append(ret, &simpleVersionInfo{"kernel", kernelVersion.String()})
}
return ret
}
func (srv *Server) ContainerKill(name string) error {
if container := srv.runtime.Get(name); container != nil {
if err := container.Kill(); err != nil {
return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
return fmt.Errorf("Error killing container %s: %s", name, err)
}
srv.LogEvent("kill", name)
} else {
return fmt.Errorf("No such container: %s", name)
}
@@ -49,13 +95,14 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
if _, err := io.Copy(out, data); err != nil {
return err
}
srv.LogEvent("export", name)
return nil
}
return fmt.Errorf("No such container: %s", name)
}
func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
r, err := registry.NewRegistry(srv.runtime.root, nil)
r, err := registry.NewRegistry(srv.runtime.root, nil, srv.versionInfos()...)
if err != nil {
return nil, err
}
@@ -98,7 +145,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
return "", err
}
if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), path); err != nil {
if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%8v/%v (%v)"), sf), path); err != nil {
return "", err
}
// FIXME: Handle custom repo, tag comment, author
@@ -205,14 +252,29 @@ func (srv *Server) DockerInfo() *APIInfo {
} else {
imgcount = len(images)
}
lxcVersion := ""
if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil {
outputStr := string(output)
if len(strings.SplitN(outputStr, ":", 2)) == 2 {
lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1])
}
}
kernelVersion := "<unknown>"
if kv, err := utils.GetKernelVersion(); err == nil {
kernelVersion = kv.String()
}
return &APIInfo{
Containers: len(srv.runtime.List()),
Images: imgcount,
MemoryLimit: srv.runtime.capabilities.MemoryLimit,
SwapLimit: srv.runtime.capabilities.SwapLimit,
Debug: os.Getenv("DEBUG") != "",
NFd: utils.GetTotalUsedFds(),
NGoroutines: runtime.NumGoroutine(),
Containers: len(srv.runtime.List()),
Images: imgcount,
MemoryLimit: srv.runtime.capabilities.MemoryLimit,
SwapLimit: srv.runtime.capabilities.SwapLimit,
Debug: os.Getenv("DEBUG") != "",
NFd: utils.GetTotalUsedFds(),
NGoroutines: runtime.NumGoroutine(),
LXCVersion: lxcVersion,
NEventsListener: len(srv.events),
KernelVersion: kernelVersion,
}
}
@@ -247,6 +309,39 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
}
func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
if container := srv.runtime.Get(name); container != nil {
output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
if err != nil {
return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output)
}
procs := APITop{}
for i, line := range strings.Split(string(output), "\n") {
if len(line) == 0 {
continue
}
words := []string{}
scanner := bufio.NewScanner(strings.NewReader(line))
scanner.Split(bufio.ScanWords)
if !scanner.Scan() {
return nil, fmt.Errorf("Error trying to use lxc-ps")
}
// no scanner.Text because we skip container id
for scanner.Scan() {
words = append(words, scanner.Text())
}
if i == 0 {
procs.Titles = words
} else {
procs.Processes = append(procs.Processes, words)
}
}
return &procs, nil
}
return nil, fmt.Errorf("No such container: %s", name)
}
func (srv *Server) ContainerChanges(name string) ([]Change, error) {
if container := srv.runtime.Get(name); container != nil {
return container.Changes()
@@ -315,8 +410,8 @@ func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
return nil
}
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoint string, token []string, sf *utils.StreamFormatter) error {
history, err := r.GetRemoteHistory(imgId, endpoint, token)
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error {
history, err := r.GetRemoteHistory(imgID, endpoint, token)
if err != nil {
return err
}
@@ -343,7 +438,7 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
return err
}
defer layer.Close()
if err := srv.runtime.graph.Register(utils.ProgressReader(layer, imgSize, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil {
if err := srv.runtime.graph.Register(utils.ProgressReader(layer, imgSize, out, sf.FormatProgress("Downloading", "%8v/%v (%v)"), sf), false, img); err != nil {
return err
}
}
@@ -351,44 +446,32 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
return nil
}
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, remote, askedTag, registryEp string, sf *utils.StreamFormatter) error {
out.Write(sf.FormatStatus("Pulling repository %s from %s", local, auth.IndexServerAddress()))
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName, remoteName, askedTag, indexEp string, sf *utils.StreamFormatter) error {
out.Write(sf.FormatStatus("Pulling repository %s", localName))
var repoData *registry.RepositoryData
var err error
if registryEp == "" {
repoData, err = r.GetRepositoryData(remote)
if err != nil {
return err
}
repoData, err := r.GetRepositoryData(indexEp, remoteName)
if err != nil {
return err
}
utils.Debugf("Updating checksums")
// Reload the json file to make sure not to overwrite faster sums
if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
return err
}
} else {
repoData = &registry.RepositoryData{
Tokens: []string{},
ImgList: make(map[string]*registry.ImgData),
Endpoints: []string{registryEp},
}
utils.Debugf("Updating checksums")
// Reload the json file to make sure not to overwrite faster sums
if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
return err
}
utils.Debugf("Retrieving the tag list")
tagsList, err := r.GetRemoteTags(repoData.Endpoints, remote, repoData.Tokens)
tagsList, err := r.GetRemoteTags(repoData.Endpoints, remoteName, repoData.Tokens)
if err != nil {
utils.Debugf("%v", err)
return err
}
if registryEp != "" {
for tag, id := range tagsList {
repoData.ImgList[id] = &registry.ImgData{
ID: id,
Tag: tag,
Checksum: "",
}
for tag, id := range tagsList {
repoData.ImgList[id] = &registry.ImgData{
ID: id,
Tag: tag,
Checksum: "",
}
}
@@ -402,7 +485,7 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
// Otherwise, check that the tag exists and use only that one
id, exists := tagsList[askedTag]
if !exists {
return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, local)
return fmt.Errorf("Tag %s not found in repository %s", askedTag, localName)
}
repoData.ImgList[id].Tag = askedTag
}
@@ -412,13 +495,15 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
continue
}
out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
if img.Tag == "" {
utils.Debugf("Image (id: %s) present in this repository but untagged, skipping", img.ID)
continue
}
out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, localName))
success := false
for _, ep := range repoData.Endpoints {
if !(strings.HasPrefix(ep, "http://") || strings.HasPrefix(ep, "https://")) {
ep = fmt.Sprintf("%s://%s", registry.UrlScheme(), ep)
}
if err := srv.pullImage(r, out, img.ID, ep+"/v1", repoData.Tokens, sf); err != nil {
if err := srv.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
continue
}
@@ -433,7 +518,7 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
if askedTag != "" && tag != askedTag {
continue
}
if err := srv.runtime.repositories.Set(local, tag, id, true); err != nil {
if err := srv.runtime.repositories.Set(localName, tag, id, true); err != nil {
return err
}
}
@@ -445,8 +530,8 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
}
func (srv *Server) poolAdd(kind, key string) error {
srv.lock.Lock()
defer srv.lock.Unlock()
srv.Lock()
defer srv.Unlock()
if _, exists := srv.pullingPool[key]; exists {
return fmt.Errorf("%s %s is already in progress", key, kind)
@@ -478,25 +563,32 @@ func (srv *Server) poolRemove(kind, key string) error {
}
return nil
}
func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
r, err := registry.NewRegistry(srv.runtime.root, authConfig)
func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
if err != nil {
return err
}
if err := srv.poolAdd("pull", name+":"+tag); err != nil {
if err := srv.poolAdd("pull", localName+":"+tag); err != nil {
return err
}
defer srv.poolRemove("pull", name+":"+tag)
defer srv.poolRemove("pull", localName+":"+tag)
remote := name
parts := strings.Split(name, "/")
if len(parts) > 2 {
remote = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
// Resolve the Repository name from fqn to endpoint + name
endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
if err != nil {
return err
}
if endpoint == auth.IndexServerAddress() {
// If pull "index.docker.io/foo/bar", it's stored locally under "foo/bar"
localName = remoteName
}
out = utils.NewWriteFlusher(out)
err = srv.pullRepository(r, out, name, remote, tag, endpoint, sf)
if err != nil && endpoint != "" {
if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil {
err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf)
if err != nil {
if err := srv.pullImage(r, out, remoteName, endpoint, nil, sf); err != nil {
return err
}
return nil
@@ -511,20 +603,20 @@ func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *util
// - Check if the archive exists, if it does not, ask the registry
// - If the archive does exists, process the checksum from it
// - If the archive does not exists and not found on registry, process checksum from layer
func (srv *Server) getChecksum(imageId string) (string, error) {
func (srv *Server) getChecksum(imageID string) (string, error) {
// FIXME: Use in-memory map instead of reading the file each time
if sums, err := srv.runtime.graph.getStoredChecksums(); err != nil {
return "", err
} else if checksum, exists := sums[imageId]; exists {
} else if checksum, exists := sums[imageID]; exists {
return checksum, nil
}
img, err := srv.runtime.graph.Get(imageId)
img, err := srv.runtime.graph.Get(imageID)
if err != nil {
return "", err
}
if _, err := os.Stat(layerArchivePath(srv.runtime.graph.imageRoot(imageId))); err != nil {
if _, err := os.Stat(layerArchivePath(srv.runtime.graph.imageRoot(imageID))); err != nil {
if os.IsNotExist(err) {
// TODO: Ask the registry for the checksum
// As the archive is not there, it is supposed to come from a pull.
@@ -571,7 +663,7 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgDat
return imgList, nil
}
func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name, registryEp string, localRepo map[string]string, sf *utils.StreamFormatter) error {
func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, indexEp string, sf *utils.StreamFormatter) error {
out = utils.NewWriteFlusher(out)
out.Write(sf.FormatStatus("Processing checksums"))
imgList, err := srv.getImageList(localRepo)
@@ -579,94 +671,64 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name, reg
return err
}
out.Write(sf.FormatStatus("Sending image list"))
srvName := name
parts := strings.Split(name, "/")
if len(parts) > 2 {
srvName = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
}
var repoData *registry.RepositoryData
if registryEp == "" {
repoData, err = r.PushImageJSONIndex(name, imgList, false, nil)
if err != nil {
return err
}
} else {
repoData = &registry.RepositoryData{
ImgList: make(map[string]*registry.ImgData),
Tokens: []string{},
Endpoints: []string{registryEp},
}
tagsList, err := r.GetRemoteTags(repoData.Endpoints, name, repoData.Tokens)
if err != nil && err.Error() != "Repository not found" {
return err
} else if err == nil {
for tag, id := range tagsList {
repoData.ImgList[id] = &registry.ImgData{
ID: id,
Tag: tag,
Checksum: "",
}
}
}
repoData, err = r.PushImageJSONIndex(indexEp, remoteName, imgList, false, nil)
if err != nil {
return err
}
for _, ep := range repoData.Endpoints {
if !(strings.HasPrefix(ep, "http://") || strings.HasPrefix(ep, "https://")) {
ep = fmt.Sprintf("%s://%s", registry.UrlScheme(), ep)
}
out.Write(sf.FormatStatus("Pushing repository %s to %s (%d tags)", name, ep, len(localRepo)))
out.Write(sf.FormatStatus("Pushing repository %s (%d tags)", localName, len(localRepo)))
// For each image within the repo, push them
for _, elem := range imgList {
if _, exists := repoData.ImgList[elem.ID]; exists {
out.Write(sf.FormatStatus("Image %s already on registry, skipping", name))
out.Write(sf.FormatStatus("Image %s already pushed, skipping", elem.ID))
continue
} else if registryEp != "" && r.LookupRemoteImage(elem.ID, registryEp, repoData.Tokens) {
fmt.Fprintf(out, "Image %s already on registry, skipping\n", name)
} else if r.LookupRemoteImage(elem.ID, ep, repoData.Tokens) {
out.Write(sf.FormatStatus("Image %s already pushed, skipping", elem.ID))
continue
}
if err := srv.pushImage(r, out, name, elem.ID, ep, repoData.Tokens, sf); err != nil {
if err := srv.pushImage(r, out, remoteName, elem.ID, ep, repoData.Tokens, sf); err != nil {
// FIXME: Continue on error?
return err
}
out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/repositories/"+srvName+"/tags/"+elem.Tag))
if err := r.PushRegistryTag(srvName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"repositories/"+remoteName+"/tags/"+elem.Tag))
if err := r.PushRegistryTag(remoteName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
return err
}
}
}
if registryEp == "" {
if _, err := r.PushImageJSONIndex(name, imgList, true, repoData.Endpoints); err != nil {
return err
}
if _, err := r.PushImageJSONIndex(indexEp, remoteName, imgList, true, repoData.Endpoints); err != nil {
return err
}
return nil
}
func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, ep string, token []string, sf *utils.StreamFormatter) error {
func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID, ep string, token []string, sf *utils.StreamFormatter) error {
out = utils.NewWriteFlusher(out)
jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgId, "json"))
jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgID, "json"))
if err != nil {
return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgId, err)
return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgID, err)
}
out.Write(sf.FormatStatus("Pushing %s", imgId))
out.Write(sf.FormatStatus("Pushing %s", imgID))
// Make sure we have the image's checksum
checksum, err := srv.getChecksum(imgId)
checksum, err := srv.getChecksum(imgID)
if err != nil {
return err
}
imgData := &registry.ImgData{
ID: imgId,
ID: imgID,
Checksum: checksum,
}
// Send the json
if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
if err == registry.ErrAlreadyExists {
out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.ID))
out.Write(sf.FormatStatus("Image %s already pushed, skipping", imgData.ID))
return nil
}
return err
@@ -675,11 +737,11 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
// Retrieve the tarball to be sent
var layerData *TempArchive
// If the archive exists, use it
file, err := os.Open(layerArchivePath(srv.runtime.graph.imageRoot(imgId)))
file, err := os.Open(layerArchivePath(srv.runtime.graph.imageRoot(imgID)))
if err != nil {
if os.IsNotExist(err) {
// If the archive does not exist, create one from the layer
layerData, err = srv.runtime.graph.TempLayerArchive(imgId, Xz, out)
layerData, err = srv.runtime.graph.TempLayerArchive(imgID, Xz, sf, out)
if err != nil {
return fmt.Errorf("Failed to generate layer archive: %s", err)
}
@@ -699,40 +761,48 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
}
// Send the layer
if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%v/%v (%v)"), sf), ep, token); err != nil {
if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%8v/%v (%v)"), sf), ep, token); err != nil {
return err
}
return nil
}
// FIXME: Allow to interupt current push when new push of same image is done.
func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
if err := srv.poolAdd("push", name); err != nil {
func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
if err := srv.poolAdd("push", localName); err != nil {
return err
}
defer srv.poolRemove("push", localName)
// Resolve the Repository name from fqn to endpoint + name
endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
if err != nil {
return err
}
defer srv.poolRemove("push", name)
out = utils.NewWriteFlusher(out)
img, err := srv.runtime.graph.Get(name)
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig)
img, err := srv.runtime.graph.Get(localName)
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
if err2 != nil {
return err2
}
if err != nil {
out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name])))
reposLen := len(srv.runtime.repositories.Repositories[localName])
out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", localName, reposLen))
// If it fails, try to get the repository
if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
if err := srv.pushRepository(r, out, name, endpoint, localRepo, sf); err != nil {
if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists {
if err := srv.pushRepository(r, out, localName, remoteName, localRepo, endpoint, sf); err != nil {
return err
}
return nil
}
return err
}
out.Write(sf.FormatStatus("The push refers to an image: [%s]", name))
if err := srv.pushImage(r, out, name, img.ID, endpoint, nil, sf); err != nil {
var token []string
out.Write(sf.FormatStatus("The push refers to an image: [%s]", localName))
if err := srv.pushImage(r, out, remoteName, img.ID, endpoint, token, sf); err != nil {
return err
}
return nil
@@ -761,7 +831,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
if err != nil {
return err
}
archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%v/%v (%v)"), sf)
archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%8v/%v (%v)"), sf)
}
img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
if err != nil {
@@ -798,14 +868,16 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
}
return "", err
}
srv.LogEvent("create", container.ShortID())
return container.ShortID(), nil
}
func (srv *Server) ContainerRestart(name string, t int) error {
if container := srv.runtime.Get(name); container != nil {
if err := container.Restart(t); err != nil {
return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
return fmt.Errorf("Error restarting container %s: %s", name, err)
}
srv.LogEvent("restart", name)
} else {
return fmt.Errorf("No such container: %s", name)
}
@@ -823,8 +895,9 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
volumes[volumeId] = struct{}{}
}
if err := srv.runtime.Destroy(container); err != nil {
return fmt.Errorf("Error destroying container %s: %s", name, err.Error())
return fmt.Errorf("Error destroying container %s: %s", name, err)
}
srv.LogEvent("destroy", name)
if removeVolume {
// Retrieve all volumes from all remaining containers
@@ -859,7 +932,6 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
if len(srv.runtime.repositories.ByID()[id]) != 0 {
return ErrImageReferenced
}
// If the image is not referenced but has children, go recursive
referenced := false
byParents, err := srv.runtime.graph.ByParent()
@@ -892,6 +964,7 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
return err
}
*imgs = append(*imgs, APIRmi{Deleted: utils.TruncateID(id)})
srv.LogEvent("delete", utils.TruncateID(id))
return nil
}
return nil
@@ -912,38 +985,56 @@ func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
return nil
}
func (srv *Server) deleteImage(img *Image, repoName, tag string) (*[]APIRmi, error) {
func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
imgs := []APIRmi{}
//If delete by id, see if the id belong only to one repository
if strings.Contains(img.ID, repoName) && tag == "" {
for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
parsedRepo := strings.Split(repoAndTag, ":")[0]
if strings.Contains(img.ID, repoName) {
repoName = parsedRepo
if len(srv.runtime.repositories.ByID()[img.ID]) == 1 && len(strings.Split(repoAndTag, ":")) > 1 {
tag = strings.Split(repoAndTag, ":")[1]
}
} else if repoName != parsedRepo {
// the id belongs to multiple repos, like base:latest and user:test,
// in that case return conflict
return imgs, nil
}
}
}
//Untag the current image
var imgs []APIRmi
tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
if err != nil {
return nil, err
}
if tagDeleted {
imgs = append(imgs, APIRmi{Untagged: img.ShortID()})
srv.LogEvent("untag", img.ShortID())
}
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
if err := srv.deleteImageAndChildren(img.ID, &imgs); err != nil {
if err != ErrImageReferenced {
return &imgs, err
return imgs, err
}
} else if err := srv.deleteImageParents(img, &imgs); err != nil {
if err != ErrImageReferenced {
return &imgs, err
return imgs, err
}
}
}
return &imgs, nil
return imgs, nil
}
func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]APIRmi, error) {
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
img, err := srv.runtime.repositories.LookupImage(name)
if err != nil {
return nil, fmt.Errorf("No such image: %s", name)
}
if !autoPrune {
if err := srv.runtime.graph.Delete(img.ID); err != nil {
return nil, fmt.Errorf("Error deleting image %s: %s", name, err.Error())
return nil, fmt.Errorf("Error deleting image %s: %s", name, err)
}
return nil, nil
}
@@ -958,7 +1049,7 @@ func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]APIRmi, error) {
return srv.deleteImage(img, name, tag)
}
func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error) {
func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
// Retrieve all images
images, err := srv.runtime.graph.All()
@@ -976,7 +1067,7 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
}
// Loop on the children of the given image and check the config
for elem := range imageMap[imgId] {
for elem := range imageMap[imgID] {
img, err := srv.runtime.graph.Get(elem)
if err != nil {
return nil, err
@@ -991,8 +1082,9 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
if container := srv.runtime.Get(name); container != nil {
if err := container.Start(hostConfig); err != nil {
return fmt.Errorf("Error starting container %s: %s", name, err.Error())
return fmt.Errorf("Error starting container %s: %s", name, err)
}
srv.LogEvent("start", name)
} else {
return fmt.Errorf("No such container: %s", name)
}
@@ -1002,8 +1094,9 @@ func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
func (srv *Server) ContainerStop(name string, t int) error {
if container := srv.runtime.Get(name); container != nil {
if err := container.Stop(t); err != nil {
return fmt.Errorf("Error stopping container %s: %s", name, err.Error())
return fmt.Errorf("Error stopping container %s: %s", name, err)
}
srv.LogEvent("stop", name)
} else {
return fmt.Errorf("No such container: %s", name)
}
@@ -1031,20 +1124,41 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
}
//logs
if logs {
if stdout {
cLog, err := container.ReadLog("stdout")
if err != nil {
utils.Debugf("Error reading logs (stdout): %s", err)
} else if _, err := io.Copy(out, cLog); err != nil {
utils.Debugf("Error streaming logs (stdout): %s", err)
cLog, err := container.ReadLog("json")
if err != nil && os.IsNotExist(err) {
// Legacy logs
utils.Debugf("Old logs format")
if stdout {
cLog, err := container.ReadLog("stdout")
if err != nil {
utils.Debugf("Error reading logs (stdout): %s", err)
} else if _, err := io.Copy(out, cLog); err != nil {
utils.Debugf("Error streaming logs (stdout): %s", err)
}
}
}
if stderr {
cLog, err := container.ReadLog("stderr")
if err != nil {
utils.Debugf("Error reading logs (stderr): %s", err)
} else if _, err := io.Copy(out, cLog); err != nil {
utils.Debugf("Error streaming logs (stderr): %s", err)
if stderr {
cLog, err := container.ReadLog("stderr")
if err != nil {
utils.Debugf("Error reading logs (stderr): %s", err)
} else if _, err := io.Copy(out, cLog); err != nil {
utils.Debugf("Error streaming logs (stderr): %s", err)
}
}
} else if err != nil {
utils.Debugf("Error reading logs (json): %s", err)
} else {
dec := json.NewDecoder(cLog)
for {
var l utils.JSONLog
if err := dec.Decode(&l); err == io.EOF {
break
} else if err != nil {
utils.Debugf("Error streaming logs: %s", err)
break
}
if (l.Stream == "stdout" && stdout) || (l.Stream == "stderr" && stderr) {
fmt.Fprintf(out, "%s", l.Log)
}
}
}
}
@@ -1114,18 +1228,33 @@ func NewServer(flGraphPath string, autoRestart, enableCors bool, dns ListOpts) (
srv := &Server{
runtime: runtime,
enableCors: enableCors,
lock: &sync.Mutex{},
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events
listeners: make(map[string]chan utils.JSONMessage),
}
runtime.srv = srv
return srv, nil
}
func (srv *Server) LogEvent(action, id string) {
now := time.Now().Unix()
jm := utils.JSONMessage{Status: action, ID: id, Time: now}
srv.events = append(srv.events, jm)
for _, c := range srv.listeners {
select { // non blocking channel
case c <- jm:
default:
}
}
}
type Server struct {
sync.Mutex
runtime *Runtime
enableCors bool
lock *sync.Mutex
pullingPool map[string]struct{}
pushingPool map[string]struct{}
events []utils.JSONMessage
listeners map[string]chan utils.JSONMessage
}

View File

@@ -1,18 +1,23 @@
package docker
import (
"github.com/dotcloud/docker/utils"
"strings"
"testing"
"time"
)
func TestContainerTagImageDelete(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
initialImages, err := srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
if err := srv.runtime.repositories.Set("utest", "tag1", unitTestImageName, false); err != nil {
t.Fatal(err)
}
@@ -25,8 +30,8 @@ func TestContainerTagImageDelete(t *testing.T) {
t.Fatal(err)
}
if len(images) != 3 {
t.Errorf("Excepted 3 images, %d found", len(images))
if len(images) != len(initialImages)+2 {
t.Errorf("Expected %d images, %d found", len(initialImages)+2, len(images))
}
if _, err := srv.ImageDelete("utest/docker:tag2", true); err != nil {
@@ -38,8 +43,8 @@ func TestContainerTagImageDelete(t *testing.T) {
t.Fatal(err)
}
if len(images) != 2 {
t.Errorf("Excepted 2 images, %d found", len(images))
if len(images) != len(initialImages)+1 {
t.Errorf("Expected %d images, %d found", len(initialImages)+1, len(images))
}
if _, err := srv.ImageDelete("utest:tag1", true); err != nil {
@@ -51,16 +56,13 @@ func TestContainerTagImageDelete(t *testing.T) {
t.Fatal(err)
}
if len(images) != 1 {
t.Errorf("Excepted 1 image, %d found", len(images))
if len(images) != len(initialImages) {
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
}
}
func TestCreateRm(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -89,11 +91,29 @@ func TestCreateRm(t *testing.T) {
}
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
runtime, err := newTestRuntime()
func TestCommit(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
if err != nil {
t.Fatal(err)
}
id, err := srv.ContainerCreate(config)
if err != nil {
t.Fatal(err)
}
if _, err := srv.ContainerCommit(id, "testrepo", "testtag", "", "", config); err != nil {
t.Fatal(err)
}
}
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
@@ -149,11 +169,9 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
}
func TestRunWithTooLowMemoryLimit(t *testing.T) {
runtime, err := newTestRuntime()
var err error
runtime := mkRuntime(t)
srv := &Server{runtime: runtime}
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
// Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
_, err = srv.ContainerCreate(
@@ -169,3 +187,126 @@ func TestRunWithTooLowMemoryLimit(t *testing.T) {
}
}
func TestLogEvent(t *testing.T) {
runtime := mkRuntime(t)
srv := &Server{
runtime: runtime,
events: make([]utils.JSONMessage, 0, 64),
listeners: make(map[string]chan utils.JSONMessage),
}
srv.LogEvent("fakeaction", "fakeid")
listener := make(chan utils.JSONMessage)
srv.Lock()
srv.listeners["test"] = listener
srv.Unlock()
srv.LogEvent("fakeaction2", "fakeid")
if len(srv.events) != 2 {
t.Fatalf("Expected 2 events, found %d", len(srv.events))
}
go func() {
time.Sleep(200 * time.Millisecond)
srv.LogEvent("fakeaction3", "fakeid")
time.Sleep(200 * time.Millisecond)
srv.LogEvent("fakeaction4", "fakeid")
}()
setTimeout(t, "Listening for events timed out", 2*time.Second, func() {
for i := 2; i < 4; i++ {
event := <-listener
if event != srv.events[i] {
t.Fatalf("Event received it different than expected")
}
}
})
}
func TestRmi(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
srv := &Server{runtime: runtime}
initialImages, err := srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
if err != nil {
t.Fatal(err)
}
containerID, err := srv.ContainerCreate(config)
if err != nil {
t.Fatal(err)
}
//To remove
err = srv.ContainerStart(containerID, hostConfig)
if err != nil {
t.Fatal(err)
}
imageID, err := srv.ContainerCommit(containerID, "test", "", "", "", nil)
if err != nil {
t.Fatal(err)
}
err = srv.ContainerTag(imageID, "test", "0.1", false)
if err != nil {
t.Fatal(err)
}
containerID, err = srv.ContainerCreate(config)
if err != nil {
t.Fatal(err)
}
//To remove
err = srv.ContainerStart(containerID, hostConfig)
if err != nil {
t.Fatal(err)
}
_, err = srv.ContainerCommit(containerID, "test", "", "", "", nil)
if err != nil {
t.Fatal(err)
}
images, err := srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
if len(images)-len(initialImages) != 2 {
t.Fatalf("Expected 2 new images, found %d.", len(images)-len(initialImages))
}
_, err = srv.ImageDelete(imageID, true)
if err != nil {
t.Fatal(err)
}
images, err = srv.Images(false, "")
if err != nil {
t.Fatal(err)
}
if len(images)-len(initialImages) != 1 {
t.Fatalf("Expected 1 new image, found %d.", len(images)-len(initialImages))
}
for _, image := range images {
if strings.Contains(unitTestImageID, image.ID) {
continue
}
if image.Repository == "" {
t.Fatalf("Expected tagged image, got untagged one.")
}
}
}

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