capitate 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/Capfile +3 -11
  2. data/History.txt +8 -1
  3. data/Manifest.txt +4 -17
  4. data/bin/capitate +51 -19
  5. data/config/hoe.rb +3 -1
  6. data/lib/capitate/plugins/base.rb +81 -35
  7. data/lib/capitate/recipes.rb +1 -2
  8. data/lib/capitate/task_node.rb +157 -0
  9. data/lib/capitate/version.rb +1 -1
  10. data/lib/capitate.rb +2 -0
  11. data/lib/profiles/centos-sick.rb +18 -16
  12. data/lib/recipes/centos/imagemagick.rb +3 -2
  13. data/lib/recipes/centos/memcached.rb +18 -3
  14. data/lib/recipes/centos/mongrel_cluster.rb +15 -5
  15. data/lib/recipes/centos/monit.rb +14 -3
  16. data/lib/recipes/centos/mysql.rb +10 -3
  17. data/lib/recipes/centos/nginx.rb +29 -3
  18. data/lib/recipes/centos/ruby.rb +2 -2
  19. data/lib/recipes/centos/sphinx.rb +19 -6
  20. data/lib/recipes/docs.rb +17 -0
  21. data/lib/recipes/gems.rb +10 -1
  22. data/lib/recipes/memcached.rb +11 -1
  23. data/lib/recipes/mongrel_cluster.rb +13 -1
  24. data/lib/recipes/mysql.rb +41 -2
  25. data/lib/recipes/nginx.rb +25 -11
  26. data/lib/recipes/packages.rb +16 -1
  27. data/lib/recipes/rails.rb +16 -1
  28. data/lib/recipes/recipes.rb +30 -0
  29. data/tasks/website.rake +9 -0
  30. data/website/index.html +46 -44
  31. data/website/index.txt +24 -31
  32. data/website/stylesheets/screen.css +31 -12
  33. data/website/template.rhtml +19 -5
  34. data/website/template_recipe.rhtml +25 -0
  35. metadata +19 -24
  36. data/lib/capitate/config.rb +0 -106
  37. data/lib/doc/centos/memcached.yml +0 -18
  38. data/lib/doc/centos/mongrel_cluster.yml +0 -11
  39. data/lib/doc/centos/monit.yml +0 -12
  40. data/lib/doc/centos/mysql.yml +0 -6
  41. data/lib/doc/centos/nginx.yml +0 -25
  42. data/lib/doc/centos/sphinx.yml +0 -14
  43. data/lib/doc/gems.yml +0 -7
  44. data/lib/doc/install.yml +0 -11
  45. data/lib/doc/memcached.yml +0 -13
  46. data/lib/doc/mongrel_cluster.yml +0 -12
  47. data/lib/doc/mysql.yml +0 -46
  48. data/lib/doc/nginx.yml +0 -23
  49. data/lib/doc/packages.yml +0 -17
  50. data/lib/doc/rails.yml +0 -15
  51. data/lib/recipes/install.rb +0 -18
  52. data/tasks/capitate.rake +0 -10
@@ -1,8 +1,19 @@
1
- namespace :centos do
1
+ namespace :monit do
2
2
 
3
- namespace :monit do
3
+ namespace :centos do
4
4
 
5
- desc "Install monit"
5
+ desc <<-DESC
6
+ Install monit.
7
+
8
+ monit_port: Monit port. Defaults to 2812.
9
+
10
+ set :monit_port, 2812
11
+
12
+ monit_password: Monit password. Defaults to password prompt.
13
+
14
+ set :monit_password, Proc.new { Capistrano::CLI.ui.ask('Monit admin password (to set): ') })
15
+
16
+ DESC
6
17
  task :install do
7
18
 
8
19
  # Settings
@@ -1,8 +1,15 @@
1
- namespace :centos do
1
+ namespace :mysql do
2
2
 
3
- namespace :mysql do
3
+ namespace :centos do
4
4
 
5
- desc "Install mysql"
5
+ desc <<-DESC
6
+ Install mysql.
7
+
8
+ mysql_admin_password_set: Mysql admin password (to set). Defaults to password prompt.
9
+
10
+ set :mysql_admin_password_set, Proc.new { Capistrano::CLI.ui.ask('Mysql admin password (to set): ') }
11
+
12
+ DESC
6
13
  task :install do
7
14
 
8
15
  # Settings
@@ -1,8 +1,26 @@
1
- namespace :centos do
1
+ namespace :nginx do
2
2
 
3
- namespace :nginx do
3
+ namespace :centos do
4
4
 
5
- desc "Install nginx, conf, initscript, nginx user and service"
5
+ desc <<-DESC
6
+ Install nginx, conf, initscript, nginx user and service.
7
+ nginx_bin_path: Nginx sbin path. Defaults to /sbin/nginx
8
+
9
+ set :nginx_bin_path, "/sbin/nginx"
10
+
11
+ nginx_conf_path: Path to nginx conf. Defaults to /etc/nginx/nginx.conf
12
+
13
+ set :nginx_conf_path, "/etc/nginx/nginx.conf"
14
+
15
+ nginx_pid_path: Path to nginx pid file. Defaults to /var/run/nginx.pid
16
+
17
+ set :nginx_pid_path, "/var/run/nginx.pid"
18
+
19
+ nginx_prefix_path: Nginx install prefix. Defaults to /var/nginx
20
+
21
+ set :nginx_prefix_path, "/var/nginx"
22
+
23
+ DESC
6
24
  task :install do
7
25
 
8
26
  # Settings
@@ -40,6 +58,14 @@ namespace :centos do
40
58
  sudo "id nginx || /usr/sbin/adduser -r nginx"
41
59
  end
42
60
 
61
+ # Restart nginx
62
+ desc "Restart nginx (service)"
63
+ task :restart do
64
+ # TODO: Monit
65
+ sudo "/sbin/service nginx restart"
66
+ end
67
+
68
+
43
69
  end
44
70
 
45
71
  end
@@ -1,6 +1,6 @@
1
- namespace :centos do
1
+ namespace :ruby do
2
2
 
3
- namespace :ruby do
3
+ namespace :centos do
4
4
 
5
5
  desc "Install ruby and rubygems"
6
6
  task :install do
@@ -1,8 +1,15 @@
1
- namespace :centos do
1
+ namespace :sphinx do
2
2
 
3
- namespace :sphinx do
3
+ namespace :centos do
4
4
 
5
- desc "Install sphinx"
5
+ desc <<-DESC
6
+ Install sphinx.
7
+
8
+ sphinx_prefix: Sphinx install prefix. Defaults to "/usr/local/sphinx"
9
+
10
+ set :sphinx_prefix, "/usr/local/sphinx"
11
+
12
+ DESC
6
13
  task :install do
7
14
 
8
15
  # Settings
@@ -22,9 +29,15 @@ namespace :centos do
22
29
  script.make_install("sphinx", sphinx_options)
23
30
  end
24
31
 
25
- desc "Setup sphinx for application"
26
- after "centos:sphinx:setup", "sphinx:setup_monit"
27
- task :setup do
32
+ desc <<-DESC
33
+ Setup sphinx for application.
34
+
35
+ sphinx_prefix: Sphinx install prefix. Defaults to "/usr/local/sphinx"
36
+
37
+ set :sphinx_prefix, "/usr/local/sphinx"
38
+
39
+ DESC
40
+ task :setup do
28
41
 
29
42
  # Settings
30
43
  fetch_or_default(:sphinx_prefix, "/usr/local/sphinx")
@@ -0,0 +1,17 @@
1
+ namespace :docs do
2
+
3
+ desc "Generate documentation for all currently loaded recipes."
4
+ task :recipes do
5
+ top_node = capitate.task_tree
6
+
7
+ puts "Tree:\n#{}"
8
+
9
+ dir = "docs/recipes"
10
+ FileUtils.rm_rf(dir)
11
+ FileUtils.mkdir_p(dir)
12
+
13
+ top_node.write_doc(dir, "index", "Recipes")
14
+
15
+ end
16
+ end
17
+
data/lib/recipes/gems.rb CHANGED
@@ -1,6 +1,15 @@
1
1
  namespace :gems do
2
2
 
3
- desc "Install gems"
3
+ desc <<-DESC
4
+ Install gems.
5
+
6
+ set :gem_list, [
7
+ "rake",
8
+ "mysql -- --with-mysql-include=/usr/include/mysql --with-mysql-lib=/usr/lib/mysql --with-mysql-config",
9
+ "raspell"
10
+ ]
11
+
12
+ DESC
4
13
  task :install do
5
14
  # Settings
6
15
  fetch(:gem_list)
@@ -1,6 +1,16 @@
1
1
  namespace :memcached do
2
2
 
3
- desc "Install memcached monit hooks"
3
+ desc <<-DESC
4
+ Install memcached monit hooks.
5
+
6
+ memcached_pid_path: Path to memcached pid file. Defaults to /var/run/memcached.pid
7
+
8
+ set :memcached_pid_path, "/var/run/memcached.pid"
9
+
10
+ memcached_port: Memcached port. Defaults to 11211.
11
+
12
+ set :memcached_port, 11211
13
+ DESC
4
14
  task :install_monit do
5
15
 
6
16
  # Settings
@@ -1,7 +1,19 @@
1
1
  # Create init script
2
2
  namespace :mongrel_cluster do
3
3
 
4
- desc "Create monit configuration for mongrel cluster"
4
+ desc <<-DESC
5
+ Create monit configuration for mongrel cluster.
6
+
7
+ mongrel_size: Number of mongrels.
8
+
9
+ set :mongrel_size, 3
10
+
11
+ mongrel_port: Starting port for mongrels. If there are 3 mongrels with port 9000, then instances
12
+ will be at 9000, 9001, and 9002
13
+
14
+ set :mongrel_port, 9000
15
+
16
+ DESC
5
17
  task :setup_monit do
6
18
 
7
19
  # See http://www.igvita.com/2006/11/07/monit-makes-mongrel-play-nice/
data/lib/recipes/mysql.rb CHANGED
@@ -1,7 +1,18 @@
1
1
  # Mysql recipes
2
2
  namespace :mysql do
3
3
 
4
- desc "Install mysql monit hooks"
4
+ desc <<-DESC
5
+ Install mysql monit hooks.
6
+
7
+ db_port: Mysql port. Defaults to 3306.
8
+
9
+ set :db_port, 3306
10
+
11
+ mysql_pid_path: Path to mysql pid file. Defaults to /var/run/mysqld/mysqld.pid
12
+
13
+ set :mysql_pid_path, "/var/run/mysqld/mysqld.pid"
14
+
15
+ DESC
5
16
  task :install_monit do
6
17
 
7
18
  # Settings
@@ -12,7 +23,35 @@ namespace :mysql do
12
23
  sudo "install -o root /tmp/mysql.monitrc /etc/monit/mysql.monitrc"
13
24
  end
14
25
 
15
- desc "Create database user, and database with appropriate permissions"
26
+ desc <<-DESC
27
+ Create database user, and database with appropriate permissions.
28
+
29
+ db_name: Database name (application).
30
+
31
+ set :db_name, "app_db_name"
32
+
33
+ db_user: Database user (application).
34
+
35
+ set :db_user, "app_db_user"
36
+
37
+ db_pass: Database password (application).
38
+
39
+ set :db_pass, "the_password"
40
+
41
+ web_host: Web host to provide access privileges to (if recipe used in context of web app).
42
+ Defaults to nil. TODO: Support multiple web hosts
43
+
44
+ set :web_host, 10.0.6.100
45
+
46
+ db_host: Database host (to provide itself with access).
47
+
48
+ set :db_host, 10.0.6.101
49
+
50
+ mysql_admin_password: Mysql admin password (to use to connect). Defaults to password prompt.
51
+
52
+ set :mysql_admin_password, Proc.new { Capistrano::CLI.ui.ask('Mysql admin password: ') })
53
+
54
+ DESC
16
55
  task :setup do
17
56
 
18
57
  # Settings
data/lib/recipes/nginx.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  # Nginx recipes
2
2
  namespace :nginx do
3
3
 
4
- # Callbacks
5
- after "nginx:setup", "nginx:restart"
4
+ desc <<-DESC
5
+ Install nginx monit hooks.
6
+
7
+ nginx_pid_path: Path to nginx pid file. Defaults to /var/run/nginx.pid
8
+
9
+ set :nginx_pid_path, "/var/run/nginx.pid"
6
10
 
7
- desc "Install nginx monit hooks"
11
+ DESC
8
12
  task :install_monit do
9
13
 
10
14
  # Settings
@@ -14,7 +18,23 @@ namespace :nginx do
14
18
  sudo "install -o root /tmp/nginx.monitrc /etc/monit/nginx.monitrc"
15
19
  end
16
20
 
17
- desc "Create and update the nginx vhost include"
21
+ desc <<-DESC
22
+ Create and update the nginx vhost include.
23
+
24
+ mongrel_size: Number of mongrels.
25
+
26
+ set :mongrel_size, 3
27
+
28
+ mongrel_port: Starting port for mongrels.
29
+ If there are 3 mongrels with port 9000, then instances will be at 9000, 9001, and 9002
30
+
31
+ set :mongrel_port, 9000
32
+
33
+ domain_name: Domain name for nginx virtual host, (without www prefix).
34
+
35
+ set :domain_name, "foo.com"
36
+
37
+ DESC
18
38
  task :setup_mongrel do
19
39
 
20
40
  # Settings
@@ -30,11 +50,5 @@ namespace :nginx do
30
50
 
31
51
  sudo "install -o root /tmp/nginx_#{application}.conf /etc/nginx/vhosts/#{application}.conf"
32
52
  end
33
-
34
- # Restart nginx
35
- task :restart do
36
- # TODO: Monit
37
- sudo "/sbin/service nginx restart"
38
- end
39
-
53
+
40
54
  end
@@ -1,6 +1,21 @@
1
1
  namespace :packages do
2
2
 
3
- desc "Remove, update and install packages"
3
+ desc <<-DESC
4
+ Remove, update and install packages.
5
+
6
+ packages_type: Package manager type. Currently can only be :yum. \n\nTODO: Support more package managers.
7
+
8
+ set :packages_type, :yum
9
+
10
+ packages_remove: Packages to remove.
11
+
12
+ set :packages_remove, [ "openoffice.org-*", "ImageMagick" ]
13
+
14
+ packages_add: Packages to add.
15
+
16
+ set :packages_add, [ "gcc", "kernel-devel", "libevent-devel", "libxml2-devel" ]
17
+
18
+ DESC
4
19
  task :install do
5
20
 
6
21
  # Settings
data/lib/recipes/rails.rb CHANGED
@@ -1,7 +1,22 @@
1
1
  # Rails recipes
2
2
  namespace :rails do
3
3
 
4
- desc "Create database yaml in shared path"
4
+ desc <<-DESC
5
+ Create database yaml in shared path.
6
+
7
+ db_name: Database name (rails).
8
+
9
+ set :db_name, "app_db_name"
10
+
11
+ db_user: Database user (rails).
12
+
13
+ set :db_user, "app_db_user"
14
+
15
+ db_pass: Database password (rails).
16
+
17
+ set :db_pass, "the_password"
18
+
19
+ DESC
5
20
  task :setup do
6
21
 
7
22
  # Settings
@@ -0,0 +1,30 @@
1
+ namespace :recipes do
2
+
3
+ desc <<-DESC
4
+ Run recipes, as user.
5
+
6
+ *recipes_run*: Recipes to run.
7
+
8
+ set :recipes, [ "centos:setup_for_web", "packages:install", "ruby:centos:install" ]
9
+
10
+ *recipes_user*: The user to run as for these recipes. Defaults to root.
11
+
12
+ set :recipes_user, "root"
13
+
14
+ DESC
15
+ task :run do
16
+
17
+ # Settings
18
+ fetch(:recipes_run)
19
+ fetch_or_default(:recipes_user, "root")
20
+
21
+ # Change user to install user for this recipes run
22
+ set_user(recipes_user)
23
+
24
+ # These run after install task and install all the apps
25
+ recipes_run.each do |task_name|
26
+ after "recipes:run", task_name
27
+ end
28
+ end
29
+
30
+ end
data/tasks/website.rake CHANGED
@@ -3,6 +3,15 @@ task :website_generate => :ruby_env do
3
3
  (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
4
  sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
5
  end
6
+
7
+ # Clean and re-create
8
+ FileUtils.rm_rf("website/recipes")
9
+ FileUtils.mkdir_p("website/recipes")
10
+ sh "cap docs:recipes"
11
+ template = File.join(File.dirname(__FILE__), '/../website/template_recipe.rhtml')
12
+ Dir['docs/recipes/**/*.txt'].each do |txt|
13
+ sh %{ #{RUBY_APP} script/txt2html #{txt} #{template} > website/recipes/#{txt.split("/").last.gsub(/txt$/,'html')} }
14
+ end
6
15
  end
7
16
 
8
17
  desc 'Upload website files to rubyforge'
data/website/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
6
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
7
  <title>
8
- Capistrano plugins, recipes and templates
8
+ &#x2192; &#8216;capitate&#8217;
9
9
  </title>
10
10
  <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
11
  <style>
@@ -21,24 +21,34 @@
21
21
  antiAlias: true,
22
22
  autoPad: true,
23
23
  validTags: ["div"]
24
- }
25
- var versionBox = new curvyCorners(settings, document.getElementById("version"));
26
- versionBox.applyCornersToAll();
24
+ };
25
+
26
+ curvy_ids = [ "version", "recipes" ];
27
+ for(id in curvy_ids) {
28
+ var box = new curvyCorners(settings, document.getElementById(curvy_ids[id]));
29
+ box.applyCornersToAll();
30
+ }
27
31
  }
28
32
  </script>
29
33
  </head>
30
34
  <body>
31
- <div id="main">
35
+ <div id="main" class="landing">
32
36
 
33
- <h1>Capistrano plugins, recipes and templates</h1>
34
- <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/capitate"; return false'>
35
- <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/capitate" class="numbers">0.1.7</a>
37
- </div>
38
37
  <h1>&#x2192; &#8216;capitate&#8217;</h1>
39
38
 
39
+ <div id="version" class="clickable box" onclick='document.location = "http://rubyforge.org/projects/capitate"; return false'>
40
+ <p>Get Version</p>
41
+ <a href="http://rubyforge.org/projects/capitate" class="numbers">0.1.8</a>
42
+ </div>
43
+
44
+ <div id="recipes" class="box">
45
+ <a href="recipes/index.html">Recipes</a> &#x2192;
46
+ <a href="http://svn.ducktyper.com/capitate/trunk/lib/capitate/plugins/">Plugins</a> &#x2192;
47
+ <a href="http://svn.ducktyper.com/capitate/trunk/lib/templates/">Templates</a>
48
+ </div>
40
49
 
41
- <h2>What</h2>
50
+ <div style="clear:both">
51
+ <h2>What</h2>
42
52
 
43
53
 
44
54
  <p>Capistrano plugins, recipes and templates.</p>
@@ -47,22 +57,19 @@
47
57
  <h2>Installing</h2>
48
58
 
49
59
 
50
- <p><pre class='syntax'><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">capitate</span></pre></p>
51
-
52
-
53
- <p>Create a Capfile (in your project):</p>
54
-
55
-
56
- <p><pre class='syntax'><span class="ident">capitate</span></pre></p>
60
+ <pre>sudo gem install capitate</pre>
57
61
 
62
+ <h2>Running</h2>
58
63
 
59
- <p>Create and set a profile in you Capfile:</p>
60
64
 
65
+ <p>Add capitate to your Capfile. Copy this somewhere near the top:</p>
61
66
 
62
- <p><pre class='syntax'><span class="comment"># load &quot;config/deployment/centos-sick.rb&quot;</span></pre></p>
63
67
 
64
-
65
- <p><em>See profiles section below for more info</em></p>
68
+ <p><pre class='syntax'>
69
+ <span class="ident">set</span> <span class="symbol">:project_root</span><span class="punct">,</span> <span class="constant">File</span><span class="punct">.</span><span class="ident">dirname</span><span class="punct">(</span><span class="constant">__FILE__</span><span class="punct">)</span>
70
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">capitate</span><span class="punct">'</span>
71
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">capitate/recipes</span><span class="punct">'</span>
72
+ </pre></p>
66
73
 
67
74
 
68
75
  <h2>The basics</h2>
@@ -79,49 +86,43 @@
79
86
  </ul>
80
87
 
81
88
 
82
- <h3>Profiles</h3>
83
-
84
-
85
- <p>Profiles are capfiles which store lists of recipes to run for cap install and deploy and settings for those recipes.</p>
86
-
89
+ <h3>Beefing up your deploy</h3>
87
90
 
88
- <p>For an example profile, see <a href="http://svn.ducktyper.com/capitate/trunk/lib/profiles/centos-sick.rb">centos-sick.rb</a></p>
89
91
 
92
+ <p>For an example deploy, see <a href="http://svn.ducktyper.com/capitate/trunk/lib/profiles/centos-sick.rb">centos-sick.rb</a></p>
90
93
 
91
- <p><span class="caps">TODO</span>: More on profiles&#8230;</p>
92
94
 
95
+ <p>You could copy this profile into config/deployment/ and add it to your Capfile:</p>
93
96
 
94
- <h3>Install recipes</h3>
95
97
 
98
+ <pre><code>load "config/deployment/centos-sick.rb"</code></pre>
96
99
 
97
- <p>To install a group of applications based on a profile (see Profiles section below):</p>
98
100
 
101
+ <h3>Use recipes</h3>
99
102
 
100
- <pre><code>cap install</code></pre>
101
103
 
104
+ <p><a href="recipes/index.html">View recipes documentation</a></p>
102
105
 
103
- <p><em>You may need to comment out &#8220;Defaults requiretty&#8221; in /etc/sudoders on the image before capistrano recipes will work.</em></p>
104
106
 
107
+ <p>For example, to script the install of a group of applications as root, use <a href="recipes/recipes.html">recipes:run</a>:</p>
105
108
 
106
- <h3>Deploying (application)</h3>
107
109
 
110
+ <p>Configure your Capfile to run it:</p>
108
111
 
109
- <p>If this is the first time you&#8217;ve deployed you&#8217;ll need to run:</p>
110
112
 
113
+ <p><pre class='syntax'>
114
+ <span class="ident">set</span> <span class="symbol">:recipes_run</span><span class="punct">,</span> <span class="punct">[</span> <span class="punct">&quot;</span><span class="string">ruby:centos:install</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">memcached:centos:install</span><span class="punct">&quot;</span> <span class="punct">]</span>
115
+ <span class="ident">set</span> <span class="symbol">:recipes_user</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">root</span><span class="punct">&quot;</span>
116
+ </pre></p>
111
117
 
112
- <pre><code>cap deploy:setup</code></pre>
113
118
 
119
+ <p>Then run:</p>
114
120
 
115
- <p>Otherwise, your standard deploy options:</p>
116
121
 
122
+ <pre><code>cap recipes:run</code></pre>
117
123
 
118
- <pre><code>cap deploy</code></pre>
119
124
 
120
-
121
- <pre><code>cap deploy:migrations (deploys and does migration)</code></pre>
122
-
123
-
124
- <pre><code>cap deploy:migrate (only does migration on existing deployment)</code></pre>
125
+ <p>This is just a basic example.</p>
125
126
 
126
127
 
127
128
  <h2>Forum</h2>
@@ -136,7 +137,7 @@
136
137
  <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
137
138
 
138
139
 
139
- <p>The trunk repository is <code>http://svn.ducktyper.com/var/svn/capitate/trunk</code> for anonymous access.</p>
140
+ <p>The trunk repository is <code>http://svn.ducktyper.com/capitate/trunk</code> for anonymous access.</p>
140
141
 
141
142
 
142
143
  <h2>License</h2>
@@ -149,6 +150,7 @@
149
150
 
150
151
 
151
152
  <p>Comments are welcome. Send an email to <a href="mailto:gabrielh@gmail.com">Gabriel Handford</a> via the <a href="http://groups.google.com/group/capitate">forum</a></p>
153
+ </div>
152
154
  <p class="coda">
153
155
  <a href="FIXME email">Gabriel Handford</a>, 21st February 2008<br>
154
156
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>