[
  {
    "path": ".gitignore",
    "content": "examples-private/\n.vagrant\nvendor/cache\n/trash/\nrdoc/*\n.com.apple.timemachine.supported\n.DS_Store\n*tmp*\npkg/*.tgz\npkg/*.gem\npkg/poolparty*/*\n.git/\nlog/*\ntest_manifest.pp\n**/*/erl_crash.dump\nlog\n*.beam\nri/\n.autosession.vim\ntags\n.session\nclouds.rb\ntest/test_dir/\nexamples/thrift/erlang/deps/thrift/ebin/*.beam\nexamples/thrift/erlang/ebin/*.beam\n*.swp\n*~\n\\#*\\#\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"vendor/gems/amazon-ec2\"]\n\tpath = vendor/gems/amazon-ec2\n\turl = git://github.com/grempe/amazon-ec2.git\n"
  },
  {
    "path": ".rdebugrc",
    "content": "set autoeval on\n"
  },
  {
    "path": ".rvmrc",
    "content": "rvm use ruby-1.9.2@poolparty --create\n"
  },
  {
    "path": "Gemfile",
    "content": "source \"http://rubygems.org\"\ngemspec\n\ngem 'amazon-ec2', '~>0.9.17'\ngem 'xml-simple'\ngem 'json'\ngem 'git-style-binaries'\n\ngroup :test do\n  gem 'fakeweb'\n  gem 'webmock'\n  gem 'shoulda'\n  gem 'rcov'\n  gem 'mocha'\n  gem 'right_http_connection'\n  gem \"jnunemaker-matchy\", \"~> 0.4.0\"\n  gem 'vagrant'\nend\n\ngroup :development do\n  gem \"rdoc\"\nend\n"
  },
  {
    "path": "License.txt",
    "content": "Copyright (c) 2009 Ari Lerner\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "Makefile",
    "content": "RUBY\t\t\t\t\t\t\t= `which ruby`\nRUBYGEMS\t\t\t\t\t= `which gem`\nGEMENV\t\t\t\t\t\t= `gem env`\n\nall: run_tests\n\ncheck_install:\n\t$(RUBY) -v\n\t$(RUBYGEMS) -v\n\t\nshow_env:\n\techo $(GEMENV)\n\t\ntest: run_tests\n\nrun_tests:\n\trake test"
  },
  {
    "path": "Manifest.txt",
    "content": ""
  },
  {
    "path": "README.rdoc",
    "content": "= PoolParty\n\nhttp://poolpartyrb.com\n\n== DESCRIPTION:\n\nPoolParty makes cloud provisioning and management easy. PoolParty provides a unified interface for defining and managing cloud infrasturcure on different cloud providers (just Ec2 for now).\n\nCode your cloud! \n\n== SYNOPSIS:\n\nPoolParty is written with the intention of being as application-agnostic as possible. It installs only the basic \nrequired software to glue the cloud together on the instances as listed below.\n\n== Quickstart\n\nFor instance, to start a basic cloud, let's write one:\n\n  pool \"demo\" do\n    cloud \"app\" do\n      instances 2..10\n      using :ec2\n      autoscale do      \n        trigger :lower_threshold => 0.3, :upper_threshold => 1.0, :measure => :cpu\n      end\n      security_group do\n        authorize :from_port => 22, :to_port => 22\n      end\n      load_balancer do\n        listener :external_port => 8080, :internal_port => 8080, :protocol => 'tcp'\n      end\n    end\n  end\n  \nSimply by issuing the command:\n  \n  cloud start\n  \nThis will create an ec2 auto scaling group that will launch the minimum_instances (2 in this case,) inside a security group. The default naming of most objects, such as security_groups, auto scaling groups, launch_configurations, load_balancers and keypairs follow the poolname-cloudname convention.\nThere are a number of commands PoolParty offers to interact with your cloud. They include:\n\n* <tt>cloud start</tt>\n* <tt>cloud terminate</tt>\n* <tt>cloud reboot</tt>\n* <tt>cloud configure</tt>\n* <tt>cloud compile</tt>\n* <tt>cloud console</tt>\n* <tt>cloud expand</tt>\n* <tt>cloud contract</tt>\n* <tt>cloud list</tt>\n* <tt>cloud show</tt>\n* <tt>cloud ssh</tt>\n* <tt>cloud run</tt>\n\nClouds are distinguished by security groups. If a security group is not specified in your cloud block, one will be created based on the naming convention poolname-cloudname.\n\n== Extending\n\nTo add a cloud_provider, there are four methods that need to be implemented. Simply sublcass the CloudProviders module and require it in your clouds.rb (or commit it back to PoolParty). Those four methods are:\n\n* <tt>run_instance</tt>\n* <tt>terminate_instance</tt>\n* <tt>describe_instances</tt>\n* <tt>describe_instance</tt>\n\n== Examples\nCheckout the [examples](examples/) directory and its README for some more ideas and examples.\n\nThat's it!\n\nMore documentation can be found at the site: <a href=\"http://poolpartyrb.com\">http://poolpartyrb.com</a>.\n\n== REQUIREMENTS:\n\n* Ruby\n\n== INSTALL:\nfrom gemcutter.org;\n\n    sudo gem install poolparty\n\n== LICENSE:\n\n(The MIT License)\n\nCopyright (c) 2009 Ari Lerner, CloudTeam\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "Rakefile",
    "content": "$:.unshift(File.join(File.dirname(__FILE__), \".\"))\nrequire 'rake'\nrequire \"bundler/gem_tasks\"\nrequire 'rake/testtask'\nrequire 'rdoc/task'\n\nrequire 'config/requirements'\n\ntask :default  => [:test, :cleanup_test]\ndesc \"Update vendor directory and run tests\"\n\nnamespace :poolparty do\n    namespace :vendor do\n        desc \"Fetch all the submodules\"\n        task :submodules do\n            `git submodule update`\n        end\n    end\nend\n\ntask :vendor => [\"poolparty:vendor:submodules\"]\n\ntask :cleanup_test do\n  ::FileUtils.rm_rf \"/tmp/poolparty\"\nend\n\n# task :test do\n#   sh \"ruby -Ilib:test #{Dir[\"#{File.dirname(__FILE__)}/../test/poolparty/*/*.rb\"].join(\" \")}\"\n# end\n\nRake::TestTask.new(:test) do |test|\n  test.libs << 'lib' << 'test'\n  test.pattern = 'test/**/*_test.rb'\n  test.verbose = true\nend\n  \nbegin\n  require 'rcov/rcovtask'\n\n  Rcov::RcovTask.new(:rcov) do |t|\n    t.libs << FileList['lib/**/*.rb']\n    t.rcov_opts = [\n      '-xRakefile', '-xrakefile',\n      '-xlib/erlang',\n      '--text-report',\n      '--sort coverage'\n    ] + FileList['tasks/*.rake'].pathmap(\"-x%p\")\n    t.test_files = FileList['test/lib/**/*_test.rb']\n    t.output_dir = 'coverage'\n    t.verbose = true\n  end\nrescue LoadError\n  puts \"RCov is not available\"\nend\n\n\ndesc \"Clean tmp directory\"\ntask :clean_tmp do |t|\n  FileUtils.rm_rf(\"#{File.dirname(__FILE__)}/Manifest.txt\") if ::File.exists?(\"#{File.dirname(__FILE__)}/Manifest.txt\")\n  FileUtils.touch(\"#{File.dirname(__FILE__)}/Manifest.txt\")\n  %w(logs tmp).each do |dir|\n    FileUtils.rm_rf(\"#{File.dirname(__FILE__)}/#{dir}\") if ::File.exists?(\"#{File.dirname(__FILE__)}/#{dir}\")\n  end\nend\n\ndesc \"Remove the pkg directory\"\ntask :clean_pkg do |t|\n  %w(pkg).each do |dir|\n    FileUtils.rm_rf(\"#{File.dirname(__FILE__)}/#{dir}\") if ::File.exists?(\"#{File.dirname(__FILE__)}/#{dir}\")\n  end\nend\n\n\nnamespace :gem do\n  desc \"Build the gem only if the tests pass\"\n  task :test_then_build => [:test, :build]\n\n  desc \"Build and install the gem only if the tests pass\"\n  task :test_then_install => [:test, :install]\nend\n\n# Generate documentation\nRake::RDocTask.new do |rd|\n  rd.main = \"README.rdoc\"\n  rd.rdoc_files.include(\"README.rdoc\", \"lib/**/*.rb\")\n  rd.rdoc_dir = \"rdoc\"\n  # rd.template = \"hanaa\"\nend\n"
  },
  {
    "path": "Vagrantfile",
    "content": "Vagrant::Config.run do |config|\n  # All Vagrant configuration is done here. The most common configuration\n  # options are documented and commented below. For a complete reference,\n  # please see the online documentation at vagrantup.com.\n\n  # Every Vagrant virtual environment requires a box to build off of.\n  config.vm.box = \"base\"\n\n  # The url from where the 'config.vm.box' box will be fetched if it\n  # doesn't already exist on the user's system.\n  # config.vm.box_url = \"http://domain.com/path/to/above.box\"\n\n  # Boot with a GUI so you can see the screen. (Default is headless)\n  # config.vm.boot_mode = :gui\n\n  # Assign this VM to a host only network IP, allowing you to access it\n  # via the IP.\n  config.vm.network \"33.33.33.10\"\n\n  # Forward a port from the guest to the host, which allows for outside\n  # computers to access the VM, whereas host only networking does not.\n  # config.vm.forward_port \"http\", 80, 8080\n\n  # Share an additional folder to the guest VM. The first argument is\n  # an identifier, the second is the path on the guest to mount the\n  # folder, and the third is the path on the host to the actual folder.\n  config.vm.share_folder \"v-data\", \"/vagrant_data\", \".\", :nfs => true\n\n  # Enable provisioning with Puppet stand alone.  Puppet manifests\n  # are contained in a directory path relative to this Vagrantfile.\n  # You will need to create the manifests directory and a manifest in\n  # the file base.pp in the manifests_path directory.\n  #\n  # An example Puppet manifest to provision the message of the day:\n  #\n  # # group { \"puppet\":\n  # #   ensure => \"present\",\n  # # }\n  # #\n  # # File { owner => 0, group => 0, mode => 0644 }\n  # #\n  # # file { '/etc/motd':\n  # #   content => \"Welcome to your Vagrant-built virtual machine!\n  # #               Managed by Puppet.\\n\"\n  # # }\n  #\n  # config.vm.provision :puppet do |puppet|\n  #   puppet.manifests_path = \"manifests\"\n  #   puppet.manifest_file  = \"base.pp\"\n  # end\n\n  # Enable provisioning with chef solo, specifying a cookbooks path (relative\n  # to this Vagrantfile), and adding some recipes and/or roles.\n  #\n  # config.vm.provision :chef_solo do |chef|\n  #   chef.cookbooks_path = \"cookbooks\"\n  #   chef.add_recipe \"mysql\"\n  #   chef.add_role \"web\"\n  #\n  #   # You may also specify custom JSON attributes:\n  #   chef.json = { :mysql_password => \"foo\" }\n  # end\n\n  # Enable provisioning with chef server, specifying the chef server URL,\n  # and the path to the validation key (relative to this Vagrantfile).\n  #\n  # The Opscode Platform uses HTTPS. Substitute your organization for\n  # ORGNAME in the URL and validation key.\n  #\n  # If you have your own Chef Server, use the appropriate URL, which may be\n  # HTTP instead of HTTPS depending on your configuration. Also change the\n  # validation key to validation.pem.\n  #\n  # config.vm.provision :chef_client do |chef|\n  #   chef.chef_server_url = \"https://api.opscode.com/organizations/ORGNAME\"\n  #   chef.validation_key_path = \"ORGNAME-validator.pem\"\n  # end\n  #\n  # If you're using the Opscode platform, your validator client is\n  # ORGNAME-validator, replacing ORGNAME with your organization name.\n  #\n  # IF you have your own Chef Server, the default validation client name is\n  # chef-validator, unless you changed the configuration.\n  #\n  #   chef.validation_client_name = \"ORGNAME-validator\"\nend\n"
  },
  {
    "path": "bin/cloud",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\nrequire 'git-style-binary/command'\n\nGitStyleBinary.primary do\n  # self.class.send :include, Printing\n\n  @theme = :short\n\n  version \"PoolParty release: #{PoolParty.version}\"\n  banner <<-EOS\nUsage: #{$0} #{all_options_string} COMMAND [ARGS]\n\nThe cloud subcommands commands are:\n  \\#{GitStyleBinary.pretty_known_subcommands(:short).join(\"  \")}\n\nSee 'cloud help COMMAND' for more information on a specific command.\nEOS\n\n  opt :clouds_dot_rb, \"Set the clouds.rb file\", :type => String, :default => \"clouds.rb\"\n  opt :very_verbose, \"Set very verbose mode on\", :type => :boolean, :default => false\n  opt :debug, \"Debug the output\", :type => :boolean, :default => false\n  opt :very_debug, \"Set very debug mode on\", :type => :boolean, :default => false\n  opt :name, \"Name of the working cloud\", :type => String, :default => nil\n  opt :chef_task, \"Name of chef task to execute\", :type => String, :default => 'default'\n\n  before_run do |command|\n    # Setup testing/debugging\n    $PP_VERBOSE     = true if command[:verbose]\n    $VERY_VERBOSE   = true if command[:very_verbose]\n    $DEBUGGING      = true if command[:debug]\n    $VERY_DEBUGGING = true if command[:very_debug]\n\n    begin\n      require command[:clouds_dot_rb]\n    rescue LoadError => e\n      puts e\n      puts e.backtrace\n      puts \"Failed loading #{command[:clouds_dot_rb]}, try using -c to specify the location of your clouds.rb\"\n      exit\n    end\n\n    pool.chef_step command[:chef_task].to_sym\n\n    @loaded_pool = pool\n    @loaded_clouds = command[:name] ? [pool.clouds[command[:name]]] : pool.clouds.map {|name,cld|cld}\n    if @loaded_clouds.size == 0\n      puts \"No clouds loaded. Check your clouds.rb or -n option\"\n      exit\n    end\n  end\n\n  run do |command|\n    subcommands = GitStyleBinary.list_subcommands\n\n    puts \"cloud %s\" % PoolParty.version\n    puts \"Usage: cloud COMMAND [ARGS]\n\n    The cloud subcommands commands are:\n      #{subcommands}\n\n    See 'cloud help COMMAND' for more information on a specific command\"\n  end\nend\n"
  },
  {
    "path": "bin/cloud-bootstrap",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Bootstrap a cloud instance\nEOS\n\n  short_desc \"Bootstrap a cloud instance\"\n  \n  opt :inst_num, \"The number of the instance to run bootstrap on\", :type => :int\n  opt :force, \"Force rebootstrapping (useful for upgrading)\", :default => false\n\n  run do |command|\n    \n    @loaded_clouds.each do |cld|\n      \n      cld.compile!\n      cld.bootstrap!\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-compile",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Configure a cloud instance\nEOS\n\n  short_desc \"Configure a cloud instance\"\n  \n  opt :inst_num, \"The number of the instance to run bootstrap on\", :type => :int\n\n  run do |command|\n    \n    @loaded_clouds.each do |cld|\n      ENV[\"POOLPARTY_NO_VALIDATION\"] = \"true\"\n      \n      cld.compile!\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-configure",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Configure a cloud instance\nEOS\n\n  short_desc \"Configure a cloud instance\"\n  \n  opt :inst_num, \"The number of the instance to run bootstrap on\", :type => :int\n  opt :generate_graph, \"Generate the dependency tree graph\", :type => :string, :default => nil\n\n  run do |command|\n    \n    @loaded_clouds.each do |cld|\n      \n      cld.configure!\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-console",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Open an irb session with the clouds.rb loaded\nEOS\n\n  short_desc \"Open an irb session with clouds.rb loaded\"\n  \n  opt :inst_num, \"The number of the instance to run bootstrap on\", :type => :int\n\n  run do |command|    \n    \n    puts \"Loading PoolParty console...\"\n    #exec \"#{irb} #{libs} --simple-prompt\"\n    require 'irb/completion'\n    require command[:clouds_dot_rb]\n    require \"#{File.dirname(__FILE__) + '/../lib/poolparty.rb'}\"\n    require 'irb'\n    pool.auto_execute = false\n    \n    IRB.setup(nil)\n    IRB.conf[:IRB_NAME]=\"cloud\"\n    IRB.conf[:PROMPT_MODE]=:CLOUD\n    IRB.conf[:PROMPT][:CLOUD]={\n      :PROMPT_I => \"%N> \",\n      :PROMPT_S => \"%l> \",\n      :PROMPT_C => \"* \",\n      :PROMPT_N => \">> \",\n      :RETURN => \"=>%s\\n\" }\n    irb=IRB::Irb.new\n    IRB.conf[:IRB_RC].call(irb.context) if IRB.conf[:IRB_RC]\n    IRB.conf[:MAIN_CONTEXT] = irb.context\n    trap(\"SIGINT\") do\n      irb.signal_handle\n    end\n    catch(:IRB_EXIT) do\n      irb.eval_input\n    end\n  end\nend\n"
  },
  {
    "path": "bin/cloud-contract",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do  \n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  contracts the cloud by a single instance\nEOS\n\n  short_desc \"contracts the cloud by a single instance\"\n\n  run do |command|    \n    @loaded_clouds.each do |cld|\n      \n      node_to_terminate = cld.nodes.last\n      # node_to_terminate.cloud = cld\n      \n      puts cld.nodes.size\n      if cld.nodes.size - 1 < cld.minimum_instances\n\tputs \"Contracting instances by 1 in cloud #{cld.name} will lower the number of instances below specified minimum (#{cld.minimum_instances})\"\n\tnext\n      end\n      msg = [\n        \"Contracting cloud #{cld.name} (#{cld.keypair}) by 1\",\n        \"#{cld.nodes.size} running instances (#{cld.minimum_instances} - #{cld.maximum_instances})\",\n        \" node: #{node_to_terminate.public_ip}\"\n      ]\n      \n      puts msg.join(\"\\n\")\n      \n      node_to_terminate.terminate!\n      \n      puts \"#{node_to_terminate.public_ip} has been terminated\"\n    end    \n  end\nend\n"
  },
  {
    "path": "bin/cloud-cssh",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  cssh into the cloud\nEOS\n\n  short_desc \"cssh into the cloud\"\n  \n  opt :user, \"the user name\", :type => :string, :default => nil\n  opt :use_keypair, \"whether or not to use the default keypair\", :type => :integer, :default => 0\n  \n  run do |command|\n    cloud = @loaded_clouds.first\n    \n    user = command[:user]\n    keyp = command[:use_keypair]\n\n    cloud.cssh( user, keyp != 0 )\n    \n  end\nend\n"
  },
  {
    "path": "bin/cloud-expand",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do  \n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  expands the cloud by a single instance\nEOS\n\n  short_desc \"expands the cloud by a single instance\"\n\n  run do |command|    \n    @loaded_clouds.each do |cld|\n      \n      msg = [\n        \"Expanding cloud #{cld.name} (#{cld.keypair})\",\n        \"#{cld.nodes.size} running instances (#{cld.minimum_instances} - #{cld.maximum_instances})\"\n      ]\n      \n      print_msg(msg)\n      \n      inst = cld.expand_by(1)\n      \n      msg = [\n        \"Your cloud has expanded by node: #{inst.public_ip}\"\n      ]\n      \n      print_msg(msg)\n\n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-list",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\n\nrequire \"poolparty\"\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  List the clouds and their nodes\n  e.g. show a list of the current instances on the cloud\nEOS\n\n  opt :instance_id, \"Describe a specific instance\", :type => String, :default => nil\n\n  short_desc \"show a list of the current instances on the clouds\"\n\n  run do |command|\n    puts \"#{pool.name}\"\n    puts \"===\"\n    @loaded_clouds.each do |cld|\n      if command[:instance_id]\n        require 'pp'\n        pp result = cld.nodes(:instance_id=>command[:instance_id])\n      else\n        msg = [\"* #{cld.name} cloud,  #{cld.image_id}, #{cld.instance_type}\"]\n\n        hsh = {}\n        \n        cld.all_nodes.each do |n| \n          (hsh[n.status] ||= []) << n\n        end\n        \n        hsh.each do |k,v|\n          msg << \"  - #{k} nodes\"\n          v.each do |a|\n            msg << \"      - #{a.instance_id}\\t#{a.status}\\t#{a.public_ip}\\t#{a.private_ip}\\t#{a.zone}\"\n          end\n          msg << \"\"\n        end\n        puts msg\n      end\n      \n    end\n  end\nend"
  },
  {
    "path": "bin/cloud-reboot",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Cycle through nodes in the cloud and wait for the autoscaler to reboot \nEOS\n  \n  short_desc \"Cycle the instances\"\n\n  run do |command|\n    \n    @loaded_clouds.each do |cld|\n      cld.reboot!\n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-rsync",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  ssh into an instance of the cloud\nEOS\n\n  short_desc \"ssh into an instance of the cloud\"\n  opt :to, \"To this directory\", :default => \"~\"\n    \n  run do |command|\n    cloud = @loaded_clouds.first\n    dir = command.argv.pop\n    \n    if !cloud.nodes.empty?\n      cloud.rsync(dir, command[:to])\n    else\n      puts \"No running instances can be found\"\n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-run",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\n\nrequire \"poolparty\"\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  Run a command on all running instances\nEOS\n\n  opt :instance_id, \"Run only on a specific instance\", :type => String, :default => nil\n  opt :command, \"Command to run\", :type => String, :default => nil\n\n  short_desc \"Run a command on all running instances\"\n\n  run do |command|\n    puts \"Running command #{command[:command]} on all nodes\"\n    @loaded_clouds.each do |cld|\n\n      output = cld.nodes.map do |n| \n        n.ssh(command[:command])\n      end\n      \n      #p output\n      \n    end\n  end\nend\n"
  },
  {
    "path": "bin/cloud-show",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  @theme = :short\n\n  version \"PoolParty #{$0} command\"\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\nshows output about the clouds.rb\n\nEOS\n\n  short_desc \"shows output about the clouds.rb\"\n\n  run do |command|\n\n    @loaded_clouds.each do |cld|\n\n      msg = [\n        \"Cloud: #{cld.name}\",\n        \"----------------------------\",\n        \"Running Instances:   #{cld.nodes.size}\",\n        \"Minimum instances:   #{cld.minimum_instances}\",\n        \"Maximum instances:   #{cld.maximum_instances}\",\n        \"Running on:          #{cld.cloud_provider.name}\",\n        \"Keypair:             #{cld.keypair.basename}\",\n        \"Security group:      #{cld.cloud_provider.security_group_names.join(', ')}\",\n        \"Availability zones:  #{cld.cloud_provider.availability_zones.join(', ')}\",\n        \"User:                #{cld.user}\",\n        \"Active recipes:      #{cld.chef._recipes(cld.pool.chef_step).join \", \" }\"\n      ]\n\n      if cld.load_balancers.size > 0\n        load_balancers = cld.cloud_provider.load_balancers.first.running_load_balancers.map {|a| a[:dns_name]}\n        msg << \"Load balancers:      #{load_balancers.join(\"\\n\\t\\t\\t\")}\"\n      end\n\n      if cld.rds_instances.size > 0\n        available = cld.cloud_provider.available_rds_instances.map{|r| \"#{r.instance_id}\\t#{r.current_status.Endpoint.Address}\" }\n        available.unshift 'RDS Instances:'\n\n        msg << available.join(\"\\n\\t\\t\\t\")\n      end\n\n      puts msg.flatten\n\n    end\n\n  end\nend\n"
  },
  {
    "path": "bin/cloud-ssh",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  ssh into an instance of the cloud\nEOS\n\n  short_desc \"ssh into an instance of the cloud\"\n  \n  opt :instance_number, \"Ssh into the instance number\", :type => :integer, :default => 0\n  \n  run do |command|\n    cloud = @loaded_clouds.first\n    \n    if !cloud.nodes.empty?\n      inst = cloud.nodes[command[:instance_number]]\n      inst ? inst.ssh : puts(\"Error: The instance number (#{command[:instance_number]}) is too high for the current number of instances\")\n    else\n      puts \"No running instances can be found\"\n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-start",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  starts a single instance in your cloud.\nEOS\n\n  short_desc \"starts a single instance in your cloud\"\n\n  run do |command|    \n    \n    @loaded_clouds.each do |cld|\n\n      cld.run\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "bin/cloud-terminate",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string} COMMAND [ARGS]\n\n  terminate the cloud\nEOS\n\n  short_desc \"terminate the cloud\"\n  \n  opt :yes, \"Answer yes to the are you sure question\", :type => :boolean, :default => false\n\n  run do |command|    \n    @loaded_clouds.each do |cld|\n      msg = [\n      \"Shutting down #{cld.name} cloud\",\n      \"Are you sure? (Y/N)\"\n      ]\n      \n      o = command[:yes] || true\n      if o\n        puts \"Shutting down cloud\"\n        cld.teardown\n      else\n        \n      end\n      \n    end    \n  end\nend"
  },
  {
    "path": "bin/cloud-vnc",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../lib\")\nrequire \"poolparty\"\n\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  banner <<-EOS\nUsage: #{$0} #{all_options_string}\n\n  start a vnc server and create an ssh tunnel\nEOS\n\n  short_desc \"ssh into an instance of the cloud\"\n  \n  opt :instance_number, \"Start VNC server on this instance number\", :type => :integer, :default => 0\n  opt :local_port, \"The local port to tunnel to\", :type => :integer, :default => 5900\n  opt :display, \"The remote display number to start the VNC Server on\", :type => :integer, :default => 0\n  \n  run do |command|\n    cloud = @loaded_clouds.first\n    \n    if !cloud.nodes.empty?\n      inst = cloud.nodes[command[:instance_number]]\n      if inst\n        inst.ssh([\"x11vnc -localhost -nopw -display :#{command[:display]}\"],\n                 {'-X' => nil,\n                  '-C' => nil,\n                  ' -o' => 'UserKnownHostsFile=/dev/null',\n                  '-L' => \"#{command[:local_port]}:localhost:5900\"})\n      else\n        puts(\"Error: The instance number (#{command[:instance_number]}) is too high for the current number of instances\")\n      end\n    else\n      puts \"No running instances can be found\"\n    end\n    \n  end\nend"
  },
  {
    "path": "config/requirements.rb",
    "content": "require 'fileutils'\ninclude FileUtils\n\nrequire 'rubygems'\nrequire 'rake'\n\n$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))\n"
  },
  {
    "path": "examples/README.md",
    "content": "\nsimple.rb\n===\nThe simple.rb configuration will create an ec2 auto scaling group that will launch the minimum_instances (1 in this case,) inside a security group. The default naming of most objects, such as security_groups, auto scaling groups, launch_configurations and load_balancers and keypairs follow the poolname-cloudname convention.  For example, the cloud below will create a security-group named 'pooolparty-simple'.  The names can be overridden, important if you want more than one.   If a keypair does not exist, it will be created.\n\nSince auto scaling is specified in this cloud, poolparty will not start the instance directly.  Instead, poolparty will create an ec2_launch_configuration and auto scaling group. \n\nSome important notes:  Some of the methods used inside the cloud block are specific to the cloud provider being used, ec2 in this example.  The cloud_provider methods are added when the cloud_provider is specified, therefore you must be sure to specify the cloud_provider before any cloud_provider specific methods.\n\nUser_data.  While not a specific feature of poolparty, we often use user_data scripts to configure instance in the cloud.  This allows for separation of concerns:\n  - PoolParty takes care of setting up an infrastructure of firewalled autoscaling, load balanced instances across multiple data centers.\n  - Userdata scripts configure the instances, optionally pulling in from a repository of additional tasks.    Userdata script can be used in conjunction with [runrul](http://alestic.com/2009/08/runurl) to run scripts form a shared repository, even installing and run chef if desired.\n  \nA benefit of userdata scripted instance configuration is that it does not require active management and monitoring. You just define your infrastructure with poolparty and let the autoscaling take care of the rest.\n\nchef_cloud.rb\n===\nThe chef_cloud.rb does not define an autoscaling group.  Since there is no autoscaling group, poolparty will launch the instances (ec2_run_instance.) and wait for ssh to be available on all the launched hosts.\nNext, if a chef-repo was specified:\n  \n  1.  The repo will be uploaded the /etc/chef on the instances.\n  2.  Ssh to the instances and call chef -c /etc/chef/solo.rb -j /etc/chef/dna.json\n\nThe dna.json can be populated either by simply editing the file dna.json in your chef-repo, or you can specify chef_attributes in your cloud block.  for example:\n\n    chef_attributes :apache2 => {:listen_ports => [\"80\", \"8080\"]} \"8080\"]}\n    \nIf you specify chef_attributes they will be compiled into a a role namded for the cloud at /etc/chef/roles/cloudname.json, and a dna.json file that will execute the clouds role on the instance.\n\nNotes, Tips and Comments:\n===\nThe goal of having an completely idempotent declarative configuration system is particularly valuable when you need to manage and update running servers. In the cloud we have found that often, it is easier to simply throw away the server and start a new one from a fresh state.\n\n  1. Update userdata scripts and launch configs\n  2. Terminate the instances (1 at a time for a rolling restart, or all at once)\n  3. Let the autoscaling (or client side poolparty) start new instances with the new userdata\n\nSince the instances are always starting from a known state (a base ami) the configuration scripts can be much simpler, simple shell scripts, possibly executed as runurls.\n\nIf runurls are being called from the userdata script, another way to update the cloud instances configuration is to update the runurl (if you are hosting it, which is recommended) you can terminate instances and the newly launched instances will use the updated runurl/\n\nWe try and keep private data out of the runurl scripts, opting to supply this data either as environment variables (possibly set by the userdata script,) as command line arguments to runrul (i.e. $1, $2 etc), or variables contained in a separate file our userdata script can download. \n\nWhen the runurl cannot be public, and we do not want to embed all the runurl scripts in the userdata, we have used an authenticate only aws user.  That is create an aws user, but do not provide a credit card or sign up for any services. Even tho the user can not create any resources, it can authenticate.  We put the authenticate only user credentials in the userdata file, and  a small bit of code at the top of our userdata file to fetch and install an s3 utility, such as s3cmd. Then the s3cmd can download private readonly s3 urls.\n\nchef\n---\nIf you want to use chef, one way to do so is to put code like the following in your userdata\n\n    # OPTIONAL: install chef-solo\n    export CLOUD=${1:-'poolparty'}\n    sudo gem install ohai chef --source http://gems.opscode.com --no-rdoc --no-ri\n    mkdir -p /etc/chef/cookpooks\n    s3sync -r https://mybucket.s3.amazonaws.com/chef-repo /etc/chef/chef\n    s3sync https://cloudteam.s3.amazonaws.com/chef-repo/$CLOUD.json /etc/chef/dna.json\n    chef-solo -c /etc/chef/chef/solo.rb -j /etc/chef/chef/dna.json\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/.gitignore",
    "content": ".rake_test_cache\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/README",
    "content": "Began as a clone of the Opscode base repo\nhttp://wiki.opscode.com/display/chef/Chef+Repository\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/Rakefile",
    "content": "#\n# Rakefile for Chef Server Repository\n#\n# Author:: Adam Jacob (<adam@opscode.com>)\n# Copyright:: Copyright (c) 2008 Opscode, Inc.\n# License:: Apache License, Version 2.0\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nrequire 'rubygems'\nrequire 'chef'\nrequire 'json'\n\n# Make sure you have loaded constants first\nrequire File.join(File.dirname(__FILE__), 'config', 'rake')\n\n# And choosen a VCS\nif File.directory?(File.join(TOPDIR, \".svn\"))\n  $vcs = :svn\nelsif File.directory?(File.join(TOPDIR, \".git\"))\n  $vcs = :git\nend\n\nload 'chef/tasks/chef_repo.rake'\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/certificates/README",
    "content": "This directory contains certificates created by the Rakefile.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/config/client.rb.example",
    "content": "#\n# Example Chef Client Config File\n#\n# We recommend using Opscode's chef cookbook for managing chef itself,\n# instead of using this file. It is provided as an example.\n\nlog_level          :info\nlog_location       STDOUT\nssl_verify_mode    :verify_none\nregistration_url   \"https://chef.localdomain\"\nopenid_url         \"https://chef.localdomain\"\ntemplate_url       \"https://chef.localdomain\"\nremotefile_url     \"https://chef.localdomain\"\nsearch_url         \"https://chef.localdomain\"\nrole_url           \"https://chef.localdomain\"\n\nfile_store_path    \"/srv/chef/file_store\"\nfile_cache_path    \"/srv/chef/cache\"\n\npid_file           \"/var/run/chef/chef-client.pid\"\n\nChef::Log::Formatter.show_time = true\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/config/rake.rb",
    "content": "###\n# Company and SSL Details\n###\n\n# The company name - used for SSL certificates, and in srvious other places\nCOMPANY_NAME = \"AT&T Interactive\"\n\n# The Country Name to use for SSL Certificates\nSSL_COUNTRY_NAME = \"US\"\n\n# The State Name to use for SSL Certificates\nSSL_STATE_NAME = \"CA\"\n\n# The Locality Name for SSL - typically, the city\nSSL_LOCALITY_NAME = \"Glendale\"\n\n# What department?\nSSL_ORGANIZATIONAL_UNIT_NAME = \"Applied Research\"\n\n# The SSL contact email address\nSSL_EMAIL_ADDRESS = \"cloudcomputing@attinteractive.com\"\n\n# License for new Cookbooks\n# Can be :apachev2 or :none\nNEW_COOKBOOK_LICENSE = :apachev2\n\n##########################\n# Chef Repository Layout #\n##########################\n\n# Where to install upstream cookbooks for serving\nCOOKBOOK_PATH = \"/srv/chef/cookbooks\"\n\n# Where to install site-local modifications to upstream cookbooks\nSITE_COOKBOOK_PATH = \"/srv/chef/site-cookbooks\"\n\n# Where to install roles\nROLE_PATH = \"/srv/chef/roles\"\n\n# Chef Config Path\nCHEF_CONFIG_PATH = \"/etc/chef\"\n\n# The location of the Chef Server Config file (on the server)\nCHEF_SERVER_CONFIG = File.join(CHEF_CONFIG_PATH, \"server.rb\")\n\n# The location of the Chef Client Config file (on the client)\nCHEF_CLIENT_CONFIG = File.join(CHEF_CONFIG_PATH, \"client.rb\")\n\n###\n# Useful Extras (which you probably don't need to change)\n###\n\n# The top of the repository checkout\nTOPDIR = File.expand_path(File.join(File.dirname(__FILE__), \"..\"))\n\n# Where to store certificates generated with ssl_cert\nCADIR = File.expand_path(File.join(TOPDIR, \"certificates\"))\n\n# Where to store the mtime cache for the recipe/template syntax check\nTEST_CACHE = File.expand_path(File.join(TOPDIR, \".rake_test_cache\"))"
  },
  {
    "path": "examples/chef_cloud/chef_repo/config/server.rb.example",
    "content": "#\n# Example Chef Server Config File\n#\n# We recommend using Opscode's chef cookbook for managing chef itself,\n# instead of using this file. It is provided as an example.\n\nlog_level          :info\nlog_location       \"/var/log/chef/server.log\"\nssl_verify_mode    :verify_none\nregistration_url   \"https://localhost\"\nopenid_url         \"https://localhost\"\ntemplate_url       \"https://localhost\"\nremotefile_url     \"https://localhost\"\nsearch_url         \"https://localhost\"\nrole_url           \"https://localhost\"\n\n#validation_token   \"change_this_token\"\n\ncookbook_path      [ \"/srv/chef/site-cookbooks\", \"/srv/chef/cookbooks\" ]\n\nfile_store_path    \"/srv/chef/file_store\"\nfile_cache_path    \"/srv/chef/cache\"\nnode_path          \"/srv/chef/nodes\"\nopenid_store_path  \"/srv/chef/openid/store\"\nopenid_cstore_path \"/srv/chef/openid/cstore\"\nsearch_index_path  \"/srv/chef/search_index\"\n\n# uncomment and modify to allow specific openid providers\n#openid_providers   [ \"https://localhost\", \"https://chef\" ]\n# uncomment and modify to lock down openid identifiers, ie 'some_user.myopenid.com'\n#authorized_openid_identifiers [ \"\" ]\n\nChef::Log::Formatter.show_time = true\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/config/solo.rb.example",
    "content": "#\n# Chef Solo Config File\n#\n\nlog_level          :info\nlog_location       STDOUT\nfile_cache_path    \"/srv/chef/cookbooks\"\nssl_verify_mode    :verify_none\nChef::Log::Formatter.show_time = false\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/README",
    "content": "This directory contains upstream or shared cookbooks.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/README.rdoc",
    "content": "= DESCRIPTION:\n\nComplete Debian/Ubuntu style Apache2 configuration.\n\n= REQUIREMENTS:\n\nDebian or Ubuntu preferred.\n\nRed Hat/CentOS and Fedora can be used but will be converted to a Debian/Ubuntu style Apache as it's far easier to manage with chef. \n\n= ATTRIBUTES:\n\nThe file attributes/apache.rb contains the following attribute types:\n\n* platform specific locations and settings.\n* general settings\n* prefork attributes\n* worker attributes\n\nGeneral settings and prefork/worker attributes are tunable.\n\n= USAGE:\n\nInclude the apache2 recipe to install Apache2 and get 'sane' default settings. Configuration is modularized through Apache vhost sites a la Debian style configuration.\n\nFor Red Hat, CentOS and Fedora you should first disable selinux as it's not supported (yet), then remove the stock httpd and all it's dependencies prior to attempting to use this recipe. Many packages in these distributions drop conflicting configs into conf.d, all of which haven't been accounted for yet. Starting from scratch will also make it far easier to debug.\n\n== Defines:\n\n* apache_module: sets up an Apache module.\n* apache_conf: sets up a config file for an apache module.\n* apache_site: sets up a vhost site. The conf file must be available.\n* web_app: copies the template for a web app and enables it as a site via apache_site.\n\n== Web Apps:\n\nVarious applications that can be set up with Apache as the front end, such as PHP, Django, Rails and others can use the web_app define to set up the template and the Apache site. The define is kind of dumb, so the template needs have the application implementation settings, since we don't know what your app is or what is needed from Apache.\n\nWe only prototype one parameter for the web_app define, \"template\". This is used to specify the name of the template to use in the current cookbook. When you use web_app, you can set up any parameters you want to use in your template. They will get passed to the template through the params hash. For example, the sample web_app.conf.erb template in this cookbook makes use of these.\n\n* docroot\n* server_name\n* server_aliases\n\nThese are available as @params[:docroot], @params[:server_name], @params[:server_aliases] within the template. \n\nIf 'cookbook' and 'template' are not specified, the current cookbook's templates/default/web_app.conf.erb will be used. If this template is not suitable for your application, copy it to your cookbook and customize as needed.\n\n== God Monitor:\n\nThere's a new recipe, apache2::god_monitor. You will need to make sure to include the 'god' recipe before using the apache2::god_monitor recipe in your cookbook.\n\n= LICENSE & AUTHOR:\n\nAuthor:: Joshua Timberman (<joshua@opscode.com>)\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/attributes/apache.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Attributes:: apache\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Where the various parts of apache are\ncase platform\nwhen \"redhat\",\"centos\",\"fedora\",\"suse\"\n  set[:apache][:dir]     = \"/etc/httpd\"\n  set[:apache][:log_dir] = \"/var/log/httpd\"\n  set[:apache][:user]    = \"apache\"\n  set[:apache][:binary]  = \"/usr/sbin/httpd\"\n  set[:apache][:icondir] = \"/var/www/icons/\"\nwhen \"debian\",\"ubuntu\"\n  set[:apache][:dir]     = \"/etc/apache2\"\n  set[:apache][:log_dir] = \"/var/log/apache2\"\n  set[:apache][:user]    = \"www-data\"\n  set[:apache][:binary]  = \"/usr/sbin/apache2\"\n  set[:apache][:icondir] = \"/usr/share/apache2/icons\"\nelse\n  set[:apache][:dir]     = \"/etc/apache2\"\n  set[:apache][:log_dir] = \"/var/log/apache2\"\n  set[:apache][:user]    = \"www-data\"\n  set[:apache][:binary]  = \"/usr/sbin/apache2\"\n  set[:apache][:icondir] = \"/usr/share/apache2/icons\"\nend\n\n###\n# These settings need the unless, since we want them to be tunable,\n# and we don't want to override the tunings.\n###\n\n# General settings\nset_unless[:apache][:listen_ports] = [ \"80\",\"443\" ]\nset_unless[:apache][:contact] = \"ops@example.com\"\nset_unless[:apache][:timeout] = 300\nset_unless[:apache][:keepalive] = \"On\"\nset_unless[:apache][:keepaliverequests] = 100\nset_unless[:apache][:keepalivetimeout] = 5\n\n# Security\nset_unless[:apache][:servertokens] = \"Prod\"\nset_unless[:apache][:serversignature] = \"On\"\nset_unless[:apache][:traceenable] = \"On\"\n\n# Prefork Attributes\nset_unless[:apache][:prefork][:startservers] = 16\nset_unless[:apache][:prefork][:minspareservers] = 16\nset_unless[:apache][:prefork][:maxspareservers] = 32\nset_unless[:apache][:prefork][:serverlimit] = 400\nset_unless[:apache][:prefork][:maxclients] = 400\nset_unless[:apache][:prefork][:maxrequestsperchild] = 10000\n\n# Worker Attributes\nset_unless[:apache][:worker][:startservers] = 4\nset_unless[:apache][:worker][:maxclients] = 1024\nset_unless[:apache][:worker][:minsparethreads] = 64\nset_unless[:apache][:worker][:maxsparethreads] = 192\nset_unless[:apache][:worker][:threadsperchild] = 64\nset_unless[:apache][:worker][:maxrequestsperchild] = 0\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/definitions/apache_conf.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Definition:: apache_conf\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndefine :apache_conf do\n  template \"#{node[:apache][:dir]}/mods-available/#{params[:name]}.conf\" do\n    source \"mods/#{params[:name]}.conf.erb\"\n    notifies :restart, resources(:service => \"apache2\")\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/definitions/apache_module.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Definition:: apache_module\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndefine :apache_module, :enable => true, :conf => false do\n  include_recipe \"apache2\"\n \n  if params[:conf]\n    apache_conf params[:name]\n  end\n \n  if params[:enable]\n    execute \"a2enmod #{params[:name]}\" do\n      command \"/usr/sbin/a2enmod #{params[:name]}\"\n      notifies :restart, resources(:service => \"apache2\")\n      not_if do (File.symlink?(\"#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.load\") and\n            ((File.exists?(\"#{node[:apache][:dir]}/mods-available/#{params[:name]}.conf\"))?\n              (File.symlink?(\"#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.conf\")):(true)))\n      end\n    end    \n  else\n    execute \"a2dismod #{params[:name]}\" do\n      command \"/usr/sbin/a2dismod #{params[:name]}\"\n      notifies :restart, resources(:service => \"apache2\")\n      only_if do File.symlink?(\"#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.load\") end\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/definitions/apache_site.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Definition:: apache_site\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndefine :apache_site, :enable => true do\n  include_recipe \"apache2\"\n  \n  if params[:enable]\n    execute \"a2ensite #{params[:name]}\" do\n      command \"/usr/sbin/a2ensite #{params[:name]}\"\n      notifies :restart, resources(:service => \"apache2\")\n      not_if do \n        File.symlink?(\"#{node[:apache][:dir]}/sites-enabled/#{params[:name]}\") or\n          File.symlink?(\"#{node[:apache][:dir]}/sites-enabled/000-#{params[:name]}\")\n      end\n      only_if do File.exists?(\"#{node[:apache][:dir]}/sites-available/#{params[:name]}\") end\n    end\n  else\n    execute \"a2dissite #{params[:name]}\" do\n      command \"/usr/sbin/a2dissite #{params[:name]}\"\n      notifies :restart, resources(:service => \"apache2\")\n      only_if do File.symlink?(\"#{node[:apache][:dir]}/sites-enabled/#{params[:name]}\") end\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/definitions/web_app.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Definition:: web_app\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndefine :web_app, :template => \"web_app.conf.erb\" do\n  \n  application_name = params[:name]\n\n  include_recipe \"apache2\"\n  include_recipe \"apache2::mod_rewrite\"\n  include_recipe \"apache2::mod_deflate\"\n  include_recipe \"apache2::mod_headers\"\n  \n  template \"#{node[:apache][:dir]}/sites-available/#{application_name}.conf\" do\n    source params[:template]\n    owner \"root\"\n    group \"root\"\n    mode 0644\n    if params[:cookbook]\n      cookbook params[:cookbook]\n    end\n    variables(\n      :application_name => application_name,\n      :params => params\n    )\n    if File.exists?(\"#{node[:apache][:dir]}/sites-enabled/#{application_name}.conf\")\n      notifies :reload, resources(:service => \"apache2\"), :delayed\n    end\n  end\n  \n  apache_site \"#{params[:name]}.conf\" do\n    enable enable_setting\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/files/default/apache2_module_conf_generate.pl",
    "content": "#!/usr/bin/perl\n\n=begin\n\nGenerates Ubuntu style module.load files.\n \n./apache2_module_conf_generate.pl /usr/lib64/httpd/modules /etc/httpd/mods-available\n\nARGV[0] is the apache modules directory, ARGV[1] is where you want 'em.\n\n=cut\n\nuse File::Find;\n\nuse strict;\nuse warnings;\n\ndie \"Must have '/path/to/modules' and '/path/to/modules.load'\"\n  unless $ARGV[0] && $ARGV[1];\n\nfind(\n  {\n    wanted => sub {\n      return 1 if $File::Find::name !~ /\\.so$/;\n      my $modfile = $_;\n      $modfile =~ /(lib|mod_)(.+)\\.so$/;\n      my $modname  = $2;\n      my $filename = \"$ARGV[1]/$modname.load\";\n      unless ( -f $filename ) {\n        open( FILE, \">\", $filename ) or die \"Cannot open $filename\";\n        print FILE \"LoadModule \" . $modname . \"_module $File::Find::name\\n\";\n        close(FILE);\n      }\n    },\n    follow => 1,\n  },\n  $ARGV[0]\n);\n\nexit 0;\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/metadata.json",
    "content": "{\n  \"description\": \"Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"apache2::mod_python\": \"Apache module 'python'\",\n    \"apache2::mod_authn_file\": \"Apache module 'authn_file'\",\n    \"apache2::mod_dir\": \"Apache module 'dir' with config file\",\n    \"apache2::mod_php5\": \"Apache module 'php5'\",\n    \"apache2::mod_proxy_balancer\": \"Apache module 'proxy_balancer'\",\n    \"apache2::mod_authz_groupfile\": \"Apache module 'authz_groupfile'\",\n    \"apache2::mod_dav\": \"Apache module 'dav'\",\n    \"apache2::mod_auth_basic\": \"Apache module 'auth_basic'\",\n    \"apache2::mod_setenvif\": \"Apache module 'setenvif' with config file\",\n    \"apache2\": \"\",\n    \"apache2::mod_authz_user\": \"Apache module 'authz_user'\",\n    \"apache2::mod_deflate\": \"Apache module 'deflate' with config file\",\n    \"apache2::mod_dav_svn\": \"Apache module 'dav_svn'\",\n    \"apache2::mod_negotiation\": \"Apache module 'negotiation' with config file\",\n    \"apache2::mod_ssl\": \"Apache module 'ssl' with config file, adds port 443 to listen_ports\",\n    \"apache2::mod_authz_host\": \"Apache module 'authz_host'\",\n    \"apache2::mod_rewrite\": \"Apache module 'rewrite'\",\n    \"apache2::mod_auth_digest\": \"Apache module 'auth_digest'\",\n    \"apache2::mod_cgi\": \"Apache module 'cgi'\",\n    \"apache2::mod_fcgid\": \"Apache module 'fcgid', package on ubuntu\\/debian, rhel\\/centos, compile source on suse; with config file\",\n    \"apache2::mod_env\": \"Apache module 'env'\",\n    \"apache2::mod_headers\": \"Apache module 'headers'\",\n    \"apache2::mod_authnz_ldap\": \"Apache module 'authnz_ldap'\",\n    \"apache2::mod_autoindex\": \"Apache module 'autoindex' with config file\",\n    \"apache2::mod_proxy\": \"Apache module 'proxy' with config file\",\n    \"apache2::mod_proxy_connect\": \"Apache module 'proxy_connect'\",\n    \"apache2\": \"Main Apache configuration\",\n    \"apache2::mod_alias\": \"Apache module 'alias' with config file\",\n    \"apache2::mod_ldap\": \"Apache module 'ldap'\",\n    \"apache2::mod_status\": \"Apache module 'status' with config file\",\n    \"apache2::mod_authz_default\": \"Apache module 'authz_default'\",\n    \"apache2::mod_log_config\": \"Apache module 'log_config'\",\n    \"apache2::god_monitor\": \"\",\n    \"apache2::mod_expires\": \"Apache module 'expires'\",\n    \"apache2::mod_proxy_http\": \"Apache module 'proxy_http'\",\n    \"apache2::mod_mime\": \"Apache module 'mime' with config file\",\n    \"apache2::mod_proxy_ajp\": \"Apache module 'proxy_ajp'\"\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ],\n    \"centos\": [\n\n    ],\n    \"debian\": [\n\n    ],\n    \"redhat\": [\n\n    ]\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.9.1\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"apache2\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n    \"apache\\/traceenable\": {\n      \"default\": \"On\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Determine behavior of TRACE requests\",\n      \"display_name\": \"Apache Trace Enable\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/timeout\": {\n      \"default\": \"300\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Connection timeout value\",\n      \"display_name\": \"Apache Timeout\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/icondir\": {\n      \"default\": \"\\/usr\\/share\\/apache2\\/icons\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Directory location for icons\",\n      \"display_name\": \"Apache Icondir\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/user\": {\n      \"default\": \"www-data\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"User Apache runs as\",\n      \"display_name\": \"Apache User\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/threadsperchild\": {\n      \"default\": \"64\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Constant number of worker threads in each server process\",\n      \"display_name\": \"Apache Worker MPM ThreadsPerChild\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/maxclients\": {\n      \"default\": \"1024\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of simultaneous connections\",\n      \"display_name\": \"Apache Worker MPM MaxClients\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of Apache prefork tuning attributes.\",\n      \"display_name\": \"Apache Worker\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/contact\": {\n      \"default\": \"ops@example.com\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Email address of webmaster\",\n      \"display_name\": \"Apache Contact\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/startservers\": {\n      \"default\": \"16\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Number of MPM servers to start\",\n      \"display_name\": \"Apache Prefork MPM StartServers\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/minspareservers\": {\n      \"default\": \"16\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Minimum number of spare server processes\",\n      \"display_name\": \"Apache Prefork MPM MinSpareServers\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/keepalivetimeout\": {\n      \"default\": \"5\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Time to wait for requests on persistent connection\",\n      \"display_name\": \"Apache Keepalive Timeout\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/keepaliverequests\": {\n      \"default\": \"100\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Number of requests allowed on a persistent connection\",\n      \"display_name\": \"Apache Keepalive Requests\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/maxrequestsperchild\": {\n      \"default\": \"0\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of request a child process will handle\",\n      \"display_name\": \"Apache Worker MPM MaxRequestsPerChild\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/listen_ports\": {\n      \"default\": [\n        \"80\",\n        \"443\"\n      ],\n      \"type\": \"array\",\n      \"multiple_values\": false,\n      \"description\": \"Ports that Apache should listen on\",\n      \"display_name\": \"Apache Listen Ports\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/dir\": {\n      \"default\": \"\\/etc\\/apache2\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location for Apache configuration\",\n      \"display_name\": \"Apache Directory\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/maxsparethreads\": {\n      \"default\": \"192\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of spare worker threads\",\n      \"display_name\": \"Apache Worker MPM MaxSpareThreads\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/maxrequestsperchild\": {\n      \"default\": \"10000\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of request a child process will handle\",\n      \"display_name\": \"Apache Prefork MPM MaxRequestsPerChild\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/serverlimit\": {\n      \"default\": \"400\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Upper limit on configurable server processes\",\n      \"display_name\": \"Apache Prefork MPM ServerLimit\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/binary\": {\n      \"default\": \"\\/usr\\/sbin\\/apache2\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Apache server daemon program\",\n      \"display_name\": \"Apache Binary\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/maxspareservers\": {\n      \"default\": \"32\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of spare server processes\",\n      \"display_name\": \"Apache Prefork MPM MaxSpareServers\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/keepalive\": {\n      \"default\": \"On\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"HTTP persistent connections\",\n      \"display_name\": \"Apache Keepalive\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of Apache attributes\",\n      \"display_name\": \"Apache Hash\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/startservers\": {\n      \"default\": \"4\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Initial number of server processes to start\",\n      \"display_name\": \"Apache Worker MPM StartServers\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\\/maxclients\": {\n      \"default\": \"400\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Maximum number of simultaneous connections\",\n      \"display_name\": \"Apache Prefork MPM MaxClients\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/prefork\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of Apache prefork tuning attributes.\",\n      \"display_name\": \"Apache Prefork\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/servertokens\": {\n      \"default\": \"Prod\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Server response header\",\n      \"display_name\": \"Apache Server Tokens\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/worker\\/minsparethreads\": {\n      \"default\": \"64\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Minimum number of spare worker threads\",\n      \"display_name\": \"Apache Worker MPM MinSpareThreads\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/serversignature\": {\n      \"default\": \"On\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Configure footer on server-generated documents\",\n      \"display_name\": \"Apache Server Signature\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"apache\\/log_dir\": {\n      \"default\": \"\\/etc\\/apache2\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location for Apache logs\",\n      \"display_name\": \"Apache Log Directory\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    }\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n\n  },\n  \"providing\": {\n    \"apache2::mod_python\": [\n\n    ],\n    \"apache2::mod_authn_file\": [\n\n    ],\n    \"apache2::mod_dir\": [\n\n    ],\n    \"apache2::mod_php5\": [\n\n    ],\n    \"apache2::mod_proxy_balancer\": [\n\n    ],\n    \"apache2::mod_authz_groupfile\": [\n\n    ],\n    \"apache2::mod_dav\": [\n\n    ],\n    \"apache2::mod_auth_basic\": [\n\n    ],\n    \"apache2::mod_setenvif\": [\n\n    ],\n    \"apache2::mod_authz_user\": [\n\n    ],\n    \"apache2::mod_deflate\": [\n\n    ],\n    \"apache2::mod_dav_svn\": [\n\n    ],\n    \"apache2::mod_negotiation\": [\n\n    ],\n    \"apache2::mod_ssl\": [\n\n    ],\n    \"apache2::mod_authz_host\": [\n\n    ],\n    \"apache2::mod_rewrite\": [\n\n    ],\n    \"apache2::mod_auth_digest\": [\n\n    ],\n    \"apache2::mod_cgi\": [\n\n    ],\n    \"apache2::mod_fcgid\": [\n\n    ],\n    \"apache2::mod_env\": [\n\n    ],\n    \"apache2::mod_headers\": [\n\n    ],\n    \"apache2::mod_authnz_ldap\": [\n\n    ],\n    \"apache2::mod_autoindex\": [\n\n    ],\n    \"apache2::mod_proxy\": [\n\n    ],\n    \"apache2::mod_proxy_connect\": [\n\n    ],\n    \"apache2::mod_alias\": [\n\n    ],\n    \"apache2::mod_ldap\": [\n\n    ],\n    \"apache2::mod_status\": [\n\n    ],\n    \"apache2::mod_authz_default\": [\n\n    ],\n    \"apache2::mod_log_config\": [\n\n    ],\n    \"apache2\": [\n\n    ],\n    \"apache2::god_monitor\": [\n\n    ],\n    \"apache2::mod_expires\": [\n\n    ],\n    \"apache2::mod_proxy_http\": [\n\n    ],\n    \"apache2::mod_mime\": [\n\n    ],\n    \"apache2::mod_proxy_ajp\": [\n\n    ]\n  },\n  \"long_description\": \"= DESCRIPTION:\\n\\nComplete Debian\\/Ubuntu style Apache2 configuration.\\n\\n= REQUIREMENTS:\\n\\nDebian or Ubuntu preferred.\\n\\nRed Hat\\/CentOS and Fedora can be used but will be converted to a Debian\\/Ubuntu style Apache as it's far easier to manage with chef. \\n\\n= ATTRIBUTES:\\n\\nThe file attributes\\/apache.rb contains the following attribute types:\\n\\n* platform specific locations and settings.\\n* general settings\\n* prefork attributes\\n* worker attributes\\n\\nGeneral settings and prefork\\/worker attributes are tunable.\\n\\n= USAGE:\\n\\nInclude the apache2 recipe to install Apache2 and get 'sane' default settings. Configuration is modularized through Apache vhost sites a la Debian style configuration.\\n\\nFor Red Hat, CentOS and Fedora you should first disable selinux as it's not supported (yet), then remove the stock httpd and all it's dependencies prior to attempting to use this recipe. Many packages in these distributions drop conflicting configs into conf.d, all of which haven't been accounted for yet. Starting from scratch will also make it far easier to debug.\\n\\n== Defines:\\n\\n* apache_module: sets up an Apache module.\\n* apache_conf: sets up a config file for an apache module.\\n* apache_site: sets up a vhost site. The conf file must be available.\\n* web_app: copies the template for a web app and enables it as a site via apache_site.\\n\\n== Web Apps:\\n\\nVarious applications that can be set up with Apache as the front end, such as PHP, Django, Rails and others can use the web_app define to set up the template and the Apache site. The define is kind of dumb, so the template needs have the application implementation settings, since we don't know what your app is or what is needed from Apache.\\n\\nWe only prototype one parameter for the web_app define, \\\"template\\\". This is used to specify the name of the template to use in the current cookbook. When you use web_app, you can set up any parameters you want to use in your template. They will get passed to the template through the params hash. For example, the sample web_app.conf.erb template in this cookbook makes use of these.\\n\\n* docroot\\n* server_name\\n* server_aliases\\n\\nThese are available as @params[:docroot], @params[:server_name], @params[:server_aliases] within the template. \\n\\nIf 'cookbook' and 'template' are not specified, the current cookbook's templates\\/default\\/web_app.conf.erb will be used. If this template is not suitable for your application, copy it to your cookbook and customize as needed.\\n\\n== God Monitor:\\n\\nThere's a new recipe, apache2::god_monitor. You will need to make sure to include the 'god' recipe before using the apache2::god_monitor recipe in your cookbook.\\n\\n= LICENSE & AUTHOR:\\n\\nAuthor:: Joshua Timberman (<joshua@opscode.com>)\\nCopyright:: 2009, Opscode, Inc\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http:\\/\\/www.apache.org\\/licenses\\/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions\"\nlong_description  IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))\nversion           \"0.9.1\"\nrecipe            \"apache2\", \"Main Apache configuration\"\nrecipe            \"apache2::mod_alias\", \"Apache module 'alias' with config file\"\nrecipe            \"apache2::mod_auth_basic\", \"Apache module 'auth_basic'\"\nrecipe            \"apache2::mod_auth_digest\", \"Apache module 'auth_digest'\"\nrecipe            \"apache2::mod_authn_file\", \"Apache module 'authn_file'\"\nrecipe            \"apache2::mod_authnz_ldap\", \"Apache module 'authnz_ldap'\"\nrecipe            \"apache2::mod_authz_default\", \"Apache module 'authz_default'\"\nrecipe            \"apache2::mod_authz_groupfile\", \"Apache module 'authz_groupfile'\"\nrecipe            \"apache2::mod_authz_host\", \"Apache module 'authz_host'\"\nrecipe            \"apache2::mod_authz_user\", \"Apache module 'authz_user'\"\nrecipe            \"apache2::mod_autoindex\", \"Apache module 'autoindex' with config file\"\nrecipe            \"apache2::mod_cgi\", \"Apache module 'cgi'\"\nrecipe            \"apache2::mod_dav\", \"Apache module 'dav'\"\nrecipe            \"apache2::mod_dav_svn\", \"Apache module 'dav_svn'\"\nrecipe            \"apache2::mod_deflate\", \"Apache module 'deflate' with config file\"\nrecipe            \"apache2::mod_dir\", \"Apache module 'dir' with config file\"\nrecipe            \"apache2::mod_env\", \"Apache module 'env'\"\nrecipe            \"apache2::mod_expires\", \"Apache module 'expires'\"\nrecipe            \"apache2::mod_fcgid\", \"Apache module 'fcgid', package on ubuntu/debian, rhel/centos, compile source on suse; with config file\"\nrecipe            \"apache2::mod_headers\", \"Apache module 'headers'\"\nrecipe            \"apache2::mod_ldap\", \"Apache module 'ldap'\"\nrecipe            \"apache2::mod_log_config\", \"Apache module 'log_config'\"\nrecipe            \"apache2::mod_mime\", \"Apache module 'mime' with config file\"\nrecipe            \"apache2::mod_negotiation\", \"Apache module 'negotiation' with config file\"\nrecipe            \"apache2::mod_php5\", \"Apache module 'php5'\"\nrecipe            \"apache2::mod_proxy\", \"Apache module 'proxy' with config file\"\nrecipe            \"apache2::mod_proxy_ajp\", \"Apache module 'proxy_ajp'\"\nrecipe            \"apache2::mod_proxy_balancer\", \"Apache module 'proxy_balancer'\"\nrecipe            \"apache2::mod_proxy_connect\", \"Apache module 'proxy_connect'\"\nrecipe            \"apache2::mod_proxy_http\", \"Apache module 'proxy_http'\"\nrecipe            \"apache2::mod_python\", \"Apache module 'python'\"\nrecipe            \"apache2::mod_rewrite\", \"Apache module 'rewrite'\"\nrecipe            \"apache2::mod_setenvif\", \"Apache module 'setenvif' with config file\"\nrecipe            \"apache2::mod_ssl\", \"Apache module 'ssl' with config file, adds port 443 to listen_ports\"\nrecipe            \"apache2::mod_status\", \"Apache module 'status' with config file\"\n\n%w{redhat centos debian ubuntu}.each do |os|\n  supports os\nend\n\nattribute \"apache\",\n  :display_name => \"Apache Hash\",\n  :description => \"Hash of Apache attributes\",\n  :type => \"hash\"\n\nattribute \"apache/dir\",\n  :display_name => \"Apache Directory\",\n  :description => \"Location for Apache configuration\",\n  :default => \"/etc/apache2\"\n\nattribute \"apache/log_dir\",\n  :display_name => \"Apache Log Directory\",\n  :description => \"Location for Apache logs\",\n  :default => \"/etc/apache2\"\n\nattribute \"apache/user\",\n  :display_name => \"Apache User\",\n  :description => \"User Apache runs as\",\n  :default => \"www-data\"\n\nattribute \"apache/binary\",\n  :display_name => \"Apache Binary\",\n  :description => \"Apache server daemon program\",\n  :default => \"/usr/sbin/apache2\"\n\nattribute \"apache/icondir\", \n  :display_name => \"Apache Icondir\",\n  :description => \"Directory location for icons\",\n  :default => \"/usr/share/apache2/icons\"\n\nattribute \"apache/listen_ports\",\n  :display_name => \"Apache Listen Ports\",\n  :description => \"Ports that Apache should listen on\",\n  :type => \"array\",\n  :default => [ \"80\", \"443\" ]\n\nattribute \"apache/contact\",\n  :display_name => \"Apache Contact\",\n  :description => \"Email address of webmaster\",\n  :default => \"ops@example.com\"\n\nattribute \"apache/timeout\",\n  :display_name => \"Apache Timeout\",\n  :description => \"Connection timeout value\",\n  :default => \"300\"\n\nattribute \"apache/keepalive\",\n  :display_name => \"Apache Keepalive\",\n  :description => \"HTTP persistent connections\",\n  :default => \"On\"\n\nattribute \"apache/keepaliverequests\",\n  :display_name => \"Apache Keepalive Requests\",\n  :description => \"Number of requests allowed on a persistent connection\",\n  :default => \"100\"\n\nattribute \"apache/keepalivetimeout\",\n  :display_name => \"Apache Keepalive Timeout\",\n  :description => \"Time to wait for requests on persistent connection\",\n  :default => \"5\"\n\nattribute \"apache/servertokens\",\n  :display_name => \"Apache Server Tokens\",\n  :description => \"Server response header\",\n  :default => \"Prod\"\n\nattribute \"apache/serversignature\",\n  :display_name => \"Apache Server Signature\",\n  :description => \"Configure footer on server-generated documents\",\n  :default => \"On\"\n\nattribute \"apache/traceenable\",\n  :display_name => \"Apache Trace Enable\",\n  :description => \"Determine behavior of TRACE requests\",\n  :default => \"On\"\n\nattribute \"apache/prefork\",\n  :display_name => \"Apache Prefork\",\n  :description => \"Hash of Apache prefork tuning attributes.\",\n  :type => \"hash\"\n\nattribute \"apache/prefork/startservers\",\n  :display_name => \"Apache Prefork MPM StartServers\",\n  :description => \"Number of MPM servers to start\",\n  :default => \"16\"\n\nattribute \"apache/prefork/minspareservers\",\n  :display_name => \"Apache Prefork MPM MinSpareServers\",\n  :description => \"Minimum number of spare server processes\",\n  :default => \"16\"\n\nattribute \"apache/prefork/maxspareservers\",\n  :display_name => \"Apache Prefork MPM MaxSpareServers\",\n  :description => \"Maximum number of spare server processes\",\n  :default => \"32\"\n\nattribute \"apache/prefork/serverlimit\",\n  :display_name => \"Apache Prefork MPM ServerLimit\",\n  :description => \"Upper limit on configurable server processes\",\n  :default => \"400\"\n\nattribute \"apache/prefork/maxclients\",\n  :display_name => \"Apache Prefork MPM MaxClients\",\n  :description => \"Maximum number of simultaneous connections\",\n  :default => \"400\"\n\nattribute \"apache/prefork/maxrequestsperchild\",\n  :display_name => \"Apache Prefork MPM MaxRequestsPerChild\",\n  :description => \"Maximum number of request a child process will handle\",\n  :default => \"10000\"\n\nattribute \"apache/worker\",\n  :display_name => \"Apache Worker\",\n  :description => \"Hash of Apache prefork tuning attributes.\",\n  :type => \"hash\"\n\nattribute \"apache/worker/startservers\",\n  :display_name => \"Apache Worker MPM StartServers\",\n  :description => \"Initial number of server processes to start\",\n  :default => \"4\"\n\nattribute \"apache/worker/maxclients\",\n  :display_name => \"Apache Worker MPM MaxClients\",\n  :description => \"Maximum number of simultaneous connections\",\n  :default => \"1024\"\n\nattribute \"apache/worker/minsparethreads\",\n  :display_name => \"Apache Worker MPM MinSpareThreads\",\n  :description => \"Minimum number of spare worker threads\",\n  :default => \"64\"\n\nattribute \"apache/worker/maxsparethreads\",\n  :display_name => \"Apache Worker MPM MaxSpareThreads\",\n  :description => \"Maximum number of spare worker threads\",\n  :default => \"192\"\n\nattribute \"apache/worker/threadsperchild\",\n  :display_name => \"Apache Worker MPM ThreadsPerChild\",\n  :description => \"Constant number of worker threads in each server process\",\n  :default => \"64\"\n\nattribute \"apache/worker/maxrequestsperchild\",\n  :display_name => \"Apache Worker MPM MaxRequestsPerChild\",\n  :description => \"Maximum number of request a child process will handle\",\n  :default => \"0\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/default.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: default\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npackage \"apache2\" do\n  case node[:platform]\n  when \"centos\",\"redhat\",\"fedora\",\"suse\"\n    package_name \"httpd\"\n  when \"debian\",\"ubuntu\"\n    package_name \"apache2\"\n  end\n  action :install\nend\n\nservice \"apache2\" do\n  case node[:platform]\n  when \"centos\",\"redhat\",\"fedora\",\"suse\"\n    service_name \"httpd\"\n    # If restarted/reloaded too quickly httpd has a habit of failing.\n    # This may happen with multiple recipes notifying apache to restart - like\n    # during the initial bootstrap.\n    restart_command \"/sbin/service httpd restart && sleep 1\"\n    reload_command \"/sbin/service httpd reload && sleep 1\"\n  when \"debian\",\"ubuntu\"\n    service_name \"apache2\"\n  end\n  supports value_for_platform(\n    \"debian\" => { \"4.0\" => [ :restart, :reload ], \"default\" => [ :restart, :reload, :status ] },\n    \"ubuntu\" => { \"default\" => [ :restart, :reload, :status ] },\n    \"centos\" => { \"default\" => [ :restart, :reload, :status ] },\n    \"redhat\" => { \"default\" => [ :restart, :reload, :status ] },\n    \"fedora\" => { \"default\" => [ :restart, :reload, :status ] },\n    \"default\" => { \"default\" => [:restart, :reload ] }\n  )\n  action :enable\nend\n\nif platform?(\"centos\", \"redhat\", \"fedora\", \"suse\")\n  directory node[:apache][:log_dir] do\n    mode 0755\n    action :create\n  end\n  \n  remote_file \"/usr/local/bin/apache2_module_conf_generate.pl\" do\n    source \"apache2_module_conf_generate.pl\"\n    mode 0755\n    owner \"root\"\n    group \"root\"\n  end\n\n  %w{sites-available sites-enabled mods-available mods-enabled}.each do |dir|\n    directory \"#{node[:apache][:dir]}/#{dir}\" do\n      mode 0755\n      owner \"root\"\n      group \"root\"\n      action :create\n    end\n  end\n    \n  execute \"generate-module-list\" do\n    if node[:kernel][:machine] == \"x86_64\" \n      libdir = \"lib64\"\n    else \n      libdir = \"lib\"\n    end\n    command \"/usr/local/bin/apache2_module_conf_generate.pl /usr/#{libdir}/httpd/modules /etc/httpd/mods-available\"\n    \n    action :run\n  end\n  \n  %w{a2ensite a2dissite a2enmod a2dismod}.each do |modscript|\n    template \"/usr/sbin/#{modscript}\" do\n      source \"#{modscript}.erb\"\n      mode 0755\n      owner \"root\"\n      group \"root\"\n    end  \n  end\n\n  # installed by default on centos/rhel, remove in favour of mods-enabled\n  file \"#{node[:apache][:dir]}/conf.d/proxy_ajp.conf\" do\n    action :delete\n    backup false\n  end\n  file \"#{node[:apache][:dir]}/conf.d/README\" do\n    action :delete\n    backup false\n  end\n  \n  # welcome page moved to the default-site.rb temlate\n  file \"#{node[:apache][:dir]}/conf.d/welcome.conf\" do\n    action :delete\n    backup false\n  end\nend\n\ndirectory \"#{node[:apache][:dir]}/ssl\" do\n  action :create\n  mode 0755\n  owner \"root\"\n  group \"root\"\nend\n\ntemplate \"apache2.conf\" do\n  case node[:platform]\n  when \"centos\",\"redhat\",\"fedora\"\n    path \"#{node[:apache][:dir]}/conf/httpd.conf\"\n  when \"debian\",\"ubuntu\"\n    path \"#{node[:apache][:dir]}/apache2.conf\"\n  end\n  source \"apache2.conf.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"apache2\")\nend\n\ntemplate \"security\" do\n  path \"#{node[:apache][:dir]}/conf.d/security\"\n  source \"security.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  backup false\n  notifies :restart, resources(:service => \"apache2\")\nend\n\ntemplate \"charset\" do\n  path \"#{node[:apache][:dir]}/conf.d/charset\"\n  source \"charset.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  backup false\n  notifies :restart, resources(:service => \"apache2\")\nend\n\ntemplate \"#{node[:apache][:dir]}/ports.conf\" do\n  source \"ports.conf.erb\"\n  group \"root\"\n  owner \"root\"\n  variables :apache_listen_ports => node[:apache][:listen_ports]\n  mode 0644\n  notifies :restart, resources(:service => \"apache2\")\nend\n\ntemplate \"#{node[:apache][:dir]}/sites-available/default\" do\n  source \"default-site.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"apache2\")\nend\n\ninclude_recipe \"apache2::mod_status\"\ninclude_recipe \"apache2::mod_alias\"\ninclude_recipe \"apache2::mod_auth_basic\"\ninclude_recipe \"apache2::mod_authn_file\"\ninclude_recipe \"apache2::mod_authz_default\"\ninclude_recipe \"apache2::mod_authz_groupfile\"\ninclude_recipe \"apache2::mod_authz_host\"\ninclude_recipe \"apache2::mod_authz_user\"\ninclude_recipe \"apache2::mod_autoindex\"\ninclude_recipe \"apache2::mod_dir\"\ninclude_recipe \"apache2::mod_env\"\ninclude_recipe \"apache2::mod_mime\"\ninclude_recipe \"apache2::mod_negotiation\"\ninclude_recipe \"apache2::mod_setenvif\"\ninclude_recipe \"apache2::mod_log_config\" if platform?(\"centos\", \"redhat\", \"suse\")\n\n# uncomment to get working example site on centos/redhat/fedora\n#apache_site \"default\"\n\nservice \"apache2\" do\n  action :start\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/god_monitor.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: god_monitor\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_service = service \"apache2\" do\n  action :nothing\nend\n\nstart_command = apache_service.start_command\nstop_command = apache_service.stop_command\nrestart_command = apache_service.restart_command\n\ngod_monitor \"apache2\" do\n  config \"apache2.god.erb\"\n  start (start_command)?start_command : \"/etc/init.d/#{apache_service.service_name} start\"\n  restart (restart_command)?restart_command : \"/etc/init.d/#{apache_service.service_name} restart\"\n  stop (stop_command)?stop_command : \"/etc/init.d/#{apache_service.service_name} stop\"\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_alias.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: alias \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"alias\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_auth_basic.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: auth_basic \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"auth_basic\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_auth_digest.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: auth_digest \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"auth_digest\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authn_file.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authn_file \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authn_file\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authnz_ldap.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authnz_ldap \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authnz_ldap\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authz_default.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authz_default \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authz_default\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authz_groupfile.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authz_groupfile \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authz_groupfile\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authz_host.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authz_host \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authz_host\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_authz_user.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: authz_user \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"authz_user\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_autoindex.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: autoindex \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"autoindex\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_cgi.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: cgi \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"cgi\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_dav.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: dav \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"dav\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_dav_svn.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: dav_svn \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npackage \"libapache2-svn\"\n\napache_module \"dav_svn\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_deflate.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: deflate \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"deflate\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_dir.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: dir \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"dir\" do \n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_env.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: env \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"env\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_expires.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: expires \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"expires\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_fcgid.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: fcgid \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nif platform?(\"debian\", \"ubuntu\")\n  package \"libapache2-mod-fcgid\"\nelsif platform?(\"centos\", \"redhat\", \"fedora\")\n  package \"mod_fcgid\" do\n    notifies :run, resources(:execute => \"generate-module-list\"), :immediately\n  end\n\n  file \"#{node[:apache][:dir]}/conf.d/fcgid.conf\" do\n    action :delete\n    backup false \n  end\nelsif platform?(\"suse\")\n  apache_lib_path = node[:architecture] == \"i386\" ? \"/usr/lib/httpd\" : \"/usr/lib64/httpd\"\n  package \"httpd-devel\"\n  bash \"install-fcgid\" do\n    code <<-EOH\n(cd /tmp; wget http://superb-east.dl.sourceforge.net/sourceforge/mod-fcgid/mod_fcgid.2.2.tgz)\n(cd /tmp; tar zxvf mod_fcgid.2.2.tgz)\n(cd /tmp; perl -pi -e 's!/usr/local/apache2!#{apache_lib_path}!g' ./mod_fcgid.2.2/Makefile)\n(cd /tmp/mod_fcgid.2.2; make install)\nEOH\n  end\nend\n\napache_module \"fcgid\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_headers.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: headers \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"headers\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_ldap.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: ldap \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"ldap\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_log_config.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: log_config \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nif platform?(\"centos\", \"redhat\", \"fedora\", \"suse\")\n  apache_module \"log_config\"\nelse\n  include_recipe \"apache2\"\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_mime.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: mime \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"mime\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_negotiation.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: negotiation \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"negotiation\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_php5.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: php5 \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ncase node[:platform]\nwhen \"debian\", \"ubuntu\"\n  package \"libapache2-mod-php5\" do\n    action :install\n  end  \nwhen \"centos\", \"redhat\", \"fedora\"\n  package \"php\" do\n    action :install\n    notifies :run, resources(:execute => \"generate-module-list\"), :immediately\n  end\nend\n\napache_module \"php5\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_proxy.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: proxy \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"proxy\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_proxy_ajp.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: proxy \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"proxy_ajp\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_proxy_balancer.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: proxy \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"proxy_balancer\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_proxy_connect.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: proxy \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"proxy_connect\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_proxy_http.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: proxy_http \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"proxy_http\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_python.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: python \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npackage \"libapache2-mod-python\"\n\napache_module \"python\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_rails.rb",
    "content": "#\n# Cookbook Name:: passenger\n# Recipe:: default\n#\n# Author:: Joshua Timberman (<joshua@opscode.com>)\n# Author:: Joshua Sierles (<joshua@37signals.com>)\n# Author:: Michael Hale (<mikehale@gmail.com>)\n# \n# Copyright:: 2009, Opscode, Inc\n# Copyright:: 2009, 37signals\n# Coprighty:: 2009, Michael Hale\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ninclude_recipe \"passenger\"\n\ntemplate \"#{node[:apache][:dir]}/mods-available/passenger.load\" do\n  cookbook \"passenger\"\n  source \"passenger.load.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0755\nend\n\ntemplate \"#{node[:apache][:dir]}/mods-available/passenger.conf\" do\n  cookbook \"passenger\"\n  source \"passenger.conf.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0755\nend\n\napache_module \"passenger\""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_rewrite.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: rewrite \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"rewrite\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_setenvif.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: setenvif \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"setenvif\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_ssl.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: ssl \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nif platform?(\"centos\", \"redhat\", \"fedora\")\n  package \"mod_ssl\" do\n    action :install\n    notifies :run, resources(:execute => \"generate-module-list\"), :immediately\n  end\n\n  file \"#{node[:apache][:dir]}/conf.d/ssl.conf\" do\n    action :delete\n    backup false \n  end\nend\n\nports = node[:apache][:listen_ports].include?(\"443\") ? node[:apache][:listen_ports] : [node[:apache][:listen_ports], \"443\"].flatten\n\ntemplate \"#{node[:apache][:dir]}/ports.conf\" do\n  source \"ports.conf.erb\"\n  variables :apache_listen_ports => ports\n  notifies :restart, resources(:service => \"apache2\")\nend\n\napache_module \"ssl\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/recipes/mod_status.rb",
    "content": "#\n# Cookbook Name:: apache2\n# Recipe:: status \n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\napache_module \"status\" do\n  conf true\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/a2dismod.erb",
    "content": "#!/bin/sh -e\n\nSYSCONFDIR='<%= @node[:apache][:dir] %>'\n\nif [ -z $1 ]; then\n        echo \"Which module would you like to disable?\"\n        echo -n \"Your choices are: \"\n        ls $SYSCONFDIR/mods-enabled/*.load | \\\n        sed -e \"s,$SYSCONFDIR/mods-enabled/,,g\" | sed -e 's/\\.load$//g;' | xargs echo\n        echo -n \"Module name? \"\n        read MODNAME\nelse\n        MODNAME=$1\nfi\n\nif ! [ -e $SYSCONFDIR/mods-enabled/$MODNAME.load ]; then\n        echo \"This module is already disabled, or does not exist!\"\n        exit 1\nfi\n\nrm -f $SYSCONFDIR/mods-enabled/$MODNAME.*\necho \"Module $MODNAME disabled; reload apache to fully disable.\""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/a2dissite.erb",
    "content": "#!/bin/sh -e\n\nSYSCONFDIR='<%= @node[:apache][:dir] %>'\n\nif [ -z $1 ]; then\n        echo \"Which site would you like to disable?\"\n        echo -n \"Your choices are: \"\n        ls $@node[:apache][:dir]/sites-enabled/* | \\\n        sed -e \"s,$SYSCONFDIR/sites-enabled/,,g\" | xargs echo\n        echo -n \"Site name? \"\n        read SITENAME\nelse\n        SITENAME=$1\nfi\n\nif [ $SITENAME = \"default\" ]; then\n        PRIORITY=\"000\"\nfi\n\nif ! [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \\\n       -e $SYSCONFDIR/sites-enabled/\"$PRIORITY\"-\"$SITENAME\" ]; then\n        echo \"This site is already disabled, or does not exist!\"\n        exit 1\nfi\n\nif ! rm $SYSCONFDIR/sites-enabled/$SITENAME 2>/dev/null; then\n        rm -f $SYSCONFDIR/sites-enabled/\"$PRIORITY\"-\"$SITENAME\"\nfi\necho \"Site $SITENAME disabled; reload apache to disable.\""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/a2enmod.erb",
    "content": "#!/bin/sh -e\n\nSYSCONFDIR='<%= @node[:apache][:dir] %>'\n\nif [ -z $1 ]; then\n        echo \"Which module would you like to enable?\"\n        echo -n \"Your choices are: \"\n        ls $SYSCONFDIR/mods-available/*.load | \\\n        sed -e \"s,$SYSCONFDIR/mods-available/,,g\" | sed -e 's/\\.load$//g;' | xargs echo\n        echo -n \"Module name? \"\n        read MODNAME\nelse\n        MODNAME=$1\nfi\n\n#figure out if we're on a prefork or threaded mpm\nif [ -x /usr/sbin/apache2 ]; then\n        PREFORK=`/usr/sbin/apache2 -l | grep prefork || true`\nfi\n\nif [ -e $SYSCONFDIR/mods-enabled/$MODNAME.load && -e $SYSCONFDIR/mods-enabled/$MODNAME.conf ]; then\n        echo \"This module is already enabled!\"\n        exit 0 \nfi\n\nif ! [ -e $SYSCONFDIR/mods-available/$MODNAME.load ]; then\n        echo \"This module does not exist!\"\n        exit 1\nfi\n\nfor i in conf load; do \n        if [ -e $SYSCONFDIR/mods-available/$MODNAME.$i -a ! -e $SYSCONFDIR/mods-enabled/$MODNAME.$i ]; then\n        ln -sf $SYSCONFDIR/mods-available/$MODNAME.$i $SYSCONFDIR/mods-enabled/$MODNAME.$i;\n        fi\ndone\n\necho \"Module $MODNAME installed; reload apache to enable.\""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/a2ensite.erb",
    "content": "#!/bin/sh -e\n\nSYSCONFDIR='<%= @node[:apache][:dir] %>'\n\nif [ -z $1 ]; then\n        echo \"Which site would you like to enable?\"\n        echo -n \"Your choices are: \"\n        ls $SYSCONFDIR/sites-available/* | \\\n        sed -e \"s,$SYSCONFDIR/sites-available/,,g\" | xargs echo\n        echo -n \"Site name? \"\n        read SITENAME\nelse\n        SITENAME=$1\nfi\n\nif [ $SITENAME = \"default\" ]; then\n        PRIORITY=\"000\"\nfi\n\nif [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \\\n     -e $SYSCONFDIR/sites-enabled/\"$PRIORITY\"-\"$SITENAME\" ]; then\n        echo \"This site is already enabled!\"\n        exit 0\nfi\n\nif ! [ -e $SYSCONFDIR/sites-available/$SITENAME ]; then\n        echo \"This site does not exist!\"\n        exit 1\nfi\n\nif [ $SITENAME = \"default\" ]; then\n        ln -sf $SYSCONFDIR/sites-available/$SITENAME \\\n               $SYSCONFDIR/sites-enabled/\"$PRIORITY\"-\"$SITENAME\"\nelse\n        ln -sf $SYSCONFDIR/sites-available/$SITENAME $SYSCONFDIR/sites-enabled/$SITENAME\nfi\n\necho \"Site $SITENAME installed; reload apache to enable.\""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/apache2.conf.erb",
    "content": "#\n# Generated by Chef\n#\n# Based on the Ubuntu apache2.conf\n\nServerRoot \"<%= @node[:apache][:dir] %>\"\n\n#\n# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.\n#\n<% if @node[:platform] == \"debian\" || @node[:platform] == \"ubuntu\" -%>\nLockFile /var/lock/apache2/accept.lock\n<% else %>\nLockFile logs/accept.lock\n<% end -%>\n\n#\n# PidFile: The file in which the server should record its process\n# identification number when it starts.\n#\n<% if @node[:platform] == \"debian\" || @node[:platform] == \"ubuntu\" -%>\nPidFile /var/run/apache2.pid\n<% elsif @node[:platform] == \"centos\" -%>\nPidFile /var/run/httpd.pid\n<% else -%>\nPidFile logs/httpd.pid\n<% end -%>\n\n#\n# Timeout: The number of seconds before receives and sends time out.\n#\nTimeout <%= @node[:apache][:timeout] %>\n\n#\n# KeepAlive: Whether or not to allow persistent connections (more than\n# one request per connection). Set to \"Off\" to deactivate.\n#\nKeepAlive <%= @node[:apache][:keepalive] %>\n\n#\n# MaxKeepAliveRequests: The maximum number of requests to allow\n# during a persistent connection. Set to 0 to allow an unlimited amount.\n# We recommend you leave this number high, for maximum performance.\n#\nMaxKeepAliveRequests <%= @node[:apache][:keepaliverequests] %>\n\n#\n# KeepAliveTimeout: Number of seconds to wait for the next request from the\n# same client on the same connection.\n#\nKeepAliveTimeout <%= @node[:apache][:keepalivetimeout] %>\n\n##\n## Server-Pool Size Regulation (MPM specific)\n## \n\n# prefork MPM\n# StartServers: number of server processes to start\n# MinSpareServers: minimum number of server processes which are kept spare\n# MaxSpareServers: maximum number of server processes which are kept spare\n# MaxClients: maximum number of server processes allowed to start\n# MaxRequestsPerChild: maximum number of requests a server process serves\n<IfModule mpm_prefork_module>\n    StartServers          <%= @node[:apache][:prefork][:startservers] %>\n    MinSpareServers       <%= @node[:apache][:prefork][:minspareservers] %>\n    MaxSpareServers       <%= @node[:apache][:prefork][:maxspareservers] %>\n    ServerLimit           <%= @node[:apache][:prefork][:serverlimit] %>\n    MaxClients            <%= @node[:apache][:prefork][:maxclients] %>\n    MaxRequestsPerChild   <%= @node[:apache][:prefork][:maxrequestsperchild] %>\n</IfModule>\n\n# worker MPM\n# StartServers: initial number of server processes to start\n# MaxClients: maximum number of simultaneous client connections\n# MinSpareThreads: minimum number of worker threads which are kept spare\n# MaxSpareThreads: maximum number of worker threads which are kept spare\n# ThreadsPerChild: constant number of worker threads in each server process\n# MaxRequestsPerChild: maximum number of requests a server process serves\n<IfModule mpm_worker_module>\n    StartServers          <%= @node[:apache][:worker][:startservers] %>\n    MaxClients            <%= @node[:apache][:worker][:maxclients] %>\n    MinSpareThreads       <%= @node[:apache][:worker][:minsparethreads] %>\n    MaxSpareThreads       <%= @node[:apache][:worker][:maxsparethreads] %>\n    ThreadsPerChild       <%= @node[:apache][:worker][:threadsperchild] %>\n    MaxRequestsPerChild   <%= @node[:apache][:worker][:maxrequestsperchild] %>\n</IfModule>\n\nUser <%= @node[:apache][:user] %>\nGroup <%= @node[:apache][:user] %>\n\n#\n# AccessFileName: The name of the file to look for in each directory\n# for additional configuration directives.  See also the AllowOverride\n# directive.\n#\n\nAccessFileName .htaccess\n\n#\n# The following lines prevent .htaccess and .htpasswd files from being \n# viewed by Web clients. \n#\n<Files ~ \"^\\.ht\">\n    Order allow,deny\n    Deny from all\n</Files>\n\n#\n# DefaultType is the default MIME type the server will use for a document\n# if it cannot otherwise determine one, such as from filename extensions.\n# If your server contains mostly text or HTML documents, \"text/plain\" is\n# a good value.  If most of your content is binary, such as applications\n# or images, you may want to use \"application/octet-stream\" instead to\n# keep browsers from trying to display binary files as though they are\n# text.\n#\nDefaultType text/plain\n\n\n#\n# HostnameLookups: Log the names of clients or just their IP addresses\n# e.g., www.apache.org (on) or 204.62.129.132 (off).\n# The default is off because it'd be overall better for the net if people\n# had to knowingly turn this feature on, since enabling it means that\n# each client request will result in AT LEAST one lookup request to the\n# nameserver.\n#\nHostnameLookups Off\n\n# ErrorLog: The location of the error log file.\n# If you do not specify an ErrorLog directive within a <VirtualHost>\n# container, error messages relating to that virtual host will be\n# logged here.  If you *do* define an error logfile for a <VirtualHost>\n# container, that host's errors will be logged there and not here.\n#\nErrorLog <%= @node[:apache][:log_dir] %>/error.log \n\n#\n# LogLevel: Control the number of messages logged to the error_log.\n# Possible values include: debug, info, notice, warn, error, crit,\n# alert, emerg.\n#\nLogLevel warn\n\n# Include module configuration:\nInclude <%= @node[:apache][:dir] %>/mods-enabled/*.load\nInclude <%= @node[:apache][:dir] %>/mods-enabled/*.conf\n\n# Include ports listing\nInclude <%= @node[:apache][:dir] %>/ports.conf\n\n#\n# The following directives define some format nicknames for use with\n# a CustomLog directive (see below).\n#\nLogFormat \"%h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" combined\nLogFormat \"%h %l %u %t \\\"%r\\\" %>s %b\" common\nLogFormat \"%{Referer}i -> %U\" referer\nLogFormat \"%{User-agent}i\" agent\n#\n\n# Customizable error responses come in three flavors:\n# 1) plain text 2) local redirects 3) external redirects\n#\n# Some examples:\n#ErrorDocument 500 \"The server made a boo boo.\"\n#ErrorDocument 404 /missing.html\n#ErrorDocument 404 \"/cgi-bin/missing_handler.pl\"\n#ErrorDocument 402 http://www.example.com/subscription_info.html\n#\n\n#\n# Putting this all together, we can internationalize error responses.\n#\n# We use Alias to redirect any /error/HTTP_<error>.html.var response to\n# our collection of by-error message multi-language collections.  We use \n# includes to substitute the appropriate text.\n#\n# You can modify the messages' appearance without changing any of the\n# default HTTP_<error>.html.var files by adding the line:\n#\n#   Alias /error/include/ \"/your/include/path/\"\n#\n# which allows you to create your own set of files by starting with the\n# /usr/share/apache2/error/include/ files and copying them to /your/include/path/, \n# even on a per-VirtualHost basis.  The default include files will display\n# your Apache version number and your ServerAdmin email address regardless\n# of the setting of ServerSignature.\n#\n# The internationalized error documents require mod_alias, mod_include\n# and mod_negotiation.  To activate them, uncomment the following 30 lines.\n\n#    Alias /error/ \"/usr/share/apache2/error/\"\n#\n#    <Directory \"/usr/share/apache2/error\">\n#        AllowOverride None\n#        Options IncludesNoExec\n#        AddOutputFilter Includes html\n#        AddHandler type-map var\n#        Order allow,deny\n#        Allow from all\n#        LanguagePriority en cs de es fr it nl sv pt-br ro\n#        ForceLanguagePriority Prefer Fallback\n#    </Directory>\n#\n#    ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var\n#    ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var\n#    ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var\n#    ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var\n#    ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var\n#    ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var\n#    ErrorDocument 410 /error/HTTP_GONE.html.var\n#    ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var\n#    ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var\n#    ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var\n#    ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var\n#    ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var\n#    ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var\n#    ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var\n#    ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var\n#    ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var\n#    ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var\n\n\n\n# Include generic snippets of statements\nInclude <%= @node[:apache][:dir] %>/conf.d/\n\n# Include the virtual host configurations:\nInclude <%= @node[:apache][:dir] %>/sites-enabled/\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/apache2.god.erb",
    "content": "God.watch do |w|\n  w.name = \"apache2\"\n  w.interval = 30.seconds # default\n  w.start = \"<%= @params[:start] %>\"\n  w.stop = \"/etc/init.d/httpd stop\"\n  w.restart = \"<%= @params[:restart] %>\"\n  w.start_grace = 10.seconds\n  w.restart_grace = 10.seconds\n  w.pid_file = \"/var/run/httpd.pid\"\n  w.behavior(:clean_pid_file)\n\n  w.start_if do |start|\n    start.condition(:process_running) do |c|\n        c.interval = 5.seconds\n        c.running = false\n        c.notify = 'admin'\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/charset.erb",
    "content": "# Read the documentation before enabling AddDefaultCharset.\n# In general, it is only a good idea if you know that all your files\n# have this encoding. It will override any encoding given in the files\n# in meta http-equiv or xml encoding tags.\n\n#AddDefaultCharset UTF-8\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/default-site.erb",
    "content": "<VirtualHost *:80>\n        ServerAdmin <%= @node[:apache][:contact] %>\n\n        DocumentRoot /var/www/\n        <Directory />\n                Options FollowSymLinks\n                AllowOverride None\n        </Directory>\n        <Directory /var/www/>\n                Options Indexes FollowSymLinks MultiViews\n                AllowOverride None\n                Order allow,deny\n                allow from all\n                # This directive allows us to have apache2's default start page\n                # in /apache2-default/, but still have / go to the right place\n                #RedirectMatch ^/$ /apache2-default/\n        </Directory>\n\n        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/\n        <Directory \"/usr/lib/cgi-bin\">\n                AllowOverride None\n                Options ExecCGI -MultiViews +SymLinksIfOwnerMatch\n                Order allow,deny\n                Allow from all\n        </Directory>\n\n        ErrorLog <%= @node[:apache][:log_dir] %>/error.log \n\n        # Possible values include: debug, info, notice, warn, error, crit,\n        # alert, emerg.\n        LogLevel warn\n\n        CustomLog <%= @node[:apache][:log_dir] %>/access.log combined\n        ServerSignature On\n\n        Alias /doc/ \"/usr/share/doc/\"\n        <Directory \"/usr/share/doc/\">\n            Options Indexes MultiViews FollowSymLinks\n            AllowOverride None\n            Order deny,allow\n            Deny from all\n            Allow from 127.0.0.0/255.0.0.0 ::1/128\n        </Directory>\n\n        <% if @node[:platform] == \"centos\" || @node[:platform] == \"redhat\" || @node[:platform] == \"fedora\" -%>\n        #\n        # This configuration file enables the default \"Welcome\"\n        # page if there is no default index page present for\n        # the root URL.  To disable the Welcome page, comment\n        # out all the lines below.\n        #\n        <LocationMatch \"^/+$\">\n            Options -Indexes\n            ErrorDocument 403 /error/noindex.html\n        </LocationMatch>\n        <% end -%>\n</VirtualHost>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/README",
    "content": "These configs are taken from a Debian apache2.2-common 2.2.11-3 install. They \nwork on CentOS 5.3 with a few conditions using erb. \n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/alias.conf.erb",
    "content": "<IfModule alias_module>\n#\n# Aliases: Add here as many aliases as you need (with no limit). The format is \n# Alias fakename realname\n#\n# Note that if you include a trailing / on fakename then the server will\n# require it to be present in the URL.  So \"/icons\" isn't aliased in this\n# example, only \"/icons/\".  If the fakename is slash-terminated, then the \n# realname must also be slash terminated, and if the fakename omits the \n# trailing slash, the realname must also omit it.\n#\n# We include the /icons/ alias for FancyIndexed directory listings.  If\n# you do not use FancyIndexing, you may comment this out.\n#\nAlias /icons/ \"<%= @node[:apache][:icondir] %>\"\n\n<Directory \"<%= @node[:apache][:icondir] %>\">\n    Options Indexes MultiViews\n    AllowOverride None\n    Order allow,deny\n    Allow from all\n</Directory>\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/autoindex.conf.erb",
    "content": "<IfModule mod_autoindex.c>\n#\n# Directives controlling the display of server-generated directory listings.\n#\n\n#\n# IndexOptions: Controls the appearance of server-generated directory\n# listings.\n# Remove/replace the \"Charset=UTF-8\" if you don't use UTF-8 for your filenames.\n#\nIndexOptions FancyIndexing VersionSort HTMLTable NameWidth=* DescriptionWidth=* Charset=UTF-8\n\n#\n# AddIcon* directives tell the server which icon to show for different\n# files or filename extensions.  These are only displayed for\n# FancyIndexed directories.\n#\nAddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip x-bzip2\n\nAddIconByType (TXT,/icons/text.gif) text/*\nAddIconByType (IMG,/icons/image2.gif) image/*\nAddIconByType (SND,/icons/sound2.gif) audio/*\nAddIconByType (VID,/icons/movie.gif) video/*\n\nAddIcon /icons/binary.gif .bin .exe\nAddIcon /icons/binhex.gif .hqx\nAddIcon /icons/tar.gif .tar\nAddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv\nAddIcon /icons/compressed.gif .Z .z .tgz .gz .zip\nAddIcon /icons/a.gif .ps .ai .eps\nAddIcon /icons/layout.gif .html .shtml .htm .pdf\nAddIcon /icons/text.gif .txt\nAddIcon /icons/c.gif .c\nAddIcon /icons/p.gif .pl .py\nAddIcon /icons/f.gif .for\nAddIcon /icons/dvi.gif .dvi\nAddIcon /icons/uuencoded.gif .uu\nAddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl\nAddIcon /icons/tex.gif .tex\n# It's a suffix rule, so simply matching \"core\" matches \"score\" as well !\nAddIcon /icons/bomb.gif /core\nAddIcon (SND,/icons/sound2.gif) .ogg\nAddIcon (VID,/icons/movie.gif) .ogm\n\nAddIcon /icons/back.gif ..\nAddIcon /icons/hand.right.gif README\nAddIcon /icons/folder.gif ^^DIRECTORY^^\nAddIcon /icons/blank.gif ^^BLANKICON^^\n\n# Default icons for OpenDocument format\nAddIcon /icons/odf6odt-20x22.png .odt\nAddIcon /icons/odf6ods-20x22.png .ods\nAddIcon /icons/odf6odp-20x22.png .odp\nAddIcon /icons/odf6odg-20x22.png .odg\nAddIcon /icons/odf6odc-20x22.png .odc\nAddIcon /icons/odf6odf-20x22.png .odf\nAddIcon /icons/odf6odb-20x22.png .odb\nAddIcon /icons/odf6odi-20x22.png .odi\nAddIcon /icons/odf6odm-20x22.png .odm\n\nAddIcon /icons/odf6ott-20x22.png .ott\nAddIcon /icons/odf6ots-20x22.png .ots\nAddIcon /icons/odf6otp-20x22.png .otp\nAddIcon /icons/odf6otg-20x22.png .otg\nAddIcon /icons/odf6otc-20x22.png .otc\nAddIcon /icons/odf6otf-20x22.png .otf\nAddIcon /icons/odf6oti-20x22.png .oti\nAddIcon /icons/odf6oth-20x22.png .oth\n\n#\n# DefaultIcon is which icon to show for files which do not have an icon\n# explicitly set.\n#\nDefaultIcon /icons/unknown.gif\n\n#\n# AddDescription allows you to place a short description after a file in\n# server-generated indexes.  These are only displayed for FancyIndexed\n# directories.\n# Format: AddDescription \"description\" filename\n#\n#AddDescription \"GZIP compressed document\" .gz\n#AddDescription \"tar archive\" .tar\n#AddDescription \"GZIP compressed tar archive\" .tgz\n\n#\n# ReadmeName is the name of the README file the server will look for by\n# default, and append to directory listings.\n#\n# HeaderName is the name of a file which should be prepended to\n# directory indexes. \nReadmeName README.html\nHeaderName HEADER.html\n\n#\n# IndexIgnore is a set of filenames which directory indexing should ignore\n# and not include in the listing.  Shell-style wildcarding is permitted.\n#\nIndexIgnore .??* *~ *# RCS CVS *,v *,t \n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/deflate.conf.erb",
    "content": "<IfModule mod_deflate.c>\n          AddOutputFilterByType DEFLATE text/html text/plain text/xml\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/dir.conf.erb",
    "content": "<IfModule mod_dir.c>\n\n          DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/fcgid.conf.erb",
    "content": "<IfModule mod_fcgid.c>\n  AddHandler    fcgid-script .fcgi\n  IPCConnectTimeout 20\n</IfModule>\n\n<% if @node[:platform] == \"centos\" || @node[:platform] == \"redhat\" || @node[:platform] == \"fedora\" -%>\n# Sane place to put sockets and shared memory file\nSocketPath run/mod_fcgid\nSharememPath run/mod_fcgid/fcgid_shm\n<% end -%>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/mime.conf.erb",
    "content": "<IfModule mod_mime.c>\n\n#\n# TypesConfig points to the file containing the list of mappings from\n# filename extension to MIME-type.\n#\nTypesConfig /etc/mime.types\n\n#\n# AddType allows you to add to or override the MIME configuration\n# file mime.types for specific file types.\n#\n#AddType application/x-gzip .tgz\n#\n# AddEncoding allows you to have certain browsers uncompress\n# information on the fly. Note: Not all browsers support this.\n# Despite the name similarity, the following Add* directives have\n# nothing to do with the FancyIndexing customization directives above.\n#\n#AddEncoding x-compress .Z\n#AddEncoding x-gzip .gz .tgz\n#AddEncoding x-bzip2 .bz2\n#\n# If the AddEncoding directives above are commented-out, then you\n# probably should define those extensions to indicate media types:\n#\nAddType application/x-compress .Z\nAddType application/x-gzip .gz .tgz\nAddType application/x-bzip2 .bz2\n\n#\n# DefaultLanguage and AddLanguage allows you to specify the language of \n# a document. You can then use content negotiation to give a browser a \n# file in a language the user can understand.\n#\n# Specify a default language. This means that all data\n# going out without a specific language tag (see below) will \n# be marked with this one. You probably do NOT want to set\n# this unless you are sure it is correct for all cases.\n#\n# * It is generally better to not mark a page as \n# * being a certain language than marking it with the wrong\n# * language!\n#\n# DefaultLanguage nl\n#\n# Note 1: The suffix does not have to be the same as the language\n# keyword --- those with documents in Polish (whose net-standard\n# language code is pl) may wish to use \"AddLanguage pl .po\" to\n# avoid the ambiguity with the common suffix for perl scripts.\n#\n# Note 2: The example entries below illustrate that in some cases \n# the two character 'Language' abbreviation is not identical to \n# the two character 'Country' code for its country,\n# E.g. 'Danmark/dk' versus 'Danish/da'.\n#\n# Note 3: In the case of 'ltz' we violate the RFC by using a three char\n# specifier. There is 'work in progress' to fix this and get\n# the reference data for rfc1766 cleaned up.\n#\n# Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl)\n# English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de)\n# Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja)\n# Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn)\n# Norwegian (no) - Polish (pl) - Portugese (pt)\n# Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv)\n# Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW)\n#\nAddLanguage ca .ca\nAddLanguage cs .cz .cs\nAddLanguage da .dk\nAddLanguage de .de\nAddLanguage el .el\nAddLanguage en .en\nAddLanguage eo .eo\n# See README.Debian for Spanish\nAddLanguage es .es\nAddLanguage et .et\nAddLanguage fr .fr\nAddLanguage he .he\nAddLanguage hr .hr\nAddLanguage it .it\nAddLanguage ja .ja\nAddLanguage ko .ko\nAddLanguage ltz .ltz\nAddLanguage nl .nl\nAddLanguage nn .nn\nAddLanguage no .no\nAddLanguage pl .po\nAddLanguage pt .pt\nAddLanguage pt-BR .pt-br\nAddLanguage ru .ru\nAddLanguage sv .sv\n# See README.Debian for Turkish\nAddLanguage tr .tr\nAddLanguage zh-CN .zh-cn\nAddLanguage zh-TW .zh-tw\n\n#\n# Commonly used filename extensions to character sets. You probably\n# want to avoid clashes with the language extensions, unless you\n# are good at carefully testing your setup after each change.\n# See http://www.iana.org/assignments/character-sets for the\n# official list of charset names and their respective RFCs.\n#\nAddCharset us-ascii    .ascii .us-ascii\nAddCharset ISO-8859-1  .iso8859-1  .latin1\nAddCharset ISO-8859-2  .iso8859-2  .latin2 .cen\nAddCharset ISO-8859-3  .iso8859-3  .latin3\nAddCharset ISO-8859-4  .iso8859-4  .latin4\nAddCharset ISO-8859-5  .iso8859-5  .cyr .iso-ru\nAddCharset ISO-8859-6  .iso8859-6  .arb .arabic\nAddCharset ISO-8859-7  .iso8859-7  .grk .greek\nAddCharset ISO-8859-8  .iso8859-8  .heb .hebrew\nAddCharset ISO-8859-9  .iso8859-9  .latin5 .trk\nAddCharset ISO-8859-10  .iso8859-10  .latin6\nAddCharset ISO-8859-13  .iso8859-13\nAddCharset ISO-8859-14  .iso8859-14  .latin8\nAddCharset ISO-8859-15  .iso8859-15  .latin9\nAddCharset ISO-8859-16  .iso8859-16  .latin10\nAddCharset ISO-2022-JP .iso2022-jp .jis\nAddCharset ISO-2022-KR .iso2022-kr .kis\nAddCharset ISO-2022-CN .iso2022-cn .cis\nAddCharset Big5        .Big5       .big5 .b5\nAddCharset cn-Big5     .cn-big5\n# For russian, more than one charset is used (depends on client, mostly):\nAddCharset WINDOWS-1251 .cp-1251   .win-1251\nAddCharset CP866       .cp866\nAddCharset KOI8      .koi8\nAddCharset KOI8-E      .koi8-e\nAddCharset KOI8-r      .koi8-r .koi8-ru\nAddCharset KOI8-U      .koi8-u\nAddCharset KOI8-ru     .koi8-uk .ua\nAddCharset ISO-10646-UCS-2 .ucs2\nAddCharset ISO-10646-UCS-4 .ucs4\nAddCharset UTF-7       .utf7\nAddCharset UTF-8       .utf8\nAddCharset UTF-16      .utf16\nAddCharset UTF-16BE    .utf16be\nAddCharset UTF-16LE    .utf16le\nAddCharset UTF-32      .utf32\nAddCharset UTF-32BE    .utf32be\nAddCharset UTF-32LE    .utf32le\nAddCharset euc-cn      .euc-cn\nAddCharset euc-gb      .euc-gb\nAddCharset euc-jp      .euc-jp\nAddCharset euc-kr      .euc-kr\n#Not sure how euc-tw got in - IANA doesn't list it???\nAddCharset EUC-TW      .euc-tw\nAddCharset gb2312      .gb2312 .gb\nAddCharset iso-10646-ucs-2 .ucs-2 .iso-10646-ucs-2\nAddCharset iso-10646-ucs-4 .ucs-4 .iso-10646-ucs-4\nAddCharset shift_jis   .shift_jis .sjis\n\n#\n# AddHandler allows you to map certain file extensions to \"handlers\":\n# actions unrelated to filetype. These can be either built into the server\n# or added with the Action directive (see below)\n#\n# To use CGI scripts outside of ScriptAliased directories:\n# (You will also need to add \"ExecCGI\" to the \"Options\" directive.)\n#\n#AddHandler cgi-script .cgi\n\n#\n# For files that include their own HTTP headers:\n#\n#AddHandler send-as-is asis\n\n#\n# For server-parsed imagemap files:\n#\n#AddHandler imap-file map\n\n#\n# For type maps (negotiated resources):\n# (This is enabled by default to allow the Apache \"It Worked\" page\n#  to be distributed in multiple languages.)\n#\nAddHandler type-map var\n\n#\n# Filters allow you to process content before it is sent to the client.\n#\n# To parse .shtml files for server-side includes (SSI):\n# (You will also need to add \"Includes\" to the \"Options\" directive.)\n#\nAddType text/html .shtml\nAddOutputFilter INCLUDES .shtml\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/negotiation.conf.erb",
    "content": "<IfModule mod_negotiation.c>\n#\n# LanguagePriority allows you to give precedence to some languages\n# in case of a tie during content negotiation.\n#\n# Just list the languages in decreasing order of preference. We have\n# more or less alphabetized them here. You probably want to change this.\n#\nLanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv tr zh-CN zh-TW\n\n#\n# ForceLanguagePriority allows you to serve a result page rather than\n# MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback)\n# [in case no accepted languages matched the available variants]\n#\nForceLanguagePriority Prefer Fallback\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/proxy.conf.erb",
    "content": "<IfModule mod_proxy.c>\n        #turning ProxyRequests on and allowing proxying from all may allow\n        #spammers to use your proxy to send email.\n\n        ProxyRequests Off\n\n        <Proxy *>\n                AddDefaultCharset off\n                Order deny,allow\n                Deny from all\n                #Allow from .example.com\n        </Proxy>\n\n        # Enable/disable the handling of HTTP/1.1 \"Via:\" headers.\n        # (\"Full\" adds the server version; \"Block\" removes all outgoing Via: headers)\n        # Set to one of: Off | On | Full | Block\n\n        ProxyVia On\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/setenvif.conf.erb",
    "content": "<IfModule mod_setenvif.c>\n\n#\n# The following directives modify normal HTTP response behavior to\n# handle known problems with browser implementations.\n#\nBrowserMatch \"Mozilla/2\" nokeepalive\nBrowserMatch \"MSIE 4\\.0b2;\" nokeepalive downgrade-1.0 force-response-1.0\nBrowserMatch \"RealPlayer 4\\.0\" force-response-1.0\nBrowserMatch \"Java/1\\.0\" force-response-1.0\nBrowserMatch \"JDK/1\\.0\" force-response-1.0\n\n#\n# The following directive disables redirects on non-GET requests for\n# a directory that does not include the trailing slash.  This fixes a \n# problem with Microsoft WebFolders which does not appropriately handle \n# redirects for folders with DAV methods.\n# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV.\n#\nBrowserMatch \"Microsoft Data Access Internet Publishing Provider\" redirect-carefully\nBrowserMatch \"MS FrontPage\" redirect-carefully\nBrowserMatch \"^WebDrive\" redirect-carefully\nBrowserMatch \"^WebDAVFS/1.[012]\" redirect-carefully\nBrowserMatch \"^gnome-vfs/1.0\" redirect-carefully\nBrowserMatch \"^XML Spy\" redirect-carefully\nBrowserMatch \"^Dreamweaver-WebDAV-SCM1\" redirect-carefully\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/ssl.conf.erb",
    "content": "<IfModule mod_ssl.c>\n#\n# Pseudo Random Number Generator (PRNG):\n# Configure one or more sources to seed the PRNG of the SSL library.\n# The seed data should be of good random quality.\n# WARNING! On some platforms /dev/random blocks if not enough entropy\n# is available. This means you then cannot use the /dev/random device\n# because it would lead to very long connection times (as long as\n# it requires to make more entropy available). But usually those\n# platforms additionally provide a /dev/urandom device which doesn't\n# block. So, if available, use this one instead. Read the mod_ssl User\n# Manual for more details.\n#\nSSLRandomSeed startup builtin\nSSLRandomSeed startup file:/dev/urandom 512\nSSLRandomSeed connect builtin\nSSLRandomSeed connect file:/dev/urandom 512\n\n##\n##  SSL Global Context\n##\n##  All SSL configuration in this context applies both to\n##  the main server and all SSL-enabled virtual hosts.\n##\n\n#\n#   Some MIME-types for downloading Certificates and CRLs\n#\nAddType application/x-x509-ca-cert .crt\nAddType application/x-pkcs7-crl    .crl\n\n#   Pass Phrase Dialog:\n#   Configure the pass phrase gathering process.\n#   The filtering dialog program (`builtin' is a internal\n#   terminal dialog) has to provide the pass phrase on stdout.\nSSLPassPhraseDialog  builtin\n\n#   Inter-Process Session Cache:\n#   Configure the SSL Session Cache: First the mechanism \n#   to use and second the expiring timeout (in seconds).\n#SSLSessionCache         dbm:/var/run/apache2/ssl_scache\n<% if @node[:platform] == \"centos\" || @node[:platform] == \"redhat\" || @node[:platform] == \"fedora\" -%>\nSSLSessionCache        shmcb:/var/cache/mod_ssl/scache(512000)\n<% else -%>\nSSLSessionCache        shmcb:/var/run/apache2/ssl_scache\n<% end -%> \nSSLSessionCacheTimeout  300\n\n#   Semaphore:\n#   Configure the path to the mutual exclusion semaphore the\n#   SSL engine uses internally for inter-process synchronization. \n<% if @node[:platform] == \"centos\" || @node[:platform] == \"redhat\" || @node[:platform] == \"fedora\" -%>\nSSLMutex  default\n<% else -%>\nSSLMutex  file:/var/run/apache2/ssl_mutex\n<% end -%>\n\n#   SSL Cipher Suite:\n#   List the ciphers that the client is permitted to negotiate.\n#   See the mod_ssl documentation for a complete list.\n#   enable only secure ciphers:\nSSLCipherSuite HIGH:MEDIUM:!ADH\n#   Use this instead if you want to allow cipher upgrades via SGC facility.\n#   In this case you also have to use something like \n#        SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128\n#   see http://httpd.apache.org/docs/2.2/ssl/ssl_howto.html.en#upgradeenc\n#SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL\n\n# enable only secure protocols: SSLv3 and TLSv1, but not SSLv2\nSSLProtocol all -SSLv2\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/mods/status.conf.erb",
    "content": "<IfModule mod_status.c>\n#\n# Allow server status reports generated by mod_status,\n# with the URL of http://servername/server-status\n# Uncomment and change the \".example.com\" to allow\n# access from other hosts.\n#\n<Location /server-status>\n    SetHandler server-status\n    Order deny,allow\n    Deny from all\n    Allow from localhost ip6-localhost\n#    Allow from .example.com\n</Location>\n\n</IfModule>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/port_apache.erb",
    "content": "# Port <%= @port %> \n-A FWR -p tcp -m tcp --dport <%= @port %> -j ACCEPT"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/ports.conf.erb",
    "content": "#This file generated via template by Chef.\n<% @apache_listen_ports.each do |port| -%>\nListen <%= port %>\nNameVirtualHost *:<%= port %>\n\n<% end -%>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/security.erb",
    "content": "#\n# Disable access to the entire file system except for the directories that\n# are explicitly allowed later.\n#\n# This currently breaks the configurations that come with some web application\n# Debian packages. It will be made the default for the release after lenny.\n#\n#<Directory />\n#\tAllowOverride None\n#\tOrder Deny,Allow\n#\tDeny from all\n#</Directory>\n\n\n# Changing the following options will not really affect the security of the\n# server, but might make attacks slightly more difficult in some cases.\n\n#\n# ServerTokens\n# This directive configures what you return as the Server HTTP response\n# Header. The default is 'Full' which sends information about the OS-Type\n# and compiled in modules.\n# Set to one of:  Full | OS | Minimal | Minor | Major | Prod\n# where Full conveys the most information, and Prod the least.\n#\n#ServerTokens Minimal\nServerTokens <%= @node[:apache][:servertokens] %> \n\n#\n# Optionally add a line containing the server version and virtual host\n# name to server-generated pages (internal error documents, FTP directory\n# listings, mod_status and mod_info output etc., but not CGI generated\n# documents or custom error documents).\n# Set to \"EMail\" to also include a mailto: link to the ServerAdmin.\n# Set to one of:  On | Off | EMail\n#\n#ServerSignature Off\nServerSignature <%= @node[:apache][:serversignature] %> \n\n#\n# Allow TRACE method\n#\n# Set to \"extended\" to also reflect the request body (only for testing and\n# diagnostic purposes).\n#\n# Set to one of:  On | Off | extended\n#\n#TraceEnable Off\nTraceEnable <%= @node[:apache][:traceenable] %> \n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apache2/templates/default/web_app.conf.erb",
    "content": "<VirtualHost *:80>\n  ServerName <%= @params[:server_name] %>\n  ServerAlias <% @params[:server_aliases].each do |a| %><%= \"#{a}\" %> <% end %>\n  DocumentRoot <%= @params[:docroot] %>\n  RewriteEngine On\n  \n  <Directory <%= @params[:docroot] %>>\n    Options FollowSymLinks\n    AllowOverride None\n    Order allow,deny\n    Allow from all\n  </Directory>\n  \n  <Directory />\n    Options FollowSymLinks\n    AllowOverride None\n  </Directory>\n\n  <Location /server-status>\n    SetHandler server-status\n\n    Order Deny,Allow\n    Deny from all\n    Allow from 127.0.0.1\n  </Location>\n\n  LogLevel info\n  ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log\n  CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined\n\n  RewriteEngine On\n  RewriteLog <%= @node[:apache][:log_dir] %>/<%= @application_name %>-rewrite.log\n  RewriteLogLevel 0\n\n  # Canonical host, <%= @params[:server_name] %>\n  RewriteCond %{HTTP_HOST}   !^<%= @params[:server_name] %> [NC]\n  RewriteCond %{HTTP_HOST}   !^$\n  RewriteRule ^/(.*)$        http://<%= @params[:server_name] %>/$1 [L,R=301]\n\n  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f\n  RewriteCond %{SCRIPT_FILENAME} !maintenance.html\n  RewriteRule ^.*$ /system/maintenance.html [L]\n</VirtualHost>"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/files/default/apt-cacher",
    "content": "# apt-cacher startup configuration file\n\n# IMPORTANT: check the apt-cacher.conf file before using apt-cacher as daemon.\n\n# set to 1 to start the daemon at boot time\nAUTOSTART=1\n\n# extra settings to override the ones in apt-cacher.conf\n# EXTRAOPT=\" daemon_port=3142 limit=30 \"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/files/default/apt-cacher.conf",
    "content": "# This file has been modified by ./apt-proxy-to-apt-cacher\n# Some lines may have been appended at the bottom of this file\n# This file has been modified by /usr/share/apt-cacher/apt-proxy-to-apt-cacher\n# Some lines may have been appended at the bottom of this file\n#################################################################\n# This is the config file for apt-cacher. On most Debian systems\n# you can safely leave the defaults alone.\n#################################################################\n\n# cache_dir is used to set the location of the local cache. This can\n# become quite large, so make sure it is somewhere with plenty of space.\ncache_dir=/var/cache/apt-cacher\n\n# The email address of the administrator is displayed in the info page\n# and traffic reports.\nadmin_email=root@localhost\n\n# For the daemon startup settings please edit the file /etc/default/apt-cacher.\n\n# Daemon port setting, only useful in stand-alone mode. You need to run the\n# daemon as root to use privileged ports (<1024).\ndaemon_port = 3142\n\n# optional settings, user and group to run the daemon as. Make sure they have\n# sufficient permissions on the cache and log directories. Comment the settings\n# to run apt-cacher as the native user.\ngroup=www-data\nuser=www-data\n\n# optional setting, binds the listening daemon to one specified IP. Use IP\n# ranges for more advanced configuration, see below.\n# daemon_addr=localhost\n\n# If your apt-cacher machine is directly exposed to the Internet and you are\n# worried about unauthorised machines fetching packages through it, you can\n# specify a list of IPv4 addresses which are allowed to use it and another\n# list of IPv4 addresses which aren't.\n# Localhost (127.0.0.1) is always allowed. Other addresses must be matched\n# by allowed_hosts and not by denied_hosts to be permitted to use the cache.\n# Setting allowed_hosts to \"*\" means \"allow all\".\n# Otherwise the format is a comma-separated list containing addresses,\n# optionally with masks (like 10.0.0.0/22), or ranges of addresses (two\n# addresses separated by a hyphen, no masks, like '192.168.0.3-192.168.0.56').\nallowed_hosts=*\ndenied_hosts=\n\n# And similiarly for IPv6 with allowed_hosts_6 and denied_hosts_6.\n# Note that IPv4-mapped IPv6 addresses (::ffff:w.x.y.z) are truncated to\n# w.x.y.z and are handled as IPv4.\nallowed_hosts_6=fec0::/16\ndenied_hosts_6=\n\n# This thing can be done by Apache but is much simplier here - limit access to\n# Debian mirrors based on server names in the URLs\n#allowed_locations=ftp.uni-kl.de,ftp.nerim.net,debian.tu-bs.de\n\n# Apt-cacher can generate usage reports every 24 hours if you set this\n# directive to 1. You can view the reports in a web browser by pointing\n# to your cache machine with '/apt-cacher/report' on the end, like this:\n#      http://yourcache.example.com/apt-cacher/report\n# Generating reports is very fast even with many thousands of logfile\n# lines, so you can safely turn this on without creating much \n# additional system load.\ngenerate_reports=1\n\n# Apt-cacher can clean up its cache directory every 24 hours if you set\n# this directive to 1. Cleaning the cache can take some time to run\n# (generally in the order of a few minutes) and removes all package\n# files that are not mentioned in any existing 'Packages' lists. This\n# has the effect of deleting packages that have been superseded by an\n# updated 'Packages' list.\nclean_cache=1\n\n# The directory to use for apt-cacher access and error logs.\n# The access log records every request in the format:\n# date-time|client ip address|HIT/MISS/EXPIRED|object size|object name\n# The error log is slightly more free-form, and is also used for debug\n# messages if debug mode is turned on.\n# Note that the old 'logfile' and 'errorfile' directives are\n# deprecated: if you set them explicitly they will be honoured, but it's\n# better to just get rid of them from old config files.\nlogdir=/var/log/apt-cacher\n\n# apt-cacher can use different methods to decide whether package lists need to\n# be updated,\n# A) looking at the age of the cached files\n# B) getting HTTP header from server and comparing that with cached data. This\n# method is more reliable and avoids desynchronisation of data and index files\n# but needs to transfer few bytes from the server every time somebody requests\n# the files (\"apt-get update\")\n# Set the following value to the maximum age (in hours) for method A or to 0\n# for method B\nexpire_hours=0\n\n# Apt-cacher can pass all its requests to an external http proxy like\n# Squid, which could be very useful if you are using an ISP that blocks\n# port 80 and requires all web traffic to go through its proxy. The\n# format is 'hostname:port', eg: 'proxy.example.com:8080'.\nhttp_proxy=proxy.example.com:8080\n\n# Use of an external proxy can be turned on or off with this flag.\n# Value should be either 0 (off) or 1 (on).\nuse_proxy=0\n\n# External http proxy sometimes need authentication to get full access. The\n# format is 'username:password'.\nhttp_proxy_auth=proxyuser:proxypass\n\n# Use of external proxy authentication can be turned on or off with this flag.\n# Value should be either 0 (off) or 1 (on).\nuse_proxy_auth=0\n\n# Rate limiting sets the maximum bandwidth in bytes per second to use\n# for fetching packages. Syntax is fully defined in 'man wget'.\n# Use 'k' or 'm' to use kilobits or megabits / second: eg, 'limit=25k'.\n# Use 0 or a negative value for no rate limiting.\nlimit=0\n\n# Debug mode makes apt-cacher spew a lot of extra debug junk to the\n# error log (whose location is defined with the 'logdir' directive).\n# Leave this off unless you need it, or your error log will get very\n# big. Acceptable values are 0 or 1.\ndebug=0\n\n# Adapt the line in the usage info web page to match your server configuration\n# example_sources_line=deb&nbsp;http://<b>my.cacher.server:3142/</b>ftp.au.debian.org/debian&nbsp;unstable&nbsp;main&nbsp;contrib&nbsp;non-free\n\n# Print a 410 (Gone) HTTP message with the specified text when accessed via\n# CGI. Useful to tell users to adapt their sources.list files when the\n# apt-cacher server is beeing relocated (via apt-get's error messages while\n# running \"update\")\n#cgi_advise_to_use = Please use http://cacheserver:3142/ as apt-cacher access URL\n#cgi_advise_to_use = Server relocated. To change sources.list, run perl -pe \"s,/apt-cacher\\??,:3142,\" -i /etc/apt/sources.list\n\n# Server mapping - this allows to hide real server names behind virtual paths\n# that appear in the access URL. This method is known from apt-proxy. This is\n# also the only method to use FTP access to the target hosts. The syntax is simple, the part of the beginning to replace, followed by a list of mirror urls, all space separated. Multiple profile are separated by semicolons\n# path_map = debian ftp.uni-kl.de/pub/linux/debian ftp2.de.debian.org/debian ; ubuntu archive.ubuntu.com/ubuntu ; security security.debian.org/debian-security ftp2.de.debian.org/debian-security\n# Note that you need to specify all target servers in the allowed_locations\n# options if you make use of it. Also note that the paths should not overlap\n# each other. FTP access method not supported yet, maybe in the future.\n\n# extra setting from apt-proxy configuration\npath_map =  ubuntu us.archive.ubuntu.com/ubuntu ; ubuntu-security security.ubuntu.com/ubuntu ; debian debian.osuosl.org/debian/ ; security security.debian.org/debian-security\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/files/default/apt-proxy-v2.conf",
    "content": "[DEFAULT]\n;; All times are in seconds, but you can add a suffix\n;; for minutes(m), hours(h) or days(d)\n\n;; commented out address so apt-proxy will listen on all IPs\n;; address = 127.0.0.1\nport = 9999\ncache_dir = /var/cache/apt-proxy\n\n;; Control files (Packages/Sources/Contents) refresh rate\nmin_refresh_delay = 1s\ncomplete_clientless_downloads = 1\n\n;; Debugging settings.\ndebug = all:4 db:0\n\ntime = 30\npassive_ftp = on\n\n;;--------------------------------------------------------------\n;; Cache housekeeping\n\ncleanup_freq = 1d\nmax_age = 120d\nmax_versions = 3\n\n;;---------------------------------------------------------------\n;; Backend servers\n;;\n;; Place each server in its own [section]\n\n[ubuntu]\n; Ubuntu archive\nbackends =\n        http://us.archive.ubuntu.com/ubuntu\n\n[ubuntu-security]\n; Ubuntu security updates\nbackends = http://security.ubuntu.com/ubuntu\n\n[debian]\n;; Backend servers, in order of preference\nbackends = \n        http://debian.osuosl.org/debian/\n\n[security]\n;; Debian security archive\nbackends = \n        http://security.debian.org/debian-security\n        http://ftp2.de.debian.org/debian-security\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/metadata.json",
    "content": "{\n  \"description\": \"Configures apt and apt services\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"apt::proxy\": \"Set up an APT proxy\",\n    \"apt\": \"\",\n    \"apt::cacher\": \"Set up an APT cache\"\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ],\n    \"debian\": [\n\n    ]\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.7.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"apt\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n\n  },\n  \"providing\": {\n    \"apt::proxy\": [\n\n    ],\n    \"apt\": [\n\n    ],\n    \"apt::cacher\": [\n\n    ]\n  },\n  \"long_description\": \"\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Configures apt and apt services\"\nversion           \"0.7\"\nrecipe            \"apt::cacher\", \"Set up an APT cache\"\nrecipe            \"apt::proxy\", \"Set up an APT proxy\"\n\n%w{ ubuntu debian }.each do |os|\n  supports os\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/recipes/cacher.rb",
    "content": "#\n# Cookbook Name:: apt\n# Recipe:: cacher\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\npackage \"apt-cacher\" do\n  action :install\nend\n\nservice \"apt-cacher\" do\n  supports :restart => true, :status => false\n  action [ :enable, :start ]\nend\n\nremote_file \"/etc/apt-cacher/apt-cacher.conf\" do\n  source \"apt-cacher.conf\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"apt-cacher\")\nend\n\nremote_file \"/etc/default/apt-cacher\" do\n  source \"apt-cacher\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"apt-cacher\")\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/recipes/default.rb",
    "content": "#\n# Cookbook Name:: apt\n# Recipe:: default\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nexecute \"apt-get-update\" do\n  command \"apt-get update\"\nend\n\n%w{/var/cache/local /var/cache/local/preseeding}.each do |dirname|\n  directory dirname do\n    owner \"root\"\n    group \"root\"\n    mode  0644\n    action :create\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/apt/recipes/proxy.rb",
    "content": "#\n# Cookbook Name:: apt\n# Recipe:: proxy\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\npackage \"apt-proxy\" do \n  action :install\nend\n\nservice \"apt-proxy\" do\n  supports :restart => true, :status => false\n  action [ :enable, :start ]\nend\n\nremote_file \"/etc/apt-proxy/apt-proxy-v2.conf\" do\n  source \"apt-proxy-v2.conf\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"apt-proxy\")\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/README.rdoc",
    "content": "= DESCRIPTION:\n\nThis cookbook bootstraps a Chef client or server when Chef is installed via RubyGems. If installing Chef from OS distribution packages, please see the 'chef' cookbook. \n\n= REQUIREMENTS:\n\nThis cookbook requires Chef installed from RubyGems. Chef v0.7.10, for attribute syntax.\n\n== Platform:\n\nServer bootstrap is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\n\nClient bootstrap is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo. OpenSolaris 11 is also tested, but there's a bug in Ohai that requires some manual intervention (OHAI-122).\n\n== Cookbooks:\n\nOpscode cookbooks, http://github.com/opscode/cookbooks:\n\nBoth clients and servers:\n\n* runit\n\nServers only:\n\n* couchdb\n* stompserver\n\nThe couchdb and stompserver recipes may be somewhat naive depending on the platform. You should view them online at the github repository to see if your platform is supported. If not, you'll need to manually install them, and remove the \"include_recipe\" statements from the bootstrap::server recipe.\n\n= ATTRIBUTES:\n\nAttributes are under 'bootstrap[:chef]' - eg: 'bootstrap[:chef][:client_version]'. You may wish to change some of these locations to customize for your environment. For the bootstrap process this is done with a JSON data file passed to chef-solo.\n\n== url_type\n\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http://server:4000'. If you set up your chef-server to use an SSL front-end, set this to 'https' and the URLs will be 'https://server/'. \n\n== init_style\n\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\n\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\n\n== path\n\nThis is the base location where chef will store its associated data. Default '/srv/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\n\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\n\n* /var/lib/chef\n\nAny BSD and Gentoo:\n\n* /var/chef\n\n== run_path\n\nLocation for pidfiles on systems using init scripts. Default '/var/run/chef'.\n\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\n\n== cache_path\n\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Some Linux distributions might prefer /var/cache/chef instead.\n\n== serve_path\n\nUsed by the Chef server as the base location to \"serve\" cookbooks, roles and other assets. Default is /srv/chef.\n\n== server_version, client_version\n\nSet the version of the Gems to install. This can be used to upgrade Chef automatically[0]. The chef gems are not managed by the Opscode Chef cookbook, however.\n\n== client_interval\n\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\n\n== client_splay\n\nSplay interval to randomly add to interval. Default '20'.\n\n== log_dir\n\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default '/var/log/chef'.\n\n== client_log, indexer_log, server_log\n\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '/var/log/chef/{client,indexer,server}.log' on other systems.\n\n== server_fqdn\n\nFully qualified domain name of the server. Default is the current node's fqdn as detected by Ohai. For clients, set this to the hostname of your environment's Chef Server.\n\n== server_token\n\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs. Use chef-client -t 'validation_token' to automatically validate the client.\n\n[0] http://blog.opscode.com/2009/08/cool-chef-tricks-upgrade-chef-with-chef.html\n[1] http://www.pathname.com/fhs/\n\n= USAGE:\n\nOpscode stores this cookbook and some others (see the requirements above) on S3. Use chef-solo:\n\n    sudo chef-solo -j chef.json -c solo.rb -r http://s3.amazonaws.com/chef-repo/bootstrap.tar.gz\n\nYou set the attributes through the chef.json file, and tell Solo where to put them with solo.rb.\n\n== Clients:\n\nCommon attributes you may wish to adjust for the client:\n\n{\n  \"bootstrap\": {\n    \"chef\": {\n      \"url_type\": \"http\",\n      \"init_style\": \"runit\",\n      \"path\": \"/srv/chef\",\n      \"server_fqdn\": \"localhost.localdomain\",\n    }\n  },\n  \"recipes\": \"bootstrap::client\"\n}\n\n== Servers:\n\nCommon attributes you may wish to adjust for the server:\n\n{\n  \"bootstrap\": {\n    \"chef\": {\n      \"url_type\": \"http\",\n      \"init_style\": \"runit\",\n      \"path\": \"/srv/chef\",\n      \"serve_path\": \"/srv/chef\",\n      \"server_fqdn\": \"localhost.localdomain\",\n    }\n  },\n  \"recipes\": \"bootstrap::server\"\n}\n\nNote that the server recipe includes the client recipe as well, since we recommend managing the chef-server with Chef.\n\nFor more information on usage and next steps, please see the Chef wiki.\n\n    http://wiki.opscode.com/display/chef/Home\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman <joshua@opscode.com>\nAuthor:: Joshua Sierles <joshua@37signals.com>\n\nCopyright 2008-2009, Opscode, Inc\nCopyright 2009, 37signals\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/attributes/bootstrap.rb",
    "content": "#\n# Cookbook Name:: bootstrap\n# Attributes:: bootstrap\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nvalidation_token = \"\"\nchars = (\"a\"..\"z\").to_a + (\"A\"..\"Z\").to_a + (\"0\"..\"9\").to_a\n20.times { |i| validation_token << chars[rand(chars.size-1)] }\n\ndefault[:bootstrap][:chef][:url_type]   = \"http\"\ndefault[:bootstrap][:chef][:init_style] = \"runit\"\ndefault[:bootstrap][:chef][:path]       = \"/srv/chef\"\ndefault[:bootstrap][:chef][:run_path]   = \"/var/run/chef\"\ndefault[:bootstrap][:chef][:cache_path] = \"/#{bootstrap[:chef][:path]}/cache\"\ndefault[:bootstrap][:chef][:serve_path] = \"/srv/chef\"\n\ndefault[:bootstrap][:chef][:server_version]  = \"0.7.10\"\ndefault[:bootstrap][:chef][:client_version]  = \"0.7.10\"\ndefault[:bootstrap][:chef][:client_interval] = \"1800\"\ndefault[:bootstrap][:chef][:client_splay]    = \"20\"\ndefault[:bootstrap][:chef][:log_dir]         = \"/var/log/chef\"\n\ncase bootstrap[:chef][:init_style]\nwhen \"runit\"\n  default[:bootstrap][:chef][:client_log]  = \"STDOUT\"\n  default[:bootstrap][:chef][:server_log]  = \"STDOUT\"\n  default[:bootstrap][:chef][:indexer_log] = \"STDOUT\"\nelse\n  default[:bootstrap][:chef][:client_log]  = \"#{bootstrap[:chef][:log_dir]}/client.log\"\n  default[:bootstrap][:chef][:server_log]  = \"#{bootstrap[:chef][:log_dir]}/server.log\"\n  default[:bootstrap][:chef][:indexer_log] = \"#{bootstrap[:chef][:log_dir]}/indexer.log\"\nend\n\ndefault[:bootstrap][:chef][:server_fqdn]  = domain ? \"chef.#{domain}\" : \"chef\"\ndefault[:bootstrap][:chef][:server_token] = validation_token\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/metadata.json",
    "content": "{\n  \"description\": \"Configures RubyGems-installed Chef\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"bootstrap::client\": \"\",\n    \"bootstrap::server\": \"\",\n    \"bootstrap\": \"\"\n  },\n  \"platforms\": {\n\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.1.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"bootstrap\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n    \"stompserver\": [\n\n    ],\n    \"runit\": [\n\n    ],\n    \"couchdb\": [\n\n    ],\n    \"apache2\": [\n\n    ]\n  },\n  \"providing\": {\n    \"bootstrap\": [\n\n    ],\n    \"bootstrap::client\": [\n\n    ],\n    \"bootstrap::server\": [\n\n    ]\n  },\n  \"long_description\": \"= DESCRIPTION:\\n\\nThis cookbook bootstraps a Chef client or server when Chef is installed via RubyGems. If installing Chef from OS distribution packages, please see the 'chef' cookbook. \\n\\n= REQUIREMENTS:\\n\\nThis cookbook requires Chef installed from RubyGems. Chef v0.7.10, for attribute syntax.\\n\\n== Platform:\\n\\nServer bootstrap is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\\n\\nClient bootstrap is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo. OpenSolaris 11 is also tested, but there's a bug in Ohai that requires some manual intervention (OHAI-122).\\n\\n== Cookbooks:\\n\\nOpscode cookbooks, http:\\/\\/github.com\\/opscode\\/cookbooks:\\n\\nBoth clients and servers:\\n\\n* runit\\n\\nServers only:\\n\\n* couchdb\\n* stompserver\\n\\nThe couchdb and stompserver recipes may be somewhat naive depending on the platform. You should view them online at the github repository to see if your platform is supported. If not, you'll need to manually install them, and remove the \\\"include_recipe\\\" statements from the bootstrap::server recipe.\\n\\n= ATTRIBUTES:\\n\\nAttributes are under 'bootstrap[:chef]' - eg: 'bootstrap[:chef][:client_version]'. You may wish to change some of these locations to customize for your environment. For the bootstrap process this is done with a JSON data file passed to chef-solo.\\n\\n== url_type\\n\\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http:\\/\\/server:4000'. If you set up your chef-server to use an SSL front-end, set this to 'https' and the URLs will be 'https:\\/\\/server\\/'. \\n\\n== init_style\\n\\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\\n\\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\\n\\n== path\\n\\nThis is the base location where chef will store its associated data. Default '\\/srv\\/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\\n\\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\\n\\n* \\/var\\/lib\\/chef\\n\\nAny BSD and Gentoo:\\n\\n* \\/var\\/chef\\n\\n== run_path\\n\\nLocation for pidfiles on systems using init scripts. Default '\\/var\\/run\\/chef'.\\n\\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\\n\\n== cache_path\\n\\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Some Linux distributions might prefer \\/var\\/cache\\/chef instead.\\n\\n== serve_path\\n\\nUsed by the Chef server as the base location to \\\"serve\\\" cookbooks, roles and other assets. Default is \\/srv\\/chef.\\n\\n== server_version, client_version\\n\\nSet the version of the Gems to install. This can be used to upgrade Chef automatically[0]. The chef gems are not managed by the Opscode Chef cookbook, however.\\n\\n== client_interval\\n\\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\\n\\n== client_splay\\n\\nSplay interval to randomly add to interval. Default '20'.\\n\\n== log_dir\\n\\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default '\\/var\\/log\\/chef'.\\n\\n== client_log, indexer_log, server_log\\n\\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '\\/var\\/log\\/chef\\/{client,indexer,server}.log' on other systems.\\n\\n== server_fqdn\\n\\nFully qualified domain name of the server. Default is the current node's fqdn as detected by Ohai. For clients, set this to the hostname of your environment's Chef Server.\\n\\n== server_token\\n\\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs. Use chef-client -t 'validation_token' to automatically validate the client.\\n\\n[0] http:\\/\\/blog.opscode.com\\/2009\\/08\\/cool-chef-tricks-upgrade-chef-with-chef.html\\n[1] http:\\/\\/www.pathname.com\\/fhs\\/\\n\\n= USAGE:\\n\\nOpscode stores this cookbook and some others (see the requirements above) on S3. Use chef-solo:\\n\\n    sudo chef-solo -j chef.json -c solo.rb -r http:\\/\\/s3.amazonaws.com\\/chef-repo\\/bootstrap.tar.gz\\n\\nYou set the attributes through the chef.json file, and tell Solo where to put them with solo.rb.\\n\\n== Clients:\\n\\nCommon attributes you may wish to adjust for the client:\\n\\n{\\n  \\\"bootstrap\\\": {\\n    \\\"chef\\\": {\\n      \\\"url_type\\\": \\\"http\\\",\\n      \\\"init_style\\\": \\\"runit\\\",\\n      \\\"path\\\": \\\"\\/srv\\/chef\\\",\\n      \\\"server_fqdn\\\": \\\"localhost.localdomain\\\",\\n    }\\n  },\\n  \\\"recipes\\\": \\\"bootstrap::client\\\"\\n}\\n\\n== Servers:\\n\\nCommon attributes you may wish to adjust for the server:\\n\\n{\\n  \\\"bootstrap\\\": {\\n    \\\"chef\\\": {\\n      \\\"url_type\\\": \\\"http\\\",\\n      \\\"init_style\\\": \\\"runit\\\",\\n      \\\"path\\\": \\\"\\/srv\\/chef\\\",\\n      \\\"serve_path\\\": \\\"\\/srv\\/chef\\\",\\n      \\\"server_fqdn\\\": \\\"localhost.localdomain\\\",\\n    }\\n  },\\n  \\\"recipes\\\": \\\"bootstrap::server\\\"\\n}\\n\\nNote that the server recipe includes the client recipe as well, since we recommend managing the chef-server with Chef.\\n\\nFor more information on usage and next steps, please see the Chef wiki.\\n\\n    http:\\/\\/wiki.opscode.com\\/display\\/chef\\/Home\\n\\n= LICENSE and AUTHOR:\\n\\nAuthor:: Joshua Timberman <joshua@opscode.com>\\nAuthor:: Joshua Sierles <joshua@37signals.com>\\n\\nCopyright 2008-2009, Opscode, Inc\\nCopyright 2009, 37signals\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http:\\/\\/www.apache.org\\/licenses\\/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\n\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/metadata.rb",
    "content": "maintainer       \"Opscode, Inc.\"\nmaintainer_email \"cookbooks@opscode.com\"\nlicense          \"Apache 2.0\"\ndescription      \"Configures RubyGems-installed Chef\"\nlong_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))\nversion          \"0.1\"\n\n%w{ runit couchdb stompserver apache2 }.each do |cb|\n  depends cb\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/recipes/client.rb",
    "content": "#\n# Cookbook Name:: bootstrap\n# Recipe:: default\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nroot_group = value_for_platform(\n  \"openbsd\" => { \"default\" => \"wheel\" },\n  \"freebsd\" => { \"default\" => \"wheel\" },\n  \"default\" => \"root\"\n)\n# case node[:platform]\n# when \"debian\", \"ubuntu\"\n#   package 'chef'\n#   require_recipe \"ubuntu\"\n# else \n#   puts \"not ubuntu\"\n# end\n\ngem_package \"chef\" do\n  version node[:bootstrap][:chef][:client_version]\nend\n\ncase node[:bootstrap][:chef][:init_style]\nwhen \"runit\"\n  client_log = node[:bootstrap][:chef][:client_log]\n  show_time  = \"false\"\n  include_recipe \"runit\"\n  runit_service \"chef-client\"\nwhen \"init\"\n  client_log = \"\\\"#{node[:bootstrap][:chef][:client_log]}\\\"\"\n  show_time  = \"true\"\n\n  directory node[:bootstrap][:chef][:run_path] do\n    action :create\n    owner \"root\"\n    group root_group\n    mode \"755\"\n  end\n\n  service \"chef-client\" do\n    action :nothing\n  end\n\n  Chef::Log.info(\"You specified service style 'init'.\")\n  Chef::Log.info(\"'init' scripts available in #{node[:languages][:ruby][:gems_dir]}/gems/chef-#{node[:bootstrap][:chef][:client_version]}/distro\")\nwhen \"bsd\"\n  client_log = node[:bootstrap][:chef][:client_log]\n  show_time  = \"false\"\n  Chef::Log.info(\"You specified service style 'bsd'. You will need to set up your rc.local file.\")\n  Chef::Log.info(\"Hint: chef-client -i #{node[:bootstrap][:chef][:client_interval]} -s #{node[:bootstrap][:chef][:client_splay]}\")\nelse\n  client_log = node[:bootstrap][:chef][:client_log]\n  show_time  = \"false\"\n  Chef::Log.info(\"Could not determine service init style, manual intervention required to start up the client service.\")\nend\n\nchef_dirs = [\n  node[:bootstrap][:chef][:log_dir],\n  node[:bootstrap][:chef][:path],\n  \"/etc/chef\"\n]\n\nchef_dirs.each do |dir|\n  directory dir do\n    owner \"root\"\n    group root_group\n    mode \"755\"\n  end\nend\n\ntemplate \"/etc/chef/client.rb\" do\n  source \"client.rb.erb\"\n  owner \"root\"\n  group root_group\n  mode \"644\"\n  variables(\n    :client_log => client_log,\n    :show_time  => show_time\n  )\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/recipes/default.rb",
    "content": "#\n# Cookbook Name:: bootstrap\n# Recipe:: client\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/recipes/server.rb",
    "content": "#\n# Author:: Joshua Timberman <joshua@opscode.com>\n# Author:: Joshua Sierles <joshua@37signals.com>\n#\n# Cookbook Name:: bootstrap\n# Recipe:: server\n#\n# Copyright 2009, Opscode, Inc.\n# Copyright 2009, 37signals\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nroot_group = value_for_platform(\n  \"openbsd\" => { \"default\" => \"wheel\" },\n  \"freebsd\" => { \"default\" => \"wheel\" },\n  \"default\" => \"root\"\n)\n\ninclude_recipe \"bootstrap::client\"\ninclude_recipe \"stompserver\"\n\ncase node[:platform]\nwhen \"ubuntu\"\n  if node[:platform_version].to_f >= 8.10\n    include_recipe \"couchdb\"\n  end\nwhen \"debian\"\n  if node[:platform_version].to_f >= 5.0 || node[:platform_version] =~ /.*sid/\n    include_recipe \"couchdb\"\n  end\nwhen \"centos\",\"redhat\",\"fedora\"\n  include_recipe \"couchdb\"\nelse\n  Chef::Log.info(\"Unknown platform for CouchDB. Manual installation of CouchDB required.\")\nend\n\n%w{ chef-server chef-server-slice }.each do |gem|\n  gem_package gem do\n    version node[:bootstrap][:chef][:server_version]\n  end\nend\n\nif node[:bootstrap][:chef][:server_log] == \"STDOUT\"\n  server_log = node[:bootstrap][:chef][:server_log]\n  show_time  = \"false\"\nelse\n  server_log = \"\\\"#{node[:bootstrap][:chef][:server_log]}\\\"\"\n  indexer_log = \"\\\"#{node[:bootstrap][:chef][:indexer_log]}\\\"\"\n  show_time  = \"true\"\nend\n\ntemplate \"/etc/chef/server.rb\" do\n  source \"server.rb.erb\"\n  owner \"root\"\n  group root_group\n  mode \"600\"\n  variables(\n    :server_log => server_log,\n    :show_time  => show_time\n  )\nend\n\n%w{ openid cache search_index openid/cstore openid/store }.each do |dir|\n  directory \"#{node[:bootstrap][:chef][:path]}/#{dir}\" do\n    owner \"root\"\n    group root_group\n    mode \"755\"\n  end\nend\n\ndirectory \"/etc/chef/certificates\" do\n  owner \"root\"\n  group root_group\n  mode \"700\"\nend\n\ndirectory node[:bootstrap][:chef][:run_path] do\n  owner \"root\"\n  group root_group\n  mode \"755\"\nend\n\ncase node[:bootstrap][:chef][:init_style]\nwhen \"runit\"\n  include_recipe \"runit\"\n  runit_service \"chef-indexer\"\n  runit_service \"chef-server\"\n  service \"chef-server\" do\n    restart_command \"sv int chef-server\"\n  end\nwhen \"init\"\n  show_time  = \"true\"\n\n  service \"chef-indexer\" do\n    action :nothing\n  end\n\n  service \"chef-server\" do\n    action :nothing\n  end\n\n  Chef::Log.info(\"You specified service style 'init'.\")\n  Chef::Log.info(\"'init' scripts available in #{node[:languages][:ruby][:gems_dir]}/gems/chef-#{node[:bootstrap][:chef][:client_version]}/distro\")\nwhen \"bsd\"\n  Chef::Log.info(\"You specified service style 'bsd'. You will need to set up your rc.local file for chef-indexer and chef-server.\")\n  Chef::Log.info(\"Server startup command: chef-server -c2 -d\")\nelse\n  Chef::Log.info(\"Could not determine service init style, manual intervention required to set up indexer and server services.\")\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/client.rb.erb",
    "content": "#\n# Chef Client Config File\n#\n# Dynamically generated by Chef - local modifications will be replaced\n#\n\nlog_level          :info\nlog_location       <%= @client_log %>\nssl_verify_mode    :verify_none\n<% if @node[:bootstrap][:chef][:url_type] == \"https\" -%>\nregistration_url   \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>\"\nopenid_url         \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>:444\"\ntemplate_url       \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>\"\nremotefile_url     \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>\"\nsearch_url         \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>\"\nrole_url           \"https://<%= @node[:bootstrap][:chef][:server_fqdn] %>\"\n<% else -%>\nregistration_url   \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nopenid_url         \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4001\"\ntemplate_url       \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nremotefile_url     \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nsearch_url         \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nrole_url           \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\n<% end -%>\n\nfile_cache_path    \"<%= @node[:bootstrap][:chef][:cache_path] %>\"\n\npid_file           \"<%= @node[:bootstrap][:chef][:run_path] %>/chef-client.pid\"\n\nChef::Log::Formatter.show_time = <%= @show_time %>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/server.rb.erb",
    "content": "#\n# Chef Server Config File\n#\n# Dynamically generated by Chef - local modifications will be replaced\n\nlog_level          :info\nlog_location       <%= @server_log %>\nssl_verify_mode    :verify_none\nregistration_url   \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nopenid_url         \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4001\"\ntemplate_url       \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nremotefile_url     \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nsearch_url         \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\nrole_url           \"http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000\"\n\nvalidation_token   \"<%= @node[:bootstrap][:chef][:server_token] %>\"\n\ncookbook_path      [ \"<%= @node[:bootstrap][:chef][:serve_path] %>/site-cookbooks\", \"<%= @node[:bootstrap][:chef][:serve_path] %>/cookbooks\" ]\n\nfile_cache_path    \"<%= @node[:bootstrap][:chef][:cache_path] %>\"\nnode_path          \"<%= @node[:bootstrap][:chef][:serve_path] %>/nodes\"\nopenid_store_path  \"<%= @node[:bootstrap][:chef][:path] %>/openid/store\"\nopenid_cstore_path \"<%= @node[:bootstrap][:chef][:path] %>/openid/cstore\"\nsearch_index_path  \"<%= @node[:bootstrap][:chef][:path] %>/search_index\"\nrole_path          \"<%= @node[:bootstrap][:chef][:serve_path] %>/roles\"\n\n# See http://wiki.opscode.com/display/chef/Securing+Chef+Server\n# For more information on these settings.\n#authorized_openid_providers   [ \"https://<%= @node[:bootstrap][:chef][:server_fqdn]%>\", \"https://chef\", \"myopenid.com\" ]\n#authorized_openid_identifiers [ \"\" ]\n\nChef::Log::Formatter.show_time = <%= @show_time %>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-client-log-run.erb",
    "content": "#!/bin/sh\nexec svlogd -tt ./main\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-client-run.erb",
    "content": "#!/bin/sh\nPATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%>\nexec 2>&1\nexec /usr/bin/env chef-client -i <%= @node[:bootstrap][:chef][:client_interval] %> -s <%= @node[:bootstrap][:chef][:client_splay] %> <% if @node[:bootstrap][:chef][:client_log] != \"STDOUT\" then -%>-L <%= @node[:bootstrap][:chef][:client_log] %><% end -%>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-indexer-log-run.erb",
    "content": "#!/bin/sh\nexec svlogd -tt ./main\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-indexer-run.erb",
    "content": "#!/bin/sh\nPATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%>\nexec 2>&1\nexec /usr/bin/env chef-indexer\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-server-log-run.erb",
    "content": "#!/bin/sh\nexec svlogd -tt ./main\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/bootstrap/templates/default/sv-chef-server-run.erb",
    "content": "#!/bin/sh\nPATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%>\nexec 2>&1\nexec /usr/bin/env chef-server -N -c2 -P <%= @node[:bootstrap][:chef][:run_path] %>/server.%s.pid\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/README.rdoc",
    "content": "= IMPORTANT CHANGES:\n\nFirst be aware of important changes in this version from previous versions.\n\n== General:\n\nThe attributes have been consolidated into one file, chef.rb, rather than split amongst chef.rb, client.rb, indexer.rb and server.rb.\n\n== Client:\n\nThis cookbook no longer manages the chef package version, it manages /etc/chef/client.rb, reloads the configuration using the new ruby_block resource if the template changes.\n\nThe client service is not managed at all. It is assumed to be set up via init script or runit from package installation or bootstrap.\n\n== Server:\n\n*This cookbook no longer configures a Chef Server under Passenger by default.* \n\nThe stompserver and couchdb cookbooks are not included by default. See below under Cookbooks requirements.\n\nThe default server recipe (chef::server) sets up two Merb Mongrel workers for the webui/api (port 4000) and openid (port 4001).\n\nThe default server recipe (chef::server), creates but does not manage the chef-indexer and chef-server services, and configures both from /etc/chef/server.rb. Some package installation methods (e.g., Debian) have a separate config file for chef-indexer.\n\nThe chef::server_proxy recipe sets up an Apache proxy vhost to provide SSL in front of the chef-server running as a Merb application.\n\n= DESCRIPTION:\n\nUse this cookbook to configure a chef client to connect to your preferred chef-server, or config a chef-server.\n\n= REQUIREMENTS:\n\nChef v0.7.10, for attribute 'default' syntax.\n\n== Platform:\n\nServer is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\n\nClient is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo.\n\n== Cookbooks:\n\nClient: \n\nrunit is suggested for RubyGem installations. Clients do not require any other cookbooks.\n\nServer:\n\ncouchdb and stompserver are suggested for RubyGem installations. On systems where Chef and dependencies were installed from platform packages, CouchDB and Stompserver should be installed and configured sufficiently. Localised configuration requires additional changes to the server recipe and may require changes when using the Opscode recipes.\n\nServer using server_proxy:\n\n* apache2 (opscode/cookbooks)\n\n= ATTRIBUTES:\n\n*A note about paths:* We try to stick with generally accepted FHS guidelines for path locations, but you might need to adjust these for your platform. See the filesystem hierarchy documentation for your operating system if you're not sure.\n\n=== url_type\n\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http://server:4000'. If you set up your chef-server to use an SSL front-end for example with chef::server_proxy, set this to 'https' and the URLs will be 'https://server/'. \n\n=== init_style\n\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\n\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\n\n=== path\n\nThis is the base location where chef will store its associated data. Default '/srv/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\n\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\n\n* /var/lib/chef\n\nAny BSD and Gentoo:\n\n* /var/chef\n\n=== run_path\n\nLocation for pidfiles on systems using init scripts. Default '/var/run/chef'.\n\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\n\n=== cache_path\n\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Linux distributions might prefer /var/cache/chef instead.\n\n=== serve_path\n\nUsed by the Chef server as the base location to \"serve\" cookbooks, roles and other assets. Default is /srv/chef.\n\n=== server_version, client_version\n\nSet the version Chef. This is now unused in the chef cookbook for any specific configuration but you can optionally override the opscode recipe with one that manages the specific version of Chef installed. Default is the latest Chef release. Informational messages may be printed using the veresion, though.\n\n=== client_interval\n\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\n\n=== client_splay\n\nSplay interval to randomly add to interval. Default '20'.\n\n=== log_dir\n\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default STDOUT when init_style is 'runit', otherwise the default is '/var/log/chef'.\n\n=== client_log, indexer_log, server_log\n\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '/var/log/chef/{client,indexer,server}.log' on other systems.\n\n=== server_fqdn\n\nFully qualified domain name of the server. Default is 'chef.domain' where domain is detected by Ohai. You should configure a DNS entry for your Chef Server.\n\nOn servers, this specifies the URLs the server expects, plus it is used in the server_ssl_req as the canonical name (CN) and in server_proxy for the vhost name.\n\nOn clients, this specifies the URLs the client uses to connect to the server.\n\n=== server_token\n\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs, and can be stored as a node attribute on the server. Use chef-client -t 'validation_token' to automatically validate the client.\n\n=== server_ssl_req\n\nUsed by the server_proxy recipe, this attribute can be used to set up a self-signed SSL certificate automatically using openssl. Fields:\n\n* C: country (two letter code)\n* ST: state/province\n* L: locality or city\n* O: organization\n* OU: organizational unit\n* CN: canonical name, usually the fully qualified domain name of the server (FQDN)\n* emailAddress: contact email address\n\n= USAGE:\n\nThis cookbook is primarily designed to configure a Chef client or server with the /etc/chef/ configuration files. Server services should be restarted when the config file changes. The running client configuration will get reloaded from the template if it changes.\n\nThe primary usage would be to set up a JSON file used with chef-client -j to set the run_list and attributes. The settings could alternately be put in a role, as well. When the JSON is used, node will have the run_list and attributes saved in the Chef Server it connected to.\n\nExample JSON to set up a client:\n\n    {\n      \"chef\": {\n        \"url_type\": \"https\",\n        \"init_style\": \"init\",\n        \"server_fqdn\": \"chef.example.com\"\n      },\n      \"recipes\": \"chef::client\"\n    }\n\nThis will tell the client to use the https style URLs (see chef::client below), that we'll have init scripts set up, and to connect to the server \"chef.example.com\"\n\n=== Passenger Not Used:\n\nAs mentioned above, Passenger is no longer used as the default. Use the server_proxy recipe to create an SSL front-end.\n\n== Server Default (chef::server)\n\nBy default, the server is setup to run as a standard Merb application with the Mongrel adapter, using the package installation or the bootstrap cookbook. The chef::server recipe is used to maintain the configuration.\n\nWhen using chef::server only, clients can use the default value for url_type (http).\n\n== Server Proxy (chef::server_proxy)\n\nIf you would like to set up an SSL front end for your server, use the chef::server_proxy recipe.\n\nWhen using this recipe, clients should have the url_type attribute set to \"https\".\n\nYou will need to edit the server_ssl_request attribute so the certificate is generated correctly.\n\nThe recipe itself will set up the Apache proxy:\n\n* Add port 444 to the listen_ports (Apache's ports.conf), required for OpenID.\n* Enable Apache modules proxy proxy_http proxy_balancer ssl rewrite headers\n* Create the SSL certificate based on the server_ssl_req attribute.\n* Set up and enable virtual hosts on ports 443 and 444 in the site config \"chef_server.conf\".\n\nThe proxy will send requests from port 443 to the Mongrel running on port 4000 (webui/api) and requests on port 444 to the Mongrel on port 4001 (openid). Be sure to adjust any firewall rules or security group settings appropriately for these ports (4000, 4001, 443, 444).\n\n=== SSL Certificates\n\nThe server_proxy recipe will generate a self-signed PEM certificate on the first run. If you use opscode's chef-repo, use rake to generate your own site-specific certificate if you wish. You can also use a purchased certificate to replace the one generated through this cookbook, but it must be named by the fully qualified domain name as used in the server_fqdn attribute.\n\n== Client Default (chef::client)\n\nIf your Chef Server's fully qualified domain name is not \"chef.domain\" where domain is the node attribute detected by ohai, then you'll need to specify the server_fqdn attribute for your clients. \n\nYou may want to adjust the path attributes as described above.\n\nMake sure you specify the correct url_type for your Chef Server. This will create the URLs in the client config file as so:\n\nhttp:: http://chef.domain:4000/\n\nhttps:: https://chef.domain/\n\n(the openid_url will be :4001 and :444 respectively.)\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman <joshua@opscode.com>\nAuthor:: Joshua Sierles <joshua@37signals.com>\n\nCopyright 2008-2009, Opscode, Inc\nCopyright 2009, 37signals\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/attributes/chef.rb",
    "content": "#\n# Author:: Joshua Timberman <joshua@opscode.com>\n# Cookbook Name:: chef\n# Attributes:: chef\n#\n# Copyright 2008-2009, Opscode, Inc\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nvalidation_token = \"\"\nchars = (\"a\"..\"z\").to_a + (\"A\"..\"Z\").to_a + (\"0\"..\"9\").to_a\n20.times { |i| validation_token << chars[rand(chars.size-1)] }\n\ndefault[:chef][:url_type]   = \"http\"\ndefault[:chef][:init_style] = \"runit\"\n\ncase platform\nwhen \"openbsd\",\"freebsd\"\n  default[:chef][:path]       = \"/var/chef\"\n  default[:chef][:run_path]   = \"/var/run\"\n  default[:chef][:cache_path] = \"/var/chef/cache\"\n  default[:chef][:serve_path] = \"/var/chef\"\nelse\n  default[:chef][:path]       = \"/srv/chef\"\n  default[:chef][:run_path]   = \"/var/run/chef\"\n  default[:chef][:cache_path] = \"#{chef[:path]}/cache\"\n  default[:chef][:serve_path] = \"/srv/chef\"\nend\n\ndefault[:chef][:server_version]  = \"0.7.10\"\ndefault[:chef][:client_version]  = \"0.7.10\"\ndefault[:chef][:client_interval] = \"1800\"\ndefault[:chef][:client_splay]    = \"20\"\ndefault[:chef][:log_dir]         = \"/var/log/chef\"\n\ncase chef[:init_style]\nwhen \"runit\"\n  default[:chef][:client_log]  = \"STDOUT\"\n  default[:chef][:indexer_log] = \"STDOUT\"\n  default[:chef][:server_log]  = \"STDOUT\"\nelse\n  default[:chef][:client_log]  = \"#{chef[:log_dir]}/client.log\"\n  default[:chef][:indexer_log] = \"#{chef[:log_dir]}/indexer.log\"\n  default[:chef][:server_log]  = \"#{chef[:log_dir]}/server.log\"\nend\n\ndefault[:chef][:server_fqdn]     = domain ? \"chef.#{domain}\" : \"chef\"\ndefault[:chef][:server_token]    = validation_token\ndefault[:chef][:server_ssl_req]  = \"/C=US/ST=Several/L=Locality/O=Example/OU=Operations/\" +\n  \"CN=#{chef[:server_fqdn]}/emailAddress=ops@#{domain}\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/metadata.json",
    "content": "{\n  \"description\": \"Installs and configures chef client and server\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"chef::server\": \"Configures a chef-server as a passenger application\",\n    \"chef\": \"\",\n    \"chef::server_proxy\": \"\",\n    \"chef::client\": \"Sets up a client to talk to a chef-server\"\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ],\n    \"rhel\": [\n\n    ],\n    \"centos\": [\n\n    ],\n    \"debian\": [\n\n    ]\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.12.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"chef\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n    \"chef\\/server_ssl_req\": {\n      \"default\": \"\\/C=US\\/ST=Several\\/L=Locality\\/O=Example\\/OU=Operations\\/CN=chef_server_fqdn\\/emailAddress=ops@domain\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Data to pass for creating the SSL certificate\",\n      \"display_name\": \"Chef Server SSL Request\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_path\": {\n      \"default\": \"gem_dir\\/gems\\/chef-server-chef_server_version\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of the Chef Server assets\",\n      \"display_name\": \"Chef Server Path\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/run_path\": {\n      \"default\": \"\\/var\\/run\\/chef\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Filesystem location for Chef 'run' files\",\n      \"display_name\": \"Chef Run Path\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/client_log\": {\n      \"default\": \"STDOUT\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of the chef client log\",\n      \"display_name\": \"Chef Client Log\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/path\": {\n      \"default\": \"\\/srv\\/chef\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Filesystem location for Chef files\",\n      \"display_name\": \"Chef Path\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_log\": {\n      \"default\": \"\\/var\\/log\\/chef\\/server.log\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of the Chef server log\",\n      \"display_name\": \"Chef Server Log\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/client_splay\": {\n      \"default\": \"20\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Random number of seconds to add to interval\",\n      \"display_name\": \"Chef Client Splay \",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/client_version\": {\n      \"default\": \"0.7.10\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Set the version of the client gem to install\",\n      \"display_name\": \"Chef Client Version\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_fqdn\": {\n      \"default\": \"hostname.domain\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"FQDN of the Chef server for Apache vhost and SSL certificate and clients\",\n      \"display_name\": \"Chef Server Fully Qualified Domain Name\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_version\": {\n      \"default\": \"0.7.10\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Set the version of the server and server-slice gems to install\",\n      \"display_name\": \"Chef Server Version\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/indexer_log\": {\n      \"default\": \"\\/var\\/log\\/chef\\/indexer.log\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of the chef-indexer log\",\n      \"display_name\": \"Chef Indexer Log \",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/client_interval\": {\n      \"default\": \"1800\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Poll chef client process to run on this interval in seconds\",\n      \"display_name\": \"Chef Client Interval \",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_token\": {\n      \"default\": \"randomly generated\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Value of the validation_token\",\n      \"display_name\": \"Chef Server Validation Token\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"chef\\/server_hostname\": {\n      \"default\": \"hostname\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Hostname for the chef server, for building FQDN\",\n      \"display_name\": \"Chef Server Hostname\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    }\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n    \"passenger_apache2\": [\n\n    ],\n    \"stompserver\": [\n\n    ],\n    \"packages\": [\n\n    ],\n    \"runit\": [\n\n    ],\n    \"couchdb\": [\n\n    ],\n    \"apache2\": [\n\n    ]\n  },\n  \"providing\": {\n    \"chef::server\": [\n\n    ],\n    \"chef::server_proxy\": [\n\n    ],\n    \"chef\": [\n\n    ],\n    \"chef::client\": [\n\n    ]\n  },\n  \"long_description\": \"= IMPORTANT CHANGES:\\n\\nFirst be aware of important changes in this version from previous versions.\\n\\n== General:\\n\\nThe attributes have been consolidated into one file, chef.rb, rather than split amongst chef.rb, client.rb, indexer.rb and server.rb.\\n\\n== Client:\\n\\nThis cookbook no longer manages the chef package version, it manages \\/etc\\/chef\\/client.rb, reloads the configuration using the new ruby_block resource if the template changes.\\n\\nThe client service is not managed at all. It is assumed to be set up via init script or runit from package installation or bootstrap.\\n\\n== Server:\\n\\n*This cookbook no longer configures a Chef Server under Passenger by default.* \\n\\nThe stompserver and couchdb cookbooks are not included by default. See below under Cookbooks requirements.\\n\\nThe default server recipe (chef::server) sets up two Merb Mongrel workers for the webui\\/api (port 4000) and openid (port 4001).\\n\\nThe default server recipe (chef::server), creates but does not manage the chef-indexer and chef-server services, and configures both from \\/etc\\/chef\\/server.rb. Some package installation methods (e.g., Debian) have a separate config file for chef-indexer.\\n\\nThe chef::server_proxy recipe sets up an Apache proxy vhost to provide SSL in front of the chef-server running as a Merb application.\\n\\n= DESCRIPTION:\\n\\nUse this cookbook to configure a chef client to connect to your preferred chef-server, or config a chef-server.\\n\\n= REQUIREMENTS:\\n\\nChef v0.7.10, for attribute 'default' syntax.\\n\\n== Platform:\\n\\nServer is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\\n\\nClient is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo.\\n\\n== Cookbooks:\\n\\nClient: \\n\\nrunit is suggested for RubyGem installations. Clients do not require any other cookbooks.\\n\\nServer:\\n\\ncouchdb and stompserver are suggested for RubyGem installations. On systems where Chef and dependencies were installed from platform packages, CouchDB and Stompserver should be installed and configured sufficiently. Localised configuration requires additional changes to the server recipe and may require changes when using the Opscode recipes.\\n\\nServer using server_proxy:\\n\\n* apache2 (opscode\\/cookbooks)\\n\\n= ATTRIBUTES:\\n\\n*A note about paths:* We try to stick with generally accepted FHS guidelines for path locations, but you might need to adjust these for your platform. See the filesystem hierarchy documentation for your operating system if you're not sure.\\n\\n=== url_type\\n\\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http:\\/\\/server:4000'. If you set up your chef-server to use an SSL front-end for example with chef::server_proxy, set this to 'https' and the URLs will be 'https:\\/\\/server\\/'. \\n\\n=== init_style\\n\\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\\n\\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\\n\\n=== path\\n\\nThis is the base location where chef will store its associated data. Default '\\/srv\\/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\\n\\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\\n\\n* \\/var\\/lib\\/chef\\n\\nAny BSD and Gentoo:\\n\\n* \\/var\\/chef\\n\\n=== run_path\\n\\nLocation for pidfiles on systems using init scripts. Default '\\/var\\/run\\/chef'.\\n\\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\\n\\n=== cache_path\\n\\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Linux distributions might prefer \\/var\\/cache\\/chef instead.\\n\\n=== serve_path\\n\\nUsed by the Chef server as the base location to \\\"serve\\\" cookbooks, roles and other assets. Default is \\/srv\\/chef.\\n\\n=== server_version, client_version\\n\\nSet the version Chef. This is now unused in the chef cookbook for any specific configuration but you can optionally override the opscode recipe with one that manages the specific version of Chef installed. Default is the latest Chef release. Informational messages may be printed using the veresion, though.\\n\\n=== client_interval\\n\\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\\n\\n=== client_splay\\n\\nSplay interval to randomly add to interval. Default '20'.\\n\\n=== log_dir\\n\\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default STDOUT when init_style is 'runit', otherwise the default is '\\/var\\/log\\/chef'.\\n\\n=== client_log, indexer_log, server_log\\n\\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '\\/var\\/log\\/chef\\/{client,indexer,server}.log' on other systems.\\n\\n=== server_fqdn\\n\\nFully qualified domain name of the server. Default is 'chef.domain' where domain is detected by Ohai. You should configure a DNS entry for your Chef Server.\\n\\nOn servers, this specifies the URLs the server expects, plus it is used in the server_ssl_req as the canonical name (CN) and in server_proxy for the vhost name.\\n\\nOn clients, this specifies the URLs the client uses to connect to the server.\\n\\n=== server_token\\n\\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs, and can be stored as a node attribute on the server. Use chef-client -t 'validation_token' to automatically validate the client.\\n\\n=== server_ssl_req\\n\\nUsed by the server_proxy recipe, this attribute can be used to set up a self-signed SSL certificate automatically using openssl. Fields:\\n\\n* C: country (two letter code)\\n* ST: state\\/province\\n* L: locality or city\\n* O: organization\\n* OU: organizational unit\\n* CN: canonical name, usually the fully qualified domain name of the server (FQDN)\\n* emailAddress: contact email address\\n\\n= USAGE:\\n\\nThis cookbook is primarily designed to configure a Chef client or server with the \\/etc\\/chef\\/ configuration files. Server services should be restarted when the config file changes. The running client configuration will get reloaded from the template if it changes.\\n\\nThe primary usage would be to set up a JSON file used with chef-client -j to set the run_list and attributes. The settings could alternately be put in a role, as well. When the JSON is used, node will have the run_list and attributes saved in the Chef Server it connected to.\\n\\nExample JSON to set up a client:\\n\\n    {\\n      \\\"chef\\\": {\\n        \\\"url_type\\\": \\\"https\\\",\\n        \\\"init_style\\\": \\\"init\\\",\\n        \\\"server_fqdn\\\": \\\"chef.example.com\\\"\\n      },\\n      \\\"recipes\\\": \\\"chef::client\\\"\\n    }\\n\\nThis will tell the client to use the https style URLs (see chef::client below), that we'll have init scripts set up, and to connect to the server \\\"chef.example.com\\\"\\n\\n=== Passenger Not Used:\\n\\nAs mentioned above, Passenger is no longer used as the default. Use the server_proxy recipe to create an SSL front-end.\\n\\n== Server Default (chef::server)\\n\\nBy default, the server is setup to run as a standard Merb application with the Mongrel adapter, using the package installation or the bootstrap cookbook. The chef::server recipe is used to maintain the configuration.\\n\\nWhen using chef::server only, clients can use the default value for url_type (http).\\n\\n== Server Proxy (chef::server_proxy)\\n\\nIf you would like to set up an SSL front end for your server, use the chef::server_proxy recipe.\\n\\nWhen using this recipe, clients should have the url_type attribute set to \\\"https\\\".\\n\\nYou will need to edit the server_ssl_request attribute so the certificate is generated correctly.\\n\\nThe recipe itself will set up the Apache proxy:\\n\\n* Add port 444 to the listen_ports (Apache's ports.conf), required for OpenID.\\n* Enable Apache modules proxy proxy_http proxy_balancer ssl rewrite headers\\n* Create the SSL certificate based on the server_ssl_req attribute.\\n* Set up and enable virtual hosts on ports 443 and 444 in the site config \\\"chef_server.conf\\\".\\n\\nThe proxy will send requests from port 443 to the Mongrel running on port 4000 (webui\\/api) and requests on port 444 to the Mongrel on port 4001 (openid). Be sure to adjust any firewall rules or security group settings appropriately for these ports (4000, 4001, 443, 444).\\n\\n=== SSL Certificates\\n\\nThe server_proxy recipe will generate a self-signed PEM certificate on the first run. If you use opscode's chef-repo, use rake to generate your own site-specific certificate if you wish. You can also use a purchased certificate to replace the one generated through this cookbook, but it must be named by the fully qualified domain name as used in the server_fqdn attribute.\\n\\n== Client Default (chef::client)\\n\\nIf your Chef Server's fully qualified domain name is not \\\"chef.domain\\\" where domain is the node attribute detected by ohai, then you'll need to specify the server_fqdn attribute for your clients. \\n\\nYou may want to adjust the path attributes as described above.\\n\\nMake sure you specify the correct url_type for your Chef Server. This will create the URLs in the client config file as so:\\n\\nhttp:: http:\\/\\/chef.domain:4000\\/\\n\\nhttps:: https:\\/\\/chef.domain\\/\\n\\n(the openid_url will be :4001 and :444 respectively.)\\n\\n= LICENSE and AUTHOR:\\n\\nAuthor:: Joshua Timberman <joshua@opscode.com>\\nAuthor:: Joshua Sierles <joshua@37signals.com>\\n\\nCopyright 2008-2009, Opscode, Inc\\nCopyright 2009, 37signals\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http:\\/\\/www.apache.org\\/licenses\\/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Installs and configures chef client and server\"\nlong_description  IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))\nversion           \"0.12\"\nrecipe            \"chef::client\", \"Sets up a client to talk to a chef-server\"\nrecipe            \"chef::server\", \"Configures a chef-server as a passenger application\"\n\n%w{ runit packages couchdb stompserver apache2 passenger_apache2 }.each do |cb|\n  depends cb\nend\n\n%w{ centos rhel ubuntu debian }.each do |os|\n  supports os\nend\n\nattribute \"chef/path\",\n  :display_name => \"Chef Path\",\n  :description => \"Filesystem location for Chef files\",\n  :default => \"/srv/chef\"\n\nattribute \"chef/run_path\",\n  :display_name => \"Chef Run Path\",\n  :description => \"Filesystem location for Chef 'run' files\",\n  :default => \"/var/run/chef\"\n\nattribute \"chef/client_version\",\n  :display_name => \"Chef Client Version\",\n  :description => \"Set the version of the client gem to install\",\n  :default => \"0.7.10\"\n\nattribute \"chef/client_interval\",\n  :display_name => \"Chef Client Interval \",\n  :description => \"Poll chef client process to run on this interval in seconds\",\n  :default => \"1800\"\n\nattribute \"chef/client_splay\",\n  :display_name => \"Chef Client Splay \",\n  :description => \"Random number of seconds to add to interval\",\n  :default => \"20\"\n\nattribute \"chef/client_log\",\n  :display_name => \"Chef Client Log\",\n  :description => \"Location of the chef client log\",\n  :default => \"STDOUT\"\n\nattribute \"chef/indexer_log\",\n  :display_name => \"Chef Indexer Log \",\n  :description => \"Location of the chef-indexer log\",\n  :default => \"/var/log/chef/indexer.log\"\n\nattribute \"chef/server_version\",\n  :display_name => \"Chef Server Version\",\n  :description => \"Set the version of the server and server-slice gems to install\",\n  :default => \"0.7.10\"\n\nattribute \"chef/server_log\",\n  :display_name => \"Chef Server Log\",\n  :description => \"Location of the Chef server log\",\n  :default => \"/var/log/chef/server.log\"\n\nattribute \"chef/server_path\",\n  :display_name => \"Chef Server Path\",\n  :description => \"Location of the Chef Server assets\",\n  :default => \"gem_dir/gems/chef-server-chef_server_version\"\n\nattribute \"chef/server_hostname\",\n  :display_name => \"Chef Server Hostname\",\n  :description => \"Hostname for the chef server, for building FQDN\",\n  :default => \"hostname\"\n\nattribute \"chef/server_fqdn\",\n  :display_name => \"Chef Server Fully Qualified Domain Name\",\n  :description => \"FQDN of the Chef server for Apache vhost and SSL certificate and clients\",\n  :default => \"hostname.domain\"\n\nattribute \"chef/server_ssl_req\", \n  :display_name => \"Chef Server SSL Request\",\n  :description => \"Data to pass for creating the SSL certificate\",\n  :default => \"/C=US/ST=Several/L=Locality/O=Example/OU=Operations/CN=chef_server_fqdn/emailAddress=ops@domain\"\n\nattribute \"chef/server_token\",\n  :display_name => \"Chef Server Validation Token\",\n  :description => \"Value of the validation_token\",\n  :default => \"randomly generated\"\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/recipes/client.rb",
    "content": "#\n# Author:: Joshua Timberman <joshua@opscode.com>\n# Author:: Joshua Sierles <joshua@37signals.com>\n# Cookbook Name:: chef\n# Recipe:: client\n#\n# Copyright 2008-2009, Opscode, Inc\n# Copyright 2009, 37signals\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nroot_group = value_for_platform(\n  \"openbsd\" => { \"default\" => \"wheel\" },\n  \"freebsd\" => { \"default\" => \"wheel\" },\n  \"default\" => \"root\"\n)\n\nif node[:chef][:client_log] == \"STDOUT\"\n  client_log = node[:chef][:client_log]\n  show_time  = \"false\"\nelse\n  directory File.dirname(node[:chef][:client_log]) do\n    action :create\n  end\n  client_log = \"\\\"#{node[:chef][:client_log]}\\\"\"\n  show_time  = \"true\"\nend\n\nruby_block \"reload_client_config\" do\n  block do\n    Chef::Config.from_file(\"/etc/chef/client.rb\")\n  end\n  action :nothing\nend\n\ntemplate \"/etc/chef/client.rb\" do\n  source \"client.rb.erb\"\n  owner \"root\"\n  group root_group\n  mode \"644\"\n  variables(\n    :client_log => client_log,\n    :show_time  => show_time\n  )\n  notifies :create, resources(:ruby_block => \"reload_client_config\")\nend\n\nif node[:chef][:server_token]\n  execute \"Register client node with Chef Server\" do\n    not_if  { File.exists?(\"#{node[:chef][:path]}/cache/registration\") }\n    command \"/usr/bin/env chef-client -t #{node[:chef][:server_token]}\"\n  end\nelse\n  execute \"Register client node with Chef Server\" do\n    command \"/usr/bin/env chef-client -t \\`cat /etc/chef/validation_token\\`\"\n    not_if  { File.exists?(\"#{node[:chef][:path]}/cache/registration\") }\n    only_if { File.exists?(\"/etc/chef/validation_token\") }\n  end\nend\n  \n\n\nexecute \"Remove the validation token\" do\n  command \"rm /etc/chef/validation_token\"\n  only_if { File.exists?(\"/etc/chef/validation_token\") }\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/recipes/default.rb",
    "content": ""
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/recipes/server.rb",
    "content": "#\n# Author:: Joshua Timberman <joshua@opscode.com>\n# Author:: Joshua Sierles <joshua@37signals.com>\n# Cookbook Name:: chef\n# Recipe:: server\n#\n# Copyright 2008-2009, Opscode, Inc\n# Copyright 2009, 37signals\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nroot_group = value_for_platform(\n  \"openbsd\" => { \"default\" => \"wheel\" },\n  \"freebsd\" => { \"default\" => \"wheel\" },\n  \"default\" => \"root\"\n)\n\ninclude_recipe \"chef::client\"\n\nservice \"chef-indexer\" do\n  action :nothing\nend\n\nservice \"chef-server\" do\n  action :nothing\n  if node[:chef][:init_style] == \"runit\"\n    restart_command \"sv int chef-server\"\n  end\nend\n\nif node[:chef][:server_log] == \"STDOUT\"\n  server_log = node[:chef][:server_log]\n  show_time  = \"false\"\nelse\n  server_log = \"\\\"#{node[:chef][:server_log]}\\\"\"\n  show_time  = \"true\"\nend\n\ntemplate \"/etc/chef/server.rb\" do\n  source \"server.rb.erb\"\n  owner \"root\"\n  group root_group\n  mode \"644\"\n  variables(\n    :server_log => server_log,\n    :show_time  => show_time\n  )\n  notifies :restart, resources(\n    :service => \"chef-indexer\",\n    :service => \"chef-server\"\n  ), :delayed\nend\n\nhttp_request \"compact chef couchDB\" do\n  action :post\n  url \"http://localhost:5984/chef/_compact\"\n  only_if do\n    begin\n      open(\"#{Chef::Config[:couchdb_url]}/chef\")\n      JSON::parse(open(\"#{Chef::Config[:couchdb_url]}/chef\").read)[\"disk_size\"] > 100_000_000\n    rescue OpenURI::HTTPError\n      nil\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/recipes/server_proxy.rb",
    "content": "#\n# Author:: Joshua Timberman <joshua@opscode.com>\n# Cookbook Name:: chef\n# Recipe:: server_proxy\n#\n# Copyright 2009, Opscode, Inc\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nroot_group = value_for_platform(\n  \"openbsd\" => { \"default\" => \"wheel\" },\n  \"freebsd\" => { \"default\" => \"wheel\" },\n  \"default\" => \"root\"\n)\n\nnode[:apache][:listen_ports] << \"444\" unless node[:apache][:listen_ports].include?(\"444\")\n\ninclude_recipe \"chef::server\"\ninclude_recipe \"apache2\"\ninclude_recipe \"apache2::mod_ssl\"\ninclude_recipe \"apache2::mod_proxy\"\ninclude_recipe \"apache2::mod_proxy_http\"\ninclude_recipe \"apache2::mod_proxy_balancer\"\ninclude_recipe \"apache2::mod_rewrite\"\ninclude_recipe \"apache2::mod_headers\"\n\ndirectory \"/etc/chef/certificates\" do\n  owner \"root\"\n  group root_group\n  mode \"700\"\nend\n\nbash \"Create SSL Certificates\" do\n  cwd \"/etc/chef/certificates\"\n  code <<-EOH\n  umask 077\n  openssl genrsa 2048 > #{node[:chef][:server_fqdn]}.key\n  openssl req -subj \"#{node[:chef][:server_ssl_req]}\" -new -x509 -nodes -sha1 -days 3650 -key #{node[:chef][:server_fqdn]}.key > #{node[:chef][:server_fqdn]}.crt\n  cat #{node[:chef][:server_fqdn]}.key #{node[:chef][:server_fqdn]}.crt > #{node[:chef][:server_fqdn]}.pem\n  EOH\n  not_if { File.exists?(\"/etc/chef/certificates/#{node[:chef][:server_fqdn]}.pem\") }\nend\n\nweb_app \"chef_server\" do\n  template \"chef_server.conf.erb\"\n  server_name node[:chef][:server_fqdn]\n  server_aliases [ node[:hostname], node[:fqdn], node[:chef][:server_fqdn] ]\n  log_dir node[:apache][:log_dir]\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/templates/default/chef_server.conf.erb",
    "content": "<VirtualHost *:443>\n  ServerName <%= @params[:server_name] %>\n  ServerAlias <% @params[:server_aliases].each do |a| %><%= \"#{a}\" %> <% end %>\n\n  <Proxy balancer://chef_server>\n    BalancerMember http://127.0.0.1:4000\n    Order deny,allow\n    Allow from all\n  </Proxy>\n\n  LogLevel info\n  ErrorLog <%= @params[:log_dir] %>/<%= @params[:name] %>-error.log\n  CustomLog <%= @params[:log_dir] %>/<%= @params[:name] %>-access.log combined\n  \n  SSLEngine On\n  SSLCertificateFile /etc/chef/certificates/<%= @params[:server_name] %>.pem\n  SSLCertificateKeyFile /etc/chef/certificates/<%= @params[:server_name] %>.pem\n\n  RequestHeader set X_FORWARDED_PROTO 'https'\n\n  RewriteEngine On\n  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f\n  RewriteRule ^/(.*)$ balancer://chef_server%{REQUEST_URI} [P,QSA,L]\n</VirtualHost>\n\n<VirtualHost *:444>\n  ServerName <%= @params[:server_name] %>\n  ServerAlias <% @params[:server_aliases].each do |a| %><%= \"#{a}\" %> <% end %>\n\n  <Proxy balancer://chef_server_openid>\n    BalancerMember http://127.0.0.1:4001\n    Order deny,allow\n    Allow from all\n  </Proxy>\n\n  LogLevel info\n  ErrorLog <%= @params[:log_dir] %>/<%= @params[:name] %>-error.log\n  CustomLog <%= @params[:log_dir] %>/<%= @params[:name] %>-access.log combined\n  \n  SSLEngine On\n  SSLCertificateFile /etc/chef/certificates/<%= @params[:server_name] %>.pem\n  SSLCertificateKeyFile /etc/chef/certificates/<%= @params[:server_name] %>.pem\n\n  RequestHeader set X_FORWARDED_PROTO 'https'\n\n  RewriteEngine On\n  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f\n  RewriteRule ^/(.*)$ balancer://chef_server_openid%{REQUEST_URI} [P,QSA,L]\n</VirtualHost>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/templates/default/client.rb.erb",
    "content": "#\n# Chef Client Config File\n#\n# Dynamically generated by Chef - local modifications will be replaced\n#\n\nlog_level          :info\nlog_location       <%= @client_log %>\nssl_verify_mode    :verify_none\n<% if @node[:chef][:url_type] == \"https\" -%>\nregistration_url   \"https://<%= @node[:chef][:server_fqdn] %>\"\nopenid_url         \"https://<%= @node[:chef][:server_fqdn] %>:444\"\ntemplate_url       \"https://<%= @node[:chef][:server_fqdn] %>\"\nremotefile_url     \"https://<%= @node[:chef][:server_fqdn] %>\"\nsearch_url         \"https://<%= @node[:chef][:server_fqdn] %>\"\nrole_url           \"https://<%= @node[:chef][:server_fqdn] %>\"\n<% else -%>\nregistration_url   \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nopenid_url         \"http://<%= @node[:chef][:server_fqdn] %>:4001\"\ntemplate_url       \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nremotefile_url     \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nsearch_url         \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nrole_url           \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\n<% end -%>\n\nfile_cache_path    \"<%= @node[:chef][:cache_path] %>\"\n\npid_file           \"<%= @node[:chef][:run_path] %>/chef-client.pid\"\n\nChef::Log::Formatter.show_time = <%= @show_time %>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/chef/templates/default/server.rb.erb",
    "content": "#\n# Chef Server Config File\n#\n# Dynamically generated by Chef - local modifications will be replaced\n\nlog_level          :info\nlog_location       <%= @server_log %>\nssl_verify_mode    :verify_none\nregistration_url   \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nopenid_url         \"http://<%= @node[:chef][:server_fqdn] %>:4001\"\ntemplate_url       \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nremotefile_url     \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nsearch_url         \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\nrole_url           \"http://<%= @node[:chef][:server_fqdn] %>:4000\"\n\nvalidation_token   \"<%= @node[:chef][:server_token] %>\"\n\ncookbook_path      [ \"<%= @node[:chef][:serve_path] %>/site-cookbooks\", \"<%= @node[:chef][:serve_path] %>/cookbooks\" ]\n\nfile_cache_path    \"<%= @node[:chef][:cache_path] %>\"\nnode_path          \"<%= @node[:chef][:serve_path] %>/nodes\"\nopenid_store_path  \"<%= @node[:chef][:path] %>/openid/store\"\nopenid_cstore_path \"<%= @node[:chef][:path] %>/openid/cstore\"\nsearch_index_path  \"<%= @node[:chef][:path] %>/search_index\"\nrole_path          \"<%= @node[:chef][:serve_path] %>/roles\"\n\n# See http://wiki.opscode.com/display/chef/Securing+Chef+Server\n# For more information on these settings.\n#authorized_openid_providers   [ \"https://<%= @node[:chef][:server_fqdn]%>\", \"https://chef\", \"myopenid.com\" ]\n#authorized_openid_identifiers [ \"\" ]\n\nChef::Log::Formatter.show_time = <%= @show_time %>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ec2/attributes/ec2_metadata.rb",
    "content": "#\n# Cookbook Name:: ec2\n# Attribute File:: ec2_metadata.rb\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nrequire 'net/http'\n\ndef get_from_ec2(thing=\"/\")\n  base_url = \"http://169.254.169.254/latest/meta-data\" + thing\n  url = URI.parse(base_url)\n  req = Net::HTTP::Get.new(url.path)\n  res = Net::HTTP.start(url.host, url.port) {|http|\n    http.request(req)\n  }\n  res.body\nend\n\nif @attribute[\"domain\"] =~ /\\.amazonaws.com$/ || @attribute[\"domain\"] == \"ec2.internal\"\n  ec2 true\n  get_from_ec2.split(\"\\n\").each do |key|\n    if key =~ /\\/$/\n      get_from_ec2(\"/#{key}\").split(\"\\n\").each do |extra_key|\n        attr_name = \"ec2-#{key}-#{extra_key}\"\n        attr_name.gsub!(\"/\", \"\")\n        @attribute[attr_name] = get_from_ec2(\"/#{key}/#{extra_key}\")\n      end\n    end\n    @attribute[\"ec2-#{key}\"] = get_from_ec2(\"/#{key}\")\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ec2/attributes/ec2_recipe_options.rb",
    "content": "#\n# Cookbook Name:: ec2\n# Attribute File:: ec2_recipe_options.rb\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nec2opts Mash.new unless attribute?(\"ec2opts\")\nec2opts[:lvm] = Mash.new unless ec2opts.has_key?(:lvm)\nec2opts[:lvm][:use_ephemeral]  = true unless ec2opts[:lvm].has_key?(:use_ephemeral)\nec2opts[:lvm][:ephemeral_mountpoint] = \"/mnt\" unless ec2opts[:lvm].has_key?(:ephemeral_mountpoint)\nec2opts[:lvm][:ephemeral_volume_group] = \"ephemeral\" unless ec2opts[:lvm].has_key?(:ephemeral_volume_group)\nec2opts[:lvm][:ephemeral_logical_volume] = \"store\" unless ec2opts[:lvm].has_key?(:ephemeral_logical_volume)\nec2opts[:lvm][:ephemeral_devices] = {\n  \"m1.small\"  => [ \"/dev/sda2\" ],\n  \"m1.large\"  => [ \"/dev/sdb\", \"/dev/sdc\" ],\n  \"m1.xlarge\" => [ \"/dev/sdb\", \"/dev/sdc\", \"/dev/sdd\", \"/dev/sde\" ],\n} unless ec2opts[:lvm].has_key?(:ephemeral_devices)\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ec2/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Manage EC2 metadata as attributes\"\nversion           \"0.9\"\n\nattribute \"ec2_metadata\",\n  :display_name => \"EC2 Metadata\",\n  :description => \"Retrieve EC2 instance metadata\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ec2/recipes/default.rb",
    "content": "#\n# Cookbook Name:: ec2\n# Recipe:: default\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/README.rdoc",
    "content": "= DESCRIPTION:\n\n= REQUIREMENTS:\n\n= ATTRIBUTES: \n\n= USAGE:\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/attributes/default.rb",
    "content": "set[:ganglia][:ganglia_this_nodes_private_ip] = ipaddress\n\n# set[:ganglia][:ganglia_gmetad_data_sources]  = \"foo\"\n# set[:ganglia][:ganglia_pool_name] = \"name\"\n# set[:ganglia][:ganglia_cloud_name]  = \"foo\"\n# set[:ganglia][:ganglia_first_node_in_clusters_ip] = \"ip\"\n# set[:ganglia][:gmond_user] = \"root\" \n# set[:ganglia][:gmetad_user] = \"root\" \n# set[:ganglia][:gmond_web_root] = \"/var/www/ganglia\" \n# set[:ganglia][:ganglia_gmetad_data_sources] = %Q{data_source \"a name goes here todo\" 127.0.0.1} # space separated ip/hostnames\n\n# # hopefully we can delete the attributes below now that the recipes are split up\n# set[:ganglia][:enable_web_interface] = false\n# set[:ganglia][:enable_gmetad] = false\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/metadata.rb",
    "content": "maintainer       \"Nate Murray\"\nmaintainer_email \"\"\nlicense          \"Apache 2.0\"\ndescription      \"Installs/Configures ganglia\"\nlong_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))\nversion          \"0.1\"\n\nrecipe \"ganglia::default\"\nrecipe \"ganglia::gmetad\"\nrecipe \"ganglia::monitor_sshd\"\nrecipe \"ganglia::monitor_watson\"\nrecipe \"ganglia::web\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/recipes/default.rb",
    "content": "#\n# Cookbook Name:: ganglia\n# Recipe:: default\n\n# install rrd\ncase node[:platform]\nwhen \"redhat\",\"centos\"\n  package \"apr-util-devel\"\n  %w{cairo-devel libxml2-devel pango-devel pango libpng-devel freetype freetype-devel libart_lgpl-devel gettext}.each {|p| package p}\n\n  package \"xorg-x11-fonts-Type1\"\n\n  # crazy hack to get it to work b/c of conflicts with centos 64/32 bit. see comment #16 http://www.cyberciti.biz/faq/howto-install-rrdtool-on-rhel-linux/\n  script \"64bit centos hack\" do\n    interpreter \"sh -x\"\n    code <<-EOH \n    (( uname -a | grep x86_64 ))\n    if [ \"$?\" -eq \"0\" ]\n    then\n       yum remove -y libxml2-devel.i386 libcairo-devel.i386 libpng12-devel.i386 libpng-devel.i386 glib2-devel.i386\n       yum install -y pango-devel.x86_64\n    fi\n\n    # for some reason chef isn't installing these properly?\n    yum install -y \"freetype-devel\"\n    yum install -y \"libpng-devel\"\n\n    EOH\n  end\n\n  script \"install rrdtool\" do\n    interpreter \"sh -x\"\n    code <<-EOH \n  mkdir -p /opt/local/src\n  cd /opt/local/src\n  wget http://oss.oetiker.ch/rrdtool/pub/rrdtool-1.3.1.tar.gz -O rrdtool-1.3.1.tar.gz\n  tar -zxvf rrdtool-1.3.1.tar.gz\n  cd rrdtool-1.3.1\n  export PKG_CONFIG_PATH=/usr/lib/pkgconfig/\n  ./configure && make && make install\n    EOH\n    creates \"/usr/local/rrdtool-1.3.1/bin/rrdtool\"\n  end\n\n  %w{rrdtool rrdcgi}.each do |r|\n    link \"/usr/bin/#{r}\" do\n      to \"/usr/local/rrdtool-1.3.1/bin/#{r}\"\n    end\n  end\n\n  script \"install libconfuse\" do\n    interpreter \"sh -x\"\n    code <<-EOH \n  mkdir -p /opt/local/src\n  cd /opt/local/src\n  wget http://bzero.se/confuse/confuse-2.6.tar.gz -O confuse-2.6.tar.gz\n  tar -xvvf confuse-2.6.tar.gz\n  cd confuse-2.6\n  ./configure CFLAGS=-fPIC --disable-nls # tricksy - http://www.mail-archive.com/ganglia-general@lists.sourceforge.net/msg04731.html\n  make && make install\n    EOH\n    creates \"/usr/local/lib/libconfuse.a\"\n  end\n\n  script \"install start-stop-daemon\" do\n    interpreter \"sh -x\"\n    code <<-EOH \n  mkdir -p /opt/local/src\n  cd /opt/local/src\n\n  wget http://ftp.de.debian.org/debian/pool/main/d/dpkg/dpkg_1.14.25.tar.gz -O dpkg_1.14.25.tar.gz\n  tar -xf dpkg_1.14.25.tar.gz\n  cd dpkg-1.14.25\n  ./configure --without-selinux --prefix=/usr\n  make\n  cd utils\n  make\n  make install\n    EOH\n    creates \"/usr/sbin/start-stop-daemon\"\n  end\n\nwhen \"ubuntu\"\n  case node[:version]\n  when \"8.04\" # need to add jaunty sources to 8.04\n    execute \"apt-get-update\" do\n      action :nothing\n      command \"apt-get update\"\n    end\n\n    template \"/etc/apt/sources.list.d/jaunty.list\" do\n      source \"jaunty.sources.list\"\n      mode \"0755\"\n      notifies :restart, resources(:execute => \"apt-get-update\"), :immediately\n    end\n  end\n\n  %w{rrdtool build-essential librrd-dev libapr1-dev libconfuse-dev libexpat1-dev python-dev}.each {|p| package p}\nend\n\nscript \"install ganglia\" do\n  interpreter \"sh -x\"\n\n  configure = \"./configure --disable-python --with-librrd=/usr/local/rrdtool-1.3.1\" \n\n  code <<-EOH \nmkdir -p /opt/local/src\ncd /opt/local/src\nwget http://superb-west.dl.sourceforge.net/sourceforge/ganglia/ganglia-3.1.2.tar.gz -O ganglia.tar.gz\ntar -xvvf ganglia.tar.gz \ncd ganglia-3.1.2/\n#{configure}\nmake && make install\n  EOH\n  creates \"/usr/sbin/gmond\"\n  notifies(:restart, resources(:service => \"apache2\")) rescue nil\nend\n\n# == configure ganglia\ndirectory \"/etc/ganglia/bin/monitors\" do\n  action :create\n  recursive true\nend\n\ntemplate \"/etc/init.d/gmond\" do\n  mode \"0755\"\n  source \"bin/gmond.erb\"\nend\nservice \"gmond\" do\n  action :nothing\nend\n\ntemplate \"/etc/ganglia/gmond.conf\" do\n  source \"gmond.conf.erb\"\n  mode \"0755\"\n  notifies :restart, resources(:service => \"gmond\")\nend\n\n# sudoers\n# /usr/sbin/adduser ves \n# ves ALL=(ALL) NOPASSWD: ALL\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/recipes/gmetad.rb",
    "content": "# Cookbook Name:: ganglia\n# Recipe:: gmetad\n\ntemplate \"/etc/init.d/gmetad\" do\n  mode \"0755\"\n  source \"bin/gmetad.erb\"\nend\n\nservice \"gmetad\" do\n  action :nothing\nend\n\ntemplate \"/etc/ganglia/gmetad.conf\" do\n  source \"gmetad.conf.erb\"\n  mode \"0755\"\n  notifies :restart, resources(:service => \"gmetad\")\nend\n\ndirectory \"/var/lib/ganglia/rrds\" do\n  action :create\n  recursive true\n  owner node[:ganglia][:gmetad_user]\n  group node[:ganglia][:gmetad_user]\nend\n\nscript \"install ganglia\" do\n  interpreter \"sh -x\"\n\n  configure = \"./configure --with-gmetad --disable-python --with-librrd=/usr/local/rrdtool-1.3.1\"\n\n  code <<-EOH \nmkdir -p /opt/local/src\ncd /opt/local/src\nwget http://superb-west.dl.sourceforge.net/sourceforge/ganglia/ganglia-3.1.2.tar.gz -O ganglia.tar.gz\ntar -xvvf ganglia.tar.gz \ncd ganglia-3.1.2/\n#{configure}\nmake && make install\n  EOH\n  creates \"/usr/sbin/gmetad\"\n  notifies(:restart, resources(:service => \"apache2\")) rescue nil\n  notifies :restart, resources(:service => \"gmetad\")\nend\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/recipes/monitor_sshd.rb",
    "content": "template \"/etc/ganglia/bin/monitors/sshd_ganglia.sh\" do\n  source \"bin/monitors/sshd_ganglia.sh.erb\"\n  mode \"0755\"\nend\n\ncron \"monitor sshd\" do\n  minute \"*/5\"\n  hour \"*\"\n  day \"*\"\n  month \"*\"\n  weekday \"*\"\n  command \"bash -c /etc/ganglia/bin/monitors/sshd_ganglia.sh\"\nend\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/recipes/monitor_watson.rb",
    "content": "template \"/etc/ganglia/bin/monitors/watson_channels.sh\" do\n  source \"bin/monitors/watson_channels.sh.erb\"\n  mode \"0755\"\nend\n\ncron \"watson-channels\" do\n  minute \"*/1\"\n  hour \"*\"\n  day \"*\"\n  month \"*\"\n  weekday \"*\"\n  command \"bash -c /etc/ganglia/bin/monitors/watson_channels.sh\"\nend\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/recipes/web.rb",
    "content": "# Cookbook Name:: ganglia\n# Recipe:: web\n\n# hmm, maybe unify with below\nexecute \"create ganglia web interface\" do\n  command \"cp -r  /opt/local/src/ganglia-3.1.2/web #{node[:ganglia][:gmond_web_root]}\"\n  action :run\n  creates node[:ganglia][:gmond_web_root]\nend\n\n# setenforce 0\nexecute \"selinux: allow httpd can network for ganglia web interface\" do\n  command \"setsebool -P httpd_can_network_connect 1\"\n  action :run\n  only_if \"/usr/sbin/getenforce | grep Enforcing\"\n  not_if \"getsebool httpd_can_network_connect | grep on\"\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/bin/gmetad.erb",
    "content": "#!/bin/sh\n\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\nDAEMON=/usr/sbin/gmetad\nNAME=gmetad\nDESC=\"Ganglia Monitor Meta-Daemon\"\n\ntest -x $DAEMON || exit 0\nset -e\n\ncase \"$1\" in\n  start)\n        echo -n \"Starting $DESC: \"\n        start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \\\n                --exec $DAEMON\n        echo \"$NAME.\"\n        ;;\n  stop)\n        echo -n \"Stopping $DESC: \"\n        start-stop-daemon --stop  --quiet --oknodo \\\n                --exec $DAEMON  2>&1 > /dev/null\n        echo \"$NAME.\"\n        ;;\n  reload)\n  ;;\n  restart|force-reload)\n        $0 stop\n        $0 start\n        ;;\n  *)\n        N=/etc/init.d/$NAME\n        # echo \"Usage: $N {start|stop|restart|reload|force-reload}\" >&2\n        echo \"Usage: $N {start|stop|restart|force-reload}\" >&2\n        exit 1\n        ;;\nesac\n\nexit 0\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/bin/gmond.erb",
    "content": "#!/bin/sh\n\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\nDAEMON=/usr/sbin/gmond\nNAME=gmond\nDESC=\"Ganglia Monitor Daemon\"\n\ntest -x $DAEMON || exit 0\nset -e\n\ncase \"$1\" in\n  start)\n        echo -n \"Starting $DESC: \"\n        start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \\\n                --exec $DAEMON\n        echo \"$NAME.\"\n        ;;\n  stop)\n        echo -n \"Stopping $DESC: \"\n        start-stop-daemon --stop  --quiet --oknodo \\\n                --exec $DAEMON  2>&1 > /dev/null\n        echo \"$NAME.\"\n        ;;\n  reload)\n  ;;\n  restart|force-reload)\n        $0 stop\n        $0 start\n        ;;\n  *)\n        N=/etc/init.d/$NAME\n        # echo \"Usage: $N {start|stop|restart|reload|force-reload}\" >&2\n        echo \"Usage: $N {start|stop|restart|force-reload}\" >&2\n        exit 1\n        ;;\nesac\n\nexit 0\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/bin/monitors/sshd_ganglia.sh.erb",
    "content": "#!/bin/bash\n# Nate Murray <nmurray@attinterative.com>\n# Date 2009-07-13\n# \n# Record number of invalid users or failed passwords in sshd\n\n# Also check if this is the right location of gmetric\nGMETRIC=/usr/bin/gmetric\nAUTH_LOG=/var/log/auth\n\nCOUNT=$(cat $AUTH_LOG | grep -iE \"(Invalid user|Failed password)\" | grep \"`date '+%b %e'`\" | wc -l)\n$GMETRIC --name \"failed-or-invalid-login-attempts\" --value $COUNT --type uint8 --units ''\nexit 0\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/bin/monitors/watson_channels.sh.erb",
    "content": "#!/bin/bash\n# 2009-10-01\n\n# Also check if this is the right location of gmetric\nGMETRIC=/usr/bin/gmetric\nAUTH_LOG=/var/log/auth\n\ndEFAULT_COUNT=0\nCOUNT=$(echo \"status\" | nc localhost 8081 | grep free |awk '{print $2}')\n[ \"x\" = \"x$COUNT\" ] && COUNT=${DEFAULT_COUNT}\n\n$GMETRIC --name \"watson-free-channels\" --value $COUNT --type uint8 --units ''\nexit 0\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/ganglia-web-conf.php.erb",
    "content": "<?php\n# $Id: conf.php.in 1831 2008-09-26 12:18:54Z carenas $\n#\n# Gmetad-webfrontend version. Used to check for updates.\n#\ninclude_once \"./version.php\";\n\n#\n# The name of the directory in \"./templates\" which contains the\n# templates that you want to use. Templates are like a skin for the\n# site that can alter its look and feel.\n#\n$template_name = \"default\";\n\n#\n# If you installed gmetad in a directory other than the default\n# make sure you change it here.\n#\n\n# Where gmetad stores the rrd archives.\n$gmetad_root = \"/var/lib/ganglia\";\n$rrds = \"$gmetad_root/rrds\";\n\n# Leave this alone if rrdtool is installed in $gmetad_root,\n# otherwise, change it if it is installed elsewhere (like /usr/bin)\ndefine(\"RRDTOOL\", \"/usr/bin/rrdtool\");\n\n# Location for modular-graph files.\n$graphdir='./graph.d';\n\n#\n# If you want to grab data from a different ganglia source specify it here.\n# Although, it would be strange to alter the IP since the Round-Robin\n# databases need to be local to be read. \n#\n$ganglia_ip = \"127.0.0.1\";\n$ganglia_port = 8652;\n\n#\n# The maximum number of dynamic graphs to display.  If you set this\n# to 0 (the default) all graphs will be shown.  This option is\n# helpful if you are viewing the web pages from a browser with a \n# small pipe.\n#\n$max_graphs = 0;\n\n#\n# In the Cluster View this sets the default number of columns used to\n# display the host grid below the summary graphs.\n#\n$hostcols = 4;\n\n#\n# In the Host View this sets the default number of columns used to\n# display the metric grid below the summary graphs.\n#\n$metriccols = 2;\n\n#\n# Turn on and off the Grid Snapshot. Now that we have a\n# hierarchical snapshot (per-cluster instead of per-node) on\n# the meta page this makes more sense. Most people will want this\n# on.\n#\n$show_meta_snapshot = \"yes\";\n\n# \n# The default refresh frequency on pages.\n#\n$default_refresh = 300;\n\n#\n# Colors for the CPU report graph\n#\n$cpu_user_color = \"3333bb\";\n$cpu_nice_color = \"ffea00\";\n$cpu_system_color = \"dd0000\";\n$cpu_wio_color = \"ff8a60\";\n$cpu_idle_color = \"e2e2f2\";\n\n#\n# Colors for the MEMORY report graph\n#\n$mem_used_color = \"5555cc\";\n$mem_shared_color = \"0000aa\";\n$mem_cached_color = \"33cc33\";\n$mem_buffered_color = \"99ff33\";\n$mem_free_color = \"00ff00\";\n$mem_swapped_color = \"9900CC\";\n\n#\n# Colors for the LOAD report graph\n#\n$load_one_color = \"CCCCCC\";\n$proc_run_color = \"0000FF\";\n$cpu_num_color  = \"FF0000\";\n$num_nodes_color = \"00FF00\";\n\n# Other colors\n$jobstart_color = \"ff3300\";\n\n#\n# Colors for the load ranks.\n#\n$load_colors = array(\n   \"100+\" => \"ff634f\",\n   \"75-100\" =>\"ffa15e\",\n   \"50-75\" => \"ffde5e\",\n   \"25-50\" => \"caff98\",\n   \"0-25\" => \"e2ecff\",\n   \"down\" => \"515151\"\n);\n\n#\n# Load scaling\n#\n$load_scale = 1.0;\n\n#\n# Default color for single metric graphs\n#\n$default_metric_color = \"555555\";\n\n#\n# Default metric \n#\n$default_metric = \"load_one\";\n\n#\n# remove the domainname from the FQDN hostnames in graphs\n# (to help with long hostnames in small charts)\n#\n$strip_domainname = false;\n\n#\n# Optional summary graphs\n#\n$optional_graphs = array('packet');\n\n# \n# Time ranges\n# Each value is the # of seconds in that range.\n#\n$time_ranges = array(\n   'hour'=>3600,\n   'day'=>86400,\n   'week'=>604800,\n   'month'=>2419200,\n   'year'=>31449600\n);\n\n# this key must exist in $time_ranges\n$default_time_range = 'hour';\n\n#\n# Graph sizes\n#\n$graph_sizes = array(\n   'small'=>array(\n     'height'=>40,\n     'width'=>130,\n     'fudge_0'=>0,\n     'fudge_1'=>0,\n     'fudge_2'=>0\n   ),\n   'medium'=>array(\n     'height'=>75,\n     'width'=>300,\n     'fudge_0'=>0,\n     'fudge_1'=>14,\n     'fudge_2'=>28\n   ),\n   'large'=>array(\n     'height'=>600,\n     'width'=>800,\n     'fudge_0'=>0,\n     'fudge_1'=>0,\n     'fudge_2'=>0\n   ),\n   # this was the default value when no other size was provided.\n   'default'=>array(\n     'height'=>100,\n     'width'=>400,\n     'fudge_0'=>0,\n     'fudge_1'=>0,\n     'fudge_2'=>0\n   )\n);\n$default_graph_size = 'default';\n$graph_sizes_keys = array_keys( $graph_sizes );\n?>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/gmetad.conf.erb",
    "content": "# This is an example of a Ganglia Meta Daemon configuration file\n#                http://ganglia.sourceforge.net/\n#\n# $Id: gmetad.conf.in 1639 2008-08-09 23:30:32Z carenas $\n#\n#-------------------------------------------------------------------------------\n# Setting the debug_level to 1 will keep daemon in the forground and\n# show only error messages. Setting this value higher than 1 will make \n# gmetad output debugging information and stay in the foreground.\n# default: 0\n# debug_level 10\n#\n#-------------------------------------------------------------------------------\n# What to monitor. The most important section of this file. \n#\n# The data_source tag specifies either a cluster or a grid to\n# monitor. If we detect the source is a cluster, we will maintain a complete\n# set of RRD databases for it, which can be used to create historical \n# graphs of the metrics. If the source is a grid (it comes from another gmetad),\n# we will only maintain summary RRDs for it.\n#\n# Format: \n# data_source \"my cluster\" [polling interval] address1:port addreses2:port ...\n# \n# The keyword 'data_source' must immediately be followed by a unique\n# string which identifies the source, then an optional polling interval in \n# seconds. The source will be polled at this interval on average. \n# If the polling interval is omitted, 15sec is asssumed. \n#\n# A list of machines which service the data source follows, in the \n# format ip:port, or name:port. If a port is not specified then 8649\n# (the default gmond port) is assumed.\n# default: There is no default value\n#\n# data_source \"my cluster\" 10 localhost  my.machine.edu:8649  1.2.3.5:8655\n# data_source \"my grid\" 50 1.3.4.7:8655 grid.org:8651 grid-backup.org:8651\n# data_source \"another source\" 1.3.4.7:8655  1.3.4.8\n# data_source \"my cluster\" localhost\n#\n<%= @node[:ganglia][:ganglia_gmetad_data_sources] %>\n#\n#\n# Round-Robin Archives\n# You can specify custom Round-Robin archives here (defaults are listed below)\n#\n# RRAs \"RRA:AVERAGE:0.5:1:244\" \"RRA:AVERAGE:0.5:24:244\" \"RRA:AVERAGE:0.5:168:244\" \"RRA:AVERAGE:0.5:672:244\" \\\n#      \"RRA:AVERAGE:0.5:5760:374\"\n#\n\n#\n#-------------------------------------------------------------------------------\n# Scalability mode. If on, we summarize over downstream grids, and respect\n# authority tags. If off, we take on 2.5.0-era behavior: we do not wrap our output\n# in <GRID></GRID> tags, we ignore all <GRID> tags we see, and always assume\n# we are the \"authority\" on data source feeds. This approach does not scale to\n# large groups of clusters, but is provided for backwards compatibility.\n# default: on\n# scalable off\n#\n#-------------------------------------------------------------------------------\n# The name of this Grid. All the data sources above will be wrapped in a GRID\n# tag with this name.\n# default: unspecified\ngridname \"<%= @node[:ganglia][:ganglia_pool_name] %>\"\n#\n#-------------------------------------------------------------------------------\n# The authority URL for this grid. Used by other gmetads to locate graphs\n# for our data sources. Generally points to a ganglia/\n# website on this machine.\n# default: \"http://hostname/ganglia/\",\n#   where hostname is the name of this machine, as defined by gethostname().\n# authority \"http://mycluster.org/newprefix/\"\n#\n#-------------------------------------------------------------------------------\n# List of machines this gmetad will share XML with. Localhost\n# is always trusted. \n# default: There is no default value\n# trusted_hosts 127.0.0.1 169.229.50.165 my.gmetad.org\n#\n#-------------------------------------------------------------------------------\n# If you want any host which connects to the gmetad XML to receive\n# data, then set this value to \"on\"\n# default: off\n# all_trusted on\n#\n#-------------------------------------------------------------------------------\n# If you don't want gmetad to setuid then set this to off\n# default: on\n# setuid off\n#\n#-------------------------------------------------------------------------------\n# User gmetad will setuid to (defaults to \"nobody\")\n# default: \"nobody\"\nsetuid_username <%= @node[:ganglia][:gmetad_user] %>\n\n\n#\n#-------------------------------------------------------------------------------\n# The port gmetad will answer requests for XML\n# default: 8651\n# xml_port 8651\n#\n#-------------------------------------------------------------------------------\n# The port gmetad will answer queries for XML. This facility allows\n# simple subtree and summation views of the XML tree.\n# default: 8652\ninteractive_port 8652\n#\n#-------------------------------------------------------------------------------\n# The number of threads answering XML requests\n# default: 4\n# server_threads 10\n#\n#-------------------------------------------------------------------------------\n# Where gmetad stores its round-robin databases\n# default: \"/var/lib/ganglia/rrds\"\n# rrd_rootdir \"/some/other/place\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/gmond.conf.erb",
    "content": "/* This configuration is as close to 2.5.x default behavior as possible\n   The values closely match ./gmond/metric.h definitions in 2.5.x */\n/* some comments borrowed from http://www-user.tu-chemnitz.de/~aas/wiki/lib/exe/fetch.php?id=projekte%3Aganglia&cache=cache&media=gmond.conf.template */\nglobals {\n  daemonize = yes\n  setuid = yes\n  user = <%= @node[:ganglia][:gmond_user] %>\n  debug_level = 0\n  max_udp_msg_len = 1472\n  mute = no\n  deaf = no \n  allow_extra_data = yes\n  host_dmax = 0 /*secs */\n  cleanup_threshold = 300 /*secs */\n  gexec = no\n  send_metadata_interval = 10 \n}\n\n/*\n * The cluster attributes specified will be used as part of the <CLUSTER>\n * tag that will wrap all hosts collected by this instance.\n */\ncluster {\n  name = \"<%= @node[:ganglia][:ganglia_cloud_name] %>\"\n  owner = \"unspecified\"\n  latlong = \"unspecified\"\n  url = \"unspecified\"\n}\n\n/* The host section describes attributes of the host, like the location */\nhost {\n  location = \"unspecified\"\n}\n\n/*\n\tUDP send channels\n\n\tGmond will use UDP send channel(s) for sending monitoring\n\tdata it collects from _the local node_ to other nodes.\n\n\tThere are two different kinds of UDP send channels:\n\t- unicast channel:\n\t  specifies a single host that is supposed to receive monitoring\n\t  data from other client nodes\n\n\t- multicast channel:\n\t  specifies a multicast domain that will be used to spread monitoring data\n\n\tNote:\n\t- the type of channel that should be used depends on the kind of monitoring \n\t  architecture you want to implement\n\t- make sure to set 'mute = no' in the global configuration section!\n\t- multiple UDP send channels can be configured\n\t- gmond will send its data through all channels simultaneously\n\t\n\tSee \"Monitoringsoftware Ganglia - Installation, Konfiguration und Bewertung\",\n\tsection \"Architektur der Monitoringsoftware Ganglia\" for further details!\n\n\tUnicast UDP send channels:\n\t- the target host has to be a node running gmond\n\t- the gmond running on the target host has to be configured to\n\t  accept data from other gmonds\n*/\n\n/* Feel free to specify as many udp_send_channels as you like.  Gmond\n   used to only support having a single channel */\nudp_send_channel {\n  /* mcast_join = <%= @node[:ganglia][:ganglia_masters_ip] %> */\n  /* host = <%= @node[:ganglia][:ganglia_masters_ip] %> */\n  host = <%= @node[:ganglia][:ganglia_first_node_in_clusters_ip] %>\n  port = 8649\n  ttl = 1\n}\n\n/*\n\tUDP receive channels\n\n\tGmond will 'listen' on all UDP receive channels for incoming\n\tmonitoring data. Incoming data from other gmonds will be added\n\tto the cluster state maintained by the local node.\n\n\tThere are two different kinds of UDP receive channels:\n\t- unicast channel:\n\t  specifies a single UDP port that will accept incoming data\n\n\t- multicast channel:\n\t  tells gmond to join a multicast domain and accept incoming\n\t  data sent by other members of the same domain\n\n\tNote:\n\t- the type of channel that should be used depends on the kind of monitoring \n\t  architecture you want to implement\n\t- make sure to set 'deaf = no' in the global configuration section!\n\t- multiple UDP receive channels can be configured\n\t- gmond will accept data on all channels simultaneously\n\n\tSee \"Monitoringsoftware Ganglia - Installation, Konfiguration und Bewertung\",\n\tsection \"Architektur der Monitoringsoftware Ganglia\" for further details!\n\n    You can specify as many udp_recv_channels as you like. */\nudp_recv_channel {\n  /* mcast_join = <%= @node[:ganglia][:ganglia_this_nodes_private_ip] %> */\n  port = 8649\n  bind = <%= @node[:ganglia][:ganglia_this_nodes_private_ip] %>  \n  /* bind = 0.0.0.0 */\n  family = inet4\n\n  acl {\n    default = \"allow\"\n  }\n}\n<%# if @node[:ganglia][:ganglia_gmond_is_master] %>\n<%# end %>\n/*\n\tTCP accept channels\n\n\tGmond will listen on all TCP accept channels for incoming connections\n\tfrom nodes running gmetad. When a gmetad connects, gmond will transmit\n\t_all monitoring data_ it has collected so far (i.e. the state of the\n\t_whole cluster_ as far as gmond knows about it).\n\n\tNote:\n\t- make sure to set 'mute = no' in the global configuration section\n\t- multiple TCP accept channels can be configured\n\t- gmond will accept requests on all channels simultaneously\n\n   You can specify as many tcp_accept_channels as you like to share\n   an xml description of the state of the cluster */\ntcp_accept_channel {\n  port = 8649\n  bind = <%= @node[:ganglia][:ganglia_this_nodes_private_ip] %>\n  acl {\n    default = \"allow\"\n  }\n}\n\n/* Each metrics module that is referenced by gmond must be specified and\n   loaded. If the module has been statically linked with gmond, it does\n   not require a load path. However all dynamically loadable modules must\n   include a load path. */\nmodules {\n  module {\n    name = \"core_metrics\"\n  }\n  module {\n    name = \"cpu_module\"\n    path = \"modcpu.so\"\n  }\n  module {\n    name = \"disk_module\"\n    path = \"moddisk.so\"\n  }\n  module {\n    name = \"load_module\"\n    path = \"modload.so\"\n  }\n  module {\n    name = \"mem_module\"\n    path = \"modmem.so\"\n  }\n  module {\n    name = \"net_module\"\n    path = \"modnet.so\"\n  }\n  module {\n    name = \"proc_module\"\n    path = \"modproc.so\"\n  }\n  module {\n    name = \"sys_module\"\n    path = \"modsys.so\"\n  }\n}\n\ninclude ('/etc/ganglia/conf.d/*.conf')\n\n/* The old internal 2.5.x metric array has been replaced by the following\n   collection_group directives.  What follows is the default behavior for\n   collecting and sending metrics that is as close to 2.5.x behavior as\n   possible. */\n\n/* This collection group will cause a heartbeat (or beacon) to be sent every\n   20 seconds.  In the heartbeat is the GMOND_STARTED data which expresses\n   the age of the running gmond. */\ncollection_group {\n  collect_once = yes\n  time_threshold = 20\n  metric {\n    name = \"heartbeat\"\n  }\n}\n\n/* This collection group will send general info about this host every\n   1200 secs.\n   This information doesn't change between reboots and is only collected\n   once. */\ncollection_group {\n  collect_once = yes\n  time_threshold = 1200\n  metric {\n    name = \"cpu_num\"\n    title = \"CPU Count\"\n  }\n  metric {\n    name = \"cpu_speed\"\n    title = \"CPU Speed\"\n  }\n  metric {\n    name = \"mem_total\"\n    title = \"Memory Total\"\n  }\n  /* Should this be here? Swap can be added/removed between reboots. */\n  metric {\n    name = \"swap_total\"\n    title = \"Swap Space Total\"\n  }\n  metric {\n    name = \"boottime\"\n    title = \"Last Boot Time\"\n  }\n  metric {\n    name = \"machine_type\"\n    title = \"Machine Type\"\n  }\n  metric {\n    name = \"os_name\"\n    title = \"Operating System\"\n  }\n  metric {\n    name = \"os_release\"\n    title = \"Operating System Release\"\n  }\n  metric {\n    name = \"location\"\n    title = \"Location\"\n  }\n}\n\n/* This collection group will send the status of gexecd for this host\n   every 300 secs.*/\n/* Unlike 2.5.x the default behavior is to report gexecd OFF. */\ncollection_group {\n  collect_once = yes\n  time_threshold = 300\n  metric {\n    name = \"gexec\"\n    title = \"Gexec Status\"\n  }\n}\n\n/* This collection group will collect the CPU status info every 20 secs.\n   The time threshold is set to 90 seconds.  In honesty, this\n   time_threshold could be set significantly higher to reduce\n   unneccessary  network chatter. */\ncollection_group {\n  collect_every = 20\n  time_threshold = 90\n  /* CPU status */\n  metric {\n    name = \"cpu_user\"\n    value_threshold = \"1.0\"\n    title = \"CPU User\"\n  }\n  metric {\n    name = \"cpu_system\"\n    value_threshold = \"1.0\"\n    title = \"CPU System\"\n  }\n  metric {\n    name = \"cpu_idle\"\n    value_threshold = \"5.0\"\n    title = \"CPU Idle\"\n  }\n  metric {\n    name = \"cpu_nice\"\n    value_threshold = \"1.0\"\n    title = \"CPU Nice\"\n  }\n  metric {\n    name = \"cpu_aidle\"\n    value_threshold = \"5.0\"\n    title = \"CPU aidle\"\n  }\n  metric {\n    name = \"cpu_wio\"\n    value_threshold = \"1.0\"\n    title = \"CPU wio\"\n  }\n  /* The next two metrics are optional if you want more detail...\n     ... since they are accounted for in cpu_system.\n  metric {\n    name = \"cpu_intr\"\n    value_threshold = \"1.0\"\n    title = \"CPU intr\"\n  }\n  metric {\n    name = \"cpu_sintr\"\n    value_threshold = \"1.0\"\n    title = \"CPU sintr\"\n  }\n  */\n}\n\ncollection_group {\n  collect_every = 20\n  time_threshold = 90\n  /* Load Averages */\n  metric {\n    name = \"load_one\"\n    value_threshold = \"1.0\"\n    title = \"One Minute Load Average\"\n  }\n  metric {\n    name = \"load_five\"\n    value_threshold = \"1.0\"\n    title = \"Five Minute Load Average\"\n  }\n  metric {\n    name = \"load_fifteen\"\n    value_threshold = \"1.0\"\n    title = \"Fifteen Minute Load Average\"\n  }\n}\n\n/* This group collects the number of running and total processes */\ncollection_group {\n  collect_every = 80\n  time_threshold = 950\n  metric {\n    name = \"proc_run\"\n    value_threshold = \"1.0\"\n    title = \"Total Running Processes\"\n  }\n  metric {\n    name = \"proc_total\"\n    value_threshold = \"1.0\"\n    title = \"Total Processes\"\n  }\n}\n\n/* This collection group grabs the volatile memory metrics every 40 secs and\n   sends them at least every 180 secs.  This time_threshold can be increased\n   significantly to reduce unneeded network traffic. */\ncollection_group {\n  collect_every = 40\n  time_threshold = 180\n  metric {\n    name = \"mem_free\"\n    value_threshold = \"1024.0\"\n    title = \"Free Memory\"\n  }\n  metric {\n    name = \"mem_shared\"\n    value_threshold = \"1024.0\"\n    title = \"Shared Memory\"\n  }\n  metric {\n    name = \"mem_buffers\"\n    value_threshold = \"1024.0\"\n    title = \"Memory Buffers\"\n  }\n  metric {\n    name = \"mem_cached\"\n    value_threshold = \"1024.0\"\n    title = \"Cached Memory\"\n  }\n  metric {\n    name = \"swap_free\"\n    value_threshold = \"1024.0\"\n    title = \"Free Swap Space\"\n  }\n}\n\ncollection_group {\n  collect_every = 40\n  time_threshold = 300\n  metric {\n    name = \"bytes_out\"\n    value_threshold = 4096\n    title = \"Bytes Sent\"\n  }\n  metric {\n    name = \"bytes_in\"\n    value_threshold = 4096\n    title = \"Bytes Received\"\n  }\n  metric {\n    name = \"pkts_in\"\n    value_threshold = 256\n    title = \"Packets Received\"\n  }\n  metric {\n    name = \"pkts_out\"\n    value_threshold = 256\n    title = \"Packets Sent\"\n  }\n}\n\n/* Different than 2.5.x default since the old config made no sense */\ncollection_group {\n  collect_every = 1800\n  time_threshold = 3600\n  metric {\n    name = \"disk_total\"\n    value_threshold = 1.0\n    title = \"Total Disk Space\"\n  }\n}\n\ncollection_group {\n  collect_every = 40\n  time_threshold = 180\n  metric {\n    name = \"disk_free\"\n    value_threshold = 1.0\n    title = \"Disk Space Available\"\n  }\n  metric {\n    name = \"part_max_used\"\n    value_threshold = 1.0\n    title = \"Maximum Disk Space Used\"\n  }\n}\n\n\n/* vim: ft=javascript */\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ganglia/templates/default/jaunty.sources.list.erb",
    "content": "deb http://archive.ubuntu.com/ubuntu/ jaunty main restricted\ndeb http://archive.ubuntu.com/ubuntu/ jaunty universe\ndeb http://archive.ubuntu.com/ubuntu/ jaunty multiverse\ndeb-src http://archive.ubuntu.com/ubuntu/ jaunty main restricted\ndeb-src http://archive.ubuntu.com/ubuntu/ jaunty universe\ndeb-src http://archive.ubuntu.com/ubuntu/ jaunty multiverse\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ntp/attributes/ntp.rb",
    "content": "ntp Mash.new unless attribute?(\"ntp\")\n\ncase platform \nwhen \"ubuntu\",\"debian\"\n  ntp[:service] = \"ntp\"\nwhen \"redhat\",\"centos\",\"fedora\"\n  ntp[:service] = \"ntpd\"\nend unless ntp.has_key?(:service)\n\nntp[:is_server] = false unless ntp.has_key?(:is_server)\nntp[:servers] = [\"0.us.pool.ntp.org\", \"1.us.pool.ntp.org\"] unless ntp.has_key?(:servers)\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ntp/metadata.json",
    "content": "{\n  \"description\": \"Installs and configures ntp as a client or server\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"ntp\": \"\"\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ],\n    \"fedora\": [\n\n    ],\n    \"centos\": [\n\n    ],\n    \"redhat\": [\n\n    ],\n    \"debian\": [\n\n    ]\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.7.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"ntp\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n    \"ntp\\/servers\": {\n      \"default\": [\n        \"0.us.pool.ntp.org\",\n        \"1.us.pool.ntp.org\"\n      ],\n      \"type\": \"array\",\n      \"multiple_values\": false,\n      \"description\": \"Array of servers we should talk to\",\n      \"display_name\": \"NTP Servers\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"ntp\\/is_server\": {\n      \"default\": \"false\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Set to true if this is an NTP server\",\n      \"display_name\": \"NTP Is Server?\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"ntp\\/service\": {\n      \"default\": \"ntp\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Name of the NTP service\",\n      \"display_name\": \"NTP Service\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"ntp\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of NTP attributes\",\n      \"display_name\": \"NTP\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    }\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n\n  },\n  \"providing\": {\n    \"ntp\": [\n\n    ]\n  },\n  \"long_description\": \"\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ntp/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Installs and configures ntp as a client or server\"\nversion           \"0.7\"\n\n%w{ ubuntu debian redhat centos fedora }.each do |os|\n  supports os\nend\n\nattribute \"ntp\",\n  :display_name => \"NTP\",\n  :description => \"Hash of NTP attributes\",\n  :type => \"hash\"\n\nattribute \"ntp/service\",\n  :display_name => \"NTP Service\",\n  :description => \"Name of the NTP service\",\n  :default => \"ntp\"\n\nattribute \"ntp/is_server\",\n  :display_name => \"NTP Is Server?\",\n  :description => \"Set to true if this is an NTP server\",\n  :default => \"false\"\n\nattribute \"ntp/servers\",\n  :display_name => \"NTP Servers\",\n  :description => \"Array of servers we should talk to\",\n  :type => \"array\",\n  :default => [\"0.us.pool.ntp.org\", \"1.us.pool.ntp.org\"]\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ntp/recipes/default.rb",
    "content": "#\n# Cookbook Name:: ntp\n# Recipe:: default\n# Author:: Joshua Timberman (<joshua@opscode.com>)\n#\n# Copyright 2009, Opscode, Inc\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ncase node[:platform] \nwhen \"ubuntu\",\"debian\"\n  package \"ntpdate\" do\n    action :install\n  end\nend\n\npackage \"ntp\" do\n  action :install\nend\n\nservice node[:ntp][:service] do\n  action :start\nend\n\ntemplate \"/etc/ntp.conf\" do\n  source \"ntp.conf.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => node[:ntp][:service])\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/ntp/templates/default/ntp.conf.erb",
    "content": "driftfile /var/lib/ntp/ntp.drift\nstatsdir /var/log/ntpstats/\n\nstatistics loopstats peerstats clockstats\nfilegen loopstats file loopstats type day enable\nfilegen peerstats file peerstats type day enable\nfilegen clockstats file clockstats type day enable\n\n<% if @node[:ntp][:is_server] -%>\nserver 0.us.pool.ntp.org\nserver 1.us.pool.ntp.org\nserver 2.us.pool.ntp.org\nserver 3.us.pool.ntp.org\n<% else -%>\n<% @node[:ntp][:servers].each do |ntpserver| -%>\n  server <%= ntpserver %>\n<% end -%>\n<% end -%>\nrestrict default kod notrap nomodify nopeer noquery\n\nrestrict 127.0.0.1 nomodify\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/README.rdoc",
    "content": "= DESCRIPTION:\n\nInstalls rsyslog to replace sysklogd for client and/or server use. By default, server will be set up to log to files.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10.\n\n== Cookbooks:\n\n= ATTRIBUTES: \n\n* rsyslog[:log_dir] - specify the directory to store logs (applicable to server only)\n* rsyslog[:server] - specify the remote rsyslog server.\n* rsyslog[:protocol] - specify whether to use udp or tcp for remote log transmission. tcp is default.\n\n= USAGE:\n\nTo replace the sysklogd syslog service with rsyslog:\n\n  include_recipe \"rsyslog\"\n  \nTo set up a client with a remote [r]syslog server:\n\n  include_recipe \"rsyslog::client\"\n  \nBy default, this cookbook will use TCP so the server should be configured for TCP. This can be done easily with the server recipe:\n\n  include_recipe \"rsyslog::server\"\n\nTo switch to UDP, change the rsyslog[:protocol] attribute. Note this needs to be done on each client as well.\n\nAlso, the server configuration will set up log_dir for each client, by date. Structure:\n\n  <%= @log_dir %>/YEAR/MONTH/DAY/HOSTNAME/\"logfile\"\n\n= LICENSE and AUTHOR:\n      \nAuthor:: Joshua Timberman (<joshua@opscode.com>)\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/attributes/rsyslog.rb",
    "content": "#\n# Cookbook Name:: rsyslog\n# Attributes:: rsyslog\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nrsyslog Mash.new unless attribute?(\"rsyslog\")\n\nrsyslog[:log_dir] = \"/srv/rsyslog\" unless rsyslog.has_key?(:log_dir)\nrsyslog[:server] = false           unless rsyslog.has_key?(:server)\nrsyslog[:protocol] = \"tcp\"         unless rsyslog.has_key?(:protocol)\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/files/default/rsyslog.default",
    "content": "# Generated by Chef\n#\n# Use v3 native mode, rather than compatibility mode by specifying -c3\n# here. Compatibility mode for older versions is not recommended as \n# custom configuration may get messy. \n# \n# See rsyslogd(8) for more details\n\nRSYSLOGD_OPTIONS=\"-c3\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/files/ubuntu-8.04/rsyslog.default",
    "content": "# Options to rsyslogd\n# -m 0 disables 'MARK' messages.\n# -r enables logging from remote machines\n# -x disables DNS lookups on messages recieved with -r\n# See rsyslogd(8) for more details\nRSYSLOGD_OPTIONS=\"-m 0\"\n\n# Options to rklogd\n# -2 prints all kernel oops messages twice; once for klogd to decode, and\n#    once for processing with 'ksymoops'\n# -x disables all klogd processing of oops messages entirely\n# See rklogd(8) for more details\nRKLOGD_OPTIONS=\"-x\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/files/ubuntu-9.10/rsyslog.default",
    "content": "# Generated by Chef\n#\n# Options for rsyslogd\n# -m 0 disables 'MARK' messages (deprecated, only used in compat mode < 3)\n# -r enables logging from remote machines (deprecated, only used in compat mode < 3)\n# -x disables DNS lookups on messages received with -r\n# -c compatibility mode\n# See rsyslogd(8) for more details\nRSYSLOGD_OPTIONS=\"-c4\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/metadata.json",
    "content": "{\n  \"description\": \"Installs and configures rsyslog\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"rsyslog::server\": \"Sets up an rsyslog server\",\n    \"rsyslog\": \"\",\n    \"rsyslog::client\": \"Sets up a client to log to a remote rsyslog server\"\n  },\n  \"platforms\": {\n\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.7.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"rsyslog\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n    \"rsyslog\\/protocol\": {\n      \"default\": \"tcp\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Set which network protocol to use for rsyslog\",\n      \"display_name\": \"Rsyslog Protocol\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"rsyslog\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of Rsyslog attributes\",\n      \"display_name\": \"Rsyslog\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"rsyslog\\/log_dir\": {\n      \"default\": \"\\/srv\\/rsyslog\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Filesystem location of logs from clients\",\n      \"display_name\": \"Rsyslog Log Directory\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    },\n    \"rsyslog\\/server\": {\n      \"default\": \"false\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Is this node an rsyslog server?\",\n      \"display_name\": \"Rsyslog Server?\",\n      \"required\": false,\n      \"recipes\": [\n\n      ]\n    }\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n\n  },\n  \"providing\": {\n    \"rsyslog::server\": [\n\n    ],\n    \"rsyslog\": [\n\n    ],\n    \"rsyslog::client\": [\n\n    ]\n  },\n  \"long_description\": \"= DESCRIPTION:\\n\\nInstalls rsyslog to replace sysklogd for client and\\/or server use. By default, server will be set up to log to files.\\n\\n= REQUIREMENTS:\\n\\n== Platform:\\n\\nTested on Ubuntu 8.10.\\n\\n== Cookbooks:\\n\\n= ATTRIBUTES: \\n\\n* rsyslog[:log_dir] - specify the directory to store logs (applicable to server only)\\n* rsyslog[:server] - specify the remote rsyslog server.\\n* rsyslog[:protocol] - specify whether to use udp or tcp for remote log transmission. tcp is default.\\n\\n= USAGE:\\n\\nTo replace the sysklogd syslog service with rsyslog:\\n\\n  include_recipe \\\"rsyslog\\\"\\n  \\nTo set up a client with a remote [r]syslog server:\\n\\n  include_recipe \\\"rsyslog::client\\\"\\n  \\nBy default, this cookbook will use TCP so the server should be configured for TCP. This can be done easily with the server recipe:\\n\\n  include_recipe \\\"rsyslog::server\\\"\\n\\nTo switch to UDP, change the rsyslog[:protocol] attribute. Note this needs to be done on each client as well.\\n\\nAlso, the server configuration will set up log_dir for each client, by date. Structure:\\n\\n  <%= @log_dir %>\\/YEAR\\/MONTH\\/DAY\\/HOSTNAME\\/\\\"logfile\\\"\\n\\n= LICENSE and AUTHOR:\\n      \\nAuthor:: Joshua Timberman (<joshua@opscode.com>)\\n\\nCopyright:: 2009, Opscode, Inc\\n\\nLicensed under the Apache License, Version 2.0 (the \\\"License\\\");\\nyou may not use this file except in compliance with the License.\\nYou may obtain a copy of the License at\\n\\n    http:\\/\\/www.apache.org\\/licenses\\/LICENSE-2.0\\n\\nUnless required by applicable law or agreed to in writing, software\\ndistributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\nSee the License for the specific language governing permissions and\\nlimitations under the License.\\n\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Installs and configures rsyslog\"\nlong_description  IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))\nversion           \"0.7\"\nrecipe            \"rsyslog::client\", \"Sets up a client to log to a remote rsyslog server\"\nrecipe            \"rsyslog::server\", \"Sets up an rsyslog server\"\n\nattribute \"rsyslog\",\n  :display_name => \"Rsyslog\",\n  :description => \"Hash of Rsyslog attributes\",\n  :type => \"hash\"\n\nattribute \"rsyslog/log_dir\",\n  :display_name => \"Rsyslog Log Directory\",\n  :description => \"Filesystem location of logs from clients\",\n  :default => \"/srv/rsyslog\"\n\nattribute \"rsyslog/server\",\n  :display_name => \"Rsyslog Server?\",\n  :description => \"Is this node an rsyslog server?\",\n  :default => \"false\"\n\nattribute \"rsyslog/protocol\",\n  :display_name => \"Rsyslog Protocol\",\n  :description => \"Set which network protocol to use for rsyslog\",\n  :default => \"tcp\"\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/recipes/client.rb",
    "content": "#\n# Cookbook Name:: rsyslog\n# Recipe:: client\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ninclude_recipe \"rsyslog\"\n\nrsyslog_server = node[:rsyslog][:server] ? node[:rsyslog][:server] : search(:node, \"rsyslog_server:true\").map { |n| n[\"fqdn\"] }.first\n\n# unless node[:rsyslog][:server]\n  template \"/etc/rsyslog.d/remote.conf\" do\n    source \"remote.conf.erb\"\n    backup false\n    variables :server => rsyslog_server, :protocol => node[:rsyslog][:protocol]\n    owner \"root\"\n    group \"root\"\n    mode 0644\n    notifies :restart, resources(:service => \"rsyslog\"), :delayed\n  end\n\n  file \"/etc/rsyslog.d/server.conf\" do\n    action :delete\n    notifies :reload, resources(:service => \"rsyslog\"), :delayed\n    only_if do File.exists?(\"/etc/rsyslog.d/server.conf\") end\n  end\n# end\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/recipes/default.rb",
    "content": "#\n# Cookbook Name:: rsyslog\n# Recipe:: default\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npackage \"rsyslog\" do\n  action :install\nend\n\nservice \"rsyslog\" do\n  supports :restart => true, :reload => true\n  action [:enable, :start]\nend\n\nremote_file \"/etc/default/rsyslog\" do\n  source \"rsyslog.default\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\nend\n\ndirectory \"/etc/rsyslog.d\" do\n  owner \"root\"\n  group \"root\"\n  mode 0755\nend\n\ntemplate \"/etc/rsyslog.conf\" do\n  source \"rsyslog.conf.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"rsyslog\"), :delayed\nend\n\ncase node[:platform]\nwhen \"ubuntu\"\n  if node[:platform_version] >= \"9.10\"\n    template \"/etc/rsyslog.d/50-default.conf\" do\n      source \"50-default.conf.erb\"\n      backup false\n      owner \"root\"\n      group \"root\"\n      mode 0644\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/recipes/server.rb",
    "content": "#\n# Cookbook Name:: rsyslog\n# Recipe:: server\n#\n# Copyright 2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ninclude_recipe \"rsyslog\"\n\ndirectory \"/srv/rsyslog\" do\n  owner \"root\"\n  group \"root\"\n  mode 0755\nend\n\ntemplate \"/etc/rsyslog.d/server.conf\" do\n  source \"server.conf.erb\"\n  backup false\n  variables :log_dir => node[:rsyslog][:log_dir], :protocol => node[:rsyslog][:protocol]\n  owner \"root\"\n  group \"root\"\n  mode 0644\n  notifies :restart, resources(:service => \"rsyslog\"), :delayed\nend\n\nfile \"/etc/rsyslog.d/remote.conf\" do\n  action :delete\n  notifies :reload, resources(:service => \"rsyslog\"), :delayed\n  only_if do File.exists?(\"/etc/rsyslog.d/remote.conf\") end\nend\n\ncron \"rsyslog_gz\" do\n  minute \"0\"\n  hour \"4\"\n  command \"find #{node[:rsyslog][:log_dir]}/$(date +\\\\%Y) -type f -mtime +1 -exec gzip -q {} \\\\;\"\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/default/remote.conf.erb",
    "content": "<% case @protocol -%>\n<% when \"tcp\" -%>\n*.* @@<%= @server %>\n<% when \"udp\" -%>\n*.* @<%= @server %>\n<% end -%>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/default/rsyslog.conf.erb",
    "content": "#  /etc/rsyslog.conf\tConfiguration file for rsyslog v3.\n#\n#\t\t\tFor more information see \n#\t\t\t/usr/share/doc/rsyslog-doc/html/rsyslog_conf.html\n\n\n#################\n#### MODULES ####\n#################\n\n$ModLoad imuxsock # provides support for local system logging\n$ModLoad imklog   # provides kernel logging support (previously done by rklogd) \n#$ModLoad immark  # provides --MARK-- message capability\n\n# provides UDP syslog reception\n#$ModLoad imudp\n#$UDPServerRun 514\n\n# provides TCP syslog reception\n#$ModLoad imtcp\n#$InputTCPServerRun 514\n\n\n###########################\n#### GLOBAL DIRECTIVES ####\n###########################\n\n#\n# Use default timestamp format.\n# To enable high precision timestamps, comment out the following line.\n#\n$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat\n\n#\n# Set the default permissions for all log files.\n#\n$FileOwner root\n$FileGroup adm\n$FileCreateMode 0640\n\n\n###############\n#### RULES ####\n###############\n\n#\n# First some standard log files.  Log by facility.\n#\nauth,authpriv.*\t\t\t/var/log/auth.log\n*.*;auth,authpriv.none\t\t-/var/log/syslog\n#cron.*\t\t\t\t/var/log/cron.log\ndaemon.*\t\t\t-/var/log/daemon.log\nkern.*\t\t\t\t-/var/log/kern.log\nlpr.*\t\t\t\t-/var/log/lpr.log\nmail.*\t\t\t\t-/var/log/mail.log\nuser.*\t\t\t\t-/var/log/user.log\n\n#\n# Logging for the mail system.  Split it up so that\n# it is easy to write scripts to parse these files.\n#\nmail.info\t\t\t-/var/log/mail.info\nmail.warn\t\t\t-/var/log/mail.warn\nmail.err\t\t\t/var/log/mail.err\n\n#\n# Logging for INN news system.\n#\nnews.crit\t\t\t/var/log/news/news.crit\nnews.err\t\t\t/var/log/news/news.err\nnews.notice\t\t\t-/var/log/news/news.notice\n\n#\n# Some \"catch-all\" log files.\n#\n*.=debug;\\\n\tauth,authpriv.none;\\\n\tnews.none;mail.none\t-/var/log/debug\n*.=info;*.=notice;*.=warn;\\\n\tauth,authpriv.none;\\\n\tcron,daemon.none;\\\n\tmail,news.none\t\t-/var/log/messages\n\n#\n# Emergencies are sent to everybody logged in.\n#\n*.emerg\t\t\t\t*\n\n#\n# I like to have messages displayed on the console, but only on a virtual\n# console I usually leave idle.\n#\n#daemon,mail.*;\\\n#\tnews.=crit;news.=err;news.=notice;\\\n#\t*.=debug;*.=info;\\\n#\t*.=notice;*.=warn\t/dev/tty8\n\n# The named pipe /dev/xconsole is for the `xconsole' utility.  To use it,\n# you must invoke `xconsole' with the `-file' option:\n# \n#    $ xconsole -file /dev/xconsole [...]\n#\n# NOTE: adjust the list below, or you'll go crazy if you have a reasonably\n#      busy site..\n#\ndaemon.*;mail.*;\\\n\tnews.err;\\\n\t*.=debug;*.=info;\\\n\t*.=notice;*.=warn\t|/dev/xconsole\n\n#\n# Include all config files in /etc/rsyslog.d/\n#\n$IncludeConfig /etc/rsyslog.d/*.conf\n\n<% case @protocol -%>\n<% when \"tcp\" -%>\n*.* @@<%= @server %>\n<% when \"udp\" -%>\n*.* @<%= @server %>\n<% end -%>"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/default/server.conf.erb",
    "content": "# Generated by Chef. \n# Local modifications will be overwritten.\n<% case @protocol -%>\n<% when \"tcp\" -%>\n$ModLoad imtcp\n$InputTCPServerRun 514\n<% when \"udp\" -%>\n$ModLoad imudp\n$UDPServerRun 514\n<% end -%>\n\n$DirGroup root\n$DirCreateMode 0755\n$FileGroup root\n\n$template PerHostAuth,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/auth.log\"\n$template PerHostCron,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/cron.log\"\n$template PerHostSyslog,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/syslog\"\n$template PerHostDaemon,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/daemon.log\"\n$template PerHostKern,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/kern.log\"\n$template PerHostLpr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/lpr.log\"\n$template PerHostUser,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/user.log\"\n$template PerHostMail,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.log\"\n$template PerHostMailInfo,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.info\"\n$template PerHostMailWarn,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.warn\"\n$template PerHostMailErr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.err\"\n$template PerHostNewsCrit,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.crit\"\n$template PerHostNewsErr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.err\"\n$template PerHostNewsNotice,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.notice\"\n$template PerHostDebug,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/debug\"\n$template PerHostMessages,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/messages\"\n\nauth,authpriv.*         ?PerHostAuth\n*.*;auth,authpriv.none  -?PerHostSyslog\ncron.*                  ?PerHostCron\ndaemon.*                -?PerHostDaemon\nkern.*                  -?PerHostKern\nlpr.*                   -?PerHostLpr\nmail.*                  -?PerHostMail\nuser.*                  -?PerHostUser\n\nmail.info               -?PerHostMailInfo\nmail.warn               ?PerHostMailWarn\nmail.err                ?PerHostMailErr\n\nnews.crit               ?PerHostNewsCrit\nnews.err                ?PerHostNewsErr\nnews.notice             -?PerHostNewsNotice\n\n*.=debug;\\\n  auth,authpriv.none;\\\n  news.none;mail.none   -?PerHostDebug\n\n*.=info;*.=notice;*.=warn;\\\n  auth,authpriv.none;\\\n  cron,daemon.none;\\\n  mail,news.none        -?PerHostMessages\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/ubuntu-9.10/50-default.conf.erb",
    "content": "#  Default rules for rsyslog.\n#\n#\t\t\tFor more information see rsyslog.conf(5) and /etc/rsyslog.conf\n\n#\n# First some standard log files.  Log by facility.\n#\nauth,authpriv.*\t\t\t/var/log/auth.log\n*.*;auth,authpriv.none\t\t-/var/log/syslog\n#cron.*\t\t\t\t/var/log/cron.log\ndaemon.*\t\t\t-/var/log/daemon.log\nkern.*\t\t\t\t-/var/log/kern.log\nlpr.*\t\t\t\t-/var/log/lpr.log\nmail.*\t\t\t\t-/var/log/mail.log\nuser.*\t\t\t\t-/var/log/user.log\n\n#\n# Logging for the mail system.  Split it up so that\n# it is easy to write scripts to parse these files.\n#\nmail.info\t\t\t-/var/log/mail.info\nmail.warn\t\t\t-/var/log/mail.warn\nmail.err\t\t\t/var/log/mail.err\n\n#\n# Logging for INN news system.\n#\nnews.crit\t\t\t/var/log/news/news.crit\nnews.err\t\t\t/var/log/news/news.err\nnews.notice\t\t\t-/var/log/news/news.notice\n\n#\n# Some \"catch-all\" log files.\n#\n*.=debug;\\\n\tauth,authpriv.none;\\\n\tnews.none;mail.none\t-/var/log/debug\n*.=info;*.=notice;*.=warn;\\\n\tauth,authpriv.none;\\\n\tcron,daemon.none;\\\n\tmail,news.none\t\t-/var/log/messages\n\n#\n# Emergencies are sent to everybody logged in.\n#\n*.emerg\t\t\t\t*\n\n#\n# I like to have messages displayed on the console, but only on a virtual\n# console I usually leave idle.\n#\n#daemon,mail.*;\\\n#\tnews.=crit;news.=err;news.=notice;\\\n#\t*.=debug;*.=info;\\\n#\t*.=notice;*.=warn\t/dev/tty8\n\n# The named pipe /dev/xconsole is for the `xconsole' utility.  To use it,\n# you must invoke `xconsole' with the `-file' option:\n# \n#    $ xconsole -file /dev/xconsole [...]\n#\n# NOTE: adjust the list below, or you'll go crazy if you have a reasonably\n#      busy site..\n#\ndaemon.*;mail.*;\\\n\tnews.err;\\\n\t*.=debug;*.=info;\\\n\t*.=notice;*.=warn\t|/dev/xconsole\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/ubuntu-9.10/remote.conf.erb",
    "content": "<% case @protocol -%>\n<% when \"tcp\" -%>\n*.* @@<%= @server %>\n<% when \"udp\" -%>\n*.* @<%= @server %>\n<% end -%>\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/rsyslog/templates/ubuntu-9.10/server.conf.erb",
    "content": "# Generated by Chef. \n# Local modifications will be overwritten.\n<% case @protocol -%>\n<% when \"tcp\" -%>\n$ModLoad imtcp\n$InputTCPServerRun 514\n<% when \"udp\" -%>\n$ModLoad imudp\n$UDPServerRun 514\n<% end -%>\n\n$DirGroup root\n$DirCreateMode 0755\n$FileGroup root\n\n$template PerHostAuth,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/auth.log\"\n$template PerHostCron,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/cron.log\"\n$template PerHostSyslog,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/syslog\"\n$template PerHostDaemon,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/daemon.log\"\n$template PerHostKern,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/kern.log\"\n$template PerHostLpr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/lpr.log\"\n$template PerHostUser,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/user.log\"\n$template PerHostMail,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.log\"\n$template PerHostMailInfo,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.info\"\n$template PerHostMailWarn,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.warn\"\n$template PerHostMailErr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.err\"\n$template PerHostNewsCrit,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.crit\"\n$template PerHostNewsErr,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.err\"\n$template PerHostNewsNotice,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.notice\"\n$template PerHostDebug,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/debug\"\n$template PerHostMessages,\"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/messages\"\n\nauth,authpriv.*         ?PerHostAuth\n*.*;auth,authpriv.none  -?PerHostSyslog\ncron.*                  ?PerHostCron\ndaemon.*                -?PerHostDaemon\nkern.*                  -?PerHostKern\nlpr.*                   -?PerHostLpr\nmail.*                  -?PerHostMail\nuser.*                  -?PerHostUser\n\nmail.info               -?PerHostMailInfo\nmail.warn               ?PerHostMailWarn\nmail.err                ?PerHostMailErr\n\nnews.crit               ?PerHostNewsCrit\nnews.err                ?PerHostNewsErr\nnews.notice             -?PerHostNewsNotice\n\n*.=debug;\\\n  auth,authpriv.none;\\\n  news.none;mail.none   -?PerHostDebug\n\n*.=info;*.=notice;*.=warn;\\\n  auth,authpriv.none;\\\n  cron,daemon.none;\\\n  mail,news.none        -?PerHostMessages\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/attributes/sv_bin.rb",
    "content": "#\n# Cookbook Name:: runit\n# Attribute File:: sv_bin\n#\n# Copyright 2008, OpsCode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nrunit Mash.new \n\ncase platform\nwhen \"ubuntu\",\"debian\"\n  runit[:sv_bin] = \"/usr/bin/sv\"\n  runit[:service_dir] = \"/etc/service\"\n  runit[:sv_dir] = \"/etc/sv\"\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/definitions/runit_service.rb",
    "content": "#\n# Cookbook Name:: runit\n# Definition:: runit_service\n#\n# Copyright 2008, OpsCode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ndefine :runit_service, :directory => nil, :only_if => false, :options => Hash.new do\n  \n  params[:directory] ||= node[:runit][:sv_dir]\n  \n  sv_dir_name = \"#{params[:directory]}/#{params[:name]}\"\n  \n  directory sv_dir_name do\n    mode 0755\n    action :create\n  end\n  \n  directory \"#{sv_dir_name}/log\" do\n    mode 0755\n    action :create\n  end\n  \n  directory \"#{sv_dir_name}/log/main\" do\n    mode 0755\n    action :create\n  end\n  \n  template \"#{sv_dir_name}/run\" do\n    mode 0755\n    source \"sv-#{params[:name]}-run.erb\"\n    if params[:options].respond_to?(:has_key?)\n      variables :options => params[:options]\n    end\n  end\n  \n  template \"#{sv_dir_name}/log/run\" do\n    mode 0755\n    source \"sv-#{params[:name]}-log-run.erb\"\n    if params[:options].respond_to?(:has_key?)\n      variables :options => params[:options]\n    end\n  end\n  \n  link \"/etc/init.d/#{params[:name]}\" do\n    to node[:runit][:sv_bin]\n  end\n  \n  link \"#{node[:runit][:service_dir]}/#{params[:name]}\" do \n    to \"#{sv_dir_name}\"\n  end\n  \n  service params[:name] do\n    supports :restart => true, :status => true\n    action :nothing\n  end\n  \n  #execute \"#{params[:name]}-down\" do\n  #  command \"/etc/init.d/#{params[:name]} down\"\n  #  only_if do params[:only_if] end\n  #end\n  \nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/files/ubuntu-6.10/runsvdir",
    "content": "start on runlevel-2\nstart on runlevel-3\nstart on runlevel-4\nstart on runlevel-5\nstop on shutdown\nrespawn /usr/sbin/runsvdir-start\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/files/ubuntu-7.04/runsvdir",
    "content": "start on runlevel 2\nstart on runlevel 3\nstart on runlevel 4\nstart on runlevel 5\nstop on shutdown\nrespawn\nexec /usr/sbin/runsvdir-start\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/files/ubuntu-7.10/runsvdir",
    "content": "start on runlevel 2\nstart on runlevel 3\nstart on runlevel 4\nstart on runlevel 5\nstop on shutdown\nrespawn\nexec /usr/sbin/runsvdir-start\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/files/ubuntu-8.04/runsvdir",
    "content": "start on runlevel 2\nstart on runlevel 3\nstart on runlevel 4\nstart on runlevel 5\nstop on shutdown\nrespawn\nexec /usr/sbin/runsvdir-start\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/metadata.json",
    "content": "{\n  \"maintainer\": \"Opscode, Inc.\",\n  \"description\": \"Installs runit and provides runit_service definition\",\n  \"recommendations\": {\n\n  },\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"suggestions\": {\n\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ],\n    \"debian\": [\n\n    ]\n  },\n  \"version\": \"0.7.0\",\n  \"recipes\": {\n    \"runit\": \"\"\n  },\n  \"name\": \"runit\",\n  \"conflicting\": {\n\n  },\n  \"attributes\": {\n    \"runit\\/service_dir\": {\n      \"default\": \"\\/etc\\/service\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Symlinks to services managed under runit\",\n      \"display_name\": \"Runit service directory\",\n      \"recipes\": [\n\n      ],\n      \"required\": false\n    },\n    \"runit\\/sv_bin\": {\n      \"default\": \"\\/usr\\/bin\\/sv\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of the sv binary\",\n      \"display_name\": \"Runit sv bin\",\n      \"recipes\": [\n\n      ],\n      \"required\": false\n    },\n    \"runit\": {\n      \"type\": \"hash\",\n      \"multiple_values\": false,\n      \"description\": \"Hash of runit attributes\",\n      \"display_name\": \"Runit\",\n      \"recipes\": [\n\n      ],\n      \"required\": false\n    },\n    \"runit\\/sv_dir\": {\n      \"default\": \"\\/etc\\/sv\",\n      \"type\": \"string\",\n      \"multiple_values\": false,\n      \"description\": \"Location of services managed by runit\",\n      \"display_name\": \"Runit sv directory\",\n      \"recipes\": [\n\n      ],\n      \"required\": false\n    }\n  },\n  \"providing\": {\n    \"runit\": [\n\n    ]\n  },\n  \"license\": \"Apache 2.0\",\n  \"long_description\": \"\",\n  \"replacing\": {\n\n  },\n  \"dependencies\": {\n\n  }\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Installs runit and provides runit_service definition\"\nversion           \"0.7\"\n\n%w{ ubuntu debian }.each do |os|\n  supports os\nend\n\nattribute \"runit\",\n  :display_name => \"Runit\",\n  :description => \"Hash of runit attributes\",\n  :type => \"hash\"\n\nattribute \"runit/sv_bin\",\n  :display_name => \"Runit sv bin\",\n  :description => \"Location of the sv binary\",\n  :default => \"/usr/bin/sv\"\n\nattribute \"runit/service_dir\",\n  :display_name => \"Runit service directory\",\n  :description => \"Symlinks to services managed under runit\",\n  :default => \"/etc/service\"\n\nattribute \"runit/sv_dir\",\n  :display_name => \"Runit sv directory\",\n  :description => \"Location of services managed by runit\",\n  :default => \"/etc/sv\"\n\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/cookbooks/runit/recipes/default.rb",
    "content": "#\n# Cookbook Name:: runit\n# Recipe:: default\n#\n# Copyright 2008, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ncase node[:platform]\nwhen \"debian\",\"ubuntu\"\n  execute \"start-runsvdir\" do\n    command value_for_platform(\n      \"debian\" => { \"default\" => \"runsvdir-start\" },\n      \"ubuntu\" => { \"default\" => \"start runsvdir\" }\n    )\n    action :nothing\n  end\n  \n  package \"runit\" do\n    action :install\n    notifies value_for_platform(\n      \"debian\" => { \"4.0\" => :run, \"default\" => :nothing  },\n      \"ubuntu\" => { \"default\" => :run }\n    ), resources(:execute => \"start-runsvdir\")\n  end\n    \n  if node[:platform_version] <= \"8.04\" && node[:platform] =~ /ubuntu/i\n    remote_file \"/etc/event.d/runsvdir\" do\n      source \"runsvdir\"\n      mode 0644\n      notifies :run, resources(:execute => \"start-runsvdir\")\n      only_if do File.directory?(\"/etc/event.d\") end\n    end\n  end\nend\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/roles/README",
    "content": "Create roles here, in either .rb or .json files. Any roles created here win vs those created in the webui.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/roles/chef-upgrade.rb",
    "content": "name \"chef-upgrade\"\ndescription \"Use this role to upgrade Chef clients and server with the Opscode Chef cookbook. Requires that nodes are using chef::client or chef::server recipes.\"\n\n# Update the version number to upgrade Chef to a newer version.\n# You may need to add an override attribute under 'chef' for 'server_path'\n# depending on your installation, eg:\n#   \"server_path\" => \"/usr/lib/ruby/gems/1.8/gems/chef-server-0.7.10\"\n# On the line after server_version. Don't forget the comma ;).\noverride_attributes(\n  \"chef\" => {\n    \"client_version\"=>\"0.7.10\",\n    \"server_version\"=>\"0.7.10\"\n  }\n)\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/README",
    "content": "This directory contains cookbooks that modify upstream ones, or that are specific to your site.\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/hosts/attributes/hosts.rb",
    "content": "hosts Mash.new unless attribute?(:hosts)"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/hosts/metadata.rb",
    "content": "maintainer        \"37signals\"\nmaintainer_email  \"sysadmins@37signals.com\"\ndescription       \"Configures hosts\"\nversion           \"0.1\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/hosts/recipes/default.rb",
    "content": "template \"/etc/hosts\" do\n  source \"hosts.erb\"\nend"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/hosts/templates/default/hosts.erb",
    "content": "127.0.0.1 localhost <%= @node[:hosts][:localhost_aliases].join(\" \") if @node[:hosts][:localhost_aliases] %>\n127.0.1.1 <%= @node['fqdn'] %> <%= @node['hostname'] %>\n\n<% if @node[:hosts][:entries] %>\n<% @node[:hosts][:entries].each do |h| %>\n<%= h.join(\" \") %>\n<% end %>\n<% end %>\n\n\n\n# The following lines are desirable for IPv6 capable hosts\n::1 ip6-localhost ip6-loopback\nfe00::0 ip6-localnet\nff00::0 ip6-mcastprefix\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\nff02::3 ip6-allhosts\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/sysadmin/recipes/default.rb",
    "content": "case node[:platform]\nwhen \"debian\", \"ubuntu\"\n  # package \"policykit\"\n  # package \"emacs22-nox\"\n  require_recipe \"apt\"\nelse \n  # package \"emacs-nox\"\nend\n\npackage \"vim\"\npackage \"tree\"\npackage \"nmap\"\npackage \"ngrep\"\npackage \"irb\"\npackage \"curl\"\npackage \"man-db\"\npackage \"strace\"\npackage \"host\"\npackage \"lsof\"\npackage \"gdb\"\npackage \"socat\"\npackage \"procmail\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/ubuntu/metadata.json",
    "content": "{\n  \"description\": \"Sets up sources for ubuntu\",\n  \"replacing\": {\n\n  },\n  \"recipes\": {\n    \"ubuntu\": \"\"\n  },\n  \"platforms\": {\n    \"ubuntu\": [\n\n    ]\n  },\n  \"maintainer\": \"Opscode, Inc.\",\n  \"version\": \"0.7.0\",\n  \"recommendations\": {\n\n  },\n  \"name\": \"ubuntu\",\n  \"maintainer_email\": \"cookbooks@opscode.com\",\n  \"attributes\": {\n\n  },\n  \"suggestions\": {\n\n  },\n  \"license\": \"Apache 2.0\",\n  \"conflicting\": {\n\n  },\n  \"dependencies\": {\n    \"apt\": [\n\n    ]\n  },\n  \"providing\": {\n    \"ubuntu\": [\n\n    ]\n  },\n  \"long_description\": \"\"\n}"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/ubuntu/metadata.rb",
    "content": "maintainer        \"Opscode, Inc.\"\nmaintainer_email  \"cookbooks@opscode.com\"\nlicense           \"Apache 2.0\"\ndescription       \"Sets up sources for ubuntu\"\nversion           \"0.7\"\ndepends           \"apt\"\nsupports          \"ubuntu\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/ubuntu/recipes/default.rb",
    "content": "#\n# Cookbook Name:: ubuntu\n# Recipe:: default\n#\n# Copyright 2008-2009, Opscode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\ntemplate \"/etc/apt/sources.list\" do\n  mode 0644\n  variables :code_name => node[:lsb][:codename]\n  source \"sources.list.erb\"\nend\n\nexecute 'opscode apt key' do\n  command \"cd /etc/apt/ && curl --output opscode.com.gpg.key http://apt.opscode.com/packages@opscode.com.gpg.key && sudo apt-key add opscode.com.gpg.key && apt-get update\" \n  creates \"/etc/apt/opscode.com.gpg.key\"\nend\n\n#include_recipe \"apt\"\n"
  },
  {
    "path": "examples/chef_cloud/chef_repo/site-cookbooks/ubuntu/templates/default/sources.list.erb",
    "content": "#\n# Ubuntu <%= @code_name %> - Generated by Chef\n#\ndeb http://apt.opscode.com/ <%= @code_name %> universe\n\ndeb http://us.archive.ubuntu.com/ubuntu <%= @code_name %> main restricted universe multiverse\ndeb-src http://us.archive.ubuntu.com/ubuntu <%= @code_name %> main restricted universe multiverse\n\ndeb http://us.archive.ubuntu.com/ubuntu <%= @code_name %>-updates main restricted universe multiverse\ndeb-src http://us.archive.ubuntu.com/ubuntu <%= @code_name %>-updates main restricted universe multiverse\n\n# \n# Security updates \n#\ndeb http://security.ubuntu.com/ubuntu <%= @code_name %>-security main restricted universe multiverse \ndeb-src http://security.ubuntu.com/ubuntu <%= @code_name %>-security main restricted universe multiverse \n"
  },
  {
    "path": "examples/chef_cloud/user_data",
    "content": "#!/bin/sh -x\necho \"Yeah, go userdata script!\"\n"
  },
  {
    "path": "examples/chef_cloud.rb",
    "content": "\npool \"poolparty\" do\n  \n  cloud \"chef\" do\n    instances 1\n    using :ec2\n    chef :solo do\n      repo File.dirname(__FILE__)+\"/chef_cloud/chef_repo\"\n      recipe \"apache2\"\n      recipe \"rsyslog::server\"\n      recipe \"collectd\"\n      attributes :apache2 => {:listen_ports => [\"80\", \"8080\"]}\n    end\n    user_data open(File.dirname(__FILE__)+\"/chef_cloud/user_data\").read\n    security_group do\n      authorize :from_port => \"22\", :to_port => \"22\"\n      authorize :from_port => \"80\", :to_port => \"80\"\n    end\n    \n  end\nend\n"
  },
  {
    "path": "examples/ec2_infrastructure_only.rb",
    "content": "require File.dirname(__FILE__)+'/../lib/poolparty.rb'\n$PP_VERBOSE=true\n\npool \"CloudteamExample\" do\n  do_not_execute = true\n\n  #TODO: declarative, serializable syntax, and allow definition outside a cloud\n  # security_group 'minerva_monitor', [\n  #   {:port=>80, :protocol=>'tcp', :network=>'0.0.0.0/0'},\n  #   {:port=>443, :protocol=>'tcp', :network=>'0.0.0.0/0'},\n  #   {:port=>22, :protocol=>'tcp', :network=>'0.0.0.0/0'},\n  #   {:port=>25826, :protocol=>'udp', :security_group=>'minerva_chacha'}\n  #  ]\n  # end\n\n  #TODO: allow definition of a load_balancer in the pool that balances between clouds, default name of pool.name\n  #TODO: default cloud load_balancer taking an array of balancer/port/protocol hashes.\n  #NOTE: loadbalancers are paid for per balancer, and are limited availabiliyt, so good to use multiple ports per LB\n  # load_balancer [ {:external_port=>80, :internal_port=>8080, :protocol=>'tcp'},\n  #                  {:external_port=>443, :internal_port=>8443, :protocol=>'tcp'} ]\n\n  cloud \"basic\" do\n    minimum_instances 1\n    maximum_instances 2\n    #keypair 'keyname' #keypair will be generated if it does not exist\n    using :ec2\n    security_group \"chaca_thin_test_group\" do\n      revoke :from_port => \"8080\", :to_port => \"8081\"  #NOTE: why have a revoke method?  closed by default, and only what is declared is open\n      authorize :from_port => \"22\", :to_port => \"22\"\n    end\n    availability_zones ['us-east-1b', 'us-east-1c']\n    load_balancer do\n      listener :external_port => 8080, :internal_port => 8080, :protocol => 'tcp'\n    end\n    autoscaler\n  end\n\nend\n\n\n\n\n\n\n\n#####################################################################################\n# Testing Stuff                                                                     #\n#####################################################################################\n\n# pool.run  #uncomment to execute the cloud\nsleep 4\nputs \"pool has been run\\n----\"\nputs \"describing current autscaling activities:\"\n\n # Set things up for amazon-ec2\n@opts={:access_key_id => ENV['EC2_ACCESS_KEY'], :secret_access_key => ENV['EC2_SECRET_KEY'], :symbolize_keys=>:snake_case}\nif ENV['EC2_URL']\n  @opts[:server] = URI.parse(ENV['EC2_URL']).host\nend\n@ec2 = AWS::EC2::Base.new(@opts)\n@elb = AWS::ELB::Base.new(@opts)\n@as = AWS::Autoscaling::Base.new(@opts)\n\n# Iterate over the clods and ensure the elb and autoscaling groups exist\npool.clouds.each do |name,cld|\n  puts \"\\ncloud[:#{name}]\\n\"\n  cld.autoscalers.each do |asg|\n    puts \"AS #{asg.first} ===========================================\\n\"\n     grp = @as.describe_autoscaling_groups['DescribeAutoScalingGroupsResult']['AutoScalingGroups']['member'].select_with_hash('AutoScalingGroupName'=>asg.first)\n     (!grp || grp.empty?) ? warn(\"ASGroup #{asg.first} was not created\") : pp(grp)\n     activities = @as.describe_scaling_activities(:autoscaling_group_name=>'cloudteam-cha')[\"DescribeScalingActivitiesResult\"][\"Activities\"][\"member\"]\n     activities.each{|act| puts act.Cause}\n  end\n  cld.load_balancers.each do |name, lb|\n    puts \"ELB #{name} ===========================================\\n\"\n    elbt = @elb.describe_load_balancers.DescribeLoadBalancersResult.LoadBalancerDescriptions.member.select_with_hash(:load_balancer_name=>name)\n    (!elbt || elbt.empty?) ? warn(\"LB #{name} was not created: #{elbt}\") : pp(elbt)\n  end\nend\n"
  },
  {
    "path": "examples/knock.sh",
    "content": "ok() {\n   exec 3>&1\n   eval `\n      exec 4>&1 >&3 3>&-\n      {\n          eval \"$@\" 2>&1 >/dev/null\n          echo \"EC=$?;\" >&4\n      } | sed 's/^/# /'\n      `\n   [ \"$EC\" = 0 ] && echo \"ok - $@\" || echo \"not ok - $@: $EC\"\n   return $EC\n}\n\n\n# example usage:\n\n # ok true\n # ok ! false\n # \n # ok \"(ok true | grep -q '^ok')\"\n # ok \"(ok false | grep -q '^not ok')\"\n # \n # # self-test\n # ok ok true\n # ok ! ok \"false\"\n # \n # ok \"(ok 'echo foo>/dev/stderr' 2>&1 | grep -q '# foo') # stderr gets commented\""
  },
  {
    "path": "examples/rds_cloud.rb",
    "content": "# example pool with RDS enabled\n\npool :poolparty do\n  cloud :app do\n    using :ec2\n\n    # this block will create an RDS DB instance\n    #   by default, the instance id will match the containing cloud\n    #   (\"poolparty-app\" in this example)\n    rds do\n      username \"admin\"                 # required\n      password \"secret\"                # required\n\n      # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~\n      # these properties have the following overridable defaults:\n      #\n      # storage 5\n      # instance_class \"db.m1.small\"\n      # engine \"db.m1.small\"\n\n\n\n      # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~\n      # by default, a user DB will be created with a name that matches the containing cloud...\n      # ...except RDS does not allow hyphens in DB names, so it will be pool name *underscore* cloud name\n      # (\"poolparty_app\" in this example).\n      #\n      # to override this, use the database method, like so:\n      # database :db1\n      #   - or -\n      # databases :production, :staging   # :databases is aliased to :database for nice DSL reading.  :)\n\n\n\n      # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~\n      # You are required to explicitly open access to the DB server to IP addresses (for outside EC2) or security groups (for inside EC2)\n      # access will be granted to your containing cloud's security groups unless you explicitly list security group authorization.\n      #\n      # to override, use the :authorize method, like so:\n      # authorize :networks => \"1.2.3.4/24\"  # <--- will authorize access to this CIDR block *in addition to* your EC2 security group\n      # authorize :networks => [\"1.2.3.4/32\", \"10.10.10.10/24\"], :security_groups => \"my_ec2_group\"\n    end\n  end\nend"
  },
  {
    "path": "examples/simple.rb",
    "content": "# the following three lines are only necessary if you want to irb -r thisfile\n$:.unshift(\"#{File.dirname(__FILE__)}/../lib\")\nrequire \"rubygems\"\nrequire \"poolparty\"\n\npool \"poolparty\" do\n  \n  cloud \"simple\" do\n    instances 1..3\n    using :ec2\n    # autoscale do      \n    #   trigger :lower_threshold => 0.3, :upper_threshold => 1.0, :measure => :cpu\n    # end\n    image_id \"ami-ccf615a5\" #alestic jaunty\n    availability_zones ['us-east-1b']\n    #TODO: accept array of hashes defining security group rules\n    # security_gropup [\n    #   {:port=>22, :protocol=>'tcp' },\n    #   {:port=>80, :protocol=>'tcp'  :source=>'10.0.0.0/8', :group=>'monitor'},\n    #   {:port=>3000..3006, :protocol=>'tcp'  :group=>'monitor' },\n    #   {:port=>53, :protocol=>'udp' }\n    # ]\n    security_group \"dummy-test-security-group\" do\n      %w(22 80 443 8642).each {|port|  authorize :from_port => port, :to_port => port}\n    end\n    # load_balancer do\n    #   listener :external_port => 8080, :internal_port => 8080, :protocol => 'tcp'\n    # end\n  end\n  \nend"
  },
  {
    "path": "lib/cloud_providers/cloud_provider.rb",
    "content": "=begin rdoc\n  CloudProvider is the base class for cloud computing services such as Ec2, Eucalyptus - where your servers run.\n=end\nmodule CloudProviders\n  class CloudProvider\n    include Dslify\n\n    default_options(\n      :image_id    => 'ami-ed46a784',\n      :user        => \"root\",\n      :bootstrap_gems => []\n    )\n\n    attr_reader :name, :init_opts\n\n    def initialize(name, init_opts={}, &block)\n      @name = name\n      if name.is_a?(Hash) && init_opts.empty?\n        @init_opts = name\n      else\n        @init_opts = init_opts\n      end\n      set_vars_from_options(init_opts)\n      instance_eval &block if block\n      after_initialized\n    end\n\n    def after_initialized\n    end\n\n    def run\n      warn \"#{self.class} does not implement run. Something is wrong\"\n    end\n\n    def default_keypair_path\n      self.class.default_keypair_path\n    end\n\n    def self.default_keypair_path\n      ENV[\"EC2_CONFIG_DIR\"] || \"#{ENV[\"HOME\"]}/.ssh\"\n    end\n\n    def bootstrap_nodes!\n    end\n\n    def method_missing(m,*a,&block)\n      if cloud && cloud.respond_to?(m)\n        cloud.send(m,*a,&block)\n      else\n        super\n      end\n    end\n\n    private\n\n    def proper_name\n      cloud.proper_name\n    end\n\n    def cloud\n      init_opts.has_key?(:cloud) ? init_opts[:cloud] : nil\n    end\n\n    def maybe(action_description, default='Y', &block)\n      puts \"About to #{action_description}. Type 'Y' to do this, 'N' to skip. #{default} will be chosen within 10 seconds.\"\n      begin\n        Timeout::timeout(10) do\n          line = $stdin.readline\n        end\n      rescue Timeout::Error => e\n        line = default\n        puts \"Timeout:  #{default} default will be used.\"\n      end\n      if line =~ /^Y/i\n        block.call\n      else\n        puts \"Skipping.\"\n      end\n    end\n\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/connections.rb",
    "content": "require \"open3\"\n\nmodule CloudProviders\n  module Connections\n        \n    # hostname or ip to use when running remote commands\n    def host(n=nil)\n      if n.nil? \n        @host ||= dns_name\n      else\n        @host = n\n      end\n    end\n    \n    def ping_port(host, port=22, retry_times=400)\n      connected = false\n      retry_times.times do |i|\n        begin\n          break if connected = TCPSocket.new(host, port).is_a?(TCPSocket)\n        rescue Exception => e\n          sleep(2)\n        end\n      end\n      connected\n    end\n    \n    def run(commands, o={})\n      ssh(commands)\n    end\n  \n    def shell_escape(str)\n      String(str).gsub(/(?=[\"'\\\\$])/n, '\\\\').\n        gsub(/\\n/, \"'\\n'\").\n        sub(/^$/, \"''\")\n    end\n\n    def ssh( commands=[], extra_ssh_ops={})\n      # commands can be single commands, as well as array\n      commands = [commands] unless commands.respond_to? :each\n\n      # Get the environment hash out of\n      # the extra_ssh_ops and then delete\n      # the element\n      ssh_error_msg=\"SSH is not available for this node. perhaps you need to authorize it?\"\n      raise PoolParty::PoolPartyError.create(\"SSHError\", ssh_error_msg) unless ssh_available?\n      env = extra_ssh_ops[:env] || {}\n      extra_ssh_ops.delete :env\n\n      # Decide to use sudo or not\n      do_sudo = user!=\"root\"\n\n      if extra_ssh_ops.has_key? :do_sudo\n        do_sudo = extra_ssh_ops[:do_sudo] \n        extra_ssh_ops.delete :do_sudo\n      end\n\n      envstring = env.collect {|k,v| \"#{k}=#{v}\"}.join ' && '\n      envstring += \" && \" unless envstring.size == 0\n      ssh_string = \"ssh #{user}@#{host} #{ssh_options(extra_ssh_ops)}\"\n\n      if commands.empty?\n        #TODO: replace this with a IO.popen call with read_nonblocking to show progress, and accept input\n        Kernel.system(ssh_string)\n      else\n        r = nil\n        commands.each do |command|\n\n          cmd = \"#{envstring}#{command}\" \n          if do_sudo\n            sudocmd = %Q% sudo sh -c \"#{shell_escape cmd}\" % \n          else\n            sudocmd = cmd\n          end\n\n          r = system_run ssh_string + %Q% \"#{shell_escape sudocmd}\"% \n        end\n        r\n      end\n    end\n\n    # remove hostname and corresponding from known_hosts file.  Avoids warning when reusing elastic_ip, and \n    # less likely, if amazone reassigns ip.  By default removes both dns_name and ip\n    def ssh_cleanup_known_hosts!(hosts=[host, public_ip])\n      hosts = [hosts] unless hosts.respond_to? :each\n      hosts.compact.each do |name|\n        system_run \"ssh-keygen -R %s\" % name\n      end\n    end\n    \n    # Take a hash of options and join them into a string, combined with default options.\n    # Default options are -o StrictHostKeyChecking=no -i keypair.full_filepath -l user\n    # {'-i'=>'keyfile, '-l' => 'fred' } would become\n    # \"-i keyfile -o StrictHostKeyChecking=no -i keypair.to_s -l fred\"\n    def ssh_options(opts={})\n      return @ssh_options if @ssh_options && opts.empty?\n      ssh_opts = {\"-i\" => keypair.full_filepath,\n           \"-o\" =>\"StrictHostKeyChecking=no\",\n           }.merge(opts)\n      @ssh_options = ssh_opts.collect{ |k,v| \"#{k} #{v}\"}.join(' ')\n    end\n    \n    def rsync( opts={} )\n      raise StandardError.new(\"You must pass a :source=>uri option to rsync\") unless opts[:source]\n      ssh_error_msg=\"SSH is not available for this node. perhaps you need to authorize it?\"\n      raise PoolParty::PoolPartyError.create(\"SSHError\", ssh_error_msg) unless ssh_available?\n      destination_path = opts[:destination] || opts[:source]\n      rsync_opts = opts[:rsync_opts] || '-va'\n      rsync_opts += %q% --rsync-path=\"sudo rsync\"% unless user==\"root\"\n      rsync_opts += %q% --exclude=.svn --exclude=.git --exclude=.cvs %\n      cmd_string =  \"rsync -L  -e 'ssh #{ssh_options}' #{rsync_opts} #{opts[:source]}  #{user}@#{host}:#{destination_path}\"\n      out = system_run(cmd_string, :quiet => true)\n      out\n    end\n    \n    def scp(opts={})\n      source = opts[:source]\n      destination_path = opts[:destination] || opts[:source]\n      raise StandardError.new(\"You must pass a local_file to scp\") unless source\n      scp_opts = opts[:scp_opts] || \"\"\n      cmd_string = \"scp #{ssh_options(scp_opts)} #{source} #{user}@#{host}:#{destination_path}\"\n      out = system_run(cmd_string)\n      out\n    end\n    \n    private\n    \n    # Execute command locally.\n    # This method is mainly broken out to ease testing in the other methods\n    # It opens the 3 IO outputs (stdin, stdout, stderr) and print the output out\n    # as the command runs, unless the quiet option is passed in\n    def system_run(cmd, o={})\n      opts = {:quiet => false, :sysread => 1024}.merge(o)\n      buf = \"\"\n      # puts(\"Running command: #{cmd}\")\n      status = Open3.popen3(cmd) do |stdout, stdin, stderr, wait_thr|\n        begin\n          while (chunk = stdin.readpartial(opts[:sysread]))\n            buf << chunk\n            unless chunk.nil? || chunk.empty?\n              if not opts[:quiet]\n                $stdout.write(chunk) #if debugging? || verbose?\n              end\n            end\n          end\n          err = stderr.readlines\n          $stderr.write_nonblock(err)\n        rescue SystemCallError => error\n          err = stderr.readlines\n          $stderr.write_nonblock(err)\n        rescue EOFError => error\n          err = stderr.readlines\n          $stderr.write_nonblock(err)\n          # used to do nothing\n        end\n        wait_thr.value\n      end\n      unless status.success?\n        warn \"Failed sshing. Check ~/.poolparty/ssh.log for details\"\n      end\n      buf\n    end\n    \n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/default/base.rb",
    "content": "module CloudProviders\n  class Base < CloudProvider\n  end\nend"
  },
  {
    "path": "lib/cloud_providers/default/helpers/base_helper.rb",
    "content": ""
  },
  {
    "path": "lib/cloud_providers/ec2/ec2.rb",
    "content": "=begin rdoc\n  EC2 CloudProvider\n  This serves as the basis for running PoolParty on Amazon's ec2 cloud.\n=end\n\nmodule CloudProviders\n  class Ec2 < CloudProvider\n    # Set the aws keys from the environment, or load from /etc/poolparty/env.yml if the environment variable is not set\n    def self.default_access_key\n      ENV['EC2_ACCESS_KEY'] || load_keys_from_file[:access_key] || load_keys_from_credential_file[:access_key]\n    end\n\n    def self.default_secret_access_key\n      ENV['EC2_SECRET_KEY'] || load_keys_from_file[:secret_access_key] || load_keys_from_credential_file[:secret_access_key]\n    end\n\n    def self.default_private_key\n      ENV['EC2_PRIVATE_KEY'] || load_keys_from_file[:private_key]\n    end\n\n    def self.default_cert\n      ENV['EC2_CERT'] || load_keys_from_file[:cert]\n    end\n\n    def self.default_user_id\n      ENV['EC2_USER_ID'] || load_keys_from_file[:user_id]\n    end\n\n    def self.default_ec2_url\n      ENV['EC2_URL'] || load_keys_from_file[:ec2_url]\n    end\n\n    def self.default_s3_url\n      ENV['S3_URL'] || load_keys_from_file[:s3_url]\n    end\n\n    def self.default_cloud_cert\n      ENV['CLOUD_CERT'] || ENV['EUCALYPTUS_CERT'] || load_keys_from_file[:cloud_cert]\n    end\n\n    def self.default_credential_file\n      ENV['AWS_CREDENTIAL_FILE'] || load_keys_from_file[:credential_file]\n    end\n\n    # Load the yaml file containing keys.  If the file does not exist, return an empty hash\n    def self.load_keys_from_file(filename=POOLPARTY_CONFIG_FILE, caching=true)\n      return @aws_yml if @aws_yml && caching==true\n      return {} unless File.exists?(filename)\n      puts(\"Reading keys from file: #{filename}\")\n      @aws_yml = YAML::load( open(filename).read ) || {}\n    end\n\n    # Load credentials from file\n    def self.load_keys_from_credential_file(filename=default_credential_file, caching=true)\n      return {:access_key => @access_key, :secret_access_key => @secret_access_key} if (@access_key && @secret_access_key && caching)\n      return {} if filename.nil? or not File.exists?(filename)\n      puts(\"Reading keys from file: #{filename}\")\n      File.open(filename).each_line do |line|\n        if line =~ /AWSAccessKeyId=([a-zA-Z0-9]+)$/\n          @access_key=$1.chomp\n        elsif line =~ /AWSSecretKey=([^   ]+)$/\n          @secret_access_key=$1.chomp\n        end\n      end\n      return {:access_key => @access_key, :secret_access_key => @secret_access_key}\n    end\n\n    default_options(\n      :instance_type          => 'm1.small',\n      :availability_zones     => [\"us-east-1a\"],\n      :user_id                => default_user_id,\n      :private_key            => default_private_key,\n      :cert                   => default_cert,\n      :cloud_cert             => default_cloud_cert,\n      :access_key             => default_access_key,\n      :secret_access_key      => default_secret_access_key,\n      :ec2_url                => default_ec2_url,\n      :s3_url                 => default_s3_url,\n      :credential_file        => default_credential_file,\n      :min_count              => 1,\n      :max_count              => 1,\n      :user_data              => '',\n      :kernel_id              => nil,\n      :ramdisk_id             => nil,\n      :block_device_mapping   => [{}],\n      :subnet_id              => nil,\n      :spot_price             => nil,\n      :launch_group           => nil,\n      :spot_persistence       => nil,\n      :disable_api_termination => nil,\n      :instance_initiated_shutdown_behavior => nil\n    )\n\n    # Called when the create command is called on the cloud\n    def create!\n      [:security_groups, :load_balancers, :rds_instances].each do |type|\n        self.send(type).each {|ele| ele.create! }\n      end\n    end\n\n    def run\n      puts \"  for cloud:         #{cloud.name}\"\n      puts \"  minimum_instances: #{minimum_instances}\"\n      puts \"  maximum_instances: #{maximum_instances}\"\n      puts \"  security_groups:   #{security_group_names.join(\", \")}\"\n      puts \"  image id:          #{image_id}\"\n      puts \"  using keypair:     #{keypair}\"\n      puts \"  with user_data:    #{user_data.to_s.inspect[0..100]} ...\"\n      puts \"  user:              #{user}\"\n      puts \"  at spot price:     #{spot_price} #{spot_persistence}\\n\" if spot_price\n\n      security_groups.each do |sg|\n        sg.run\n      end\n\n      unless rds_instances.empty?\n        rds_instances.each do |rdsi|\n          puts \"    rds instance: #{rdsi.name}\"\n          rdsi.run\n        end\n      end\n\n      if autoscalers.empty? # not using autoscaling\n        puts \"---- live, running instances (#{nodes.size}) ----\"\n        if nodes.size < minimum_instances\n          expansion_count = minimum_instances - nodes.size\n          puts \"-----> expanding the cloud because the #{expansion_count} minimum_instances is not satisified: \"\n          maybe('expand cloud') do\n            expand_by(expansion_count)\n          end\n        elsif nodes.size > maximum_instances\n          contraction_count = nodes.size - maximum_instances\n          puts \"-----> contracting the cloud because the instances count exceeds the #{maximum_instances} maximum_instances by #{contraction_count}\"\n          maybe('contract cloud') do\n            contract_by(contraction_count)\n          end\n        end\n        progress_bar_until(\"Waiting for the instances to be launched\") do\n          reset!\n          running_nodes = nodes.select {|n| n.running? }\n          running_nodes.size >= minimum_instances\n        end\n        reset!\n        # ELASTIC IPS\n      else\n        autoscalers.each do |a|\n          puts \"    autoscaler: #{a.name}\"\n          puts \"-----> The autoscaling groups will launch the instances\"\n          a.run\n\n          progress_bar_until(\"Waiting for autoscaler to launch instances\") do\n            reset!\n            running_nodes = nodes.select {|n| n.running? }\n            running_nodes.size >= minimum_instances\n          end\n          reset!\n        end\n      end\n\n      from_ports = security_groups.map {|a| a.authorizes.map {|t| t.from_port.to_i }.flatten }.flatten\n      if from_ports.include?(22)\n        progress_bar_until(\"Waiting for the instances to be accessible by ssh\") do\n          running_nodes = nodes.select {|n| n.running? }\n          accessible_count = running_nodes.map do |node|\n            node.accessible?\n          end.size\n          accessible_count == running_nodes.size\n        end\n      end\n\n      unless load_balancers.empty?\n        load_balancers.each do |lb|\n          puts \"    load balancer: #{lb.name}\"\n          lb.run\n        end\n      end\n\n      assign_elastic_ips\n      cleanup_ssh_known_hosts!\n      puts \"Attaching EBS volumes\"\n      assign_ebs_volumes # Assign EBS volumes\n    end\n\n    def teardown\n      puts \"------ Tearing down and cleaning up #{cloud.name} cloud\"\n      unless autoscalers.empty?\n        puts \"Tearing down autoscalers\"\n      end\n    end\n\n    def expand_by(num=1)\n      e = Ec2Instance.run!({\n          :image_id             => image_id,\n          :min_count            => num,\n          :max_count            => num,\n          :key_name             => keypair.basename,\n          :security_groups      => security_groups,\n          :user_data            => decoded_user_data,\n          :instance_type        => instance_type,\n          :availability_zone    => availability_zones.first,\n          :base64_encoded       => true,\n          :cloud                => cloud,\n          :block_device_mapping => block_device_mapping,\n          :subnet_id            => subnet_id,\n          :spot_price           => spot_price,\n          :launch_group         => launch_group,\n          :spot_persistence     => spot_persistence,\n          :disable_api_termination => disable_api_termination,\n          :instance_initiated_shutdown_behavior => instance_initiated_shutdown_behavior\n        })\n      return if e == 'spot instances requested'\n      progress_bar_until(\"Waiting for node to launch...\") do\n        wait_for_node(e)\n      end\n      all_nodes.detect {|n| n.instance_id == e.instance_id }\n    end\n\n    def decoded_user_data\n      if user_data\n        if File.file?(user_data)\n          open(user_data).read\n        else\n          user_data\n        end\n      end\n    end\n\n    def wait_for_node(instance)\n      reset!\n      inst = all_nodes.detect {|n| n.instance_id == instance.instance_id }\n      inst.running? if inst\n    end\n\n    def contract_by(num=1)\n      raise RuntimeError, \"Contracting instances by #{num} will lower the number of instances below specified minimum\" unless nodes.size - num > minimum_instances\n      num.times do |i|\n        node = nodes[-num]\n        id = node.instance_id\n        node.ssh_cleanup_known_hosts!\n        Ec2Instance.terminate!(:instance_id => id, :cloud => cloud)\n      end\n      reset!\n    end\n\n    def bootstrap_nodes!(tmp_path=nil)\n      unless security_groups.map {|a| a.authorizes.map {|t| t.from_port.to_i }.flatten }.flatten.include?(22)\n        warn \"Cloud security_groups are not authorized for ssh. Cannot bootstrap.\"\n        return\n      end\n      tmp_path ||= cloud.tmp_path\n      nodes.each do |node|\n        next unless node.in_service?\n        node.cloud_provider = self\n        node.rsync_dir(tmp_path)\n        node.bootstrap_chef!\n        node.run_chef!\n      end\n    end\n\n    def configure_nodes!(tmp_path=nil)\n      # removed duplicated code (now configure_nodes! invokes\n      # node.bootstrap_chef!, while old version did not, but I believe\n      # this is harmless)\n      bootstrap_nodes!(tmp_path)\n\n      ebs_volume_groups.each do |vol_grp|\n        vol_grp.verify_attachments nodes\n      end\n    end\n\n    def assign_elastic_ips\n      unless elastic_ips.empty?\n        unused_elastic_ip_addresses = ElasticIp.unused_elastic_ips(self).map {|i| i.public_ip }\n        used_elastic_ip_addresses = ElasticIp.elastic_ips(self).map {|i| i.public_ip }\n\n        elastic_ip_objects = ElasticIp.unused_elastic_ips(self).select {|ip_obj| elastic_ips.include?(ip_obj.public_ip) }\n\n        assignee_nodes = nodes.select {|n| !ElasticIp.elastic_ips(self).include?(n.public_ip) }\n\n        elastic_ip_objects.each_with_index do |eip, idx|\n          # Only get the nodes that do not have elastic ips associated with them\n          begin\n            if assignee_nodes[idx]\n              puts \"Assigning elastic ip: #{eip.public_ip} to node: #{assignee_nodes[idx].instance_id}\"\n              ec2.associate_address(:instance_id => assignee_nodes[idx].instance_id, :public_ip => eip.public_ip)\n            end\n          rescue Exception => e\n            p [:error, e.inspect]\n          end\n          reset!\n        end\n      end\n    end\n\n    def cleanup_ssh_known_hosts!(nodes_to_cleanup=nodes,\n                                 even_unavailable=false)\n      puts \"cleaning up .ssh/known_hosts\"\n      nodes_to_cleanup.find_all do |node|\n        even_unavailable || node.ssh_available?\n      end.each do |node|\n        node.ssh_cleanup_known_hosts!\n      end\n    end\n\n    def nodes\n      all_nodes.select {|i| i.in_service? }#describe_instances.select {|i| i.in_service? && security_groups.include?(i.security_groups) }\n    end\n\n    # === Description\n    #\n    # Return all the security groups of the instance that are prefixed with #poolparty.\n    #\n    # These are special security groups used only for tagging\n    #\n    # === Parameters\n    #   instance    -   An ec2 instance as returned from describe_instances\n    def tags(instance)\n      return [] if instance.groupSet.nil? || instance.groupSet.item.empty?\n      instance.groupSet.item.collect{|g| g.groupId }.select {|s| s.start_with? \"#poolparty\"}\n    end\n\n    def all_nodes\n      @nodes ||= describe_instances.select { |i|\n        !(security_group_names & tags(i)).empty?\n      }.sort {|a,b|\n        DateTime.parse(a.launchTime) <=> DateTime.parse(b.launchTime)\n      }\n    end\n\n    # Describe instances\n    # Describe the instances that are available on this cloud\n    # @params id (optional) if present, details about the instance\n    # with the id given will be returned\n    # if not given, details for all instances will be returned\n    def describe_instances(id=nil)\n      begin\n        @describe_instances = ec2.describe_instances.reservationSet.item.map do |r|\n          r.instancesSet.item.map do |i|\n            inst_options = i.merge(r.merge(:cloud => cloud)).merge(cloud.cloud_provider.dsl_options)\n            Ec2Instance.new(inst_options)\n          end\n        end.flatten\n      rescue AWS::InvalidClientTokenId => e # AWS credentials invalid\n        puts \"Error contacting AWS: #{e}\"\n        raise e\n      rescue Exception => e\n        []\n      end\n    end\n\n    # Extras!\n\n    def block_device_mapping(o=[], given_name=cloud.proper_name )\n      @mappings ||= o\n    end\n\n    def load_balancer(given_name=cloud.proper_name, o={}, &block)\n      load_balancers << ElasticLoadBalancer.new(given_name, sub_opts.merge(o || {}), &block)\n    end\n    def autoscale(given_name=cloud.proper_name, o={}, &block)\n      autoscalers << ElasticAutoScaler.new(given_name, sub_opts.merge(o || {}), &block)\n    end\n    def security_group(given_name=cloud.proper_name, o={}, &block)\n      existing_security_group = security_groups.detect{|grp| grp.name == given_name }\n      if existing_security_group\n        existing_security_group.merge!(sub_opts.merge(o || {}), &block)\n      else\n        security_groups << SecurityGroup.new(given_name, sub_opts.merge(o || {}), &block)\n      end\n    end\n    def elastic_ip(*ips)\n      ips.each {|ip| elastic_ips << ip}\n    end\n\n    def rds(given_name=cloud.proper_name, o={}, &block)\n      rds_instances << RdsInstance.new(given_name, sub_opts.merge(o || {}), &block)\n    end\n\n    def available_rds_instances\n      rds_instances.select{|r| r.available? }\n    end\n    \n    # prepare options for AWS gem\n    def aws_options(opts={})\n      uri=URI.parse(ec2_url)\n      { :access_key_id    => access_key, \n        :secret_access_key=> secret_access_key, \n        :use_ssl          => (uri.scheme=='https'), \n        :path             => uri.path, \n        :host             => uri.host,\n        :port             => uri.port\n      }.merge(opts)\n      \n    end\n\n    # Proxy to the raw Grempe amazon-aws @ec2 instance\n    def ec2\n      @ec2 ||= begin\n       AWS::EC2::Base.new( aws_options )\n      rescue AWS::ArgumentError => e # AWS credentials missing?\n        puts \"Error contacting AWS: #{e}\"\n        raise e\n      rescue Exception => e\n        puts \"Generic error #{e.class}: #{e}\"\n      end\n    end\n\n    # Proxy to the raw Grempe amazon-aws autoscaling instance\n    def as\n      @as = AWS::Autoscaling::Base.new( aws_options )\n    end\n\n    # Proxy to the raw Grempe amazon-aws elastic_load_balancing instance\n    def elb\n      @elb ||= AWS::ELB::Base.new( aws_options )\n    end\n\n    def awsrds\n      @awsrds ||= AWS::RDS::Base.new( aws_options )\n    end\n\n    def security_group_names\n      security_groups.map {|a| a.to_s }\n    end\n    def security_groups\n      @security_groups ||= []\n    end\n    def load_balancers\n      @load_balancers ||= []\n    end\n    def autoscalers\n      @autoscalers ||= []\n    end\n    def elastic_ips\n      @elastic_ips ||= []\n    end\n\n    def ebs_volume_groups\n      @ebs_volume_groups ||= []\n    end\n\n    # dsl method for EBS volumes. E.G.:\n    #   ebs_volumes do\n    #     volumes \"vol-001248ff\", \"vol-01ff4b85\" # use existing volumes, not mandatory\n    #     device \"/dev/sdf\"\n    #     snapshot_id \"snap-602030dd\"\n    #     size 200\n    #   end\n    def ebs_volumes(name=nil, &block)\n      ebs_volume_groups << ElasticBlockStoreGroup.new(sub_opts,&block) if block\n    end\n\n    def assign_ebs_volumes\n      ebs_volume_groups.each{|ebs_volume_group| ebs_volume_group.attach(nodes)}\n    end\n\n    def rds_instances\n      @rds_instances ||= []\n    end\n\n    # Clear the cache\n    def reset!\n      @nodes = @describe_instances = nil\n    end\n\n    # Get existing volumes on EC2. filters is a hash of filters, either single valued or multivalued (value is an array of possible values).\n    # The function will return volumes matching *all* filters. A volume is a filter match if *any* one of the filter values equals the volume parameter value.\n    def list_ec2_volumes(filters=nil)\n      @volumes_on_ec2=ec2.describe_volumes.volumeSet.item unless @volumes_on_ec2\n      (if filters.nil? # no filter to check, so return at once\n        @volumes_on_ec2\n      else\n        @volumes_on_ec2.select{|vol| # select volumes for which no filter failed\n          not filters.map {|filter_key, filter_val|\n            filter_key=filter_key.to_s if filter_key.is_a?(Symbol) # filter_key may be given as a symbol\n            raise ArgumentError, \"Filter key #{filter_key} is invalid\" unless vol.has_key?(filter_key)\n            if filter_val.is_a?(Array) # Deal with multiple filter values\n              filter_val.map{|val| val.is_a?(String) ? val : val.to_s}.member?(vol[filter_key]) # make sure fiter_val array values are Strings before checking for match\n            else\n              (filter_val.is_a?(String) ? filter_val : filter_val.to_s)==vol[filter_key] # make sure fiter_val is a String before comparing\n            end\n            }.member?(false) # Check if a filter failed, the 'not' statement at the beginning of the map block negates this so 'select' will choose only when no filter failed\n          }.compact # remove nil results from volume set.\n        end\n        ).map{|vol| ElasticBlockStore.new(vol,:cloud => cloud)}\n    end\n\n    # Read credentials from credential_file if one exists\n    def credential_file(file=nil)\n      unless file.nil?\n        dsl_options[:credential_file]=file\n        dsl_options.merge!(Ec2.load_keys_from_credential_file(file))\n      else\n        fetch(:credential_file)\n      end\n    end\n\n    private\n    # Helper to get the options with self as parent\n    def sub_opts\n      dsl_options.merge(:parent => self, :cloud => cloud)\n    end\n    def generate_keypair(n=nil)\n      puts \"[EC2] generate_keypair is called with #{default_keypair_path/n}\"\n      begin\n        hsh = ec2.create_keypair(:key_name => n)\n        string = hsh.keyMaterial\n        FileUtils.mkdir_p default_keypair_path unless File.directory?(default_keypair_path)\n        puts \"[EC2] Generated keypair #{default_keypair_path/n}\"\n        puts \"[EC2] #{string}\"\n        File.open(default_keypair_path/n, \"w\") {|f| f << string }\n        File.chmod 0600, default_keypair_path/n\n      rescue Exception => e\n        puts \"[EC2] The keypair exists in EC2, but we cannot find the keypair locally: #{n} (#{e.inspect})\"\n      end\n      keypair n\n    end\n\n  end\nend\n\nrequire \"#{File.dirname(__FILE__)}/ec2_instance\"\nrequire \"#{File.dirname(__FILE__)}/helpers/ec2_helper\"\n%w( security_group\n    authorize\n    elastic_auto_scaler\n    elastic_block_device_mapping\n    elastic_block_store\n    elastic_block_store_group\n    elastic_load_balancer\n    elastic_ip\n    rds_instance\n    revoke).each do |lib|\n  require \"#{File.dirname(__FILE__)}/helpers/#{lib}\"\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/ec2_instance.rb",
    "content": "module CloudProviders\n  class Ec2Instance < RemoteInstance\n\n    default_options(\n      :security_groups      => [],\n      :private_ip           => nil,\n      :dns_name             => nil,\n      :instance_type        => nil,\n      :public_ip            => nil,\n      :key_name             => nil,\n      :launch_time          => nil,\n      :availability_zones   => [],\n      :block_device_mapping => [{}],\n      :subnet_id            => nil,\n      :spot_price           => nil,\n      :launch_group         => nil,\n      :spot_persistence     => nil,\n      :disable_api_termination => nil,\n      :instance_initiated_shutdown_behavior => nil\n    )\n\n    def initialize(raw_response={})\n      @raw_response = raw_response\n      self.instance_id                          = raw_response[\"instanceId\"] rescue nil\n      self.security_groups                      = raw_response.groupSet.item.map{|sg| sg.groupId }.sort rescue nil\n      self.image_id                             = raw_response[\"imageId\"] rescue nil\n      self.private_ip                           = raw_response[\"privateIpAddress\"] rescue nil\n      self.dns_name                             = raw_response[\"dnsName\"] rescue nil\n      self.instance_type                        = raw_response[\"instanceType\"] rescue nil\n      self.public_ip                            = raw_response[\"ipAddress\"] rescue nil\n      self.key_name                             = raw_response[\"keyName\"] rescue nil\n      self.launch_time                          = raw_response[\"launchTime\"] rescue nil\n      self.availability_zones                   = raw_response[\"placement\"][\"availabilityZone\"] rescue nil\n      self.status                               = raw_response[\"instanceState\"][\"name\"] rescue nil\n      self.block_device_mapping                 = raw_response[\"blockDeviceMapping\"] rescue nil\n      self.subnet_id                            = raw_response[\"subnetId\"] rescue nil\n      self.launch_group                         = raw_response[\"launchGroup\"] rescue nil\n      # disable_api_termination and instance_initiated_shutdown_behavior don't currently get returned in the request -- you'd need to later call describe_instance_attribute\n      self.disable_api_termination              = raw_response[\"disableApiTermination\"] rescue nil\n      self.instance_initiated_shutdown_behavior = raw_response[\"instanceInitiatedShutdownBehavior\"] rescue nil\n      super\n    end\n\n    def keypair(n=nil)\n      return @keypair if @keypair\n      @keypair = (cloud.keypair.basename == self.key_name) ? cloud.keypair : Keypair.new(self.key_name, cloud.keypair.extra_paths)\n    end\n\n    def security_group_names\n      security_groups.map{|a| a.to_s }\n    end\n\n    def zone\n      availability_zones.first\n    end\n\n    def reachable?\n      ping_port self.public_ip, 22\n    end\n\n    def ssh_available?\n      cloud.security_groups.map {|a|\n        a.authorizes.map {|t| t.from_port.to_i }.flatten\n      }.flatten.include?(22) and\n        reachable? and\n        in_service? and\n        keypair and keypair.exists?\n    end\n\n    def in_service?\n      running?\n    end\n\n    def run!\n      if spot_price.to_f > 0\n        request_spot_instances!\n      else\n        launch_instances!\n      end\n    end\n    def self.run!(hsh); new(hsh).run!; end\n\n    def launch_instances!\n      r = cloud_provider.ec2.run_instances(\n        :image_id             => image_id,\n        :min_count            => min_count,\n        :max_count            => max_count,\n        :key_name             => keypair.basename,\n        :security_group       => cloud.security_group_names,\n        :user_data            => user_data,\n        :instance_type        => instance_type,\n        :availability_zone    => availability_zone,\n        :block_device_mapping => block_device_mapping,\n        :disable_api_termination => disable_api_termination,\n        :instance_initiated_shutdown_behavior => instance_initiated_shutdown_behavior,\n        :base64_encoded       => true)\n      r.instancesSet.item.map do |i|\n        inst_options = i.merge(r.merge(:cloud => cloud)).merge(cloud.cloud_provider.dsl_options)\n        Ec2Instance.new(inst_options)\n      end.first\n    end\n\n    def request_spot_instances!\n      r = cloud_provider.ec2.request_spot_instances(\n        :spot_price           => spot_price.to_s,\n        :launch_group         => launch_group.to_s,\n        :instance_count       => max_count,\n        :type                 => spot_persistence,\n        # TODO: valid_from, valid_until, availability_zone_group\n        :image_id             => image_id,\n        :key_name             => keypair.basename,\n        :security_group       => cloud.security_group_names,\n        :user_data            => user_data,\n        :instance_type        => instance_type,\n        :availability_zone    => availability_zone,\n        :block_device_mapping => block_device_mapping,\n        :launch_group         => launch_group,\n        :base64_encoded       => true)\n      p r\n      return 'spot instances requested'\n    end\n\n    def terminate!\n      cloud_provider.ec2.terminate_instances(:instance_id => [self.instance_id])\n      cloud_provider.reset!\n    end\n    def self.terminate!(hsh={}); new(hsh).terminate!; end\n\n    # list of directories and files to exclude when bundling an instance\n    def rsync_excludes(array_of_abs_paths_to_exclude=nil)\n      array_of_abs_paths_to_exclude ||= %w[\n            /sys\n            /proc\n            /dev/pts\n            /dev\n            /media\n            /mnt\n            /proc\n            /sys\n            /etc/ssh/ssh_host_*\n            /etc/ssh/moduli\n            /etc/udev/rules.d/70-persistent-net.rules\n            /etc/udev/rules.d/z25_persistent-net.rules\n            ]\n      array_of_abs_paths_to_exclude.inject(''){|str, path| str << \"--exclude=#{path}\" ; str}\n    end\n\n    # create an image file and copy this instance to the image file.\n    def make_image(opts={})\n      opts = {:volume       => '/',\n              :size         => 6000,\n              :destination  => '/mnt/bundle',\n              :exclude      => nil\n              }.merge(opts)\n      image_file = File.join(opts[:destination], opts[:prefix] )\n      cmds = [\"mkdir -p #{opts[:destination]}\"]\n      cmds << \"dd if=/dev/zero of=#{image_file} bs=1M count=#{opts[:size]}\"\n      cmds << \"mkfs.ext3 -F -j #{image_file}\"\n      cmds << \"mkdir -p #{opts[:destination]}/loop\"\n      cmds << \"mount -o loop #{image_file} #{opts[:destination]}/loop\"\n      cmds << \"rsync -ax #{rsync_excludes(opts[:exclude])} #{opts[:volume]}/ #{opts[:destination]}/loop/\"\n      cmds << \"if [[ -f /etc/init.d/ec2-ssh-host-key-gen ]]; then chmod u+x /etc/init.d/ec2-ssh-host-key-gen ;fi\"\n      cmds << \"umount #{opts[:destination]}/loop\"\n      self.ssh cmds\n      image_file\n    end\n\n    # TODO: WIP:  bundle up the instance and register it as a new ami.\n    # An image of the running node will be creatd, or\n    # if a path to an image file on the remote node is given, that will be used\n    def bundle_and_register(img=nil, opts={})\n      opts = {:cert         => cert,\n              :bucket       => nil,\n              :prefix       => image_id,\n              :kernel       => kernel_id,\n              :ramdisk      => ramdisk_id,\n              :ec2cert      => cloud_cert\n              }.merge(opts)\n      raise \"You must specify a bucket to bundle to\" if opts[:bucket].nil?\n      scp ec2cert, \"/mnt/bundle/\"\n      scp cert, \"/mnt/bundle/\"\n      arch = self[:instanceType].match(/m1\\.small|c1\\.medium/) ? 'i386' : 'x86_64'\n      image = img ? img : make_image(opts)\n      ssh \"ec2-bundle-image #{image} -d /mnt/bundle -u #{self[:ownerId]} -k /mnt/bundle/pk-*.pem -c /tmp/cert-*.pem\"\n      manifest = \"/mnt/bundle/#{opts[:prefix]}.manifest.xml\"\n      ssh \"ec2-upload-bundle -a #{access_key} -s #{secret_access_key} -m #{manifest}\"\n      ami_str = ssh \"ec2-register-bundle\"\n      ami = ami_str.grep(/ami-\\w*/).first\n      return ami\n    end\n\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/authorize.rb",
    "content": "module CloudProviders\n  class Authorize < Ec2Helper\n    default_options({\n                :protocol   => \"tcp\",\n                :from_port  => \"22\",\n                :to_port    => \"22\",\n                :network    => \"0.0.0.0/0\",\n                :group_name => nil,\n                :owner_id   => nil})\n    \n    def run\n      options = \n      if group_name\n        puts \"Authorizing #{name} for group named: #{group_name} of owner id: #{owner_id}\"\n        {:group_name => name, :source_security_group_name=> group_name, :source_security_group_owner_id => owner_id}\n      else\n        puts \"Authorizing: #{name} for #{protocol} to #{from_port}:#{to_port} #{network}\"\n        to_hash\n      end\n      begin\n        ec2.authorize_security_group_ingress(options) \n      rescue AWS::InvalidPermissionDuplicate => e\n        nil\n      end\n        \n    end\n    \n    def to_hash\n      if group_name\n        {:group_name => group_name}\n      else\n        {\n          :group_name   => name,\n          :ip_protocol  => protocol,\n          :from_port    => from_port,\n          :to_port      => to_port,\n          :cidr_ip      => network\n        }\n      end\n    end\n    \n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/ec2_helper.rb",
    "content": "module CloudProviders\n  class Ec2Helper < CloudProvider\n\n    def initialize(name=cloud.proper_name, init_opts={}, &block)\n      @name = name\n      if name.is_a?(Hash)\n        @name = name[:name]\n        @init_opts = name if init_opts.empty?\n      else\n        @init_opts = init_opts\n      end\n      set_vars_from_options(init_opts)\n      instance_eval &block if block\n      after_initialized\n    end\n\n    def elb\n      cloud.elb\n    end\n\n    def ec2\n      cloud.ec2\n    end\n\n    def as\n      cloud.as\n    end\n\n    def rds\n      cloud.awsrds\n    end\n\n    def pool\n      cloud.parent\n    end\n\n    def self.property(*names)\n      names.each do |name|\n        define_method name do |*args|\n          instance_variable_set(\"@#{name}\", args.first) unless args.empty?\n          instance_variable_get(\"@#{name}\")\n        end\n      end\n    end\n\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_auto_scaler.rb",
    "content": "module CloudProviders\n  class ElasticAutoScaler < Ec2Helper\n    default_options(\n      :cooldown => nil,\n      :desired_capacity => nil\n    )\n    def run      \n      if should_create_autoscaling_group?\n        puts \"Creating autoscaling group\"\n        create_launch_configuration!\n        create_autoscaling_group!\n      else\n        puts \"-----> Checking for launch configuration named: #{old_launch_configuration_name}\"\n        if should_create_launch_configuration?\n          create_launch_configuration!\n        elsif should_update_launch_configuration? || should_update_autoscaling_group?\n          update_launch_configuration!\n          \n          puts \"Updating autoscaling group\"\n          update_autoscaling_group!\n          puts \"Deleting old launch configuration: #{old_launch_configuration_name}\"\n          as.delete_launch_configuration(:launch_configuration_name => old_launch_configuration_name)\n        end\n      end\n      \n      triggers.each do |trigger|\n        trigger.run\n      end\n    end\n    \n    # First, change the min_count to \n    def teardown\n      triggers.each do |trigger|\n        trigger.teardown\n      end\n      if autoscaling_groups.select {|n| n.name == name }.empty?\n        puts \"Cloud #{cloud.name} autoscaling group does not exist\"\n      else\n        self.minimum_instances = 0\n        self.maximum_instances = 0\n        @new_launch_configuration_name = old_launch_configuration_name\n        puts \"Updating autoscaling group: #{@new_launch_configuration_name}\"\n        update_autoscaling_group!\n        puts \"Terminating nodes in autoscaling group: #{name}\"\n        reset!\n        # cloud.nodes.each {|n| n.terminate! }\n        delete_autoscaling_group!\n        delete_launch_configuration!\n        puts \"\"\n      end\n    end\n    \n    private\n    def delete_autoscaling_group!\n      ensure_no_scaling_activities\n      reset!\n      begin\n        as.delete_autoscaling_group(:autoscaling_group_name => name)\n      rescue AWS::Error => e\n        if e.message =~ /You cannot delete an AutoScalingGroup while there are scaling activities in progress/\n          delete_autoscaling_group!\n        end\n      rescue Exception => e\n        p e.inspect\n      end\n    end\n    def delete_launch_configuration!(n=new_launch_configuration_name)\n      ensure_no_scaling_activities\n      as.delete_launch_configuration(:launch_configuration_name => n)\n    end\n    def ensure_no_scaling_activities\n      # loop do\n      #   reset!\n      #   activities = scaling_activities.select {|a| !a[:complete] }\n      #   running_nodes = cloud.nodes.select {|n| n.running? }\n      #   if activities.empty? && running_nodes.empty?\n      #     break\n      #   else\n      #     $stdout.print \".\"\n      #     $stdout.flush\n      #     sleep 1\n      #   end\n      # end\n      progress_bar_until do\n        reset!\n        activities = scaling_activities.select {|a| !a[:complete] }\n        running_nodes = cloud.nodes.select {|n| n.running? }\n        activities.empty? && running_nodes.empty?\n      end\n      reset!\n    end\n    public\n    def should_create_autoscaling_group?\n      known = autoscaling_groups.select {|ag| ag.name == cloud.proper_name }\n      if known.empty?\n        true\n      else\n        puts \"Autoscaling group already defined...: #{name}\"\n        false\n      end\n    end\n    def should_create_launch_configuration?\n      known = launch_configurations.select {|lc| lc.name =~ /#{name}/ }\n      if known.empty?\n        true\n      else\n        false\n      end\n    end\n    def should_update_launch_configuration?\n      known = launch_configurations.select {|lc| lc.name =~ /#{name}/ }\n      if known.empty?\n        true\n      else\n        differences = known.map do |k|\n          t = k.diff({\n            :image_id => image_id,\n            :instance_type => instance_type,\n            :security_groups => parent.security_group_names.flatten,\n            :key_name => keypair.to_s,\n            :user_data => user_data,\n            }, :user_data, :image_id, :instance_type, :security_groups, :key_name)\n          t.empty? ? nil : t\n        end.reject {|a| a.nil? }\n        if differences.empty?\n          false\n        else\n          true\n        end\n      end\n    end\n    def update_launch_configuration!\n      create_launch_configuration!\n    end\n    def create_launch_configuration!(lc=new_launch_configuration_name)\n      puts \"-----> Creating launch configuration: #{new_launch_configuration_name} for #{proper_name}\"\n      begin\n        @launch_configuration_name = lc\n        as.create_launch_configuration({\n          :launch_configuration_name => new_launch_configuration_name,\n          :image_id => image_id,\n          :instance_type => instance_type,\n          :security_groups => parent.security_group_names,\n          :key_name => keypair.to_s,\n          :user_data => user_data,\n          :kernel_id => kernel_id,\n          :ramdisk_id => ramdisk_id,\n          :block_device_mapping => block_device_mapping\n        })\n      rescue Exception => e\n        puts <<-EOE\n-----> There was an error: #{e.inspect} when creating the launch_configurations\n        EOE\n      ensure\n        reset!\n      end\n    end\n    def launch_configurations\n      begin\n        @launch_configurations ||= as.describe_launch_configurations.DescribeLaunchConfigurationsResult.LaunchConfigurations.member.map do |a|\n          {\n            :name => a[\"LaunchConfigurationName\"],\n            :ramdisk_id => a[\"RamdiskId\"],\n            :image_id => a[\"ImageId\"],\n            :security_groups => (a[\"SecurityGroups\"][\"member\"] rescue [\"default\"]),\n            :created_time => a[\"CreatedTime\"],\n            :user_data => a[\"UserData\"] || \"\",\n            :key_name => a[\"KeyName\"],\n            :instance_type => a[\"InstanceType\"]\n          }\n        end\n      rescue Exception => e\n        []\n      end\n    end\n    def create_autoscaling_group!\n      as.create_autoscaling_group({\n        :autoscaling_group_name => name,\n        :availability_zones => availability_zones,\n        :launch_configuration_name => new_launch_configuration_name,\n        :min_size => minimum_instances.to_s,\n        :max_size => maximum_instances.to_s,\n        :load_balancer_names => load_balancers.map {|lb| lb.name }\n      })\n      reset!\n    end\n    \n    def should_update_autoscaling_group?\n      known = autoscaling_groups.select {|lc| lc.name =~ /#{name}/ }\n      if known.empty?\n        true\n      else\n        differences = known.map do |k|\n          hsh = {\n            :min_size => minimum_instances.to_s, :max_size => maximum_instances.to_s,\n            :availability_zones => availability_zones,\n            :launch_configuration_name => old_launch_configuration_name\n          }\n          hsh.merge!(:cooldown => cooldown.to_s) if cooldown\n          \n          t = hsh.diff(k, :cooldown,\n                          :min_size,\n                          :max_size, \n                          :availability_zones, \n                          :launch_configuration_name)\n          t.empty? ? nil : t\n        end.reject {|a| a.nil? }\n        if differences.empty?\n          false\n        else\n          puts \"-----> Recreating the autoscaling group as details have changed: #{differences.inspect}\"\n          true\n        end\n      end\n    end\n    \n    def update_autoscaling_group!\n      as.update_autoscaling_group(\n        :autoscaling_group_name => name,\n        :availability_zones => availability_zones.first, # TODO: Figure out how to support multiple availability_zones\n        :launch_configuration_name => new_launch_configuration_name,\n        :min_size => minimum_instances.to_s,\n        :max_size => maximum_instances.to_s,\n        :cooldown => cooldown.to_s,\n        :load_balancer_names => load_balancers.map {|lb| lb.name }\n      )\n    end\n    \n    def autoscaling_groups\n      @autoscaling_groups ||= as.describe_autoscaling_groups.DescribeAutoScalingGroupsResult.AutoScalingGroups.member.map do |g|\n        {\n          :cooldown => g[\"Cooldown\"],\n          :desired_capacity => g[\"DesiredCapacity\"],\n          :created_time => g[\"CreatedTime\"],\n          :min_size => g[\"MinSize\"],\n          :max_size => g[\"MaxSize\"],\n          :load_balancer_names => (g[\"LoadBalancerNames\"][\"member\"] rescue []),\n          :availability_zones => (g[\"AvailabilityZones\"][\"member\"] rescue []),\n          :launch_configuration_name => g[\"LaunchConfigurationName\"],\n          :name => g[\"AutoScalingGroupName\"],\n          :instances => (g[\"Instances\"][\"member\"] rescue []).map {|i|\n            {:instance_id => i[\"InstanceId\"],\n            :state => i[\"LifecycleState\"],\n            :availability_zone => i[\"AvailabilityZone\"]\n          }}\n        }\n      end rescue []\n    end\n    def scaling_activities\n      @scaling_activities ||= as.describe_scaling_activities(:autoscaling_group_name => name).DescribeScalingActivitiesResult.Activities.member.map do |action|\n        {\n          :cause        => action[\"Cause\"],\n          :progress     => action[\"Progress\"].to_i,\n          :activity_id  => action[\"ActivityId\"],\n          :description  => action[\"Description\"],\n          :status_code  => action[\"StatusCode\"],\n          :complete     => action[\"StatusCode\"] == \"Pending\" ? false : true,\n          :start_time   => action[\"StartTime\"]\n        }\n      end rescue []\n    end\n    # Temporary names so we can create and recreate launch_configurations\n    def new_launch_configuration_name\n      @new_launch_configuration_name ||= \"#{name}#{used_launched_config_id.zero? ? 1 : 0}\"\n    end\n    def old_launch_configuration_name\n      @old_launch_configuration_name ||= \"#{name}#{used_launched_config_id.zero? ? 0 : 1}\"\n    end\n    # Compute the next configuration launch id. We'll be cycling through the usage of 0 and 1\n    # Here we are just looking for which one that is, either zero or 1\n    def used_launched_config_id\n      return @used_launched_config_id if @used_launched_config_id\n      used_configuration_names = launch_configurations.map {|hsh| hsh[:name] =~ /#{name}/ ? hsh[:name] : nil }.reject {|a| a.nil?}\n      used_launched_config_id = used_configuration_names.map {|a| a.gsub(/#{name}/, '').to_i }.reject {|a| a.zero? }.first\n      used_launched_config_id = 0 if used_launched_config_id.nil?\n      @used_launched_config_id = used_launched_config_id\n    end\n    \n    def new_auto_scaling_group_name\n      @new_auto_scaling_group_name ||= \"#{name}#{used_autoscaling_group_id.zero? ? 1 : 0}\"\n    end\n    \n    def old_auto_scaling_group_name\n      @old_auto_scaling_group_name ||= \"#{name}#{used_autoscaling_group_id.zero? ? 0 : 1}\"\n    end\n    \n    def used_autoscaling_group_id\n      return @used_autoscaling_group_id if @used_autoscaling_group_id\n      used_autoscaling_groups = launch_configurations.map {|hsh| hsh[:name] =~ /#{name}/ ? hsh[:name] : nil }.reject {|a| a.nil?}\n      used_autoscaling_group_id = used_autoscaling_groups.map {|a| a.gsub(/#{name}/, '').to_i }.reject {|a| a.zero? }.first\n      used_autoscaling_group_id = 0 if used_autoscaling_group_id.nil?\n      @used_autoscaling_group_id ||= used_autoscaling_group_id\n    end\n    \n    # Convenience methods\n    # Return an array of hashes describing the autoscaling groups\n    def list\n      describe_autoscaling_groups.DescribeAutoScalingGroupsResult.AutoScalingGroups.member\n    end\n    \n    def trigger(*trigger_hashes)\n      trigger_hashes.each do |hsh, blk|\n        triggers << ElasticTrigger.new(name, hsh.merge(:cloud => cloud), &blk)\n      end\n    end\n    \n    private\n    def triggers\n      @triggers ||= []\n    end\n    def reset!\n      @old_auto_scaling_group_name = \n        @new_auto_scaling_group_name = \n          @autoscaling_groups = @scaling_activities =\n            @launch_configurations = nil\n      cloud.reset!\n    end\n  end\n  class ElasticTrigger < Ec2Helper\n    default_options(\n      :measure => :cpu,\n      :period => 60,\n      :statistic => :average,\n      :unit => \"Percent\",\n      :lower_threshold => 20,\n      :upper_threshold => 60,\n      :trigger_name => \"CpuTrigger\",\n      :lower_breach_scale_increment => -1,\n      :upper_breach_scale_increment => 1,\n      :breach_duration => 120,\n      :namespace => 'AWS/EC2'\n    )\n    \n    def measure_names\n      {:cpu => \"CPUUtilization\"}\n    end\n    \n    def statistic_names\n      {:min => \"Minimum\", :max => \"Maximum\", :average => \"Average\", :sum => \"Sum\"}\n    end\n        \n    def run\n      if autoscaling_triggers.empty?\n        create_autoscaling_trigger!\n      else\n        t = autoscaling_triggers.map do |hsh|\n          diff(hsh)\n        end.flatten\n        unless t.empty?\n          puts \"Creating or updating trigger: #{trigger_name}\"\n          create_autoscaling_trigger!\n        end\n      end\n    end\n    \n    def teardown\n      autoscaling_triggers.each do |trigger|\n        puts \"Deleting trigger: #{trigger[:trigger_name]}\"\n        as.delete_trigger(:trigger_name => trigger[:trigger_name], :autoscaling_group_name => name)\n      end\n    end\n    \n    def diff(hsh={})\n      [ :measure_name, \n        :period, \n        :statistic, \n        :lower_threshold, \n        :lower_breach_scale_increment, \n        :upper_threshold, \n        :upper_breach_scale_increment,\n        :unit,\n        :trigger_name].reject do |k|\n        hsh[k].to_s.capitalize == self.send(k).to_s.capitalize\n      end\n    end\n    \n    private\n    \n    def autoscaling_triggers\n      begin\n        as.describe_triggers(:autoscaling_group_name => name).DescribeTriggersResult.Triggers.member.map do |trigger|\n          {\n            :trigger_name => trigger[\"TriggerName\"],\n            :statistic => trigger[\"Statistic\"],\n            :status => trigger[\"Status\"],\n            :lower_threshold => trigger[\"LowerThreshold\"],\n            :created_time => trigger[\"CreatedTime\"],\n            :measure_name => trigger[\"MeasureName\"],\n            :upper_threshold => trigger[\"UpperThreshold\"],\n            :lower_breach_scale_increment => trigger[\"LowerBreachScaleIncrement\"],\n            :period => trigger[\"Period\"],\n            :upper_breach_scale_increment => trigger[\"UpperBreachScaleIncrement\"],\n            :breach_duration => trigger[\"BreachDuration\"],\n            :dimensions => trigger[\"Dimensions\"],\n            :unit => trigger[\"Unit\"],\n            :autoscaling_group_name => trigger[\"AutoScalingGroupName\"],\n            :namespace => trigger['Namespace']\n          }\n        end\n      rescue Exception => e\n        []\n      end\n    end\n    def create_autoscaling_trigger!\n      as.create_or_updated_scaling_trigger(\n        :autoscaling_group_name => name,\n        :dimensions => {:name => \"AutoScalingGroupName\", :value => name},\n        :measure_name => measure_name,\n        :period => \"#{period}\",\n        :trigger_name => trigger_name,\n        :statistic => (statistic_names[statistic] || statistic),\n        :unit => unit,\n        :breach_duration => breach_duration,\n        :lower_threshold => \"#{lower_threshold}\",\n        :lower_breach_scale_increment => \"#{lower_breach_scale_increment}\",\n        :upper_threshold => \"#{upper_threshold}\",\n        :upper_breach_scale_increment => \"#{upper_breach_scale_increment}\",\n        :namespace => namespace\n      )\n    end\n    \n    def measure_name\n      measure_names[measure] || measure\n    end\n    \n    def trigger_name\n      \"#{(measure_names[measure] || measure)}-#{name}\" || name\n    end\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_block_device_mapping.rb",
    "content": "module CloudProviders\n  class ElasticBlockDeviceMapping < Ec2Helper\n    def initialize(name, init_opts={}, &block)\n      super\n    end\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_block_store.rb",
    "content": "module CloudProviders\n  class ElasticBlockStore < Ec2Helper\n\n    # instance methods\n    attr_reader :volumeId, :size, :snapshotId, :status, :attachments, :device, :availabilityZone, :instanceId\n    attr_reader :createTime \n\n    alias :volume_id :volumeId\n    alias :snapshot_id :snapshotId\n    alias :availability_zone :availabilityZone \n    alias :create_time :createTime\n    alias :instance_id :instanceId\n\n    def createTime(create_time)\n      unless create_time.class==DateTime\n        @create_time=(DateTime.new(create_time) rescue nil) \n      else\n        @createTime=create_time\n      end\n    end\n    def initialize(raw_response,init_opts={},&block)\n      parse_raw_response(raw_response)\n      super(volumeId,init_opts,&block)\n    end\n\n    def parse_raw_response(raw_response)\n      @raw_respons = raw_response\n      raw_response.each{|k,v| instance_variable_set(\"@\"+k,v) if respond_to?(k) }\n      unless raw_response.attachmentSet.nil?\n        @attachments=raw_response.attachmentSet.item \n        @attachments.each{|attch| if attch.status==\"attached\" or attch.status==\"attaching\"\n            @instanceId=attch.instanceId \n            @device=attch.device\n          end\n        }\n      end\n    end\n\n    def attached?(fn_instance_id=nil)\n      return false unless @status==\"in-use\" or @status==\"attaching\"\n      return true if fn_instance_id.nil?\n      return true if fn_instance_id == instance_id\n      return false\n    end\n\n    def available?\n       @status==\"available\"\n    end\n\n    def attach(ec2_instance,device)\n      if ec2.attach_volume(:volume_id => volume_id, :instance_id => ec2_instance.instance_id, :device => device).return==\"true\"\n        update!\n        return true\n      end\n      false\n    end\n\n    def detach\n      if ec2.detach_volume(:volume_id => volume_id).return==\"true\"\n        update!\n        return true\n      end\n      false\n    end\n\n    def detach!\n      ec2.detach_volume(:volume_id => volume_id, :force => true).return==\"true\"\n    end\n\n    def delete!\n      ec2.delete(:volume_id => volume_id).return == \"true\"\n    end\n\n    def update!\n      parse_raw_response ec2.describe_volumes(:volume_id => volume_id)\n    end\n  \n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_block_store_group.rb",
    "content": "\nmodule CloudProviders\n  # ElasticBlockStoreGroup class allows easy manipulation of EBS volumes matching defined criterias.\n  # Existing volumes in *cloud*'s availability zones that match the criterias will be selected for the group. When cloud instances need to attach EBS volumes from the group, the attach method should called.\n  # When attaching volumes the ElasticBlockStoreGroup will select existing (unattached) volumes until there are non, afterwhich the group will create new volumes according to the criterias given as needed.\n  #\n  # Currently, EBS volumes will not be deleted when tearing down a cloud. This is because poolparty is stateless and thus deleting drives from it will probably result in catastroph (deletions will be too general and delete stuff you don't want deleted).\n  # Hopefully, we will come up with a scheme for a deletion flag of some sort to solve this situation.\n  class ElasticBlockStoreGroup < Ec2Helper\n\n    default_options(:device => nil, :size => 0, :snapshot_id => nil)\n    alias :snapshotId :snapshot_id\n    \n    def initialize(name=cloud.proper_name, init_opts={}, &block)\n      @volumes=[]\n      super\n    end\n    def after_initialized\n      unless @volumes.size > 0 \n        filters={:size => size, :availabilityZone => availability_zones}\n        filters[:snapshotId]=snapshot_id if snapshot_id\n        @volumes=cloud.list_ec2_volumes filters\n      end\n    end\n    def volumes(*volume_ids)\n      return @volumes if volume_ids.size==0\n      volume_ids.each{|volume_id| @volumes << cloud.list_ec2_volumes(:volumeId => volume_id)}\n    end\n    def volumes_attached_to(instanceId)\n      @volumes.select {|vol| vol.attached?(instanceId)}\n    end\n\n    # get volumes that are not attached\n    def free_volumes(availability_zone)\n      @volumes.flatten.select{|vol| vol.available? and vol.availability_zone == availability_zone}\n    end\n    # Get a free volume from existing volumes in group or create a new one\n    def get_free_volume(availability_zone)\n      free=free_volumes(availability_zone)\n      if free.size>=1\n        return free[0]\n      end\n      create(availability_zone)\n    end\n\n    # Create new volume on availability_zone\n    def create(availability_zone)\n      options={:availability_zone => availability_zone, :size => size.to_s}\n      options[:snapshot_id]=snapshot_id if snapshot_id\n      vol=ElasticBlockStore.new(ec2.create_volume(options),:cloud => cloud)\n      @volumes<<vol\n      vol\n    end\n    \n    def attach(nodes)\n      nodes.each{|node|\n        # Check no volumes are attached to node on device\n        skip_node=false\n        cloud.list_ec2_volumes.each{|vol| \n          if vol.attached?(node.instance_id) and vol.device == device\n            warn \"A volume is allready attached to device #{device} of instance #{node.instance_id}\" \n            skip_node = true\n          end\n        }\n        unless skip_node\n          vol=get_free_volume(node.zone)\n          vol.attach(node,device) \n        end\n      }\n    end\n    \n    def verify_attachments(nodes)\n      nodes_without_volume=nodes.select do |node|\n        volumes_attached_to(node.id).size=0\n      end\n      attach nodes_without_volume if nodes_without_volume.any?\n    end\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_ip.rb",
    "content": "module CloudProviders\n\n  class ElasticIp < Ec2Helper\n    \n    default_options(:instance_id => nil, :public_ip => nil)\n    \n    def initialize(raw_response={})\n      @raw_response = raw_response\n      self.instance_id = raw_response[\"instanceId\"]\n      self.public_ip = raw_response[\"publicIp\"]\n    end\n    \n    def assign_to(node)\n      puts \"-----> Assigning #{public_ip} to node: #{node.instance_id}\"\n    end\n    \n    def self.unused_elastic_ips(ec2_instance)\n      @unused_elastic_ips ||= elastic_ips(ec2_instance).select {|ip| ip.instance_id.nil? }\n    end\n    \n    def self.elastic_ips(ec2_instance)\n      begin\n        @elastic_ips ||= ec2_instance.ec2.describe_addresses.addressesSet.item.map do |i|\n          new(i)\n        end\n      rescue Exception => e\n        []\n      end\n    end\n    \n    def self.reset!\n      @elastic_ips = @unused_elastic_ips = nil\n    end\n    \n  end\n\nend"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/elastic_load_balancer.rb",
    "content": "module CloudProviders\n  class ElasticLoadBalancer < Ec2Helper\n    default_options(\n      :listeners => []\n    )\n    def create!\n      if should_create_load_balancer?\n        puts \"-----> Creating ElasticLoadBalancer: #{name}\"\n        create_load_balancer!\n      end\n    end\n    \n    def run\n      create! # Just for now, while we migrate to 2 commands\n      if should_update_load_balancer?\n        create_load_balancer!\n      end\n      _health_checks.each do |ck|\n        configure_health_check!(ck)\n      end\n      # Remove old nodes that are no longer alive\n      detach_instances_if_necessary\n      # Try to unregister and reregister nodes that are out of service, perhaps it was just a setup bug that the setup took too long\n      out_of_service_node_listing = instance_healths.select {|a| a[:state] == \"OutOfService\" }.map {|a| a[:instance_id] }\n      reset!\n      out_of_service_nodes = nodes.select {|n| out_of_service_node_listing.include?(n.instance_id)}\n      unless out_of_service_nodes.empty?\n        puts \"Uh oh. Out of service instance!: #{out_of_service_nodes.inspect}\"\n        elb.deregister_instances_from_load_balancer(:load_balancer_name => name, :instances => out_of_service_nodes)\n        elb.register_instances_with_load_balancer(:load_balancer_name => name, :instances => out_of_service_nodes)\n      end\n      # Attach new nodes if there are any new nodes\n      attach_instances_if_necessary\n    end\n    \n    def teardown\n      puts \"-----> Tearing down load balancer: #{name}\"\n      elb.delete_load_balancer(:load_balancer_name => name)\n    end\n    \n    def listener(*listener_hashes)\n      listener_hashes.each do |hsh|\n        _listeners << ElasticListener.new(hsh)\n      end\n    end\n    \n    def health_check(*health_check_hashes)\n      health_check_hashes.each do |hsh|\n        _health_checks << HealthCheck.new(hsh)\n      end\n    end\n        \n    private\n    def _listeners\n      @_listeners ||= []\n    end\n    def _health_checks\n      @_health_checks ||= []\n    end\n    def real_name\n      name\n    end\n    public \n    def attach_instances_if_necessary\n      parent.reset!\n      instances = parent.nodes.map {|a| a.instance_id } # ec2 gem requires this be an array of names\n      elb.register_instances_with_load_balancer(:instances => instances, :load_balancer_name => \"#{name}\") unless instances.empty?\n    end\n    def detach_instances_if_necessary\n      parent.reset!\n      begin\n        instances = parent.all_nodes.select {|a| !a.running? }.map {|a| a.instance_id }\n        elb.deregister_instances_from_load_balancer(:instances => instances, :load_balancer_name => \"#{name}\") unless instances.empty?\n      rescue Exception => e\n      end\n    end\n    def should_create_load_balancer?\n      elastic_load_balancers.select {|lb| lb.name == name }.empty?\n    end\n    def create_load_balancer!\n      elb.delete_load_balancer(:load_balancer_name => name)\n      elb.create_load_balancer(\n        :availability_zones => parent.availability_zones,\n        :load_balancer_name => real_name,\n        :listeners => _listeners.map {|l| l.to_hash }\n      )\n    end\n    def configure_health_check!(hc)\n      # puts \"Configuring health_check: #{hc.to_hash.inspect}\"\n      elb.configure_health_check(:health_check => hc.to_hash, :load_balancer_name => name)\n    end\n    def should_update_load_balancer?\n      known = elastic_load_balancers.select {|lc| lc.name =~ /#{name}/ }.flatten\n      if known.empty?\n        true\n      else\n        known_listeners = known.map {|a| a[:listeners]}.flatten\n        # Take the known listeners (that are defined on the cloud_provider)\n        # and compare their describable values to those that are defined in\n        # the clouds.rb. Select only those that are different.\n        differences = _listeners.reject do |listener|\n          known_listeners.reject {|kl| listener.diff(kl).empty? }.empty?\n        end.flatten\n        if differences.empty?\n          false\n        else\n          true\n        end\n      end\n    end\n    \n    def running_load_balancers\n      elastic_load_balancers.select {|lc| lc.name =~ /#{name}/ }.flatten\n    end\n    def elastic_load_balancers\n      begin\n        @elastic_load_balancers ||= elb.describe_load_balancers.DescribeLoadBalancersResult.LoadBalancerDescriptions.member.map do |lb|\n          {\n            :created_time => lb[\"CreatedTime\"],\n            :availability_zones => (lb[\"AvailabilityZones\"][\"member\"] rescue []),\n            :dns_name => lb[\"DNSName\"],\n            :name => lb[\"LoadBalancerName\"],\n            :instances => (g[\"Instances\"][\"member\"] rescue []).map {|i| {:instance_id => i[\"InstanceId\"]}},\n            :health_check => ([lb[\"HealthCheck\"]] rescue []).map do |hc|\n              {\n                :healthy_threshold => hc[\"HealthyThreshold\"],\n                :timeout => hc[\"Timeout\"],\n                :unhealthy_threshold => hc[\"UnhealthyThreshold\"],\n                :interval => hc[\"Interval\"],\n                :target => hc[\"Target\"]\n              }\n            end,\n            :listeners => (lb[\"Listeners\"][\"member\"] rescue []).map do |listener|\n              {\n                :instance_port => listener[\"InstancePort\"],\n                :protocol => listener[\"Protocol\"],\n                :load_balancer_port => listener[\"LoadBalancerPort\"]\n              }\n            end\n          }\n        end\n      rescue Exception => e\n        []\n      end      \n    end\n    def instance_healths\n      @instance_healths ||= \n      begin\n        elb.describe_instance_health(:load_balancer_name => name).DescribeInstanceHealthResult.InstanceStates.member.map do |i|\n          {\n            :instance_id => i[\"InstanceId\"],\n            :reason_code => i[\"ReasonCode\"],\n            :state => i[\"State\"],\n            :description => i[\"Description\"]\n          }\n        end\n      rescue Exception => e\n        []\n      end\n    end\n  end\n  class HealthCheck < Ec2Helper\n    default_options(\n      :target => \"HTTP:80/\",\n      :interval => 5,\n      :timeout => 3,\n      :unhealthy_threshold => 2,\n      :healthy_threshold => 2\n    )\n    def initialize(name, init_opts={}, &block)\n      set_vars_from_options(name)\n      super\n    end\n    \n    def to_hash\n      {   :target => target, \n          :interval => interval.to_s, \n          :timeout => timeout.to_s, \n          :unhealthy_threshold => unhealthy_threshold.to_s, \n          :healthy_threshold => healthy_threshold.to_s}\n    end\n  end\n  class ElasticListener < Ec2Helper\n    default_options(\n      :instance_port => 80,\n      :load_balancer_port => 80,\n      :protocol => \"http\"\n    )\n    def initialize(name, init_opts={}, &block)\n      set_vars_from_options(name)\n      super\n    end\n    \n    def to_hash\n      {:protocol => protocol, :load_balancer_port => load_balancer_port.to_s, :instance_port => instance_port.to_s}\n    end\n    \n    def diff(hsh={})\n      [:protocol, :load_balancer_port, :instance_port].reject do |k|\n        hsh[k].to_s.capitalize == self.send(k).to_s.capitalize\n      end\n    end    \n  end\nend"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/rds_instance.rb",
    "content": "module CloudProviders\n  class RdsInstance < Ec2Helper\n    property :username, :password, :storage, :instance_class, :engine\n\n    def authorize(options)\n      options.each do |key, value|\n        authorizations[key.to_s] = value\n      end\n    end\n\n    def database(*db_names)\n      @databases ||= []\n      @databases = @databases + db_names unless db_names.empty?\n      @databases\n    end\n    alias_method :databases, :database\n\n    def create!\n      if should_create_rds_instance?\n        puts \"-----> Creating RDS Instance: #{instance_id}\"\n        create_rds_instance!\n      end\n    end\n\n    def run\n      create! # Just for now, while we migrate to 2 commands\n      authorize_access\n      # TODO : wait until accessible?\n    end\n\n    def teardown\n      puts \"-----> Tearing down RDS Instance: #{instance_id}\"\n      delete_rds_instance!\n    end\n\n    def current_status\n      rds_instances.detect{|i| i.DBInstanceIdentifier == instance_id }\n    end\n\n    def exists?\n      ! current_status.nil?\n    end\n\n    def available?\n      exists? && current_status.DBInstanceStatus == 'available'\n    end\n\n    def instance_id\n      name.to_s\n    end\n\n  private\n\n    def authorizations\n      @authorizations ||= {}\n    end\n\n    def after_initialized\n      raise \"username must be specified\" if self.username.nil?\n      raise \"password must be specified\" if self.password.nil?\n      raise \"invalid password format (letters and digits only)\" unless self.password =~ /[a-z][a-z0-9]*/i\n      raise \"EC2 user id must be defined in ENV or config\" if Ec2.default_user_id.nil?\n    end\n\n    def rds_instances\n      @rds_instances ||= (rds.describe_db_instances.DescribeDBInstancesResult.DBInstances || {})['DBInstance'] || []\n      @rds_instances = [@rds_instances] unless @rds_instances.is_a?(Array)\n      @rds_instances\n    end\n\n    def should_create_rds_instance?\n      ! exists?\n    end\n\n    def create_rds_instance!\n      db_name = (databases.shift || instance_id).to_s.gsub(/\\-/, '_')\n      params = {\n        :db_instance_identifier => instance_id,\n        :allocated_storage      => storage || 5,\n        :db_instance_class      => instance_class || \"db.m1.small\",\n        :engine                 => engine || \"MySQL5.1\",\n        :master_username        => username,\n        :master_user_password   => password,\n        :db_name                => db_name\n      }\n\n      # TODO : optional params : :port, :db_parameter_group, :db_security_groups, :availability_zone, :preferred_backup_window, :backend_retention_period\n      rds.create_db_instance(params)\n\n      # TODO : create additional databases\n    end\n\n    def delete_rds_instance!\n      rds.delete_db_instance(:db_instance_identifier => instance_id, :skip_final_snapshot => \"true\")\n    end\n\n    def authorize_access\n      authorizations[:security_groups] = cloud.security_groups.map{|sg| sg.name } if authorizations[:security_groups].nil?\n      authorizations.each do |type, values|\n        [*values].each do |value|\n          begin\n            # TODO : allow customization of db sec group name\n            params = {:db_security_group_name => \"default\"}\n\n            if type.to_s =~ /network/\n              puts \"authorizing NET access for #{value}...\"\n              params[:cidrip] = value\n            else\n              puts \"authorizing SECGRP access for #{value}/#{Ec2.default_user_id}...\"\n              params[:ec2_security_group_name] = value\n              params[:ec2_security_group_owner_id] = Ec2.default_user_id\n            end\n\n            rds.authorize_db_security_group(params)\n          rescue AWS::Error => e\n            raise e unless e.message =~ /Authorization already exists/\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/revoke.rb",
    "content": "module CloudProviders\n\n  class Revoke < Ec2Helper\n    default_options({\n                :protocol => \"tcp\",\n                :from_port => \"22\",\n                :to_port => \"22\",\n                :cidr_ip => \"0.0.0.0/0\"})\n    def run\n      puts \"Revoking: #{name} for #{protocol} to #{from_port}:#{to_port} #{network}\"\n      options = { :group_name => name,\n                  :ip_protocol => protocol,\n                  :from_port => from_port,\n                  :to_port => to_port,\n                  :cidr_ip => network}\n\n      ec2.revoke_security_group_ingress(options) rescue nil\n    end\n\n    alias :network :cidr_ip\n\n  end\n\nend\n"
  },
  {
    "path": "lib/cloud_providers/ec2/helpers/security_group.rb",
    "content": "module CloudProviders\n  class SecurityGroup < Ec2Helper\n\n    def merge! init_opts, &block\n      set_vars_from_options(init_opts)\n      instance_eval &block if block\n    end\n\n    def run\n      if should_create_security_group?\n        create_security_group!\n      end\n      current_security_groups = security_groups.map {|a|\n        # Example:\n        #    [{ :ip_permissions=>[\n        #       {:ip_ranges=>[{:cidr_ip=>\"0.0.0.0/0\"}], :from_port=>\"22\", :protocol=>\"tcp\", :to_port=>\"22\"},\n        #       {:ip_ranges=>[{:cidr_ip=>\"0.0.0.0/0\"}], :from_port=>\"80\", :protocol=>\"tcp\", :to_port=>\"80\"} ],\n        #     :description=>\"PoolParty generated security group: clyde-chefclient\", :name=>\"clyde-chefclient\"}]\n        #\n        a[:ip_permissions].map do |perm|\n          if perm[:group_name]\n            {\n              :group_name => perm[:group_name]\n            }\n          else\n            (perm[:ip_ranges] || [\"0.0.0.0/0\"]).map do |range|\n              range = range[:cidr_ip] if range.is_a?(Hash)\n              {\n                :group_name  => a[:name],\n                :from_port   => perm[:from_port].to_i,\n                :to_port     => perm[:to_port].to_i,\n                :cidr_ip     => range,\n                :ip_protocol => perm[:protocol]\n              }\n            end.flatten\n          end\n        end.flatten\n      }.flatten.uniq\n      # p ['running', name, 'with', authorizes.map{|a| a.to_hash}, 'currently', current_security_groups]\n\n      authorizes_requested        = authorizes.select{|a| a.name.to_s == name.to_s }\n      authorizes_requested_hashes = authorizes_requested.map{|a| a.to_hash}\n      authorizes_needed = []\n\n      # take each requested authorization. If it doesn't exist in the current_security_groups, we need to add it.\n      authorizes_requested.each do |a|\n        next if current_security_groups.include?(a.to_hash)\n        p ['authorize needed:', name, a.to_hash]\n        authorizes_needed << a\n      end\n      # conversely, every current_security_groups authorization that isn't in the authorizes_requested list must be revoked\n      current_security_groups.each do |hsh|\n        next if authorizes_requested_hashes.include?(hsh)\n        if name == 'default'\n          p ['Not revoking, but please check that this security opening is valid:', name, hsh]\n        else\n          p ['revoke needed:', name, hsh]\n          revoke(hsh.merge(:protocol => hsh[:ip_protocol]))\n        end\n      end\n\n      maybe 'revoke security group settings' do\n        revokes.each{|r| r.run }\n      end unless revokes.blank?\n      if not authorizes_needed.blank?\n        authorizes_needed.each{|a| a.run}\n      end\n    end\n    def authorize(o={}, &block)\n      authorizes << Authorize.new(\"#{name}\", o.merge(:parent => parent, :cloud => cloud), &block)\n    end\n    def revoke(o={}, &block)\n      revokes << Revoke.new(\"#{name}\", o.merge(:parent => parent, :cloud => cloud), &block)\n    end\n    def create_security_group!\n      $stderr.puts \"creating security group #{name}\"\n      ec2.create_security_group(:group_name => name, :group_description => \"PoolParty generated security group: #{name}\")\n    end\n    def should_create_security_group?\n      security_groups.empty?\n    end\n    def security_groups\n      @security_groups ||= all_security_groups.select{|sg| sg[:name] == name }\n    end\n    def all_security_groups\n      @all_security_groups ||= self.class.all_security_groups(ec2)\n    end\n    def self.all_security_groups(ec2)\n      @all_security_groups ||= ec2.describe_security_groups.securityGroupInfo.item.map do |sg|\n        perms = sg[\"ipPermissions\"] || {\"item\" => []} rescue [{\"item\" => []}]\n        {\n          :name => sg[\"groupName\"],\n          :description => sg[\"groupDescription\"],\n          :ip_permissions => perms[\"item\"].map do |i|\n            ip_ranges = i[\"ipRanges\"] || {\"item\" => []} rescue {\"item\" => []}\n            hsh = {\n              :protocol => i[\"ipProtocol\"],\n              :from_port => i[\"fromPort\"],\n              :to_port => i[\"toPort\"],\n              :ip_ranges => ip_ranges[\"item\"].map do |ip|\n                {\n                  :cidr_ip => ip[\"cidrIp\"]\n                }\n              end\n            }\n            if i[\"groups\"].blank?\n              hsh\n            else\n              i[\"groups\"][\"item\"].map{|grp| hsh.merge :group_name => grp[\"groupName\"] }\n            end\n          end.flatten\n        }\n      end\n    end\n    def to_s\n      name.to_s\n    end\n    def authorizes\n      @authorizes ||= []\n    end\n    def revokes\n      @revokes ||= []\n    end\n  end\n\nend\n"
  },
  {
    "path": "lib/cloud_providers/remote_instance.rb",
    "content": "=begin rdoc\n  Remote instances\n=end\nmodule CloudProviders\n  class RemoteInstance\n    include Dslify, Connections\n    \n    attr_reader :name, :init_opts, :raw_response\n    attr_accessor :cloud_provider\n    \n    default_options(\n      :instance_id => nil,\n      :image_id => nil,\n      :status => nil\n    )\n    \n    def initialize(init_opts={}, &block)\n      @init_opts = init_opts\n      set_vars_from_options(init_opts)\n      instance_eval &block if block\n      after_initialized\n    end\n    \n    def keypair(n=nil)\n      @keypair ||= n.nil? ? nil : Keypair.new(n)\n    end\n    \n    def after_initialized\n    end\n    \n    def accessible?\n      ping_port(public_ip, 22, 40)\n    end\n    \n    def rsync_dir(dir)\n      rsync :source => dir/\"*\", :destination => \"/\"\n    end\n    \n    def chef_bootstrapped?\n      @chef_bootstrapped ||= cloud.chef.node_bootstrapped?(self)\n    end\n    \n    # TODO: chef_bootstrapped? should go away, since Chef#node_bootstrap!\n    # already checks node_bootstrap!.  There is a force flag as well.\n    def bootstrap_chef!\n      cloud.chef.node_bootstrap!(self)\n    end\n    \n    def run_chef!\n      cloud.chef.node_run!(self)\n    end\n        \n    def run\n      warn \"#{self.class} does not implement run. Something is wrong\"\n    end\n    \n    def default_keypair_path\n      self.class.default_keypair_path\n    end\n    \n    ## provide hash like methods to access and iterate over node attributes\n    def each\n      dsl_options.each{ |k,v| yield k,v }\n    end\n    \n    def [](k)\n      if dsl_options.has_key? k\n        dsl_options[k]\n      else\n        nil\n      end\n    end\n    \n    def []=(k,v)\n      dsl_options[k] = v\n    end\n    \n    def has_key?(key)\n      dsl_options.has_key?(key)\n    end\n    \n    def keys\n      dsl_options.keys\n    end\n       \n    def values\n      dsl_options.values\n    end\n    \n    def to_hash\n      dsl_options\n    end\n    ##end of hash like methods\n    \n    # Is this instance running?\n    def running?\n      !(status =~ /running/).nil?\n    end\n    # Is this instance pending?\n    def pending?\n      !(status =~ /pending/).nil?\n    end\n    # Is this instance terminating?\n    def terminating?\n      !(status =~ /shutting/).nil?\n    end\n    # Has this instance been terminated?\n    def terminated?\n      !(status =~ /terminated/).nil?\n    end\n    \n    # elapsed seconds since node launch time\n    def elapsed_runtime\n      Time.now - Time.parse(launch_time)\n    end\n    \n    def ssh_available?\n      warn \"Implemented in cloudprovider instance class. something is wrong\"\n    end\n    # def  to_s\n    #  (cloud ? to_hash.merge(:cloud=>cloud.name) : to_hash)\n    # end\n    \n    private\n    def cloud\n      init_opts.has_key?(:cloud) ? init_opts[:cloud] : nil\n    end\n    \n    def cloud_provider\n      cloud.cloud_provider\n    end\n    \n  end\nend\n"
  },
  {
    "path": "lib/cloud_providers.rb",
    "content": "=begin rdoc\n  CloudProvider is the base class for cloud computing services such as Ec2, Eucalyptus - where your servers run.\n=end\nmodule CloudProviders\n\n  # List of all defined cloud_providers\n  def self.all\n    @all ||= []\n  end\n\nend\n\n%w(connections remote_instance cloud_provider).each do |lib|\n  require File.dirname(__FILE__)+\"/cloud_providers/#{lib}\"\nend\n\n%w(ec2).each do |lib|\n  require \"cloud_providers/#{lib}/#{lib}\"\nend"
  },
  {
    "path": "lib/core/array.rb",
    "content": "=begin rdoc\n  Array extensions\n=end\n\nclass Array\n\n  # Example  nodes.select_with_hash(:status=>'running')\n  def select_with_hash(conditions={})\n    return self if conditions.empty?\n    select do |node|\n      conditions.any? do |k,v|\n        ( node.has_key?(k) && node[k]==v ) or ( node.respond_to?(k) && node.send(k)==v )\n      end\n    end\n  end\n    \nend"
  },
  {
    "path": "lib/core/hash.rb",
    "content": "=begin rdoc\n  Hash extentions\n=end\nclass Hash\n    \n  # Return a hash of all the elements where the block evaluates to true\n  def choose(&block)\n    Hash[*self.select(&block).inject([]){|res,(k,v)| res << k << v}]\n  end\n  \n  # Computes the difference between two hashes\n  def diff(other, *hsh)\n    o = {}\n    keys.map do |k|\n      if hsh.include?(k) || hsh.empty?\n        other[k] == self[k] ? nil : o.merge!({k => other[k]})\n      end\n    end.reject {|b| b.nil? }\n    o\n  end\n  \n  def merge_if!(k, v)\n    self[k] = v if v\n    self\n  end\n  \n  # Converts all of the keys to strings\n  # can pass in a :key_modifier that will be sent to each key, before being symbolized.\n  # This can be usefull if you want to downcase, or snake_case each key.\n  # >> {'Placement' => {'AvailabilityZone'=>\"us-east-1a\"} }.symbolize_keys(:snake_case)\n  # => {:placement=>{:availability_zone=>\"us-east-1a\"}}  \n  def symbolize_keys!(key_modifier=nil) \n    keys.each{|k| \n      v = delete(k)\n      if key_modifier && k.respond_to?(key_modifier)\n        k = k.send(key_modifier)\n      end\n      self[k.to_sym] = v\n      v.symbolize_keys!(key_modifier) if v.is_a?(Hash)\n      v.each{|p| p.symbolize_keys!(key_modifier) if p.is_a?(Hash)} if v.is_a?(Array)\n    }\n    self\n  end\n    \n  def method_missing(sym, *args, &block)\n    if has_key?(sym.to_sym)\n      fetch(sym)\n    elsif has_key?(sym.to_s)\n      fetch(sym.to_s)\n    else\n      super\n    end\n  end  \nend"
  },
  {
    "path": "lib/core/object.rb",
    "content": "class Object\n    \n  def pool(name=nil, &block)\n    @@pool ||= PoolParty::Pool.new(name, &block)\n  end\n  \n  def reset!\n    @@pool = nil\n  end\n  \n  def print_msg(msg_arr)\n    msg_arr.each do |line|\n      puts line\n    end\n  end\n  \n  # return true if nil?, empty? or size==0\n  def blank?\n    return true if nil?\n    return true if self.respond_to?('empty?') && self.empty?\n    return true if self.respond_to?('size') && self.size==0\n    return false\n  end\n\n  # === Description\n  #\n  # Change +attr+ to +val+ within the scope of block\n  # and then sets it back again\n  #\n  def change_attr attr, val, &block\n    old_val = instance_variable_get attr\n    begin\n      instance_variable_set attr, val\n      yield\n    ensure\n      instance_variable_set attr, old_val\n    end\n  end\n  \n  def progress_bar_until(msg=nil, &block)\n    print \"#{msg}\" if msg\n    loop do\n      if block.call\n        break\n      else\n        $stdout.print \".\"\n        $stdout.flush\n        sleep 1\n      end\n    end\n    print \" OK\" if msg\n    puts \"\" if msg\n  end\n  \n  \nend\n"
  },
  {
    "path": "lib/core/string.rb",
    "content": "class String\n  # Turn a downcased string and capitalize it\n  # so that it can be a class\n  # doc_river #=> DocRiver\n  def camelcase\n    gsub(/(^|_|-)(.)/) { $2.upcase }\n  end\n  \n  # \"FooBar\".snake_case #=> \"foo_bar\"\n  def snake_case\n   gsub(/\\B[A-Z]+/, '_\\&').downcase\n  end\n \n  # \"FooBar\".dasherize #=> \"foo-bar\"\n  def dasherize\n    gsub(/\\B[A-Z]+/, '-\\&').downcase\n  end\n    \n  # Turn a string from lowercased with a .\n  # to a classified classname\n  # rice_and_beans #=> \"RiceAndBeans\"\n  # handles subclassed and namespaced classes as well\n  # for instance\n  #   rice::and::beans #=> Rice::And::Beans\n  def classify\n    self.sub(/.*\\./, '').split(\"::\").map {|ele| ele.camelcase }.join(\"::\")\n  end\n  # Constantize tries to find a declared constant with the name specified\n  # in the string. It raises a NameError when the name is not in CamelCase\n  # or is not initialized.\n  #\n  # Examples\n  #   \"Module\".constantize #=> Module\n  #   \"Class\".constantize #=> Class\n  def constantize(mod=Object)\n    camelcased_word = classify\n    begin\n      mod.module_eval(camelcased_word, __FILE__, __LINE__)\n    rescue NameError\n      nil\n    end\n  end\n  \n  def /(o)\n    File.join(self, o.to_s)\n  end\n  \nend"
  },
  {
    "path": "lib/core/symbol.rb",
    "content": "class Symbol\n  # def >(num);\"#{self} > #{num}\";end\n  # def <(num);\"#{self} < #{num}\";end\n  # def >=(num);\"#{self} >= #{num}\";end\n  # def <=(num);\"#{self} <= #{num}\";end\n  # def ==(num);\"#{self} > #{num}\";end\n  \n  def sanitize\n    self.to_s.sanitize\n  end\n  def <=>(b)\n    \"#{self}\" <=> \"#{b}\"\n  end\n  ##\n  # @param o<String, Symbol> The path component to join with the string.\n  #\n  # @return <String> The original path concatenated with o.\n  #\n  # @example\n  #   :merb/\"core_ext\" #=> \"merb/core_ext\"\n  def /(o)\n    File.join(self.to_s, o.to_s)\n  end\n  \n  # Classify the symbol\n  def classify\n    to_s.classify.to_sym\n  end\nend"
  },
  {
    "path": "lib/keypair.rb",
    "content": "=begin rdoc\n  ssh key used to login to remote instances\\\n=end\nclass Keypair\n\n  include SearchablePaths\n  has_searchable_paths(:prepend_paths => [Dir.pwd, '/etc/poolparty/keys', \"#{ENV[\"HOME\"]}/.ssh/\", \"#{ENV[\"HOME\"]}/.ec2/\", ENV['EC2_CONFIG_DIR']])\n\n  # Amazon will not append suffix, but public key may have '.pem' suffix\n  SEARCH_SUFFIXES = %w( .pem )\n\n  attr_accessor :filepath\n  attr_reader :extra_paths, :opts\n  attr_reader :search_suffixes\n\n  # Create a new key that defaults to id_rsa as the name.\n  def initialize(fpath, extra_paths=[], opts={})\n    @filepath = fpath\n    @opts = opts\n    @extra_paths = [extra_paths].flatten.map {|a| File.expand_path(a) }\n    @search_suffixes = SEARCH_SUFFIXES\n  end\n\n  # If the full_filepath is nil or false, then the key doesn't exist\n  def exists?\n    !! full_filepath\n  end\n\n  # Read the content of the key\n  def content\n    @content ||= exists? ? open(full_filepath).read : nil\n  end\n\n  # Returns the full_filepath of the key. If a full filepath is passed, we just return the expanded filepath\n  # for the keypair, otherwise query where it is against known locations\n  def full_filepath\n    @full_filepath ||=\n      find_file_in_path_with_suffix(filepath, extra_paths,\n                                    search_suffixes) || false\n  end\n\n  def to_s\n    basename\n  end\n\n  #TODO: gracefully handle the case when a passpharase is needed\n  # Generate a public key from the private key\n  # net/ssh already has this built-in from our extension.\n  def public_key\n    if !@public_key_string || @public_key_string.empty?\n      pkey = Net::SSH::KeyFactory.load_private_key(full_filepath)\n      @public_key_string = pkey.public_key\n    else\n      @public_key_string\n    end\n  end\n\n  def public_key=(str)\n     @public_key_string = str\n  end\n\n  # Basename of the keypair\n  def basename\n    @basename ||= ::File.basename(filepath, ::File.extname(filepath))\n  end\n\n  # Just the filename of the keypair\n  def filename\n    @filename ||= ::File.basename(full_filepath) rescue filepath\n  end\n\n  # Support to add the enumerable each to keys\n  def each\n    yield full_filepath\n  end\n\n  # Validation checks\n  # if all of the validations pass, the object is considered valid\n  # the validations are responsible for raising a PoolPartyError (StandardError)\n  def valid?\n    validations.each {|validation| self.send(validation.to_sym) }\n  end\n\n  private\n\n  # Validations\n  def validations\n    [:keypair_found?, :has_proper_permissions?]\n  end\n\n  # Check the proper permissions\n  def has_proper_permissions?\n    perm_truth = [:readable?, :writable?, :executable?].map {|meth| File.send(meth, full_filepath)} == [true, true, false]\n    raise StandardError.new(\"Your keypair #{full_filepath} has improper file permissions. Keypairs must be 0600 permission. Please chmod your keypair file and try again\") unless perm_truth\n  end\n  def keypair_found?\n    if exists?\n      true\n    else\n      raise StandardError.new(\"#{filepath} key file cannot be found\") unless filepath.nil?\n    end\n  end\n\n  # try filename with suffix and without suffixes.\n  # Checks all paths without suffix first, then try all paths for all suffixes.\n  def find_file_in_path_with_suffix(file, extra_paths, suffixes=[],\n                                    try_wo_suffix=true)\n    suffixes_to_try = suffixes.dup\n    suffixes_to_try.push '' if try_wo_suffix\n\n    suffixes_to_try.map {|s| file + s }.each do |suffixed|\n      fullpath = if File.file?(File.expand_path(suffixed))\n                   ::File.expand_path(suffixed)\n                 else\n                   search_in_known_locations(suffixed, extra_paths)\n                 end\n      return fullpath if fullpath\n    end\n\n    nil\n  end\n\nend\n"
  },
  {
    "path": "lib/poolparty/base.rb",
    "content": "=begin rdoc\n  Base class for all PoolParty objects\n=end\nmodule PoolParty\n  \n  class Base\n    include Dslify\n    attr_reader :name\n    def initialize(name, o={}, &block)\n      @name = name\n      @init_opts = o\n      set_vars_from_options(o)\n      instance_eval &block if block\n      after_initialized\n    end\n    def after_initialized\n    end\n    def run\n      warn \"#{self.class} does not implement run. Something is wrong\"\n    end\n    def method_missing(m,*a,&block)\n      if parent.respond_to?(m)\n        parent.send(m,*a,&block)\n      else\n        super\n      end\n    end\n    \n    private\n  end\n\nend"
  },
  {
    "path": "lib/poolparty/chef.rb",
    "content": "module PoolParty\n  class Chef < Base\n\n    BOOTSTRAP_PACKAGES = %w( ruby ruby1.8-dev libopenssl-ruby1.8 rdoc\n      ri irb build-essential wget ssl-cert rubygems git-core rake\n      librspec-ruby libxml-ruby zlib1g-dev libxml2-dev )\n    # thin couchdb \n    BOOTSTRAP_GEMS = %w( chef )\n\n    # we dont specifically install these binaries, they installed by\n    # packages and gems above, but we check for them\n    BOOTSTRAP_BINS = %w( gem chef-solo chef-client )\n    BOOTSTRAP_DIRS = %w( /var/log/chef /var/cache/chef /var/run/chef )\n\n    def compile!\n      build_tmp_dir\n    end\n\n    def self.types\n      return [:solo,:client]\n    end\n    \n    def self.get_chef(type,cloud,&block)\n      (\"Chef\" + type.to_s.capitalize).constantize(PoolParty).send(:new,type,:cloud => cloud,&block)\n    end\n    # Chef    \n    \n    def attributes(hsh={}, &block)\n      @attributes ||= ChefAttribute.new(hsh, &block)\n    end\n\n    def override_attributes(hsh={}, &block)\n      @override_attributes ||= ChefAttribute.new(hsh, &block)\n    end\n\n\n    # === Description\n    #\n    # Provides the ability to specify steps that can be\n    # run via chef\n    #\n    # pool \"mycluster\" do\n    #   cloud \"mycloud\" do\n    #       \n    #       on_step :download_install do\n    #           recipe \"myrecipes::download\"\n    #           recipe \"myrecipes::install\"\n    #       end\n    #\n    #       on_step :run => :download_install do\n    #           recipe \"myrecipes::run\"\n    #       end\n    #   end\n    # end\n    #\n    # Then from the command line you can do\n    #\n    # cloud-configure --step=download_install \n    #\n    # to only do the partial job or\n    #\n    # cloud-configure --step=run\n    #\n    # to do everything\n    #\n    def on_step action, &block\n      if action.is_a? Hash\n        t = action\n        action = t.keys[0]\n        depends = t.values[0]\n      else\n        depends = nil\n      end\n      change_attr :@_current_action, action do\n        yield\n        if depends\n          # Merge the recipes of the dependency into\n          # the current recipes\n          _recipes(depends).each do |r|\n            recipe r\n          end\n        end\n      end\n    end\n    \n    # Adds a chef recipe to the cloud\n    #\n    # The hsh parameter is inserted into the override_attributes.\n    # The insertion is performed as follows. If\n    # the recipe name = \"foo::bar\" then effectively the call is\n    #\n    # override_attributes.merge! { :foo => { :bar => hsh } }\n    def recipe(recipe_name, hsh={})\n      _recipes << recipe_name unless _recipes.include?(recipe_name)\n\n      head = {}\n      tail = head\n      recipe_name.split(\"::\").each do |key|\n        unless key == \"default\"\n          n = {}\n          tail[key] = n\n          tail = n\n        end\n      end\n      tail.replace hsh\n\n      override_attributes.merge!(head) unless hsh.empty?\n    end\n    \n    def recipes(*recipes)\n      recipes.each do |r|\n        recipe(r)\n      end\n    end\n\n    def node_run!(remote_instance)\n      node_stop!(remote_instance)\n      node_configure!(remote_instance)\n\n      envhash = {\n        :GEM_BIN => %q%$(gem env | grep \"EXECUTABLE DIRECTORY\" | awk \"{print \\\\$4}\")%\n      }\n      cmds = chef_cmd\n      cmds = [cmds] unless cmds.respond_to? :each\n\n      remote_instance.ssh(cmds.map{|c| c.strip.squeeze(' ')}, :env => envhash )\n    end\n\n    def node_stop!(remote_instance)\n      remote_instance.ssh(\"killall -q chef-client chef-solo; [ -f /etc/init.d/chef-client ] && invoke-rc.d chef-client stop\")\n    end\n\n    def node_configure!(remote_instance)\n      # nothing in the superclass\n    end\n\n    def node_bootstrapped?(remote_instance, quiet=true)\n      # using which command instead of calling gem directly.  On\n      # ubuntu, calling a command from package not installed\n      # 'helpfully' prints message, which result confuses detection\n      #\n      cmd = \"which %s\" % BOOTSTRAP_BINS.join(' ') +\n        \" && dpkg -l %s \" % BOOTSTRAP_PACKAGES.join(' ') +\n        BOOTSTRAP_GEMS.map{ |gem|\n          \"&& gem search '^#{gem}$' | grep -v GEMS | wc -l | grep -q 1\"\n        }.join(' ') +\n        BOOTSTRAP_DIRS.map{ |dir|\n          \"&& [[ -d #{dir} ]] \"\n        }.join(' ') +\n        (quiet ? \" >/dev/null \" : \"\" ) +\n        \" && echo OK || echo MISSING\"\n\n      r = remote_instance.ssh(cmd, :do_sudo => false )\n      r.split(\"\\n\").to_a.last.chomp == \"OK\"\n    end\n\n    def node_bootstrap!(remote_instance, force=false)\n      return if !force && node_bootstrapped?(remote_instance)\n\n      # TODO: this should not be hardcoded (like in node_run)\n      deb_gem_bin='/var/lib/gems/1.8/bin'\n      gem_src='http://gems.opscode.com'\n\n      bootstrap_cmds =\n        [\n         'apt-get update',\n         'apt-get autoremove -y',\n         'apt-get install -y %s' % BOOTSTRAP_PACKAGES.join(' '),\n         \"gem source -l | grep -q #{gem_src} || gem source -a #{gem_src} \",\n         'gem install %s --no-rdoc --no-ri' % \n            (BOOTSTRAP_GEMS + remote_instance.bootstrap_gems).join(' '),\n         \"apt-get install -y %s\" % BOOTSTRAP_PACKAGES.join(' '),\n         \"[ -d #{deb_gem_bin} ] && ln -sf #{deb_gem_bin}/* /usr/local/bin\",\n         \"mkdir -p %s\" % BOOTSTRAP_DIRS.join(' ')\n        ]\n\n      remote_instance.ssh(bootstrap_cmds)\n      end\n\n    \n    def _recipes action = nil\n      action = action.to_sym unless action.nil?\n      @_recipes ||= {:default => [] }\n      key = action || _current_action\n      @_recipes[key] ||= []\n    end\n\n    private\n\n    def _current_action\n      @_current_action ||= :default\n    end\n    \n    def chef_cmd\n\n      if ENV[\"CHEF_DEBUG\"]\n        debug = \"-l debug\"\n      else\n        debug = \"\"\n      end\n\n      return <<-CMD\n        PATH=\"$PATH:$GEM_BIN\" #{chef_bin} -j /etc/chef/dna.json -c /etc/chef/client.rb -d -i 1800 -s 20 #{debug}\n      CMD\n    end\n    \n    def method_missing(m,*args,&block)\n      if cloud.respond_to?(m)\n        cloud.send(m,*args,&block)\n      else\n        super\n      end\n    end\n    \n  end\nend\n"
  },
  {
    "path": "lib/poolparty/chef_attribute.rb",
    "content": "module PoolParty\n  class ChefAttribute < Base\n    attr_reader :init_opts\n    def initialize(opts={}, &block)\n      @init_block = block\n      @init_opts = opts\n      instance_eval &block if block\n      @base_name = self.name\n    end\n    \n    def merge!(h={})\n      init_opts.merge!(h)\n    end\n    \n    def to_dna(recipes, filepath, opts=init_opts)\n      if recipes && !recipes.empty?\n        (opts[:recipes] ||= []) << recipes\n        opts[:recipes].flatten!\n      end\n      \n      opts.delete(:name) if opts[:name] && opts[:name].empty?\n      File.open(filepath, \"w\") do |f|\n        f << JSON.pretty_generate(opts)\n      end\n    end\n    \n    def method_missing(m,*a,&block)\n      if @init_opts.has_key?(m)\n        @init_opts[m]\n      else\n        @init_opts.merge!(m => a)\n      end\n    end\n    \n  end\nend\n"
  },
  {
    "path": "lib/poolparty/chef_client.rb",
    "content": "require 'uri' # for URI.parse in write_bootstrap_files\n\nmodule PoolParty\n  # Chef class bootstrapping chef-client.\n  class ChefClient < Chef\n    dsl_methods :server_url,:validation_token, :validation_key, :validation_client_name\n\n    # When init_style.nil?, old behavior is used (just run the client).\n    # If init_style is specified, bootstrap::client cookbook is executed\n    # To this init style.\n    dsl_methods :init_style\n\n    def openid_url(url=nil)\n      if url.nil?\n        return @openid_url||= (u=URI.parse(server_url)\n        u.port=4001\n        openid_url u.to_s)\n      else\n        @openid_url=url \n      end\n    end\n    \n    def roles(*roles)\n      return @_roles||=[cloud.name] if roles.empty?\n      @_roles=roles\n    end\n\n    private\n    def after_initialized\n      raise PoolPartyError.create(\"ChefArgumentMissing\", \"server_url must be specified!\") unless server_url\n    end\n    def chef_bin\n      \"chef-client\"\n    end\n\n    def chef_cmd\n      # without init_style, let parent class start chef-client\n      return super unless init_style\n\n      'invoke-rc.d chef-client start'\n    end\n\n    def node_configure!(remote_instance)\n      super\n      cmds = \n        [ 'PATH=\"$PATH:$GEM_BIN\" chef-solo -j /tmp/chef/chef.json -c /tmp/chef/solo.rb',\n          'invoke-rc.d chef-client stop',\n          'PATH=\"$PATH:$GEM_BIN\" chef-client -j /etc/chef/dna.json -c /etc/chef/client.rb',\n        ]\n\n      remote_instance.ssh cmds\n    end\n\n    # The NEW actual chef resolver.\n    def build_tmp_dir\n      base_directory = tmp_path/\"etc\"/\"chef\"\n      FileUtils.rm_rf base_directory\n      FileUtils.mkdir_p base_directory   \n      FileUtils.cp validation_key, base_directory if validation_key\n      puts \"Creating the dna.json\"\n      attributes.to_dna [], base_directory/\"dna.json\", {:run_list => roles.map{|r| \"role[#{r}]\"} + _recipes.map{|r| \"recipe[#{r}]\"}}.merge(attributes.init_opts)\n      unless init_style then    # original style init\n        write_client_dot_rb\n      else\n        bootstrap_tmp_dir = tmp_path/\"tmp/chef\"\n        FileUtils.rm_rf bootstrap_tmp_dir\n        FileUtils.mkdir_p bootstrap_tmp_dir\n        write_bootstrap_files bootstrap_tmp_dir/\"solo.rb\", bootstrap_tmp_dir/\"chef.json\"\n      end\n    end\n    \n    def write_client_dot_rb(to=tmp_path/\"etc\"/\"chef\"/\"client.rb\")\n      content = <<-EOE\nlog_level          :info\nlog_location       \"/var/log/chef/client.log\"\nssl_verify_mode    :verify_none\nfile_cache_path    \"/var/cache/chef\"\npid_file           \"/var/run/chef/client.pid\"\nChef::Log::Formatter.show_time = true\nopenid_url         \"#{openid_url}\"\n      EOE\n      %w(chef_server_url).each{|url|\n        content+=\"#{url}   \\\"#{server_url}\\\"\\n\"\n      }\n      content+=\"validation_token  \\\"#{validation_token}\\\"\\n\" if validation_token\n      content+=\"validation_key    \\\"/etc/chef/#{File.basename validation_key}\\\"\\n\" if validation_key\n      content+=\"validation_client_name  \\\"#{validation_client_name}\\\"\\n\" if validation_client_name\n      File.open(to, \"w\") do |f|\n        f << content\n      end\n    end\n\n    def write_bootstrap_files(solo_rb, chef_json)\n      uri=URI.parse(server_url)\n      # this maybe reduntant, URL should have a port in there\n      uri.port=4000 if uri.port == 80 # default port for chef\n\n      contents_solo_rb = <<-EOE\nfile_cache_path \"/tmp/chef-solo\"\ncookbook_path \"/tmp/chef-solo/cookbooks\"\nrecipe_url \"http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz\"\n      EOE\n      File.open(solo_rb, \"w\") do |f| f << contents_solo_rb end\n\n      bootstrap_json = \n        {\n        :bootstrap => {\n          :chef => {\n            :url_type =>  uri.scheme,\n            :init_style => init_style,\n            :path => \"/srv/chef\",\n            :serve_path => \"/srv/chef\",\n            :server_fqdn => uri.host + uri.path,\n            :server_port => uri.port,\n          },\n        },\n        :run_list => [ 'recipe[bootstrap::client]' ],\n      }\n      if validation_client_name\n        bootstrap_json[:bootstrap][:chef][:validation_client_name] = validation_client_name\n      end\n      ChefAttribute.new(bootstrap_json).to_dna([], chef_json)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/poolparty/chef_solo.rb",
    "content": "require \"fileutils\"\n\nmodule PoolParty\n  class ChefSolo < Chef\n    dsl_methods :repo \n\n    private\n    def chef_bin\n      \"chef-solo\"\n    end\n\n    def chef_cmd\n\n      if ENV[\"CHEF_DEBUG\"]\n        debug = \"-l debug\"\n      else\n        debug = \"\"\n      end\n\n      return <<-CMD\n        PATH=\"$PATH:$GEM_BIN\" #{chef_bin} -j /etc/chef/dna.json -c /etc/chef/solo.rb #{debug}\n      CMD\n    end\n\n\n    # The NEW actual chef resolver.\n    def build_tmp_dir\n      base_directory = tmp_path/\"etc\"/\"chef\"\n      roles_dir = \"#{base_directory}/roles\"\n      FileUtils.rm_rf base_directory # cleanup old chef temp directory\n      puts \"Copying the chef-repo into the base directory from #{repo}\"\n      \n      FileUtils.mkdir_p base_directory\n      FileUtils.mkdir_p roles_dir # Why do we need this??!?\n      if File.directory?(repo)\n        if File.exist?(base_directory)\n          # First remove the directory\n          FileUtils.remove_entry base_directory, :force => true\n        end\n        cookbook_path = \"#{base_directory}/cookbooks\"\n        FileUtils.mkdir_p cookbook_path\n        FileUtils.cp_r \"#{repo}/.\", cookbook_path\n      else\n        raise \"#{repo} chef repo directory does not exist\"\n      end\n      puts \"Creating the dna.json\"\n      attributes.to_dna [], base_directory/\"dna.json\", {:run_list => [\"role[#{cloud.name}]\"]}\n      write_solo_dot_rb\n      # Make sure the roles directory exists\n      FileUtils.mkdir_p roles_dir\n      write_chef_role_json \"#{roles_dir}/#{cloud.name}.json\"\n    end\n    \n    def write_solo_dot_rb(to=tmp_path/\"etc\"/\"chef\"/\"solo.rb\")\n      content = <<-EOE\ncookbook_path     [\"/etc/chef/cookbooks/cookbooks\", \"/etc/chef/cookbooks/site-cookbooks\"]\nrole_path         \"/etc/chef/roles\"\nlog_level         :info\n      EOE\n\n      File.open(to, \"w\") do |f|\n        f << content\n      end\n    end\n    \n    def write_chef_role_json(to=tmp_path/\"etc\"/\"chef\"/\"dna.json\")\n\n      # Add the parent name and the name of the cloud to\n      # the role for easy access in recipes.\n      pp = {\n        :poolparty => {\n            :parent_name => cloud.parent.name,\n            :name => cloud.name,\n            :pool_info => pool.to_hash\n        }\n      }\n\n      override_attributes.merge! pp\n      ca = ChefAttribute.new({\n        :name => cloud.name,\n        :json_class => \"Chef::Role\",\n        :chef_type => \"role\",\n        :default_attributes => attributes.init_opts,\n        :override_attributes => override_attributes.init_opts,\n        :description => description\n      })\n      ca.to_dna _recipes(pool.chef_step).map {|a| File.basename(a) }, to\n    end\n  end\nend\n"
  },
  {
    "path": "lib/poolparty/cloud.rb",
    "content": "module PoolParty\n  class Cloud < Base\n    default_options(\n      :description            => \"PoolParty cloud\",\n      :minimum_instances      => 1,\n      :maximum_instances      => 3\n    )\n\n    # returns an instance of Keypair\n    # You can pass either a filename which will be searched for in ~/.ec2/ and ~/.ssh/\n    # Or you can pass a full filepath\n    def keypair(n=nil, extra_paths=[])\n      return @keypair if @keypair\n      @keypair = case n\n      when String\n        Keypair.new(n, extra_paths)\n      when nil\n        fpath = CloudProviders::CloudProvider.default_keypair_path/\"#{proper_name}\"\n        File.exists?(fpath) ? Keypair.new(fpath, extra_paths) : generate_keypair(extra_paths)\n      else\n        raise ArgumentError, \"There was an error when defining the keypair\"\n      end\n    end\n\n    private\n    def generate_keypair(extra_paths=[])\n      puts \"Generate the keypair for this cloud because its not found: #{proper_name}\"\n      cloud_provider.send :generate_keypair, proper_name\n      Keypair.new(proper_name, extra_paths)\n    end\n\n    def after_initialized\n      raise PoolParty::PoolPartyError.create(\"NoCloudProvider\", <<-EOE\nYou did not specify a cloud provider in your clouds.rb. Make sure you have a block that looks like:\n\n  using :ec2\n      EOE\n      ) unless cloud_provider\n      security_group(proper_name, :authorize => {:from_port => 22, :to_port => 22}) if security_groups.empty?\n    end\n\n    public\n    def instances(arg)\n      case arg\n      when Range\n        minimum_instances arg.first\n        maximum_instances arg.last\n      when Fixnum\n        minimum_instances arg\n        maximum_instances arg\n      when Hash\n        minimum_instances arg[:instances].to_i\n        maximum_instances arg[:instances].to_i\n        # nodes(arg)\n      else\n        raise PoolParty::PoolPartyError.create(\"DslMethodCall\", \"You must call instances with either a number, a range or a hash (for a list of nodes)\")\n      end\n    end\n\n    # Upload the source to dest ( using rsync )\n    def upload source, dest\n      @uploads ||= []\n      @uploads << { :source => source, :dest => dest }\n    end\n\n    # The pool can either be the parent (the context where the object is declared)\n    # or the global pool object\n    def pool\n      parent || pool\n    end\n\n    def tmp_path\n      \"/tmp/poolparty\" / pool.name / name\n    end\n\n    public\n\n    attr_reader :cloud_provider\n    def using(provider_name, &block)\n      return @cloud_provider if @cloud_provider\n      @cloud_provider = \"#{provider_name}\".constantize(CloudProviders).send(:new, provider_name, :cloud => self, &block)\n      # Decorate the cloud with the cloud_provider methods\n      (class << self; self; end).instance_variable_set('@cloud_provider', @cloud_provider)\n        (class << self; self; end).class_eval do\n          @cloud_provider.public_methods(false).each do |meth|\n            next if respond_to?(meth) || method_defined?(meth) || private_method_defined?(meth)\n            eval <<-EOE\n              def #{meth}(*args, &block)\n                @cloud_provider.send(:#{meth}, *args, &block)\n              end\n            EOE\n        end\n      end\n    end\n\n    def chef(chef_type=:solo, &block)\n      raise ArgumentError, \"Chef type must be one of #{Chef.types.map{|v| \":\" + v.to_s}.join(\",\")}.\" unless Chef.types.include?(chef_type)\n      @chef||=Chef.get_chef(chef_type,self,&block)\n    end\n    # compile the cloud spec and execute the compiled system and remote calls\n    def run\n      puts \"  running on #{cloud_provider.class}\"\n      cloud_provider.run\n      unless @chef.nil?\n        compile!\n        bootstrap!\n      end\n    end\n\n\n    # TODO: Incomplete and needs testing\n    # Shutdown and delete the load_balancers, auto_scaling_groups, launch_configurations,\n    # security_groups, triggers and instances defined by this cloud\n    def teardown\n      raise \"Only Ec2 teardown supported\" unless cloud_provider.name.to_s == 'ec2'\n      puts \"! Tearing down cloud #{name}\"\n      # load_balancers.each do |name, lb|\n      #   puts \"! Deleting load_balaner #{lb_name}\"\n      #   lb.teardown\n      # end\n      load_balancers.each do |lb|\n        puts \"-----> Tearing down load balancer: #{lb.name}\"\n        lb.teardown\n      end\n\n      rds_instances.each do |rds|\n        puts \"-----> Tearing down RDS Instance: #{rds.name}\"\n        rds.teardown\n      end\n      # instances belonging to an auto_scaling group must be deleted before the auto_scaling group\n      #THIS SCARES ME! nodes.each{|n| n.terminate_instance!}\n      # loop {nodes.size>0 ? sleep(4) : break }\n      if autoscalers.empty?\n        nodes.each do |node|\n          node.terminate!\n        end\n      else\n        autoscalers.each do |a|\n          puts \"-----> Tearing down autoscaler #{a.name}\"\n          a.teardown\n        end\n      end\n      # autoscalers.keys.each do |as_name|\n      #   puts \"! Deleting auto_scaling_group #{as_name}\"\n      #   cloud_provider.as.delete_autoscaling_group('AutoScalingGroupName' => as_name)\n      # end\n      #TODO: keypair.delete # Do we want to delete the keypair?  probably, but not certain\n    end\n\n    def reboot!\n      orig_nodes = nodes\n      if autoscalers.empty?\n        puts <<-EOE\nNo autoscalers defined\n  Launching new nodes and then shutting down original nodes\n        EOE\n        # Terminate the nodes\n        orig_nodes.each_with_index do |node, i|\n          # Start new nodes\n          print \"Starting node: #{i}...\\n\"\n          expand_by(1)\n          print \"Terminating node: #{i}...\\n\"\n          node.terminate!\n          puts \"\"\n        end\n      else\n        # Terminate the nodes\n        @num_nodes = orig_nodes.size\n        orig_nodes.each do |node|\n          node.terminate!\n          puts \"----> Terminated node: #{node.instance_id}\"\n          # Wait for the autoscaler to boot the next node\n          puts \"----> Waiting for new node to boot via the autoscaler\"\n          loop do\n            reset!\n            break if nodes.size == @num_nodes\n            $stdout.print \".\"\n            $stdout.flush\n            sleep 1\n          end\n        end\n      end\n      run\n      puts \"\"\n    end\n\n    def compile!\n      unless @uploads.nil?\n        puts \"Uploading files via rsync\"\n        @uploads.each do |upload|\n          rsync upload[:source], upload[:dest]\n        end\n      end\n      @chef.compile! unless @chef.nil?\n    end\n\n    def bootstrap!\n      cloud_provider.bootstrap_nodes!(tmp_path)\n    end\n\n    def configure!\n      compile!\n      cloud_provider.configure_nodes!(tmp_path)\n    end\n\n    def reset!\n      cloud_provider.reset!\n    end\n\n    def ssh(num=0)\n      nodes[num].ssh\n    end\n\n    def rsync(source, dest)\n      nodes.each do |node|\n        node.rsync(:source => source, :destination => dest)\n      end\n    end\n\n    # TODO: list of nodes needs to be consistentley sorted\n    def nodes\n      cloud_provider.nodes.select {|a| a.in_service? }\n    end\n\n    # Run command/s on all nodes in the cloud.\n    # Returns a hash of instance_id=>result pairs\n    def cmd(commands, opts={})\n      key_by = opts.delete(:key_by) || :instance_id\n      results = {}\n      threads = nodes.collect do |n|\n        puts \"result for #{n.instance_id} ==> n.ssh(#{commands.inspect}, #{opts.inspect})\"\n        Thread.new{ results[ n.send(key_by) ] = n.ssh(commands, opts) }\n      end\n      threads.each{ |aThread| aThread.join }\n      results\n    end\n\n    def cssh(user = nil, use_keypair = nil)\n      opts = []\n      opts.push \"-i #{keypair.full_filepath}\" if use_keypair\n      opts.push \"-l #{user}\" if user\n      opts = opts.join(\" \")\n      puts \"cssh -o '#{opts}' \" + nodes.map{|n| n.public_ip}.join(\" \") + \" &\"\n      system \"cssh -o '#{opts}' \" + nodes.map{|n| n.public_ip}.join(\" \") + \" &\"\n    end\n\n    # Explicit proxies to cloud_provider methods\n    def run_instance(o={}); cloud_provider.run_instance(o);end\n    def terminate_instance!(o={}); cloud_provider.terminate_instance!(o);end\n    def describe_instances(o={}); cloud_provider.describe_instances(o);end\n    def describe_instance(o={}); cloud_provider.describe_instance(o);end\n\n    def proper_name\n      \"#{parent.name}-#{name}\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/poolparty/pool.rb",
    "content": "module PoolParty\n    \n  class Pool < Base\n    attr_accessor :verbose, :very_verbose, :debugging, :very_debugging, :auto_execute\n    \n    def cloud(name, &block)\n      c = Cloud.new(name.to_s, {:parent => self}, &block)\n      clouds[name.to_s] = c\n      # Create a dummy security group for tagging purposes. Do not want to\n      # conflict with advance usage of security groups\n      c.security_group \"#poolparty-#{c.proper_name}\"\n    end\n    \n    def clouds\n      @clouds ||= {}\n    end\n    \n    # Run command/s on all nodes in the pool.\n    # Returns a hash in the form of {cloud => [{instance_id=>result}]}\n    def cmd(commands, opts={})\n      results = {}\n      threads = clouds.collect do |name, c|\n        Thread.new{ results[ name ] = c.cmd(commands, opts) }\n      end\n      threads.each{ |aThread| aThread.join }\n      results\n    end\n        \n    at_exit do\n      if pool.auto_execute\n        puts <<-EOE\n----> Running #{pool.name} #{pool.auto_execute}\n        EOE\n        pool.run\n      end\n    end\n    \n    # === Description\n    #\n    # Set / Get the chef_step which will be executed on the remote\n    # host\n    def chef_step name = nil\n      @selected_chef_step ||= :default\n      if name\n        @selected_chef_step = name.to_sym\n      end\n      @selected_chef_step\n    end\n    \n    def run\n      clouds.each do |cloud_name, cld|\n        puts \"----> Starting to build cloud #{cloud_name}\"\n        cld.run\n      end\n    end\n\n    def to_hash\n      c = clouds.collect do |cloud_name, cld|\n        nodes = cld.nodes.collect do |node|\n          h = {}\n          [:dns_name, :private_ip, :public_ip].each do |f|\n            h[f] = node[f]\n          end\n          h\n        end\n        { cloud_name => nodes }\n      end\n      h = c.inject({})do |old, new|\n       old.merge! new\n      end \n      {:clouds => h }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "lib/poolparty/pool_party_error.rb",
    "content": "=begin rdoc\n  PoolPartyError\n  \n  Create an StandardError on the fly\n=end\nmodule PoolParty\n  class PoolPartyError\n    \n    # Create an error with the class_name and error message\n    # If the StandardError is not yet defined, define it, subclassing\n    # StandardError and return the new class\n    # Note: the class is set on Object\n    def self.create(class_name=\"StandardError\", msg=\"Error\")\n      Object.const_set(class_name, Class.new(StandardError)) unless Object.const_defined?(class_name)\n      class_name.constantize.send(:new, msg)\n    end\n    \n  end\nend"
  },
  {
    "path": "lib/poolparty/version.rb",
    "content": "module PoolParty\n  VERSION = \"1.7.0.pre\"\nend\n"
  },
  {
    "path": "lib/poolparty.rb",
    "content": "$LOAD_PATH.unshift(File.dirname(__FILE__))\n\nt=Time.now\n\nrequire 'yaml'\n\n# Load system gems\n%w(rubygems logger erb open-uri fileutils timeout).each do |lib|\n  require lib\nend\n\nbegin\n  require 'AWS'\nrescue LoadError\n  puts <<-EOM\n  There was an error requiring AWS\nEOM\nend\n\nrequire 'pp'\n\n# Add all vendor gems to the load paths\nDir[File.dirname(__FILE__)+\"/../vendor/gems/*\"].each {|lib| $LOAD_PATH.unshift(File.expand_path(\"#{lib}/lib\")) }\n\n# Load local gems\n%w(dslify json searchable_paths).each do |dep|\n  require dep\nend\n\nrequire \"poolparty/version\"\nmodule PoolParty\n  def self.version\n    VERSION\n  end\n\n  def self.lib_dir\n    File.join(File.dirname(__FILE__), \"..\")\n  end\nend\n\n# Require the poolparty error so we can use it ubiquitously\nrequire \"poolparty/pool_party_error\"\n\n# Core object overloads\n%w( object\n    string\n    array\n    hash\n    symbol\n  ).each do |lib|\n  require \"core/#{lib}\"\nend\n\nrequire \"keypair\"\n\nPOOLPARTY_CONFIG_FILE = \"#{ENV[\"HOME\"]}/.poolparty/aws\" unless defined?(POOLPARTY_CONFIG_FILE)\n\n# PoolParty core\n$LOAD_PATH.unshift(File.dirname(__FILE__)/\"poolparty\")\n%w( base\n    chef_attribute\n    chef\n    chef_solo\n    chef_client\n    cloud pool\n  ).each do |lib|\n  require \"poolparty/#{lib}\"\nend\n\nrequire 'cloud_providers'\n\nputs \"PoolParty core loadtime: #{Time.now-t}\"\n"
  },
  {
    "path": "poolparty.gemspec",
    "content": "# -*- encoding: utf-8 -*-\n$:.push File.expand_path(\"../lib\", __FILE__)\nrequire \"poolparty/version\"\n\nGem::Specification.new do |s|\n  s.name        = \"poolparty\"\n  s.version     = PoolParty::VERSION \n\n  s.authors     = [\"Ari Lerner\", \"Michael Fairchild\", \"Nate Murray\"]\n  s.email       = %q{arilerner@mac.com}\n  s.homepage    = %q{http://poolpartyrb.com}\n  s.summary     = %q{Simple DSL to describe and realize cloud deployment architectures.}\n  s.description = %q{PoolParty: The easy, open-source, cross-cloud management solution}\n\n  s.extra_rdoc_files = [ \"README.rdoc\" ]\n  s.rdoc_options = [\"--quiet\", \"--title\", \"PoolParty documentation\", \"--line-numbers\", \"--main\", \"README.rdoc\"]\n\n  s.files         = `git ls-files`.split(\"\\n\")\n  s.test_files    = `git ls-files -- {test,spec,features}/*`.split(\"\\n\")\n  s.executables   = `git ls-files -- bin/*`.split(\"\\n\").map{ |f| File.basename(f) }\n  s.require_paths = [\"lib\"]\n\n  s.add_runtime_dependency(\"amazon-ec2\", \"~> 0.9.17\")\n  s.add_runtime_dependency(\"xml-simple\", \">= 0\")\n  s.add_runtime_dependency(\"json\", \">= 0\")\nend\n\n"
  },
  {
    "path": "setup.rb",
    "content": "#\n# setup.rb\n#\n# Copyright (c) 2000-2005 Minero Aoki\n#\n# This program is free software.\n# You can distribute/modify this program under the terms of\n# the GNU LGPL, Lesser General Public License version 2.1.\n#\n\nunless Enumerable.method_defined?(:map)   # Ruby 1.4.6\n  module Enumerable\n    alias map collect\n  end\nend\n\nunless File.respond_to?(:read)   # Ruby 1.6\n  def File.read(fname)\n    open(fname) {|f|\n      return f.read\n    }\n  end\nend\n\nunless Errno.const_defined?(:ENOTEMPTY)   # Windows?\n  module Errno\n    class ENOTEMPTY\n      # We do not raise this exception, implementation is not needed.\n    end\n  end\nend\n\ndef File.binread(fname)\n  open(fname, 'rb') {|f|\n    return f.read\n  }\nend\n\n# for corrupted Windows' stat(2)\ndef File.dir?(path)\n  File.directory?((path[-1,1] == '/') ? path : path + '/')\nend\n\n\nclass ConfigTable\n\n  include Enumerable\n\n  def initialize(rbconfig)\n    @rbconfig = rbconfig\n    @items = []\n    @table = {}\n    # options\n    @install_prefix = nil\n    @config_opt = nil\n    @verbose = true\n    @no_harm = false\n  end\n\n  attr_accessor :install_prefix\n  attr_accessor :config_opt\n\n  attr_writer :verbose\n\n  def verbose?\n    @verbose\n  end\n\n  attr_writer :no_harm\n\n  def no_harm?\n    @no_harm\n  end\n\n  def [](key)\n    lookup(key).resolve(self)\n  end\n\n  def []=(key, val)\n    lookup(key).set val\n  end\n\n  def names\n    @items.map {|i| i.name }\n  end\n\n  def each(&block)\n    @items.each(&block)\n  end\n\n  def key?(name)\n    @table.key?(name)\n  end\n\n  def lookup(name)\n    @table[name] or setup_rb_error \"no such config item: #{name}\"\n  end\n\n  def add(item)\n    @items.push item\n    @table[item.name] = item\n  end\n\n  def remove(name)\n    item = lookup(name)\n    @items.delete_if {|i| i.name == name }\n    @table.delete_if {|name, i| i.name == name }\n    item\n  end\n\n  def load_script(path, inst = nil)\n    if File.file?(path)\n      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path\n    end\n  end\n\n  def savefile\n    '.config'\n  end\n\n  def load_savefile\n    begin\n      File.foreach(savefile()) do |line|\n        k, v = *line.split(/=/, 2)\n        self[k] = v.strip\n      end\n    rescue Errno::ENOENT\n      setup_rb_error $!.message + \"\\n#{File.basename($0)} config first\"\n    end\n  end\n\n  def save\n    @items.each {|i| i.value }\n    File.open(savefile(), 'w') {|f|\n      @items.each do |i|\n        f.printf \"%s=%s\\n\", i.name, i.value if i.value? and i.value\n      end\n    }\n  end\n\n  def load_standard_entries\n    standard_entries(@rbconfig).each do |ent|\n      add ent\n    end\n  end\n\n  def standard_entries(rbconfig)\n    c = rbconfig\n\n    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])\n\n    major = c['MAJOR'].to_i\n    minor = c['MINOR'].to_i\n    teeny = c['TEENY'].to_i\n    version = \"#{major}.#{minor}\"\n\n    # ruby ver. >= 1.4.4?\n    newpath_p = ((major >= 2) or\n                 ((major == 1) and\n                  ((minor >= 5) or\n                   ((minor == 4) and (teeny >= 4)))))\n\n    if c['rubylibdir']\n      # V > 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = c['rubylibdir']\n      librubyverarch  = c['archdir']\n      siteruby        = c['sitedir']\n      siterubyver     = c['sitelibdir']\n      siterubyverarch = c['sitearchdir']\n    elsif newpath_p\n      # 1.4.4 <= V <= 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = c['sitedir']\n      siterubyver     = \"$siteruby/#{version}\"\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    else\n      # V < 1.4.4\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = \"#{c['prefix']}/lib/ruby/#{version}/site_ruby\"\n      siterubyver     = siteruby\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    end\n    parameterize = lambda {|path|\n      path.sub(/\\A#{Regexp.quote(c['prefix'])}/, '$prefix')\n    }\n\n    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }\n      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]\n    else\n      makeprog = 'make'\n    end\n\n    [\n      ExecItem.new('installdirs', 'std/site/home',\n                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\\\n          {|val, table|\n            case val\n            when 'std'\n              table['rbdir'] = '$librubyver'\n              table['sodir'] = '$librubyverarch'\n            when 'site'\n              table['rbdir'] = '$siterubyver'\n              table['sodir'] = '$siterubyverarch'\n            when 'home'\n              setup_rb_error '$HOME was not set' unless ENV['HOME']\n              table['prefix'] = ENV['HOME']\n              table['rbdir'] = '$libdir/ruby'\n              table['sodir'] = '$libdir/ruby'\n            end\n          },\n      PathItem.new('prefix', 'path', c['prefix'],\n                   'path prefix of target environment'),\n      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),\n                   'the directory for commands'),\n      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),\n                   'the directory for libraries'),\n      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),\n                   'the directory for shared data'),\n      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),\n                   'the directory for man pages'),\n      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),\n                   'the directory for system configuration files'),\n      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),\n                   'the directory for local state data'),\n      PathItem.new('libruby', 'path', libruby,\n                   'the directory for ruby libraries'),\n      PathItem.new('librubyver', 'path', librubyver,\n                   'the directory for standard ruby libraries'),\n      PathItem.new('librubyverarch', 'path', librubyverarch,\n                   'the directory for standard ruby extensions'),\n      PathItem.new('siteruby', 'path', siteruby,\n          'the directory for version-independent aux ruby libraries'),\n      PathItem.new('siterubyver', 'path', siterubyver,\n                   'the directory for aux ruby libraries'),\n      PathItem.new('siterubyverarch', 'path', siterubyverarch,\n                   'the directory for aux ruby binaries'),\n      PathItem.new('rbdir', 'path', '$siterubyver',\n                   'the directory for ruby scripts'),\n      PathItem.new('sodir', 'path', '$siterubyverarch',\n                   'the directory for ruby extentions'),\n      PathItem.new('rubypath', 'path', rubypath,\n                   'the path to set to #! line'),\n      ProgramItem.new('rubyprog', 'name', rubypath,\n                      'the ruby program using for installation'),\n      ProgramItem.new('makeprog', 'name', makeprog,\n                      'the make program to compile ruby extentions'),\n      SelectItem.new('shebang', 'all/ruby/never', 'ruby',\n                     'shebang line (#!) editing mode'),\n      BoolItem.new('without-ext', 'yes/no', 'no',\n                   'does not compile/install ruby extentions')\n    ]\n  end\n  private :standard_entries\n\n  def load_multipackage_entries\n    multipackage_entries().each do |ent|\n      add ent\n    end\n  end\n\n  def multipackage_entries\n    [\n      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',\n                               'package names that you want to install'),\n      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',\n                               'package names that you do not want to install')\n    ]\n  end\n  private :multipackage_entries\n\n  ALIASES = {\n    'std-ruby'         => 'librubyver',\n    'stdruby'          => 'librubyver',\n    'rubylibdir'       => 'librubyver',\n    'archdir'          => 'librubyverarch',\n    'site-ruby-common' => 'siteruby',     # For backward compatibility\n    'site-ruby'        => 'siterubyver',  # For backward compatibility\n    'bin-dir'          => 'bindir',\n    'bin-dir'          => 'bindir',\n    'rb-dir'           => 'rbdir',\n    'so-dir'           => 'sodir',\n    'data-dir'         => 'datadir',\n    'ruby-path'        => 'rubypath',\n    'ruby-prog'        => 'rubyprog',\n    'ruby'             => 'rubyprog',\n    'make-prog'        => 'makeprog',\n    'make'             => 'makeprog'\n  }\n\n  def fixup\n    ALIASES.each do |ali, name|\n      @table[ali] = @table[name]\n    end\n    @items.freeze\n    @table.freeze\n    @options_re = /\\A--(#{@table.keys.join('|')})(?:=(.*))?\\z/\n  end\n\n  def parse_opt(opt)\n    m = @options_re.match(opt) or setup_rb_error \"config: unknown option #{opt}\"\n    m.to_a[1,2]\n  end\n\n  def dllext\n    @rbconfig['DLEXT']\n  end\n\n  def value_config?(name)\n    lookup(name).value?\n  end\n\n  class Item\n    def initialize(name, template, default, desc)\n      @name = name.freeze\n      @template = template\n      @value = default\n      @default = default\n      @description = desc\n    end\n\n    attr_reader :name\n    attr_reader :description\n\n    attr_accessor :default\n    alias help_default default\n\n    def help_opt\n      \"--#{@name}=#{@template}\"\n    end\n\n    def value?\n      true\n    end\n\n    def value\n      @value\n    end\n\n    def resolve(table)\n      @value.gsub(%r<\\$([^/]+)>) { table[$1] }\n    end\n\n    def set(val)\n      @value = check(val)\n    end\n\n    private\n\n    def check(val)\n      setup_rb_error \"config: --#{name} requires argument\" unless val\n      val\n    end\n  end\n\n  class BoolItem < Item\n    def config_type\n      'bool'\n    end\n\n    def help_opt\n      \"--#{@name}\"\n    end\n\n    private\n\n    def check(val)\n      return 'yes' unless val\n      case val\n      when /\\Ay(es)?\\z/i, /\\At(rue)?\\z/i then 'yes'\n      when /\\An(o)?\\z/i, /\\Af(alse)\\z/i  then 'no'\n      else\n        setup_rb_error \"config: --#{@name} accepts only yes/no for argument\"\n      end\n    end\n  end\n\n  class PathItem < Item\n    def config_type\n      'path'\n    end\n\n    private\n\n    def check(path)\n      setup_rb_error \"config: --#{@name} requires argument\"  unless path\n      path[0,1] == '$' ? path : File.expand_path(path)\n    end\n  end\n\n  class ProgramItem < Item\n    def config_type\n      'program'\n    end\n  end\n\n  class SelectItem < Item\n    def initialize(name, selection, default, desc)\n      super\n      @ok = selection.split('/')\n    end\n\n    def config_type\n      'select'\n    end\n\n    private\n\n    def check(val)\n      unless @ok.include?(val.strip)\n        setup_rb_error \"config: use --#{@name}=#{@template} (#{val})\"\n      end\n      val.strip\n    end\n  end\n\n  class ExecItem < Item\n    def initialize(name, selection, desc, &block)\n      super name, selection, nil, desc\n      @ok = selection.split('/')\n      @action = block\n    end\n\n    def config_type\n      'exec'\n    end\n\n    def value?\n      false\n    end\n\n    def resolve(table)\n      setup_rb_error \"$#{name()} wrongly used as option value\"\n    end\n\n    undef set\n\n    def evaluate(val, table)\n      v = val.strip.downcase\n      unless @ok.include?(v)\n        setup_rb_error \"invalid option --#{@name}=#{val} (use #{@template})\"\n      end\n      @action.call v, table\n    end\n  end\n\n  class PackageSelectionItem < Item\n    def initialize(name, template, default, help_default, desc)\n      super name, template, default, desc\n      @help_default = help_default\n    end\n\n    attr_reader :help_default\n\n    def config_type\n      'package'\n    end\n\n    private\n\n    def check(val)\n      unless File.dir?(\"packages/#{val}\")\n        setup_rb_error \"config: no such package: #{val}\"\n      end\n      val\n    end\n  end\n\n  class MetaConfigEnvironment\n    def initialize(config, installer)\n      @config = config\n      @installer = installer\n    end\n\n    def config_names\n      @config.names\n    end\n\n    def config?(name)\n      @config.key?(name)\n    end\n\n    def bool_config?(name)\n      @config.lookup(name).config_type == 'bool'\n    end\n\n    def path_config?(name)\n      @config.lookup(name).config_type == 'path'\n    end\n\n    def value_config?(name)\n      @config.lookup(name).config_type != 'exec'\n    end\n\n    def add_config(item)\n      @config.add item\n    end\n\n    def add_bool_config(name, default, desc)\n      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)\n    end\n\n    def add_path_config(name, default, desc)\n      @config.add PathItem.new(name, 'path', default, desc)\n    end\n\n    def set_config_default(name, default)\n      @config.lookup(name).default = default\n    end\n\n    def remove_config(name)\n      @config.remove(name)\n    end\n\n    # For only multipackage\n    def packages\n      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages\n    end\n\n    # For only multipackage\n    def declare_packages(list)\n      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages = list\n    end\n  end\n\nend   # class ConfigTable\n\n\n# This module requires: #verbose?, #no_harm?\nmodule FileOperations\n\n  def mkdir_p(dirname, prefix = nil)\n    dirname = prefix + File.expand_path(dirname) if prefix\n    $stderr.puts \"mkdir -p #{dirname}\" if verbose?\n    return if no_harm?\n\n    # Does not check '/', it's too abnormal.\n    dirs = File.expand_path(dirname).split(%r<(?=/)>)\n    if /\\A[a-z]:\\z/i =~ dirs[0]\n      disk = dirs.shift\n      dirs[0] = disk + dirs[0]\n    end\n    dirs.each_index do |idx|\n      path = dirs[0..idx].join('')\n      Dir.mkdir path unless File.dir?(path)\n    end\n  end\n\n  def rm_f(path)\n    $stderr.puts \"rm -f #{path}\" if verbose?\n    return if no_harm?\n    force_remove_file path\n  end\n\n  def rm_rf(path)\n    $stderr.puts \"rm -rf #{path}\" if verbose?\n    return if no_harm?\n    remove_tree path\n  end\n\n  def remove_tree(path)\n    if File.symlink?(path)\n      remove_file path\n    elsif File.dir?(path)\n      remove_tree0 path\n    else\n      force_remove_file path\n    end\n  end\n\n  def remove_tree0(path)\n    Dir.foreach(path) do |ent|\n      next if ent == '.'\n      next if ent == '..'\n      entpath = \"#{path}/#{ent}\"\n      if File.symlink?(entpath)\n        remove_file entpath\n      elsif File.dir?(entpath)\n        remove_tree0 entpath\n      else\n        force_remove_file entpath\n      end\n    end\n    begin\n      Dir.rmdir path\n    rescue Errno::ENOTEMPTY\n      # directory may not be empty\n    end\n  end\n\n  def move_file(src, dest)\n    force_remove_file dest\n    begin\n      File.rename src, dest\n    rescue\n      File.open(dest, 'wb') {|f|\n        f.write File.binread(src)\n      }\n      File.chmod File.stat(src).mode, dest\n      File.unlink src\n    end\n  end\n\n  def force_remove_file(path)\n    begin\n      remove_file path\n    rescue\n    end\n  end\n\n  def remove_file(path)\n    File.chmod 0777, path\n    File.unlink path\n  end\n\n  def install(from, dest, mode, prefix = nil)\n    $stderr.puts \"install #{from} #{dest}\" if verbose?\n    return if no_harm?\n\n    realdest = prefix ? prefix + File.expand_path(dest) : dest\n    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)\n    str = File.binread(from)\n    if diff?(str, realdest)\n      verbose_off {\n        rm_f realdest if File.exist?(realdest)\n      }\n      File.open(realdest, 'wb') {|f|\n        f.write str\n      }\n      File.chmod mode, realdest\n\n      File.open(\"#{objdir_root()}/InstalledFiles\", 'a') {|f|\n        if prefix\n          f.puts realdest.sub(prefix, '')\n        else\n          f.puts realdest\n        end\n      }\n    end\n  end\n\n  def diff?(new_content, path)\n    return true unless File.exist?(path)\n    new_content != File.binread(path)\n  end\n\n  def command(*args)\n    $stderr.puts args.join(' ') if verbose?\n    system(*args) or raise RuntimeError,\n        \"system(#{args.map{|a| a.inspect }.join(' ')}) failed\"\n  end\n\n  def ruby(*args)\n    command config('rubyprog'), *args\n  end\n  \n  def make(task = nil)\n    command(*[config('makeprog'), task].compact)\n  end\n\n  def extdir?(dir)\n    File.exist?(\"#{dir}/MANIFEST\") or File.exist?(\"#{dir}/extconf.rb\")\n  end\n\n  def files_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.file?(\"#{dir}/#{ent}\") }\n    }\n  end\n\n  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )\n\n  def directories_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.dir?(\"#{dir}/#{ent}\") } - DIR_REJECT\n    }\n  end\n\nend\n\n\n# This module requires: #srcdir_root, #objdir_root, #relpath\nmodule HookScriptAPI\n\n  def get_config(key)\n    @config[key]\n  end\n\n  alias config get_config\n\n  # obsolete: use metaconfig to change configuration\n  def set_config(key, val)\n    @config[key] = val\n  end\n\n  #\n  # srcdir/objdir (works only in the package directory)\n  #\n\n  def curr_srcdir\n    \"#{srcdir_root()}/#{relpath()}\"\n  end\n\n  def curr_objdir\n    \"#{objdir_root()}/#{relpath()}\"\n  end\n\n  def srcfile(path)\n    \"#{curr_srcdir()}/#{path}\"\n  end\n\n  def srcexist?(path)\n    File.exist?(srcfile(path))\n  end\n\n  def srcdirectory?(path)\n    File.dir?(srcfile(path))\n  end\n  \n  def srcfile?(path)\n    File.file?(srcfile(path))\n  end\n\n  def srcentries(path = '.')\n    Dir.open(\"#{curr_srcdir()}/#{path}\") {|d|\n      return d.to_a - %w(. ..)\n    }\n  end\n\n  def srcfiles(path = '.')\n    srcentries(path).select {|fname|\n      File.file?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\n  def srcdirectories(path = '.')\n    srcentries(path).select {|fname|\n      File.dir?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\nend\n\n\nclass ToplevelInstaller\n\n  Version   = '3.4.1'\n  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'\n\n  TASKS = [\n    [ 'all',      'do config, setup, then install' ],\n    [ 'config',   'saves your configurations' ],\n    [ 'show',     'shows current configuration' ],\n    [ 'setup',    'compiles ruby extentions and others' ],\n    [ 'install',  'installs files' ],\n    [ 'test',     'run all tests in test/' ],\n    [ 'clean',    \"does `make clean' for each extention\" ],\n    [ 'distclean',\"does `make distclean' for each extention\" ]\n  ]\n\n  def ToplevelInstaller.invoke\n    config = ConfigTable.new(load_rbconfig())\n    config.load_standard_entries\n    config.load_multipackage_entries if multipackage?\n    config.fixup\n    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)\n    klass.new(File.dirname($0), config).invoke\n  end\n\n  def ToplevelInstaller.multipackage?\n    File.dir?(File.dirname($0) + '/packages')\n  end\n\n  def ToplevelInstaller.load_rbconfig\n    if arg = ARGV.detect {|arg| /\\A--rbconfig=/ =~ arg }\n      ARGV.delete(arg)\n      load File.expand_path(arg.split(/=/, 2)[1])\n      $\".push 'rbconfig.rb'\n    else\n      require 'rbconfig'\n    end\n    ::Config::CONFIG\n  end\n\n  def initialize(ardir_root, config)\n    @ardir = File.expand_path(ardir_root)\n    @config = config\n    # cache\n    @valid_task_re = nil\n  end\n\n  def config(key)\n    @config[key]\n  end\n\n  def inspect\n    \"#<#{self.class} #{__id__()}>\"\n  end\n\n  def invoke\n    run_metaconfigs\n    case task = parsearg_global()\n    when nil, 'all'\n      parsearg_config\n      init_installers\n      exec_config\n      exec_setup\n      exec_install\n    else\n      case task\n      when 'config', 'test'\n        ;\n      when 'clean', 'distclean'\n        @config.load_savefile if File.exist?(@config.savefile)\n      else\n        @config.load_savefile\n      end\n      __send__ \"parsearg_#{task}\"\n      init_installers\n      __send__ \"exec_#{task}\"\n    end\n  end\n  \n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\"\n  end\n\n  def init_installers\n    @installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  #\n  # Hook Script API bases\n  #\n\n  def srcdir_root\n    @ardir\n  end\n\n  def objdir_root\n    '.'\n  end\n\n  def relpath\n    '.'\n  end\n\n  #\n  # Option Parsing\n  #\n\n  def parsearg_global\n    while arg = ARGV.shift\n      case arg\n      when /\\A\\w+\\z/\n        setup_rb_error \"invalid task: #{arg}\" unless valid_task?(arg)\n        return arg\n      when '-q', '--quiet'\n        @config.verbose = false\n      when '--verbose'\n        @config.verbose = true\n      when '--help'\n        print_usage $stdout\n        exit 0\n      when '--version'\n        puts \"#{File.basename($0)} version #{Version}\"\n        exit 0\n      when '--copyright'\n        puts Copyright\n        exit 0\n      else\n        setup_rb_error \"unknown global option '#{arg}'\"\n      end\n    end\n    nil\n  end\n\n  def valid_task?(t)\n    valid_task_re() =~ t\n  end\n\n  def valid_task_re\n    @valid_task_re ||= /\\A(?:#{TASKS.map {|task,desc| task }.join('|')})\\z/\n  end\n\n  def parsearg_no_options\n    unless ARGV.empty?\n      task = caller(0).first.slice(%r<`parsearg_(\\w+)'>, 1)\n      setup_rb_error \"#{task}: unknown options: #{ARGV.join(' ')}\"\n    end\n  end\n\n  alias parsearg_show       parsearg_no_options\n  alias parsearg_setup      parsearg_no_options\n  alias parsearg_test       parsearg_no_options\n  alias parsearg_clean      parsearg_no_options\n  alias parsearg_distclean  parsearg_no_options\n\n  def parsearg_config\n    evalopt = []\n    set = []\n    @config.config_opt = []\n    while i = ARGV.shift\n      if /\\A--?\\z/ =~ i\n        @config.config_opt = ARGV.dup\n        break\n      end\n      name, value = *@config.parse_opt(i)\n      if @config.value_config?(name)\n        @config[name] = value\n      else\n        evalopt.push [name, value]\n      end\n      set.push name\n    end\n    evalopt.each do |name, value|\n      @config.lookup(name).evaluate value, @config\n    end\n    # Check if configuration is valid\n    set.each do |n|\n      @config[n] if @config.value_config?(n)\n    end\n  end\n\n  def parsearg_install\n    @config.no_harm = false\n    @config.install_prefix = ''\n    while a = ARGV.shift\n      case a\n      when '--no-harm'\n        @config.no_harm = true\n      when /\\A--prefix=/\n        path = a.split(/=/, 2)[1]\n        path = File.expand_path(path) unless path[0,1] == '/'\n        @config.install_prefix = path\n      else\n        setup_rb_error \"install: unknown option #{a}\"\n      end\n    end\n  end\n\n  def print_usage(out)\n    out.puts 'Typical Installation Procedure:'\n    out.puts \"  $ ruby #{File.basename $0} config\"\n    out.puts \"  $ ruby #{File.basename $0} setup\"\n    out.puts \"  # ruby #{File.basename $0} install (may require root privilege)\"\n    out.puts\n    out.puts 'Detailed Usage:'\n    out.puts \"  ruby #{File.basename $0} <global option>\"\n    out.puts \"  ruby #{File.basename $0} [<global options>] <task> [<task options>]\"\n\n    fmt = \"  %-24s %s\\n\"\n    out.puts\n    out.puts 'Global options:'\n    out.printf fmt, '-q,--quiet',   'suppress message outputs'\n    out.printf fmt, '   --verbose', 'output messages verbosely'\n    out.printf fmt, '   --help',    'print this message'\n    out.printf fmt, '   --version', 'print version and quit'\n    out.printf fmt, '   --copyright',  'print copyright and quit'\n    out.puts\n    out.puts 'Tasks:'\n    TASKS.each do |name, desc|\n      out.printf fmt, name, desc\n    end\n\n    fmt = \"  %-24s %s [%s]\\n\"\n    out.puts\n    out.puts 'Options for CONFIG or ALL:'\n    @config.each do |item|\n      out.printf fmt, item.help_opt, item.description, item.help_default\n    end\n    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',\"running ruby's\"\n    out.puts\n    out.puts 'Options for INSTALL:'\n    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'\n    out.printf fmt, '--prefix=path',  'install path prefix', ''\n    out.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    @installer.exec_config\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    @installer.exec_setup\n  end\n\n  def exec_install\n    @installer.exec_install\n  end\n\n  def exec_test\n    @installer.exec_test\n  end\n\n  def exec_show\n    @config.each do |i|\n      printf \"%-20s %s\\n\", i.name, i.value if i.value?\n    end\n  end\n\n  def exec_clean\n    @installer.exec_clean\n  end\n\n  def exec_distclean\n    @installer.exec_distclean\n  end\n\nend   # class ToplevelInstaller\n\n\nclass ToplevelInstallerMulti < ToplevelInstaller\n\n  include FileOperations\n\n  def initialize(ardir_root, config)\n    super\n    @packages = directories_of(\"#{@ardir}/packages\")\n    raise 'no package exists' if @packages.empty?\n    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\", self\n    @packages.each do |name|\n      @config.load_script \"#{@ardir}/packages/#{name}/metaconfig\"\n    end\n  end\n\n  attr_reader :packages\n\n  def packages=(list)\n    raise 'package list is empty' if list.empty?\n    list.each do |name|\n      raise \"directory packages/#{name} does not exist\"\\\n              unless File.dir?(\"#{@ardir}/packages/#{name}\")\n    end\n    @packages = list\n  end\n\n  def init_installers\n    @installers = {}\n    @packages.each do |pack|\n      @installers[pack] = Installer.new(@config,\n                                       \"#{@ardir}/packages/#{pack}\",\n                                       \"packages/#{pack}\")\n    end\n    with    = extract_selection(config('with'))\n    without = extract_selection(config('without'))\n    @selected = @installers.keys.select {|name|\n                  (with.empty? or with.include?(name)) \\\n                      and not without.include?(name)\n                }\n  end\n\n  def extract_selection(list)\n    a = list.split(/,/)\n    a.each do |name|\n      setup_rb_error \"no such package: #{name}\"  unless @installers.key?(name)\n    end\n    a\n  end\n\n  def print_usage(f)\n    super\n    f.puts 'Inluded packages:'\n    f.puts '  ' + @packages.sort.join(' ')\n    f.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    run_hook 'pre-config'\n    each_selected_installers {|inst| inst.exec_config }\n    run_hook 'post-config'\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    run_hook 'pre-setup'\n    each_selected_installers {|inst| inst.exec_setup }\n    run_hook 'post-setup'\n  end\n\n  def exec_install\n    run_hook 'pre-install'\n    each_selected_installers {|inst| inst.exec_install }\n    run_hook 'post-install'\n  end\n\n  def exec_test\n    run_hook 'pre-test'\n    each_selected_installers {|inst| inst.exec_test }\n    run_hook 'post-test'\n  end\n\n  def exec_clean\n    rm_f @config.savefile\n    run_hook 'pre-clean'\n    each_selected_installers {|inst| inst.exec_clean }\n    run_hook 'post-clean'\n  end\n\n  def exec_distclean\n    rm_f @config.savefile\n    run_hook 'pre-distclean'\n    each_selected_installers {|inst| inst.exec_distclean }\n    run_hook 'post-distclean'\n  end\n\n  #\n  # lib\n  #\n\n  def each_selected_installers\n    Dir.mkdir 'packages' unless File.dir?('packages')\n    @selected.each do |pack|\n      $stderr.puts \"Processing the package `#{pack}' ...\" if verbose?\n      Dir.mkdir \"packages/#{pack}\" unless File.dir?(\"packages/#{pack}\")\n      Dir.chdir \"packages/#{pack}\"\n      yield @installers[pack]\n      Dir.chdir '../..'\n    end\n  end\n\n  def run_hook(id)\n    @root_installer.run_hook id\n  end\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\nend   # class ToplevelInstallerMulti\n\n\nclass Installer\n\n  FILETYPES = %w( bin lib ext data conf man )\n\n  include FileOperations\n  include HookScriptAPI\n\n  def initialize(config, srcroot, objroot)\n    @config = config\n    @srcdir = File.expand_path(srcroot)\n    @objdir = File.expand_path(objroot)\n    @currdir = '.'\n  end\n\n  def inspect\n    \"#<#{self.class} #{File.basename(@srcdir)}>\"\n  end\n\n  def noop(rel)\n  end\n\n  #\n  # Hook Script API base methods\n  #\n\n  def srcdir_root\n    @srcdir\n  end\n\n  def objdir_root\n    @objdir\n  end\n\n  def relpath\n    @currdir\n  end\n\n  #\n  # Config Access\n  #\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\n  def verbose_off\n    begin\n      save, @config.verbose = @config.verbose?, false\n      yield\n    ensure\n      @config.verbose = save\n    end\n  end\n\n  #\n  # TASK config\n  #\n\n  def exec_config\n    exec_task_traverse 'config'\n  end\n\n  alias config_dir_bin noop\n  alias config_dir_lib noop\n\n  def config_dir_ext(rel)\n    extconf if extdir?(curr_srcdir())\n  end\n\n  alias config_dir_data noop\n  alias config_dir_conf noop\n  alias config_dir_man noop\n\n  def extconf\n    ruby \"#{curr_srcdir()}/extconf.rb\", *@config.config_opt\n  end\n\n  #\n  # TASK setup\n  #\n\n  def exec_setup\n    exec_task_traverse 'setup'\n  end\n\n  def setup_dir_bin(rel)\n    files_of(curr_srcdir()).each do |fname|\n      update_shebang_line \"#{curr_srcdir()}/#{fname}\"\n    end\n  end\n\n  alias setup_dir_lib noop\n\n  def setup_dir_ext(rel)\n    make if extdir?(curr_srcdir())\n  end\n\n  alias setup_dir_data noop\n  alias setup_dir_conf noop\n  alias setup_dir_man noop\n\n  def update_shebang_line(path)\n    return if no_harm?\n    return if config('shebang') == 'never'\n    old = Shebang.load(path)\n    if old\n      $stderr.puts \"warning: #{path}: Shebang line includes too many args.  It is not portable and your program may not work.\" if old.args.size > 1\n      new = new_shebang(old)\n      return if new.to_s == old.to_s\n    else\n      return unless config('shebang') == 'all'\n      new = Shebang.new(config('rubypath'))\n    end\n    $stderr.puts \"updating shebang: #{File.basename(path)}\" if verbose?\n    open_atomic_writer(path) {|output|\n      File.open(path, 'rb') {|f|\n        f.gets if old   # discard\n        output.puts new.to_s\n        output.print f.read\n      }\n    }\n  end\n\n  def new_shebang(old)\n    if /\\Aruby/ =~ File.basename(old.cmd)\n      Shebang.new(config('rubypath'), old.args)\n    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'\n      Shebang.new(config('rubypath'), old.args[1..-1])\n    else\n      return old unless config('shebang') == 'all'\n      Shebang.new(config('rubypath'))\n    end\n  end\n\n  def open_atomic_writer(path, &block)\n    tmpfile = File.basename(path) + '.tmp'\n    begin\n      File.open(tmpfile, 'wb', &block)\n      File.rename tmpfile, File.basename(path)\n    ensure\n      File.unlink tmpfile if File.exist?(tmpfile)\n    end\n  end\n\n  class Shebang\n    def Shebang.load(path)\n      line = nil\n      File.open(path) {|f|\n        line = f.gets\n      }\n      return nil unless /\\A#!/ =~ line\n      parse(line)\n    end\n\n    def Shebang.parse(line)\n      cmd, *args = *line.strip.sub(/\\A\\#!/, '').split(' ')\n      new(cmd, args)\n    end\n\n    def initialize(cmd, args = [])\n      @cmd = cmd\n      @args = args\n    end\n\n    attr_reader :cmd\n    attr_reader :args\n\n    def to_s\n      \"#! #{@cmd}\" + (@args.empty? ? '' : \" #{@args.join(' ')}\")\n    end\n  end\n\n  #\n  # TASK install\n  #\n\n  def exec_install\n    rm_f 'InstalledFiles'\n    exec_task_traverse 'install'\n  end\n\n  def install_dir_bin(rel)\n    install_files targetfiles(), \"#{config('bindir')}/#{rel}\", 0755\n  end\n\n  def install_dir_lib(rel)\n    install_files libfiles(), \"#{config('rbdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    install_files rubyextentions('.'),\n                  \"#{config('sodir')}/#{File.dirname(rel)}\",\n                  0555\n  end\n\n  def install_dir_data(rel)\n    install_files targetfiles(), \"#{config('datadir')}/#{rel}\", 0644\n  end\n\n  def install_dir_conf(rel)\n    # FIXME: should not remove current config files\n    # (rename preious file to .old/.org)\n    install_files targetfiles(), \"#{config('sysconfdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_man(rel)\n    install_files targetfiles(), \"#{config('mandir')}/#{rel}\", 0644\n  end\n\n  def install_files(list, dest, mode)\n    mkdir_p dest, @config.install_prefix\n    list.each do |fname|\n      install fname, dest, mode, @config.install_prefix\n    end\n  end\n\n  def libfiles\n    glob_reject(%w(*.y *.output), targetfiles())\n  end\n\n  def rubyextentions(dir)\n    ents = glob_select(\"*.#{@config.dllext}\", targetfiles())\n    if ents.empty?\n      setup_rb_error \"no ruby extention exists: 'ruby #{$0} setup' first\"\n    end\n    ents\n  end\n\n  def targetfiles\n    mapdir(existfiles() - hookfiles())\n  end\n\n  def mapdir(ents)\n    ents.map {|ent|\n      if File.exist?(ent)\n      then ent                         # objdir\n      else \"#{curr_srcdir()}/#{ent}\"   # srcdir\n      end\n    }\n  end\n\n  # picked up many entries from cvs-1.11.1/src/ignore.c\n  JUNK_FILES = %w( \n    core RCSLOG tags TAGS .make.state\n    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb\n    *~ *.old *.bak *.BAK *.orig *.rej _$* *$\n\n    *.org *.in .*\n  )\n\n  def existfiles\n    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))\n  end\n\n  def hookfiles\n    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|\n      %w( config setup install clean ).map {|t| sprintf(fmt, t) }\n    }.flatten\n  end\n\n  def glob_select(pat, ents)\n    re = globs2re([pat])\n    ents.select {|ent| re =~ ent }\n  end\n\n  def glob_reject(pats, ents)\n    re = globs2re(pats)\n    ents.reject {|ent| re =~ ent }\n  end\n\n  GLOB2REGEX = {\n    '.' => '\\.',\n    '$' => '\\$',\n    '#' => '\\#',\n    '*' => '.*'\n  }\n\n  def globs2re(pats)\n    /\\A(?:#{\n      pats.map {|pat| pat.gsub(/[\\.\\$\\#\\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')\n    })\\z/\n  end\n\n  #\n  # TASK test\n  #\n\n  TESTDIR = 'test'\n\n  def exec_test\n    unless File.directory?('test')\n      $stderr.puts 'no test in this package' if verbose?\n      return\n    end\n    $stderr.puts 'Running tests...' if verbose?\n    begin\n      require 'test/unit'\n    rescue LoadError\n      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to invoke this task.'\n    end\n    runner = Test::Unit::AutoRunner.new(true)\n    runner.to_run << TESTDIR\n    runner.run\n  end\n\n  #\n  # TASK clean\n  #\n\n  def exec_clean\n    exec_task_traverse 'clean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias clean_dir_bin noop\n  alias clean_dir_lib noop\n  alias clean_dir_data noop\n  alias clean_dir_conf noop\n  alias clean_dir_man noop\n\n  def clean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'clean' if File.file?('Makefile')\n  end\n\n  #\n  # TASK distclean\n  #\n\n  def exec_distclean\n    exec_task_traverse 'distclean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias distclean_dir_bin noop\n  alias distclean_dir_lib noop\n\n  def distclean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'distclean' if File.file?('Makefile')\n  end\n\n  alias distclean_dir_data noop\n  alias distclean_dir_conf noop\n  alias distclean_dir_man noop\n\n  #\n  # Traversing\n  #\n\n  def exec_task_traverse(task)\n    run_hook \"pre-#{task}\"\n    FILETYPES.each do |type|\n      if type == 'ext' and config('without-ext') == 'yes'\n        $stderr.puts 'skipping ext/* by user option' if verbose?\n        next\n      end\n      traverse task, type, \"#{task}_dir_#{type}\"\n    end\n    run_hook \"post-#{task}\"\n  end\n\n  def traverse(task, rel, mid)\n    dive_into(rel) {\n      run_hook \"pre-#{task}\"\n      __send__ mid, rel.sub(%r[\\A.*?(?:/|\\z)], '')\n      directories_of(curr_srcdir()).each do |d|\n        traverse task, \"#{rel}/#{d}\", mid\n      end\n      run_hook \"post-#{task}\"\n    }\n  end\n\n  def dive_into(rel)\n    return unless File.dir?(\"#{@srcdir}/#{rel}\")\n\n    dir = File.basename(rel)\n    Dir.mkdir dir unless File.dir?(dir)\n    predir = Dir.pwd\n    Dir.chdir dir\n    $stderr.puts '---> ' + rel if verbose?\n    @currdir = rel\n    yield\n    Dir.chdir predir\n    $stderr.puts '<--- ' + rel if verbose?\n    @currdir = File.dirname(rel)\n  end\n\n  def run_hook(id)\n    path = [ \"#{curr_srcdir()}/#{id}\",\n             \"#{curr_srcdir()}/#{id}.rb\" ].detect {|cand| File.file?(cand) }\n    return unless path\n    begin\n      instance_eval File.read(path), path, 1\n    rescue\n      raise if $DEBUG\n      setup_rb_error \"hook #{path} failed:\\n\" + $!.message\n    end\n  end\n\nend   # class Installer\n\n\nclass SetupError < StandardError; end\n\ndef setup_rb_error(msg)\n  raise SetupError, msg\nend\n\nif $0 == __FILE__\n  begin\n    ToplevelInstaller.invoke\n  rescue SetupError\n    raise if $DEBUG\n    $stderr.puts $!.message\n    $stderr.puts \"Try 'ruby #{$0} --help' for detailed usage.\"\n    exit 1\n  end\nend\n"
  },
  {
    "path": "test/fixtures/bad_perms_test_key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQI\nxYJG8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOh\nMykU4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS\n92sUSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMX\nXe64JuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+w\nHH6RLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIwKCAQBczhm9aFceHs3k0vsv\nljzDDbONVZxIM96d69ZW0xDtYdunLbrd8mmTNlGu4n5P930UOqyRKQZme+YcsZhO\nOjE17ELvTCAJot2acs4l/f2L1PQ2b1+iW+xJuiU3zxB/e6e98PqY4Jwge+9W9Y+/\nXWAh2RpCGRNpxbKDI1UJR95usRxhxlmY0RmUtpDjc3qEOPRgj7E2iC4fFVdvYzKt\nFBkGR6Gv2/jqm+c/TmRCFnyaWJXC8W6LkkACjUc6IKUOBSbs6l+3DH0PBOr+XbGv\npeExAfYCTfvGy/NNPpzP0JJUJ92sWaZUPUTf8McSsgrTTRBfklsJuf9Hje/8abcr\nAheLAoGBAPGX3CDMU68BTgO8bOvGhFHQSu9AypIhEh0PrE1CYsEvYrIRg9h23fuz\n1nz7Z6kIYTNMywxfphEL65CTiJ5eSJV+UGMFAKYziCwH7MDD4Wc6cPLrGmA0eYDz\nQMUQJwqfuXKq/dMw2VB6qGbNmbERWmq3wteF/afyTatd6poV4UcXAoGBANcd/o4s\nzf1SwxKoT4GGp62gtqT+gIbGkV0AzWBcaDarRNbcV7uFZLL7wzPcCR8/cPZiN+ks\n+LsVYvDfrFHRxtdzIesxcqG2v6LazB/+/rZp4Hqc1a4OwxSdOYzINjA01GV2HcET\nXzoJIQA8ZYuVpELaNzjLtKBZ6mrQmBh7RRVBAoGBAJ7C4RzeCxs7XycGyzvaObIb\nKe2uO/mgtCG516B8FQKbe18S0vv2V1xC+qnnCZr24MnworBcHKwdxq925L/Xjsij\ndqd4UOI/Hvhc+qqPWZubbsuEjazvSIfwTyJps0F+55R+/pIYyVIkt86HG9rCQrso\nTNbFw/IFoMER1K5mJlNJAoGAT+aRv8d/tdzpXrOLPrz8c7C43jKkxFhh4LcnthOx\nrefXvYUKpLyEfP5tE0MZVL/K3yvLn8A/IOqvuI2Xxp5fzF32p9CJqceJAfl/BJHp\nlDX0SsyJ4ZB0WB0kARcqEee8mrbX2f/hipWtK/ktB/XAqx3Z/ycXND6nhsKBorFx\nbksCgYEAtPns7oc98wmF8j37ELikMFJOvQgccbGTzcJ1RVzji95HfN4p3kA6emo/\nhRyP8XNedEI/CD6MmthKKymw5Ck1I51nwDW4+zTEDAN14nh4T9p6Jqe7lSENqLaY\nA5jkgXV8e0YqKkjLNec5hAzoEY09KryQdz81KXeHvbEUfIiItTk=\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "test/fixtures/chef/recipes/sudo/attributes/sudoers.rb",
    "content": "#\n# Cookbook Name:: sudo\n# Attribute File:: sudoers\n#\n# Copyright 2008, OpsCode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nauthorization Mash.new unless attribute?(\"authorization\")\n\nauthorization[:sudo] = Mash.new unless authorization.has_key?(:sudo)\n\nunless authorization[:sudo].has_key?(:groups)\n  authorization[:sudo][:groups] = Array.new \nend\n\nunless authorization[:sudo].has_key?(:users)\n  authorization[:sudo][:users] = Array.new\nend\n"
  },
  {
    "path": "test/fixtures/chef/recipes/sudo/recipes/default.rb",
    "content": "#\n# Cookbook Name:: sudo\n# Recipe:: default\n#\n# Copyright 2008, OpsCode, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\npackage \"sudo\" do\n  action :upgrade\nend\n\ntemplate \"/etc/sudoers\" do\n  source \"sudoers.erb\"\n  mode 0440\n  owner \"root\"\n  group \"root\"\n  variables(\n    :sudoers_groups => node[:authorization][:sudo][:groups], \n    :sudoers_users => node[:authorization][:sudo][:users]\n  )\nend"
  },
  {
    "path": "test/fixtures/chef/recipes/sudo/templates/default/sudoers.erb",
    "content": "#\n# /etc/sudoers\n# \n# Generated by Chef for <%= @node[:fqdn] %>\n# \n\nDefaults        !lecture,tty_tickets,!fqdn\n\n# User privilege specification\nroot    \t\t\tALL=(ALL) ALL\n\n<% @sudoers_users.each do |user| -%>\n<%= user %> ALL=(ALL) ALL\n<% end -%>\n\n# Members of the sysadmin group may gain root privileges\n%sysadmin \t\tALL=(ALL) ALL\n\n<% @sudoers_groups.each do |group| -%>\n# Members of the group '<%= group %>' may gain root privileges\n%<%= group %> ALL=(ALL) ALL\n<% end -%>"
  },
  {
    "path": "test/fixtures/clouds/rds_cloud.rb",
    "content": "# test RDS pool\n\npool :poolparty do\n  cloud :fake_cloud do\n    keypair File.dirname(__FILE__)+\"/../keys/test_key\"\n    using :ec2\n\n    rds :db1 do\n      username \"admin\"\n      password \"secret\"\n      storage 5\n    end\n  end\nend"
  },
  {
    "path": "test/fixtures/clouds/rds_missing_params.rb",
    "content": "# test RDS pool\n\npool :poolparty do\n  cloud :fake_cloud do\n    keypair File.dirname(__FILE__)+\"/../keys/test_key\"\n    using :ec2\n\n    rds :db1 do\n    end\n  end\nend"
  },
  {
    "path": "test/fixtures/clouds/simple_cloud.rb",
    "content": "# Poolparty spec\n\npool \"poolparty\" do\n  \n  cloud :fake_cloud do\n    keypair File.dirname(__FILE__)+\"/../keys/test_key\"\n    using :ec2 do\n    end\n  end\n  \nend"
  },
  {
    "path": "test/fixtures/clouds/ssh_cloud.rb",
    "content": "pool :tssh do\n  cloud :tgarden do\n    instances 2\n    keypair File.join(FIXTURES_PATH, 'keys/test_key')\n    using :ssh do\n      user 'fairchild'  #default is root\n      hosts %w(beet squash)\n    end\n    has_file '/etc/poolparty/welcome', :content=>\"Welcome to the #{self.name} cloud\" \n  end\nend\n"
  },
  {
    "path": "test/fixtures/clouds/vmware_cloud.rb",
    "content": "pool \"local\" do\n  \n  cloud \"local_app\" do\n    keypair \"id_rsa\"\n    using :vmware do\n      image_id \"/Users/alerner/Documents/vm/Ubuntu32bitVM.vmwarevm/Ubuntu32bitVM.vmx\"\n      public_ip \"192.168.248.133\"\n    end\n    \n    has_file \"/etc/motd\", :content => \"BURN! Pocket Aces\"\n    \n    apache\n    \n  end\n  \nend"
  },
  {
    "path": "test/fixtures/ec2/ec2-describe-instances_response_body.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<DescribeInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2008-12-01/\">\n  <requestId>89d95a27-25b1-47bd-82a2-a70a936e0913</requestId>\n  <reservationSet>\n    <item>\n      <reservationId>r-c72545ae</reservationId>\n      <ownerId>481524450359</ownerId>\n      <groupSet>\n        <item>\n          <groupId>poolparty-fake_cloud</groupId>\n        </item>\n      </groupSet>\n      <instancesSet>\n        <item>\n          <instanceId>i-7fd89416</instanceId>\n          <imageId>ami-bf5eb9d6</imageId>\n          <instanceState>\n            <code>16</code>\n            <name>running</name>\n          </instanceState>\n          <privateDnsName>ip-10-250-46-144.ec2.internal</privateDnsName>\n          <dnsName>ec2-75-101-141-103.compute-1.amazonaws.com</dnsName>\n          <reason/>\n          <keyName>test_key</keyName>\n          <amiLaunchIndex>0</amiLaunchIndex>\n          <productCodes/>\n          <instanceType>m1.small</instanceType>\n          <launchTime>2009-05-31T17:56:42.000Z</launchTime>\n          <placement>\n            <availabilityZone>us-east-1c</availabilityZone>\n          </placement>\n          <kernelId>aki-a71cf9ce</kernelId>\n          <ramdiskId>ari-a51cf9cc</ramdiskId>\n        </item>\n      </instancesSet>\n    </item>\n    <item>\n      <reservationId>r-e9b4ff80</reservationId>\n      <ownerId>481524450359</ownerId>\n      <groupSet>\n        <item>\n          <groupId>poolparty-fake_cloud</groupId>\n        </item>\n      </groupSet>\n      <instancesSet>\n        <item>\n          <instanceId>i-7f000516</instanceId>\n          <imageId>ami-0d729464</imageId>\n          <instanceState>\n            <code>16</code>\n            <name>running</name>\n          </instanceState>\n          <privateDnsName>ip-10-251-74-198.ec2.internal</privateDnsName>\n          <dnsName>ec2-67-202-10-73.compute-1.amazonaws.com</dnsName>\n          <reason/>\n          <keyName>test_key</keyName>\n          <amiLaunchIndex>0</amiLaunchIndex>\n          <productCodes/>\n          <instanceType>m1.small</instanceType>\n          <launchTime>2009-07-20T20:35:51.000Z</launchTime>\n          <placement>\n            <availabilityZone>us-east-1c</availabilityZone>\n          </placement>\n          <kernelId>aki-a71cf9ce</kernelId>\n          <ramdiskId>ari-a51cf9cc</ramdiskId>\n        </item>\n      </instancesSet>\n    </item>\n  </reservationSet>\n</DescribeInstancesResponse>"
  },
  {
    "path": "test/fixtures/ec2/ec2-describe-security-groups_response_body.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<DescribeSecurityGroupsResponse xmlns=\"http://ec2.amazonaws.com/doc/2007-03-01\">\n  <securityGroupInfo>\n    <item>\n      <ownerId>1234567890</ownerId>\n      <groupName>poolparty-fake_cloud</groupName>\n      <groupDescription>poolparty-fake_cloud</groupDescription>\n      <ipPermissions>\n        <item>\n          <ipProtocol>tcp</ipProtocol>\n          <fromPort>80</fromPort>\n          <toPort>80</toPort>\n          <groups/>\n          <ipRanges>\n            <item>\n              <cidrIp>0.0.0.0/0</cidrIp>\n            </item>\n          </ipRanges>\n        </item>\n      </ipPermissions>\n    </item>\n  </securityGroupInfo>\n</DescribeSecurityGroupsResponse>\n"
  },
  {
    "path": "test/fixtures/ec2/ec2-run-instances_response_body.xml",
    "content": "<RunInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2009-04-04/\">\n  <requestId>c1128a8d-59e6-4aad-8923-12b07ff873ec</requestId>\n  <reservationId>r-51D70925</reservationId>\n  <ownerId>admin</ownerId>\n  <groupSet>\n    <item>\n      <groupId>admin-default</groupId>\n    </item>\n  </groupSet>\n  <instancesSet>\n    <item>\n      <instanceId>i-485C07DE</instanceId>\n      <imageId>emi-39CA160F</imageId>\n      <instanceState>\n        <code>0</code>\n        <name>pending</name>\n      </instanceState>\n      <privateDnsName>0.0.0.0</privateDnsName>\n      <dnsName>0.0.0.0</dnsName>\n      <keyName>eucalyptus_sample</keyName>\n      <amiLaunchIndex>0</amiLaunchIndex>\n      <productCodes/>\n      <instanceType>m1.small</instanceType>\n      <launchTime>2009-07-22T00:09:29.293Z</launchTime>\n      <placement>\n        <availabilityZone>garden</availabilityZone>\n      </placement>\n      <kernelId>eki-AE9D17DD</kernelId>\n      <ramdiskId>eri-171A1927</ramdiskId>\n      <monitoring>\n        <state>false</state>\n      </monitoring>\n    </item>\n  </instancesSet>\n</RunInstancesResponse>"
  },
  {
    "path": "test/fixtures/ec2/ec2-terminate-instances_response_body.xml",
    "content": "<TerminateInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2009-04-04/\">\n  <requestId>d16d104e-f450-4d5c-8354-70a8cad2dacd</requestId>\n  <instancesSet>\n    <item>\n      <instanceId>i-3B3506A0</instanceId>\n      <shutdownState>\n        <code>32</code>\n        <name>shutting-down</name>\n      </shutdownState>\n      <previousState>\n        <code>16</code>\n        <name>running</name>\n      </previousState>\n    </item>\n  </instancesSet>\n</TerminateInstancesResponse>\n"
  },
  {
    "path": "test/fixtures/ec2/elb-describe-load-balancers.xml",
    "content": "<DescribeLoadBalancersResponse xmlns=\"http://elasticloadbalancing.amazonaws.com/doc/2009-05-15/\">\n  <DescribeLoadBalancersResult>\n    <LoadBalancerDescriptions>\n      <member>\n        <LoadBalancerName>hemant-watson-lb</LoadBalancerName>\n        <DNSName>hemant-watson-lb-1501915372.us-east-1.elb.amazonaws.com</DNSName>\n        <Listeners>\n          <member>\n            <Protocol>HTTP</Protocol>\n            <LoadBalancerPort>80</LoadBalancerPort>\n            <InstancePort>8080</InstancePort>\n          </member>\n        </Listeners>\n        <AvailabilityZones>\n          <member>us-east-1c</member>\n        </AvailabilityZones>\n        <Instances>\n          <member>\n            <InstanceId>i-61835409</InstanceId>\n          </member>\n          <member>\n            <InstanceId>i-ab8453c3</InstanceId>\n          </member>\n        </Instances>\n        <HealthCheck>\n          <Target>TCP:8080</Target>\n          <Interval>30</Interval>\n          <Timeout>5</Timeout>\n          <UnhealthyThreshold>2</UnhealthyThreshold>\n          <HealthyThreshold>10</HealthyThreshold>\n        </HealthCheck>\n        <CreatedTime>2009-09-22T22:00:35.790Z</CreatedTime>\n      </member>\n      <member>\n        <LoadBalancerName>minerva-pool</LoadBalancerName>\n        <DNSName>minerva-pool-1740816084.us-east-1.elb.amazonaws.com</DNSName>\n        <Listeners>\n          <member>\n            <Protocol>HTTP</Protocol>\n            <LoadBalancerPort>80</LoadBalancerPort>\n            <InstancePort>80</InstancePort>\n          </member>\n        </Listeners>\n        <AvailabilityZones>\n          <member>us-east-1a</member>\n        </AvailabilityZones>\n        <Instances>\n          <member>\n            <InstanceId>i-49b67f21</InstanceId>\n          </member>\n          <member>\n            <InstanceId>i-a3935dcb</InstanceId>\n          </member>\n          <member>\n            <InstanceId>i-ad26efc5</InstanceId>\n          </member>\n          <member>\n            <InstanceId>i-f531f89d</InstanceId>\n          </member>\n        </Instances>\n        <HealthCheck>\n          <Target>TCP:80</Target>\n          <Interval>30</Interval>\n          <Timeout>5</Timeout>\n          <UnhealthyThreshold>2</UnhealthyThreshold>\n          <HealthyThreshold>10</HealthyThreshold>\n        </HealthCheck>\n        <CreatedTime>2009-09-18T01:42:43.470Z</CreatedTime>\n      </member>\n    </LoadBalancerDescriptions>\n  </DescribeLoadBalancersResult>\n  <ResponseMetadata>\n    <RequestId>61cc2880-a890-11de-8090-bb69e1dec4b2</RequestId>\n  </ResponseMetadata>\n</DescribeLoadBalancersResponse>\n"
  },
  {
    "path": "test/fixtures/ec2/rds-describe-db-instances-empty_response_body.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<DescribeDBInstancesResponse xmlns=\"http://rds.amazonaws.com/admin/2009-10-16/\">\n  <DescribeDBInstancesResult>\n    <DBInstances/>\n  </DescribeDBInstancesResult>\n  <ResponseMetadata>\n    <RequestId>5e547870-fa2d-11de-8e05-53428aa3290f</RequestId>\n  </ResponseMetadata>\n</DescribeDBInstancesResponse>\n"
  },
  {
    "path": "test/fixtures/keys/pem_key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQI\nxYJG8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOh\nMykU4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS\n92sUSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMX\nXe64JuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+w\nHH6RLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIwKCAQBczhm9aFceHs3k0vsv\nljzDDbONVZxIM96d69ZW0xDtYdunLbrd8mmTNlGu4n5P930UOqyRKQZme+YcsZhO\nOjE17ELvTCAJot2acs4l/f2L1PQ2b1+iW+xJuiU3zxB/e6e98PqY4Jwge+9W9Y+/\nXWAh2RpCGRNpxbKDI1UJR95usRxhxlmY0RmUtpDjc3qEOPRgj7E2iC4fFVdvYzKt\nFBkGR6Gv2/jqm+c/TmRCFnyaWJXC8W6LkkACjUc6IKUOBSbs6l+3DH0PBOr+XbGv\npeExAfYCTfvGy/NNPpzP0JJUJ92sWaZUPUTf8McSsgrTTRBfklsJuf9Hje/8abcr\nAheLAoGBAPGX3CDMU68BTgO8bOvGhFHQSu9AypIhEh0PrE1CYsEvYrIRg9h23fuz\n1nz7Z6kIYTNMywxfphEL65CTiJ5eSJV+UGMFAKYziCwH7MDD4Wc6cPLrGmA0eYDz\nQMUQJwqfuXKq/dMw2VB6qGbNmbERWmq3wteF/afyTatd6poV4UcXAoGBANcd/o4s\nzf1SwxKoT4GGp62gtqT+gIbGkV0AzWBcaDarRNbcV7uFZLL7wzPcCR8/cPZiN+ks\n+LsVYvDfrFHRxtdzIesxcqG2v6LazB/+/rZp4Hqc1a4OwxSdOYzINjA01GV2HcET\nXzoJIQA8ZYuVpELaNzjLtKBZ6mrQmBh7RRVBAoGBAJ7C4RzeCxs7XycGyzvaObIb\nKe2uO/mgtCG516B8FQKbe18S0vv2V1xC+qnnCZr24MnworBcHKwdxq925L/Xjsij\ndqd4UOI/Hvhc+qqPWZubbsuEjazvSIfwTyJps0F+55R+/pIYyVIkt86HG9rCQrso\nTNbFw/IFoMER1K5mJlNJAoGAT+aRv8d/tdzpXrOLPrz8c7C43jKkxFhh4LcnthOx\nrefXvYUKpLyEfP5tE0MZVL/K3yvLn8A/IOqvuI2Xxp5fzF32p9CJqceJAfl/BJHp\nlDX0SsyJ4ZB0WB0kARcqEee8mrbX2f/hipWtK/ktB/XAqx3Z/ycXND6nhsKBorFx\nbksCgYEAtPns7oc98wmF8j37ELikMFJOvQgccbGTzcJ1RVzji95HfN4p3kA6emo/\nhRyP8XNedEI/CD6MmthKKymw5Ck1I51nwDW4+zTEDAN14nh4T9p6Jqe7lSENqLaY\nA5jkgXV8e0YqKkjLNec5hAzoEY09KryQdz81KXeHvbEUfIiItTk=\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "test/fixtures/keys/pem_pub_key.pem",
    "content": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQIxYJG\n8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOhMykU\n4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS92sU\nSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMXXe64\nJuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+wHH6R\nLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIw==\n-----END RSA PUBLIC KEY-----"
  },
  {
    "path": "test/fixtures/keys/test_key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQI\nxYJG8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOh\nMykU4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS\n92sUSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMX\nXe64JuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+w\nHH6RLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIwKCAQBczhm9aFceHs3k0vsv\nljzDDbONVZxIM96d69ZW0xDtYdunLbrd8mmTNlGu4n5P930UOqyRKQZme+YcsZhO\nOjE17ELvTCAJot2acs4l/f2L1PQ2b1+iW+xJuiU3zxB/e6e98PqY4Jwge+9W9Y+/\nXWAh2RpCGRNpxbKDI1UJR95usRxhxlmY0RmUtpDjc3qEOPRgj7E2iC4fFVdvYzKt\nFBkGR6Gv2/jqm+c/TmRCFnyaWJXC8W6LkkACjUc6IKUOBSbs6l+3DH0PBOr+XbGv\npeExAfYCTfvGy/NNPpzP0JJUJ92sWaZUPUTf8McSsgrTTRBfklsJuf9Hje/8abcr\nAheLAoGBAPGX3CDMU68BTgO8bOvGhFHQSu9AypIhEh0PrE1CYsEvYrIRg9h23fuz\n1nz7Z6kIYTNMywxfphEL65CTiJ5eSJV+UGMFAKYziCwH7MDD4Wc6cPLrGmA0eYDz\nQMUQJwqfuXKq/dMw2VB6qGbNmbERWmq3wteF/afyTatd6poV4UcXAoGBANcd/o4s\nzf1SwxKoT4GGp62gtqT+gIbGkV0AzWBcaDarRNbcV7uFZLL7wzPcCR8/cPZiN+ks\n+LsVYvDfrFHRxtdzIesxcqG2v6LazB/+/rZp4Hqc1a4OwxSdOYzINjA01GV2HcET\nXzoJIQA8ZYuVpELaNzjLtKBZ6mrQmBh7RRVBAoGBAJ7C4RzeCxs7XycGyzvaObIb\nKe2uO/mgtCG516B8FQKbe18S0vv2V1xC+qnnCZr24MnworBcHKwdxq925L/Xjsij\ndqd4UOI/Hvhc+qqPWZubbsuEjazvSIfwTyJps0F+55R+/pIYyVIkt86HG9rCQrso\nTNbFw/IFoMER1K5mJlNJAoGAT+aRv8d/tdzpXrOLPrz8c7C43jKkxFhh4LcnthOx\nrefXvYUKpLyEfP5tE0MZVL/K3yvLn8A/IOqvuI2Xxp5fzF32p9CJqceJAfl/BJHp\nlDX0SsyJ4ZB0WB0kARcqEee8mrbX2f/hipWtK/ktB/XAqx3Z/ycXND6nhsKBorFx\nbksCgYEAtPns7oc98wmF8j37ELikMFJOvQgccbGTzcJ1RVzji95HfN4p3kA6emo/\nhRyP8XNedEI/CD6MmthKKymw5Ck1I51nwDW4+zTEDAN14nh4T9p6Jqe7lSENqLaY\nA5jkgXV8e0YqKkjLNec5hAzoEY09KryQdz81KXeHvbEUfIiItTk=\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "test/fixtures/keys/test_pub_key",
    "content": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCAKCAQEAywLYTlQ+keNiZI2FeBik6q34xStF3fF2+XPk3e21B0YQfbQIxYJG\n8gbSro90Tu1hnEBZfYm+AC8HXsR9Kx9LpfTSa3aGFRREwdsi8xuaoeHWNxOhMykU\n4UcxahT0Ft5+738kLmtVhw8bjjkqcpxCSgrpcJbad2B2ft1KBE02kiU2y7yS92sU\nSWBzVkkJTmiWBDvn5pT9y6IpVCKseWbumGQ6nozEfXe4ihUsKAH42XPxSXMXXe64\nJuONQlxZPrqyF7L/lt6ZeyKQ7yXVcxr6P4W3rPqlBhq5yXNI3vV67KUNCh+wHH6R\nLagaguS0VTdBYwo3dvkmuL6TJqnzPzrv1wIBIw==\n-----END RSA PUBLIC KEY-----"
  },
  {
    "path": "test/fixtures/resources/fake_plugin.rb",
    "content": "module PoolParty\n  module Resources\n    \n    class FakePlugin < Resource\n      \n      def self.has_method_name\n        \"fake_plugin\"\n      end\n      \n      def name\n        \"fake_plugin\"\n      end\n      \n      def after_loaded\n        has_file \"/etc/my_configs/special_config\" do\n          requires get_directory(\"/etc/my_configs\")\n        end\n        has_directory(\"/etc/my_configs\")\n      end\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "test/fixtures/resources/fake_resource.rb",
    "content": "class FakeResource < PoolParty::Resource\n  \n  default_options(\n    :name => nil\n  )\n  def self.has_method_name\n    \"tester\"\n  end\n          \n  def print_to_chef        \n    <<-EOE\nfake \"<%= name %>\" do\n  content \"<%= content %>\"\nend\n    EOE\n  end\n  \nend"
  },
  {
    "path": "test/fixtures/resources/fake_subclassed_plugin.rb",
    "content": "module PoolParty\n  module Resources\n    \n    class FakeSubclassedPlugin < Resource\n      \n      def self.has_method_name\n        \"subclassed\"\n      end\n      \n      def after_loaded\n        has_file \"/etc/my_configs/special_config\" do\n          requires get_directory(\"/etc/my_configs\")\n        end\n      end\n      \n    end\n    \n  end\nend"
  },
  {
    "path": "test/fixtures/resources/random_proc_file.rb",
    "content": "a = []\n\n@b = Proc.new do\n  @str = \"I have a bee\"\nend\n\n@c = \"cats\""
  },
  {
    "path": "test/fixtures/templates/apache_conf.erb",
    "content": "# Apache conf file\napache <%= cloud.name %>"
  },
  {
    "path": "test/fixtures/test_template.erb",
    "content": "Hello <%= friends %>"
  },
  {
    "path": "test/lib/core/array_test.rb",
    "content": "require \"test_helper\"\n\nclass ArrayTest < Test::Unit::TestCase\n  def setup\n    @arr = %w(a b c d)\n    @hash_arr = [\n                  {:name => \"peter\", :occupation => \"computer scientist\"},\n                  {:name => \"al\", :occupation => \"computer scientist\"},\n                  {:name => \"matt\", :occupation => \"doctor\"},\n                  {:name => \"jenna\", :occupation => \"lawyer\"}\n                ]\n  end\n      \n  def test_be_able_to_select_with_hash\n    assert_equal @hash_arr.select_with_hash(:name => \"matt\").first[:occupation], \"doctor\"\n    assert_equal @hash_arr.select_with_hash(:occupation => \"computer scientist\").first[:name], \"peter\"\n    assert @hash_arr.select_with_hash(:occupation => \"matt\").empty?\n  end\n  \nend"
  },
  {
    "path": "test/lib/core/hash_test.rb",
    "content": "require 'test_helper'\n\nclass HashTest < Test::Unit::TestCase\n  context \"Hash\" do\n    setup do\n      @hsh = {:a => \"a\", :b => \"b\", :c => \"c\"}\n    end\n    \n    should \"have choose to select hashes\" do      \n      assert_equal @hsh.choose {|k,v| k == :a}, {:a => \"a\"}\n      assert_equal @hsh.choose {|k,v| k == :z}, {}\n      assert_equal @hsh.choose {|k,v|[:b,:a].include?(k)}.keys.sort{|a,b|\"#{a}\"<=>\"#{b}\"}, [:a,:b]\n    end\n            \n    should \"be able to call methods on the hash of their keys\" do\n      assert_equal @hsh.a, \"a\"\n      assert_equal @hsh.b, \"b\"\n      assert_equal @hsh.c, \"c\"\n    end\n    \n    should \"compute the differences in the hashes\" do\n      assert_equal ({:a => \"a\"}).diff({:a => \"a\"}), {}\n      assert_equal ({:a => \"a\"}).diff({:a => \"b\"}), {:a => \"b\"}\n      assert_equal ({:a => \"a\", :b => \"b\"}).diff({:a => \"b\"}, :a), {:a => \"b\"}\n      assert_equal ({:a => \"a\", :b => \"b\"}).diff({:b => \"b\"}, :b), {}\n      assert_equal ({:a => \"a\", :b => \"b\"}).diff({:b => \"c\"}, :b), {:b => \"c\"}\n      assert_equal ({:a => \"a\", :b => \"b\"}).diff({:b => \"c\"}), {:b => \"c\", :a => nil}\n      assert_equal ({:a => \"a\", :b => \"b\"}).diff({:b => \"c\"}, :a), {:a => nil}\n    end\n    \n  end\n  \nend"
  },
  {
    "path": "test/lib/core/object_test.rb",
    "content": "require 'test_helper'\n\nclass ObjectTest < Test::Unit::TestCase\n  context \"object\" do\n    setup do\n      reset!\n    end\n    context \"global methods\" do\n      setup do\n        @o = Object.new\n      end\n            \n      should \"have the pools method\" do\n        assert @o.respond_to?(:pool)\n      end\n      \n      should \"make a pool when calling pool\" do\n        assert_nil @@pool\n        @@pool = pool :fun_pool do\n        end\n        assert_not_nil @@pool\n      end\n      \n    end\n    \n    \n  end\n  \nend"
  },
  {
    "path": "test/lib/core/string_test.rb",
    "content": "require 'test_helper'\n\nclass StringTest < Test::Unit::TestCase\n  context \"string\" do\n            \n    should \"camelcase properly\" do\n      assert_equal \"DocRiver\", \"doc_river\".camelcase\n      assert_equal \"AWholeLottaHotdogs\", \"a_whole_lotta_hotdogs\".camelcase\n      assert_equal \"One\", \"one\".camelcase\n    end\n    \n    should \"snake_case properly\" do\n      assert_equal \"one\", \"one\".snake_case\n      assert_equal \"plenty_of_moons\", \"PlentyOfMoons\".snake_case\n      assert_equal \"girls_make_boys_make_girls\", \"GirlsMakeBoysMakeGirls\".snake_case\n    end\n    \n    should \"dasherize properly\" do\n      assert_equal \"mini-coopers-rock\", \"MiniCoopersRock\".dasherize\n      assert_equal \"only-the-best\", \"OnlyTheBest\".dasherize\n      assert_equal \"one\", \"one\".dasherize\n    end\n    \n    should \"classify properly\" do\n      assert_equal \"ABird\", \"a_bird\".classify\n      assert_equal \"Macguyver\", \"macguyver\".classify\n      assert_equal \"RiceAndBeans\", \"rice_and_beans\".classify\n      assert_equal \"Rice::And::Beans\", \"rice::and::beans\".classify\n      assert_equal \"Pepper\", \"dr.pepper\".classify\n      assert_equal \"Dr::Pepper\", \"dr::pepper\".classify\n    end\n        \n    should \"have the / for filepaths\" do\n      assert_equal \"/root/home/stuff\", \"/root\"/\"home\"/\"stuff\"\n      assert_equal \"/root/box\", \"/root\" / \"box\"\n    end\n    \n  end\n  \nend"
  },
  {
    "path": "test/lib/core/symbol_test.rb",
    "content": "require 'test_helper'\n\nclass SymbolTest < Test::Unit::TestCase\n  context \"Symbol\" do\n    should \"be able to compare to strings\" do\n      assert_equal [:a, :c, :b].sort, [:a, :b, :c]\n      assert_nothing_raised do\n        :a <=> :b\n      end\n    end\n    \n    should \"have path separaters\" do\n      assert_equal :a / :b, \"a/b\"\n    end\n    \n    should \"classify the symbol\" do\n      assert_equal :C, :c.classify\n    end\n    \n  end\n  \nend"
  },
  {
    "path": "test/lib/poolparty/cloud_test.rb",
    "content": "require 'test_helper'\n# require 'rr'\n\nclass CloudTest < Test::Unit::TestCase\n  # include RR::Adapters::TestUnit\n  def setup\n    clear!\n    @filepath = File.join(FIXTURES_PATH, \"clouds/simple_cloud.rb\")\n    require @filepath\n    @cloud = pool.clouds[pool.clouds.keys.first]\n    stub_ec2_calls\n  end\n    \n  def test_have_a_pool_name\n    assert_equal pool.name, @cloud.pool.name\n  end\n  \n  def test_have_a_keypair\n    assert_not_nil @cloud.keypair\n    assert_equal 'test_key', @cloud.keypair.basename\n  end\n        \n  def test_be_using_ec2_cloud_provider_by_default\n    assert_equal :ec2, @cloud.cloud_provider.name\n    assert_kind_of ::CloudProviders::Ec2, @cloud.cloud_provider\n  end\n  \n  def test_set_the_cloud_provider_cloud_and_keypair_with_cloud_provider\n    assert_equal @cloud, @cloud.cloud_provider.cloud\n    assert_equal @cloud.keypair.basename, @cloud.cloud_provider.keypair.basename\n  end\n  \n  def test_set_the_cloud_provider_with_a_using_block\n    @cloud.instance_eval do\n      using :ec2\n      keypair \"test_key\", File.join(FIXTURES_PATH, \"keys\")\n      image_id 'emi-39921602'\n    end\n    assert_equal :ec2, @cloud.cloud_provider.name\n    assert_equal CloudProviders::Ec2, @cloud.cloud_provider.class\n    assert_equal \"emi-39921602\", @cloud.cloud_provider.image_id\n  end\n  \n  def test_nodes\n    assert_respond_to @cloud, :nodes\n    assert_respond_to @cloud.nodes, :each\n    assert @cloud.nodes.size>1, \"Cloudsize was: #{@cloud.nodes.size}\"\n  end\n      \n  def test_run\n    # WHAT?\n    # result = @cloud.run('uptime')\n    # assert_match /uptime/, result[\"app\"]\n  end\n    \n  def test_expansion\n    #TODO: improve this test\n    # size = @cloud.nodes.size\n    # assert_equal size+1, @cloud.expand.nodes.size\n    # assert_nothing_raised @cloud.expand\n  end\n  \n  def test_contract!\n    #TODO: need to better mock the terminate! ec2 call\n    # size = @cloud.nodes.size\n    # result = @cloud.contract!\n    # assert_equal 'shuttin-down',  result.status\n    # assert_equal size-1, @cloud.nodes.size\n  end\n  \n  def test_change_ssh_port\n    clear!\n    pool \"ssh_port\" do\n      cloud \"babity\" do\n        keypair \"test_key\"\n        ssh_port 1922\n      end\n    end\n    assert_equal 1922, clouds[\"babity\"].ssh_port\n    assert_equal 22, clouds[\"noneity\"].ssh_port\n  end\n  \n  def test_change_ssh_port\n    clear!\n    pool \"ssher\" do\n      cloud \"custom\" do\n        keypair \"test_key\"\n        # ssh_options(\"-P\" => \"1992\")\n      end\n      cloud \"noneity\" do\n        keypair \"test_key\"\n      end\n    end\n    # assert_equal \"1992\", clouds[\"custom\"].ssh_options[\"-P\"]\n  end\n  \n  \n  \nend"
  },
  {
    "path": "test/lib/poolparty/keypair_test.rb",
    "content": "require 'test_helper'\n\nclass KeypairTest < Test::Unit::TestCase\n  context \"Base\" do\n    setup do\n      Keypair.searchable_paths << File.join(FIXTURES_PATH, \"keys\")\n      @keypair = Keypair.new(File.join(FIXTURES_PATH, \"keys\", \"test_key\"))\n      @keypair_pem = Keypair.new(File.join(FIXTURES_PATH, \"keys\", \"pem_key\"))\n    end\n    \n    should \"set the file given as the file for the keypair\" do\n      assert_equal @keypair.filepath, File.join(FIXTURES_PATH, \"keys\", \"test_key\")\n      assert_equal @keypair.full_filepath, File.expand_path(File.join(FIXTURES_PATH, \"keys\", \"test_key\"))\n      assert_match @keypair.to_s, File.expand_path(File.join(FIXTURES_PATH, \"keys\", \"test_key\"))\n    end\n\n    should \"find the suffixed file given without pem suffix\" do\n      assert_equal @keypair_pem.filepath, File.join(FIXTURES_PATH, \"keys\", \"pem_key\")\n      assert_equal @keypair_pem.full_filepath, File.expand_path(File.join(FIXTURES_PATH, \"keys\", \"pem_key.pem\"))\n      assert_match @keypair_pem.to_s, File.expand_path(File.join(FIXTURES_PATH, \"keys\", \"pem_key\"))\n    end\n\n    should \"find the suffixed file given without pem suffix or dir\" do\n      basename = File.basename(@keypair_pem.full_filepath)\n      basename_no_suffix = File.basename(basename, '.pem')\n\n      search_dirs = [File.dirname(@keypair_pem.full_filepath)]\n\n      keypair = Keypair.new(basename, search_dirs)\n      keypair_no_suffix = Keypair.new(basename_no_suffix, search_dirs)\n\n      assert_equal keypair.full_filepath, @keypair_pem.full_filepath\n      assert_equal keypair_no_suffix.full_filepath, @keypair_pem.full_filepath\n    end\n    \n    should \"have the content of the file available\" do\n      assert_equal @keypair.content, open(File.join(FIXTURES_PATH, \"keys\", \"test_key\")).read\n    end\n    \n    should \"be able to generate the public key from the private\" # do\n    #       # assert_equal @keypair.public_key, \"#{open(FIXTURES_PATH/\"test_pub_key\").read}\"\n    #     end\n    \n    should \"have the basename of the keypair\" do\n      assert_equal @keypair.basename, \"test_key\"\n      assert_equal @keypair.filename, \"test_key\"      \n    end\n    \n    should \"be valid if it's 600 permissions\" do\n      assert @keypair.valid?\n    end\n    \n    should \"be invalid if the file permissions are executable\" do\n      assert_raises StandardError do\n        Keypair.new(File.join(FIXTURES_PATH, \"bad_perms_test_key\")).valid?\n      end\n    end\n  end  \nend\n"
  },
  {
    "path": "test/lib/poolparty/pool_party_error_test.rb",
    "content": "require 'test_helper'\n\nclass PoolPartyErrorTest < Test::Unit::TestCase\n  include PoolParty\n  context \"Error\" do\n    should \"be able to create a PoolPartyError\" do\n      assert_nothing_raised do\n        PoolPartyError.create \"TestError\", \"New error\"\n      end\n    end\n    \n    should \"raise when called with the test error\" do\n      assert_raise TestError do\n        raise PoolPartyError.create(\"TestError\", \"New error\")\n      end\n    end\n    \n  end\n  \nend"
  },
  {
    "path": "test/lib/poolparty/pool_test.rb",
    "content": "require 'test_helper'\n\nclass PoolTest < Test::Unit::TestCase  \n  def setup\n    stub_keypair_searchable_paths\n  end\n  \n  def test_set_up_pool_object\n    reset!\n    pool \"hi\" do\n    end\n    assert_equal @@pool.name, \"hi\"\n  end\nend"
  },
  {
    "path": "test/lib/poolparty/rds_test.rb",
    "content": "require 'test_helper'\n\nclass RdsTest < Test::Unit::TestCase\n  def setup\n    stub_ec2_calls\n    stub_response(AWS::EC2::Base, :describe_security_groups, 'ec2-describe-security-groups')\n    stub_response(AWS::EC2::Base, :run_instances,            'ec2-run-instances')\n    stub_response(AWS::RDS::Base, :describe_db_instances,    'rds-describe-db-instances-empty')\n    reset!\n  end\n\n  def test_basic\n    scenario \"rds_cloud\"\n  end\n\n  def test_required_properties\n    assert_raises(RuntimeError) { scenario \"rds_missing_params\" }\n  end\n\n  private\n\n  def scenario(filename)\n    clear!\n\n    @filepath = File.join(FIXTURES_PATH, \"clouds/#{filename}.rb\")\n    require @filepath\n    @cloud = pool.clouds[pool.clouds.keys.first]\n\n    @cloud.run\n  end\n\n  def stub_response(klass, method, fixture_filename)\n    klass.any_instance.stubs(method).returns AWS::Response.parse(:xml => open(File.join(FIXTURES_PATH, \"ec2/#{fixture_filename}_response_body.xml\")).read)\n  end\nend"
  },
  {
    "path": "test/test_helper.rb",
    "content": "$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))\n$LOAD_PATH.unshift(File.dirname(__FILE__))\n\nENV['RACK_ENV'] ||= 'test'\n\n# Test dependencies\n%w(fakeweb right_http_connection matchy shoulda).each do |dep|\n  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),'..', 'vendor/gems', dep, 'lib'))\n  # require \"#{dep}\"\nend\n\nrequire 'poolparty'\n\nrequire \"rubygems\"\nrequire \"test/unit\"\n# TODO: Rip out shoulda\nrequire \"shoulda\"\nrequire 'mocha' # ARG!  don't want to introduce additional test dependencies, but FakeWeb can only handle one fake post per URL!!!\nrequire 'webmock/test_unit'\nrequire 'pathname'\n\nrequire 'git-style-binary/command'\n\nrequire \"test_methods\"\n\nGitStyleBinary.run = true\n\nFIXTURES_PATH = Pathname.new(File.expand_path('../fixtures', __FILE__))"
  },
  {
    "path": "test/test_methods.rb",
    "content": "class Test::Unit::TestCase\n  # Helpers\n  def FIXTURES_PATH\n    \"#{::File.dirname(__FILE__)}/fixtures\"\n  end\n\n  def test_dir\n    \"#{File.dirname(__FILE__)}/test_dir\"\n  end\n\n  def clear!\n    $pools = $clouds = nil\n  end\n\n  def modify_env_with_hash(h={})\n    orig_env = Kernel.const_get(:ENV)\n  \n    h.each do |k,v|\n      orig_env.delete(k)\n      orig_env[k] = v\n      orig_env[k].freeze\n    end\n\n    if RUBY_VERSION.scan(/1.8/).pop\n      # Kernel.send :remove_const, 'ENV' if Kernel.const_defined?('ENV')\n      Kernel.stubs(:ENV).returns(orig_env)\n    elsif RUBY_VERSION.scan(/1.9/).pop\n      Object.stubs(:ENV).returns(orig_env)\n      # Object.send :remove_const, 'ENV' if Object.const_defined?('ENV')\n    else\n      raise \"can't determine what version of ruby you are running.\"\n    end\n    \n    # Kernel.const_set(:ENV, orig_env)\n  end\n\n  def capture_stdout(&block)\n     old_stdout = $stdout\n     old_stderr = $stderr\n     out = StringIO.new\n     $stdout = out\n     old_stderr = StringIO.new\n     begin\n        block.call if block\n     ensure\n        $stdout = old_stdout\n        $stderr = old_stderr\n     end\n     out.string\n  end\n\n  def stub_keypair_searchable_paths\n    Keypair.searchable_paths << File.join(FIXTURES_PATH, \"keys\")\n  end\n  \n  def read_fixture(path)\n    open(File.join(FIXTURES_PATH, \"ec2\", path)).read\n  end\n\n  def stub_ec2_calls(&block)\n    stub_keypair_searchable_paths\n    \n    modify_env_with_hash(\n      \"EC2_ACCESS_KEY\" => \"fake_access_key\",\n      \"EC2_SECRET_KEY\" => \"fake_secret_key\",\n      \"EC2_PRIVATE_KEY\" => ::File.dirname(__FILE__) + \"/fixtures/keys/test_key\",\n      \"EC2_CERT\"        => ::File.dirname(__FILE__) + \"/fixtures/keys/test_key\",\n      \"EC2_USER_ID\"     => '1234567890'\n      )\n  \n    # FakeWeb.allow_net_connect=false\n    stub_request(:get, /.*Action=DescribeInstances.*/).\n      to_return(:status => 200, :body => read_fixture('ec2-describe-instances_response_body.xml'))\n\n    stub_request(:get, /.*Action=RunInstances.*/).\n      to_return(:status => 200, :body => read_fixture('ec2-run-instances_response_body.xml'))\n\n\n    stub_request(:get, /.*Action=TerminateInstances.*/).\n      to_return(:status => 200, :body => read_fixture('ec2-terminate-instances_response_body.xml'))\n      \n    stub_request(:post, /elasticloadbalancing\\.amazonaws\\.com/).\n      to_return(:status => 200, :body => read_fixture('elb-describe-load-balancers.xml'))\n    \n    stub_request(:post, /\\//).\n      to_return(:status => 200, :body => read_fixture('ec2-describe-instances_response_body.xml'))\n\n    # FakeWeb.register_uri(:get, /.*Action=TerminateInstances.*/, :status => [\"200\", \"OK\"],\n    #                      :body => open(FIXTURES_PATH/\"ec2/ec2-terminate-instances_response_body.xml\").read)\n    #                      \n    # FakeWeb.register_uri(:post, /elasticloadbalancing\\.amazonaws\\.com/, :status => [\"200\", \"OK\"],\n    #                      :body => open(FIXTURES_PATH/\"ec2/elb-describe-load-balancers.xml\").read)\n    #                      \n    # FakeWeb.register_uri(:post, /\\//, :status => [\"200\", \"OK\"],\n    #                     :body => open(FIXTURES_PATH/\"ec2/ec2-describe-instances_response_body.xml\").read)\n  \n    instance_eval &block if block\n  end\nend"
  },
  {
    "path": "vendor/gems/dslify/.gitignore",
    "content": "pkg/*\npkg/\ntmp"
  },
  {
    "path": "vendor/gems/dslify/LICENSE",
    "content": "Copyright (c) 2009 Ari Lerner\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/gems/dslify/README.rdoc",
    "content": "= dslify\n\nDslify, born out of a need for improvement on Dslify\n\nAdd dsl accessors to any class.\n\nUsage:\n  class MyClass\n    include Dslify\n    \n    dsl_methods :award, :people\n  end\n  \n  mc = MyClass.new\n  mc.award \"Tony Award\"\n  mc.people [\"Bob\", \"Frank\", \"Ben\"]\n  \nYou can set defaults as well:\n  class MyClass\n    default_options :award => \"Tony Award\"\n  end\n\nFinally, if your tree of available accessors runs higher and longer than\njust 1 file, for instance, if you use Parenting, you can set forwarders to \nforward the query up the chain\n\nclass MyClass\n  forwards_to :parent\nend\n\n== Copyright\n\nCopyright (c) 2009 Ari Lerner. See LICENSE for details.\n"
  },
  {
    "path": "vendor/gems/dslify/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"dslify\"\n    gem.summary = %Q{TODO}\n    gem.email = \"arilerner@mac.com\"\n    gem.homepage = \"http://github.com/auser/dslify\"\n    gem.authors = [\"Ari Lerner\"]\n\n    # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings\n  end\nrescue LoadError\n  puts \"Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com\"\nend\n\nrequire 'rake/testtask'\nRake::TestTask.new(:test) do |test|\n  test.libs << 'lib' << 'test'\n  test.pattern = 'test/**/*_test.rb'\n  test.verbose = false\nend\n\nbegin\n  require 'rcov/rcovtask'\n  Rcov::RcovTask.new do |test|\n    test.libs << 'test'\n    test.pattern = 'test/**/*_test.rb'\n    test.verbose = true\n  end\nrescue LoadError\n  task :rcov do\n    abort \"RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov\"\n  end\nend\n\n\ntask :default => :test\n\nrequire 'rake/rdoctask'\nRake::RDocTask.new do |rdoc|\n  if File.exist?('VERSION.yml')\n    config = YAML.load(File.read('VERSION.yml'))\n    version = \"#{config[:major]}.#{config[:minor]}.#{config[:patch]}\"\n  else\n    version = \"\"\n  end\n\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title = \"dslify #{version}\"\n  rdoc.rdoc_files.include('README*')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n\n"
  },
  {
    "path": "vendor/gems/dslify/VERSION.yml",
    "content": "--- \n:major: 0\n:minor: 1\n:patch: 0\n"
  },
  {
    "path": "vendor/gems/dslify/dslify.gemspec",
    "content": "# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{dslify}\n  s.version = \"0.1.0\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Ari Lerner\"]\n  s.date = %q{2009-05-14}\n  s.email = %q{arilerner@mac.com}\n  s.extra_rdoc_files = [\"README.rdoc\", \"LICENSE\"]\n  s.files = [\"README.rdoc\", \"VERSION.yml\", \"lib/dslify.rb\", \"test/dslify_test.rb\", \"test/test_helper.rb\", \"LICENSE\"]\n  s.has_rdoc = true\n  s.homepage = %q{http://github.com/auser/dslify}\n  s.rdoc_options = [\"--inline-source\", \"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.2}\n  s.summary = %q{TODO}\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n"
  },
  {
    "path": "vendor/gems/dslify/lib/dslify.rb",
    "content": "module Dslify\n  def self.included(base)\n    base.send     :include, InstanceMethods\n    base.extend(ClassMethods)\n  end\n  \n  module ClassMethods    \n    def default_options(hsh={})\n      (@_dsl_options ||= {}).merge! hsh\n      set_default_options(@_dsl_options)\n    end\n    \n    def dsl_options\n      @_dsl_options ||= {}\n    end\n    def options\n      dsl_options\n    end\n    \n    def dsl_methods(*syms)\n      syms.each {|sym| set_default_options({sym => nil}) }\n    end\n    \n    def set_default_options(new_options)\n      new_options.each do |k,v|\n        dsl_options[k] = v\n        class_eval define_dsl_method_str(k)\n      end\n    end\n    \n    def define_dsl_method_str(k)\n      <<-EOE\n        def #{k}(n=nil)\n          if n.nil?\n            fetch(:#{k})\n          else\n            self.#{k}=n\n          end          \n        end\n        def #{k}=(n)\n          dsl_options[:#{k}] = n\n        end\n        def fetch(k)\n          dsl_options[k]                    \n        end\n      EOE\n    end\n    \n    def inherited(subclass)\n      subclass.set_default_options(dsl_options)\n    end\n  end\n  module InstanceMethods\n    def dsl_options\n      @dsl_options ||= self.class.dsl_options.clone\n    end\n    def default_options\n      Hash[*dsl_options.select{|k,v| self.class.default_options.has_key?(k) }.inject([]){|res,(k,v)| res << k << v }]\n    end\n    def set_vars_from_options(hsh={})\n      hsh.each do |k,v| \n        instance_eval self.class.define_dsl_method_str(k) unless self.respond_to?(k)\n        self.send k, v\n      end\n    end\n    \n    def set_default_options(hsh={})\n      self.class.set_default_options(hsh)\n    end\n    \n    def method_missing(m,*a,&block)\n      if m.to_s[-1..-1] == '?'\n        t = m.to_s.gsub(/\\?/, '').to_sym\n        warn \"DEPRECATED: Dslify will no longer support ? methods. Fix yo code.: #{m}\"\n        respond_to?(t) && !self.send(t, *a, &block).nil?\n      else\n        super\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/gems/dslify/test/dslify_test.rb",
    "content": "require \"#{File.dirname(__FILE__)}/test_helper\"\n\nclass Quickie\n  include Dslify\n  def initialize(&block)\n    instance_eval &block if block\n  end\nend\n\nclass QuickieTest < Test::Unit::TestCase\n  context \"setting\" do\n    before do\n      Quickie.class_eval do\n        dsl_methods :bank, :snobs, :author, :gilligans_island\n      end\n      @q = Quickie.new\n    end\n    it \"should be able to set methods on self\" do\n      assert_nothing_raised do\n        @q.bank \"bobs\"\n      end\n    end\n    it \"should set and then retrieve the same value back\" do\n      @q.snobs \"are mean\"\n      assert_equal @q.snobs, \"are mean\"\n    end\n    it \"should set and retrieve values back with an = sign\" do\n      @q.author = [\"Ari Lerner\"]\n      @q.snobs = \"Michael\"\n      assert_equal @q.author, [\"Ari Lerner\"]\n      assert_equal @q.snobs, \"Michael\"\n    end\n    it \"should set these values in the h Hash on the object\" do\n      assert_raise NoMethodError do\n        @q.movies \"can be fun\"\n      end\n    end\n    it \"should set multiple keys with set_vars_from_options\" do\n      @q.set_vars_from_options({:a => \"a\", :b => \"b\"})\n      assert_equal @q.a, \"a\"\n      assert_equal @q.b, \"b\"\n    end\n    it \"should set methods even when they are called with a block\" do\n      @q.author Quickie.new do\n      end\n      assert_equal @q.author.class, Quickie\n    end\n  end\n  \n  context \"calling methods on an instance\" do\n    setup do\n      class Detective\n        include Dslify\n        attr_reader :snooped\n        def snoop(*n)\n          @snooped = \"done!\"\n        end\n      end\n      @d= Detective.new\n    end\n    should \"Call the method snoop with set_vars_from_options\" do\n      @d.set_vars_from_options(:snoop => true)\n      assert @d.snooped\n    end\n  end\n  \n  context \"default options\" do\n    setup do\n      class Bang\n        include Dslify\n        default_options(\n          :says => 'vmrun'\n        )\n        def initialize(opts={}, &block)\n          instance_eval &block if block\n        end\n      end\n      @bang = Bang.new\n    end\n\n    should \"overwrite the default dsl option in instance_eval\" do\n      assert_equal @bang.says, \"vmrun\"\n      @bang = Bang.new do\n        says \"snake\"\n      end\n      assert_equal @bang.says, \"snake\"\n    end\n  end\n  \n  \n  context \"with inheritance and classes\" do\n    before do\n      class Pop\n        include Dslify\n        default_options :name => \"pop\", :flavor=>'cherry'\n        def initialize(o={})\n          set_vars_from_options(o)\n        end\n        \n        def real_method\n          \"the real deal, no magic\"\n        end\n      end\n      \n      class Foo < Pop\n        default_options :name=>'fooey'\n      end\n      \n      class Bar < Pop\n        default_options :name=>'pangy', :taste => \"spicy\"\n      end\n      \n      class Dad < Pop\n      end\n      \n      class Grandad < Dad\n      end\n      \n      class Defaults < Pop\n        default_options(\n          :global_default => \"red_rum\"\n        )\n      end\n      \n      @pop = Pop.new      \n      @foo = Foo.new\n      @bar = Bar.new\n    end\n    it \"should take the default options set on the class\" do\n      assert_equal @pop.dsl_options[:name], \"pop\"\n      assert_equal @pop.name, \"pop\"\n    end\n    it \"should allow us to add defaults on the instance by calling dsl_options\" do      \n      # QuickieTest::Pop.name == \"Cinnamon\"\n      @poptart = Pop.new :name => \"Cinnamon\"\n      assert_equal @poptart.name, \"Cinnamon\"\n    end\n    it \"should take the default options on a second class that inherits from the base\" do\n      assert_equal @foo.name, \"fooey\"\n    end\n    it \"should take the default options on a third inheriting class\" do\n      assert_equal @bar.name, \"pangy\"\n    end\n    it \"should not add a method not in the default_options\" do\n      assert_equal @bar.respond_to?(:boat), false      \n    end\n    it \"should return the original default options test\" do\n      assert_equal @bar.dsl_options[:taste], \"spicy\"\n      assert_equal @bar.dsl_options[:name], \"pangy\"\n    end\n    it \"should set the default options of the child to the superclass's if it doesn't exist\" do\n      # QuickieTest::Dad => QuickieTest::Pop\n      d = Dad.new\n      assert Pop.new.name == 'pop'\n      assert_equal \"pop\", d.name\n      d.name \"Frankenstein\"\n      assert_equal d.name, \"Frankenstein\"\n    end\n    it \"should raise if the method isn't found on itself, the parent or in the rest of the method missing chain\" do\n      assert_raise NoMethodError do\n        Class.new.sanitorium\n      end\n    end\n    it \"should be able to reach the grandparent through the chain of dsify-ed classes\" do\n      # QuickieTest::Grandad => QuickieTest::Dad => QuickieTest::Pop\n      assert Dad.method_defined?(:name)\n      assert Dad.new.flavor == 'cherry'\n      assert Grandad.new.name, \"pop\"\n    end\n    it \"should grab the default options from the dsl options (instance method)\" do\n      d = Dad.new(:star => \"bucks\")\n      assert_equal d.default_options.keys.map {|k| k.to_s }.sort, %w(flavor name)\n    end\n  end\n  context \"methods\" do\n    setup do\n      class MrDanger\n        include Dslify\n        default_options :where_to => \"The Grand Canyon\"\n        def initialize(o={})\n          set_vars_from_options(o)\n        end\n        def where_to(*a)\n          \"New York City\"\n        end\n      end\n    end\n\n    should \"not override the method where_to\" do\n      assert_equal MrDanger.new.where_to, \"New York City\"\n    end\n    should \"not override the method where_to when called with set_vars_from_options\" do\n      assert_equal MrDanger.new(:where_to => \"Bank of America\").where_to, \"New York City\"\n    end\n  end\n  \n  context \"when calling with a block\" do\n    setup do\n      class ToddTheSquare\n        include Dslify\n        default_options :provider => :vmrun, :t => :nothing\n        \n        def provider(&block)\n          instance_eval &block if block\n        end\n      end\n    end\n    \n    should \"should not evaluate the block\" do\n      tts = ToddTheSquare.new\n      assert_equal tts.t, :nothing\n    end\n\n    should \"should evaluate the block\" do\n      tts = ToddTheSquare.new\n      tts.provider do\n        self.t = :something\n      end\n      assert_equal tts.t, :something\n    end\n  end\n  \n  context \"set_vars_from_options\" do\n    setup do\n      class VarrrrrrrrMatey\n        include Dslify\n        default_options :say => \"hello\", :to => \"world\"\n        \n        def initialize(o={}, &block)\n          set_vars_from_options(o)\n          instance_eval &block if block\n        end\n        \n        def to_s\n          say + \" \" + to\n        end\n      end\n    end\n\n    should \"set the vars on the options with no options\" do\n      assert_equal VarrrrrrrrMatey.new.to_s, \"hello world\"\n    end\n    should \"update the options if called with options\" do\n      assert_equal VarrrrrrrrMatey.new({:say => \"goodbye\"}).to_s, \"goodbye world\"\n    end\n    should \"update the options if called with block\" do\n      @v = VarrrrrrrrMatey.new do\n        to \"me\"\n      end\n      assert_equal @v.to_s, \"hello me\"\n    end\n  end\n  \n  context \"dsl_methods and methods on the object\" do\n    setup do\n      class PluginMoopieMoop\n        include Dslify\n        default_options :stars => to_s\n        \n        def self.inherited(s)\n          # stuff\n          super\n        end\n      end\n      class DoopyDoop < PluginMoopieMoop        \n        def stars\n          \"right now\"\n        end\n      end\n      @obj = DoopyDoop.new\n    end\n\n    should \"have the method :stars\" do\n      assert @obj.respond_to?(:stars)\n    end\n    should \"use the method on the instance\" do\n      assert_equal @obj.stars, \"right now\"\n    end\n  end\n  \n  \n  \nend"
  },
  {
    "path": "vendor/gems/dslify/test/test_helper.rb",
    "content": "require 'rubygems'\nrequire 'test/unit'\nrequire 'shoulda'\nrequire \"context\"\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))\nrequire 'dslify'"
  },
  {
    "path": "vendor/gems/git-style-binaries/.document",
    "content": "README.rdoc\nlib/**/*.rb\nbin/*\nfeatures/**/*.feature\nLICENSE\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/.gitignore",
    "content": "*.sw?\n.DS_Store\ncoverage\nrdoc\npkg\n.autosession.vim\n.sessions\n.session\ntags\nREADME.html\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/.gitmodules",
    "content": ""
  },
  {
    "path": "vendor/gems/git-style-binaries/README.markdown",
    "content": "git-style-binaries\n==================\n\nRidiculously easy git-style binaries.\n\nThis gem uses [`trollop`](http://trollop.rubyforge.org/) for option parsing\n\n## Installation\n\n    gem install jashmenn-git-style-binaries --source=http://gems.github.com\n\n## Screencast\n\nCheckout <a href=\"http://www.xcombinator.com/movies/git-style-binaries.mov\">the new screencast!</a>\n\n<a href=\"http://www.xcombinator.com/movies/git-style-binaries.mov\"><img src=\"http://github.com/jashmenn/git-style-binaries/tree/master/doc/gsb-screencast.png?raw=true\" width='880' height='784' border=0></a>\n\n## Try it out\n\n    cd `gem env gemdir`/gems/jashmenn-git-style-binaries-0.1.4/test/fixtures\n    ./wordpress -h\n    ./wordpress help post\n\n## Goal\n\nLets use the imaginary `wordpress` gem. Let's say we have three different\nactions we want to specify:\n\n* categories\n* list\n* post\n\nEach command has its own binary in a directory structure like this:\n\n    bin/\n    |-- wordpress\n    |-- wordpress-categories\n    |-- wordpress-list\n    `-- wordpress-post\n\nThe goal is to be able to call commands in this manner:\n\n    wordpress -h          # gives help summary of all commands\n    wordpress-list -h     # gives long help of wordpress-list\n    wordpress list -h     # ditto\n    echo \"about me\" | wordpress-post --title=\"new post\"  # posts a new post with that title\n\n## Example code\nOur `bin/wordpress` binary is called the *primary* . Our primary only needs to contain the following line:\n\n    #!/usr/bin/env ruby\n    require 'git-style-binary/command'\n\n`git-style-binary` will automatically make this command the primary. \n\nThe `bin/wordpress-post` binary could contain the following: \n\n    #!/usr/bin/env ruby\n    require 'git-style-binary/command'\n\n    GitStyleBinary.command do\n      short_desc \"create a blog post\"\n      banner <<-EOS\n    Usage: #{command.full_name} #{all_options_string} {content|STDIN}\n\n    Posts content to a wordpress blog\n\n    EOS\n      opt :blog,     \"short name of the blog to use\", :default => 'default'\n      opt :category, \"tag/category. specify multiple times for multiple categories\", :type => String, :multi => true\n      opt :title,    \"title for the post\", :required => true, :type => String\n      opt :type,     \"type of the content [html|xhtml|text]\", :default => 'html', :type => String\n\n      run do |command|\n        command.die :type, \"type must be one of [html|xhtml|text]\" unless command.opts[:type] =~ /^(x?html|text)$/i\n\n        puts \"Subcommand name:     #{command.name.inspect}\"\n        puts \"Options:             #{command.opts.inspect}\"\n        puts \"Remaining arguments: #{command.argv.inspect}\"\n      end\n    end\n\nAnd so on with the other binaries.\n\n## Running the binaries \n\nNow if we run `wordpress -h` we get the following output:\n     \n    NAME\n          wordpress\n\n    VERSION\n          0.0.1 (c) 2009 Nate Murray - local\n\n    SYNOPSIS\n          wordpress [--version] [--test-primary] [--help] [--verbose] COMMAND [ARGS]\n\n    SUBCOMMANDS\n       wordpress-categories\n           do something with categories\n\n       wordpress-help      \n           get help for a specific command\n\n       wordpress-list      \n           list blog postings\n\n       wordpress-post      \n           create a blog post\n\n\n      See 'wordpress help COMMAND' for more information on a specific command.\n\n    OPTIONS\n        -v, --verbose         \n          verbose\n\n\n        -t, --test-primary=<s>\n          test an option on the primary\n\n\n        -e, --version         \n          Print version and exit\n\n\n        -h, --help            \n          Show this message\n\n\n\nDefault **options**, **version string**, and **usage banner** are automatically selected for you. \nThe subcommands and their short descriptions are loaded automatically!\n\nYou can pass the `-h` flag to any one of the subcommands (with or without the\nconnecting `-`) or use the built-in `help` subcommand for the same effect. For instance:\n\n    $ wordpress help post\n\n    NAME\n          wordpress-post - create a blog post\n\n    VERSION\n          0.0.1 (c) 2009 Nate Murray - local\n\n    SYNOPSIS\n          wordpress-post [--type] [--version] [--test-primary] [--blog] [--help] [--verbose] [--category]\n          [--title] COMMAND [ARGS] {content|STDIN} \n\n    OPTIONS\n        -v, --verbose         \n          verbose\n\n\n        -t, --test-primary=<s>\n          test an option on the primary\n\n\n        -b, --blog=<s>        \n          short name of the blog to use (default: default)\n\n\n        -c, --category=<s>    \n          tag/category. specify multiple times for multiple\n          categories\n\n\n        -i, --title=<s>       \n          title for the post\n\n\n        -y, --type=<s>        \n          type of the content [html|xhtml|text] (default: html)\n\n\n        -e, --version         \n          Print version and exit\n\n\n        -h, --help            \n          Show this message\n\n\nFor more examples, see the binaries in `test/fixtures/`.\n\n## Primary options\n\nOften you may *want* the primary to have its own set of options. Simply call `GitStyleBinary.primary` with a block like so:\n\n    #!/usr/bin/env ruby\n    require 'git-style-binary/command'\n    GitStyleBinary.primary do\n      version \"#{command.full_name} 0.0.1 (c) 2009 Nate Murray - local\"\n      opt :test_primary, \"a primary string option\", :type => String\n\n      run do |command|\n        puts \"Primary Options: #{command.opts.inspect}\"\n      end\n    end\n\nPrimary options are **inherited** by all subcommands. That means in this case\nall subcommands will now get the `--test-primary` option available to them as\nwell as this new `version` string.\n\n## Option parsing\n\nOption parsing is done by [trollop](http://trollop.rubyforge.org/).\n`git-style-binary` uses this more-or-less exactly. See the [trollop\ndocumentation](http://trollop.rubyforge.org/) for information on how to setup\nthe options and flags.\n\n## Callbacks\n\nCallbacks are available on the primary and subcommands. Available callbacks currently\nare before/after_run. These execute before the run block of the command parser and take\ntake one argument, which is the command itself\n\n## The `run` block\n\nTo get the 'introspection' on the individual binaries every binary is `load`ed\non `primary help`. We need a way to get that information while not running\nevery command when calling `primary help`. To achieve that you need to put what\nwill be run in the `run` block. \n\n`run` `yields` a `Command` object which contains a number of useful options\nsuch as `name`, `full_name`, `opts`, and `argv`. \n\n* `command.opts` is a hash of the options parsed\n* `command.argv` is an array of the remaining arguments\n\n## Features\n* automatic colorization\n* automatic paging\n\n## To Learn more\n\nPlay with the examples in the `test/fixtures` directory.\n\n## Credits\n* `git-style-binary` was written by Nate Murray `<nate@natemurray.com>`\n* `trollop` was written by [William Morgan](http://trollop.rubyforge.org/) \n* Inspiration comes from Ari Lerner's [git-style-binaries](http://blog.xnot.org/2008/12/16/git-style-binaries/) for [PoolParty.rb](http://poolpartyrb.com)\n* [`colorize.rb`](http://colorize.rubyforge.org) by Michal Kalbarczyk\n* Automatic less paging by [Nathan Weizenbaum](http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby)\n* Color inspiration from [Brian Henderson](http://xcombinator.com) teaching me how to get `man git` colors using `less` on MacOSX\n\n## TODO\n* automagic tab completion - Automatic for subcommands and options for any library that uses this\n\n## Known Bugs/Problems\n* Young\n* A few places of really ugly code\n* A feeling that this could be done in 1/2 lines of code\n\n## Authors\nBy Nate Murray and Ari Lerner\n\n## Copyright\n\nThe MIT License\n\nCopyright (c) 2009 Nate Murray. See LICENSE for details.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"git-style-binaries\"\n    gem.description = %Q{Ridiculously easy git-style binaries}\n    gem.summary =<<-EOF \n    Add git-style binaries to your project easily.\n    EOF\n    gem.email = \"nate@natemurray.com\"\n    gem.homepage = \"http://github.com/jashmenn/git-style-binaries\"\n    gem.authors = [\"Nate Murray\"]\n    gem.add_dependency 'trollop'\n    gem.add_dependency 'thoughtbot-shoulda' # for running the tests\n\n    excludes = /(README\\.html)/\n    gem.files = (FileList[\"[A-Z]*.*\", \"{bin,examples,generators,lib,rails,spec,test,vendor}/**/*\", 'Rakefile', 'LICENSE*']).delete_if{|f| f =~ excludes}\n    gem.extra_rdoc_files = FileList[\"README*\", \"ChangeLog*\", \"LICENSE*\"].delete_if{|f| f =~ excludes}\n  end\nrescue LoadError\n  puts \"Jeweler not available. Install it with: sudo gem install jeweler\"\nend\n\nrequire 'rake/testtask'\nRake::TestTask.new(:test) do |test|\n  test.libs << 'lib' << 'test'\n  test.pattern = 'test/**/*_test.rb'\n  test.verbose = true\nend\n\nbegin\n  require 'rcov/rcovtask'\n  Rcov::RcovTask.new do |test|\n    test.libs << 'test'\n    test.pattern = 'test/**/*_test.rb'\n    test.verbose = true\n  end\nrescue LoadError\n  task :rcov do\n    abort \"RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov\"\n  end\nend\n\n\ntask :default => :test\n\nrequire 'rdoc/task'\nRake::RDocTask.new do |rdoc|\n  if File.exist?('VERSION.yml')\n    config = YAML.load(File.read('VERSION.yml'))\n    version = \"#{config[:major]}.#{config[:minor]}.#{config[:patch]}\"\n  else\n    version = \"\"\n  end\n\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title = \"git-style-binaries #{version}\"\n  rdoc.rdoc_files.include('README*')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n\ntask :bump => ['version:bump:patch', 'gemspec', 'build']\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/VERSION.yml",
    "content": "--- \n:patch: 10\n:major: 0\n:minor: 1\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/doc/EXAMPLES",
    "content": "see test/fixtures\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/doc/poolparty-binaries.screenplay",
    "content": "#!/usr/bin/env castanaut\n# Castanaut screencast file. sudo gem install castanaut\n\n# see if there is a terminal module\n# download the 'ttyrecord' binary\n# get castanaut src\n# get applescript docs\nplugin \"terminal\"\nplugin \"keystack\"\n\ndef cleanup\n  FileUtils.rm_rf(File.expand_path(\"~/poolparty-gsb-test/bin\"))\nend\n\ncleanup\n\nperform \"Introduction\" do\n  launch \"Terminal\", at(10, 10, 800, 600)\n  pause 1\n\n  say <<-eos\n  Hey, welcome to the git-style-binaries screencast. \n  First, lets talk a little about what a git-style-binary even is. \n  eos\nend\n\ncli \"cd #{ENV['POOLPARTY_SRC']}\" \n\nperform \"Describing Git Binaries\" do\n  pause 1\n  while_saying \"as you can see here, git has over one hundred binaries that all perform various functions.\" do\n    type \"git-\"\n    pause 1\n    keystroke_literal('tab')\n    keystroke_literal('tab')\n    type \"y\"\n    pause 2\n    type \" \"\n    keystroke_using('u', :control)\n  end\n\n  while_saying \"for instance, we have. git-add for adding files. git-status for\n  getting the status of our repo and so on\" do\n    cli \"git-add\"\n    pause 2\n    cli \"git-status\"\n  end\n\n  while_saying \"one of the nice things about the git-style-binaries is that you\n  can choose to call the command with or without the dash.. so for instance, i\n  can call either 'git-add' or 'git add'.\" do\n    cli \"git-add\"\n    pause 2\n    cli \"git add\"\n  end\n\n  perform \"Describe Help\" do\n    while_saying \"the help in git is also very handy. for instance, if you call\n    git help it will give you a listing of many of the available subcommands\" do\n      cli \"git help\"\n      move to(44, 94)\n      move to(133, 87)\n      move to(127, 346)\n      move to(41, 343)\n      move to(44, 94)\n    end\n\n    while_saying \"you can also ask for help about any of the subcommands. if we\n    want to get help on 'git-add', we simply type 'git help add'\" do\n      cli \"git help add\"\n      type 'q'\n    end\n  end\n\n  pause 2\n\n  perform \"Describe Validation\" do\n    while_saying \"git also performs option validation, as you would expect. for\n    instance, if we provide an invalid option such as 'asdf' we get an error\" do\n      cli \"git add --asdf\"\n    end\n  end\n\n  while_saying \"the goal of the git-style-binaries ruby gem is to bring this\n  functionality to your own custom binaries in an easy-to-use way. so lets take\n  a look at an example\" \n  pause 2\n\nend\n\n\nperform \"Introducing PoolParty\" do\n  while_saying \"we're going to be using PoolParty's binaries as an example on\n  how to build git-style-binaries using this gem\" do\n  end\n\n  while_saying \"just in case you're not familiar with poolparty, its a cloud\n  management system by Ari Lerner. It allows you to manage your cloud using ruby\n  code and plugins rather than, say, folders of bash scripts.\" do\n    # launch \"Safari\", at(10, 10, 800, 600)\n    # url \"http://www.poolpartyrb.com\" # ?\n    # pause 3\n    # keystroke_literal_using('tab', :command) # go back to terminal\n  end\n\n  while_saying \"in poolparty the main binary is 'cloud'. we can do cloud help to see all of the available subcommands.\" do\n    cli \"cloud help\"\n  end\n\n  while_saying \"as you can see here we have 'cloud-start', for starting our\n  cloud, 'cloud configure' to reconfigure our cloud after we change something,\n  even cloud-ssh, to ssh directly into a node of our cloud.\" do\n    pause 2\n    shake 37, 499\n    pause 2\n    shake 37, 219\n  end\n\n  pause 2\n  type \"q\"\n\n  while_saying \"what i'd like to do is, rather than just opening up the existing\n  binaries, Im going to build poolparty-like binaries from the ground up. this\n  way you can see how to do this on your own.\"\nend\n\n\nperform \"entering poolpary\" do\n  cli \"cd ~\" \n  cli \"mkdir -p poolparty-gsb-test/bin\"\n  cli \"cd poolparty-gsb-test\"\nend\n \nperform \"creating primary\" do\n    while_saying \"first we need to create our *primary* binary.\" do\n      cli \"vim bin/cloud\"\n      pause 2\n      type_pre <<-eof \ni#!/usr/bin/env ruby\nrequire 'git-style-binary/command'\u001b\neof\n      cli \":w\"\n      cli \":e\"\n    end\n\n    while_saying \"and thats it! thats all we need if we want the default functionality\"  do\n      cli \":x\"\n    end\nend\n\npause 1\n\n# opt :cloud_name, \"Name of the working cloud\", :type => String, :default => nil\n\nperform \"create cloud-start\" do\n  while_saying \"now lets create cloud-start.\n  we start by requiring git-style-binary/command, just like last time.\n  now we open up a #command block.\n  specify a version.\n  specify a banner and a short description.\n  and we put what we want to do in the 'run' block.\" do\n\n  cli \"vim bin/cloud-start\"\n  pause 1\n  vim_insert <<-eof\n#!/usr/bin/env ruby\neof\n  cli \":w\"\n  cli \":e\"\n  cli \":set paste\" # no auto indending\n  type \"j\"\n\n  vim_insert <<-eof\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  version \"PoolParty cloud-start 0.0.1\"  \n  banner <<-\\EOS\nUsage: cloud-start \\#{all_options_string}\n\nEOS\neof\n\n  vim_insert <<-eof\n  short_desc \"List the clouds\"\n\n  run do |command|\n    puts \"Options: \\#{command.opts.inspect}\"\n  end\nend\neof\n  end\n\n  while_saying \"the run block yields a command object. commands has an 'opts' attribute accessor, or you can just use brackets on 'command'\" do\n    type \":0\r/puts\rDiputs \\\"verbose is: \\#{command[:verbose].to_s}\\\"\u001b\"\n    cli \":w\"\n  end\n\n  while_saying \"you can add more options by calling 'opt' in the command block\" do\n    vim_line_after(\"short_\")\n    vim_insert \"  opt :name, \\\"the name of the cloud you are starting\\\", :type => String,\r    :default => \\\"default\\\"\"\n  end\n\n  while_saying \"git-style-binaries uses the gem trollop for the option parsing.\n  trollop allows you to easily add validations and type conversions to options.\n  see their website for information on the syntax\" do\n  end\n  # cli \":x\"\n  pause 2\nend\n\nperform \"running cloud-start\" do\n  while_saying \"now lets run cloud-start -h\" do\n    keystroke_using('t', :command) # go back to terminal\n    pause 1\n    cli \"cd poolparty-gsb-test\"\n    cli \"chmod +x bin/*\"\n    cli \"./bin/cloud-start -h\"\n  end\n  pause 2\n  while_saying \"notice a few things here. we've got automatic coloring, a list of all of our flags, and a list of all of our options. trollop has even automatically created the short flags for us\"  do\n    move to(39, 178)\n    pause 1\n    move to(103, 202)\n    pause 1\n    move to(79, 357)\n    move to(90, 522)\n    move to(79, 357)\n    pause 1\n    move to(203, 299)\n    move to(470, 300)\n    pause 1\n    shake 54, 441\n  end\n  pause 3\n  type \"q\"\n  keystroke_using('w', :command) # go back to terminal\n  pause 2\nend\n\n\nperform \"creating cloud-ssh\" do\n\n  while_saying \"i'd like to show you a few more features of gsb. first lets create one more simple binary - cloud ssh\" do\n  cli \":x\"\n  pause 1\n\n  cli \"vim bin/cloud-ssh\"\n  pause 1\n  vim_insert <<-eof\n#!/usr/bin/env ruby\neof\n  cli \":w\"\n  cli \":e\"\n  cli \":set paste\" # no auto indending\n  type \"j\"\n\n  vim_insert <<-eof\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  version \"PoolParty cloud-ssh 0.0.1\"  \n  banner <<-\\EOS\nUsage: cloud-ssh \\#{all_options_string}\n\nEOS\neof\n\n  vim_insert <<-eof\n  short_desc \"ssh into your cloud\"\n  opt :name,    \"name of the cloud\", :type => String\n\n  run do |command|\n    puts \"you are sshing into \\#{command[:name]}!\"\n  end\nend\neof\n  pause 1\n  cli \":x\"\n  pause 2\n  end\n\nend\n\nperform \"show help with both binaries\" do\n\n  while_saying \"now we have two binaries, cloud-start and cloud-ssh\" do\n    cli \"tree .\"\n  end\n\n  while_saying \"one of the cool things about gsb is that it will automatically pick up these files when you run the help commands\" do\n    cli \"./bin/cloud -h\"\n  end\n\n  while_saying \"see, here we have both cloud-start and cloud-ssh, along with their short descriptions, which are automatically loaded from their respective files\" do\n    pause 0.5 \n    shake 46, 401\n    pause 0.5\n    shake 49, 338\n    pause 0.5\n    move to(88, 291)\n    move to(354, 297)\n    pause 1\n    cli 'q'\n  end\n\nend\n\nperform \"modify cloud primary\" do\n\n  while_saying \"notice that if we do cloud help start. we see that it already\n  has a number of options. these options come from the default binary options.\" do\n    cli \"./bin/cloud help start\"\n    pause 1\n    move to(123, 266)\n    pause 1\n    shake 116, 431\n    pause 1\n    move to(99, 515)\n    type 'q'\n  end\n\n  while_saying \"gsb's get their options from three places 1) the default in code 2) the primary and 3) the subcommand itself\" do\n    type \"1) default options (in code)\"\n    pause 0.5\n    keystroke_using('u', :control)\n    type \"2) primary (ex: ./bin/cloud)\"\n    pause 0.5\n    keystroke_using('u', :control)\n    type \"3) subcommand (./bin/cloud-start)\"\n    pause 0.5\n    keystroke_using('u', :control)\n  end\n\n  while_saying \"if we add options to our primary these will be automatically inherited by the subcommands.\" do\n  end\n\n  while_saying \"we want to be able to specify the name of our clouds.rb\n  specfile in any of the subcommands. so all we need to do is add that to the\n  primary.\n\n  now when we want to customize the primary we need to do a bit more work.\n  \" do \n    cli \"vim bin/cloud\"\n     pause 2\n    type \"jj\"\n    type 'o' + '\u001b'\n    vim_insert <<-eof\nGitStyleBinary.primary do\n  version \"PoolParty cloud command\"  \nbanner <<-\\EOS\neof\n    vim_insert <<-eof\nUsage: cloud \\\\\\#{all_options_string} COMMAND [ARGS]\n\nThe cloud subcommands commands are:\n  \\\\\\#{GitStyleBinary.pretty_known_subcommands(:short).join(\"  \")}\nEOS\n  opt :spec, \"The name of the clouds.rb file\", :type => String\n\nrun do\n  end\nend\neof\n    pause 2\n    type \":x\r\"\n  end\nend\n\nperform \"show subcommand opts\" do\n\n  while_saying \"now if we run the subcommand -h, we see that the spec option is there\" do\n    cli \"./bin/cloud-start -h\"\n    pause 1\n    shake 54, 342\n    pause 1\n    type \"q\"\n  end\n\n  while_saying \"you can also specify callbacks in your primary if you want to.\n  for instance, say you want to call something before the run block of each\n    subcommand. simply define a before_run block in your primary\" do\n\n     cli \"vim bin/cloud\"\n     pause 2\n     vim_line_after(\"opt \")\n     vim_insert <<-eof\nbefore_run do\n  puts \"this happened before run\"\nend\neof\n     pause 2\n     type \":x\r\"\n    \n  end\n\n  while_saying \"now we run our subcommand again. and you can see that it gets the options!\" do\n    cli \"./bin/cloud-start\"\n  end\n\nend\n\nperform \"summary\" do\n  while_saying \"i hope this has been helpful for you. now go out and create your own git-style-binaries!\"\nend\n\n\nat_exit do\n  cleanup\nend\n\n# vim: ft=ruby\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/git-style-binaries.gemspec",
    "content": "# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{git-style-binaries}\n  s.version = \"0.1.10\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Nate Murray\"]\n  s.date = %q{2009-06-12}\n  s.description = %q{Ridiculously easy git-style binaries}\n  s.email = %q{nate@natemurray.com}\n  s.extra_rdoc_files = [\n    \"README.markdown\"\n  ]\n  s.files = [\n    \"README.markdown\",\n    \"Rakefile\",\n    \"VERSION.yml\",\n    \"lib/ext/colorize.rb\",\n    \"lib/ext/core.rb\",\n    \"lib/git-style-binary.rb\",\n    \"lib/git-style-binary/autorunner.rb\",\n    \"lib/git-style-binary/command.rb\",\n    \"lib/git-style-binary/commands/help.rb\",\n    \"lib/git-style-binary/helpers/name_resolver.rb\",\n    \"lib/git-style-binary/helpers/pager.rb\",\n    \"lib/git-style-binary/parser.rb\",\n    \"test/fixtures/flickr\",\n    \"test/fixtures/flickr-download\",\n    \"test/fixtures/wordpress\",\n    \"test/fixtures/wordpress-categories\",\n    \"test/fixtures/wordpress-list\",\n    \"test/fixtures/wordpress-post\",\n    \"test/git-style-binary/command_test.rb\",\n    \"test/git_style_binary_test.rb\",\n    \"test/running_binaries_test.rb\",\n    \"test/shoulda_macros/matching_stdio.rb\",\n    \"test/test_helper.rb\",\n    \"vendor/gems/trollop/FAQ.txt\",\n    \"vendor/gems/trollop/History.txt\",\n    \"vendor/gems/trollop/Manifest.txt\",\n    \"vendor/gems/trollop/README.txt\",\n    \"vendor/gems/trollop/Rakefile\",\n    \"vendor/gems/trollop/lib/trollop.rb\",\n    \"vendor/gems/trollop/release-script.txt\",\n    \"vendor/gems/trollop/test/test_trollop.rb\",\n    \"vendor/gems/trollop/www/index.html\"\n  ]\n  s.has_rdoc = true\n  s.homepage = %q{http://github.com/jashmenn/git-style-binaries}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.2}\n  s.summary = %q{Add git-style binaries to your project easily.}\n  s.test_files = [\n    \"test/git-style-binary/command_test.rb\",\n    \"test/git_style_binary_test.rb\",\n    \"test/running_binaries_test.rb\",\n    \"test/shoulda_macros/matching_stdio.rb\",\n    \"test/test_helper.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n      s.add_runtime_dependency(%q<trollop>, [\">= 0\"])\n      s.add_runtime_dependency(%q<thoughtbot-shoulda>, [\">= 0\"])\n    else\n      s.add_dependency(%q<trollop>, [\">= 0\"])\n      s.add_dependency(%q<thoughtbot-shoulda>, [\">= 0\"])\n    end\n  else\n    s.add_dependency(%q<trollop>, [\">= 0\"])\n    s.add_dependency(%q<thoughtbot-shoulda>, [\">= 0\"])\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/ext/colorize.rb",
    "content": "#\n# Colorize String class extension.\n#\nclass String\n\n  #\n  # Version string\n  #\n  COLORIZE_VERSION = '0.5.6'\n\n  #\n  # Colors Hash\n  #\n  COLORS = {\n    :black          => 0,\n    :red            => 1,\n    :green          => 2,\n    :yellow         => 3,\n    :blue           => 4,\n    :magenta        => 5,\n    :cyan           => 6,\n    :white          => 7,\n    :default        => 9,\n\n    :light_black    => 10,\n    :light_red      => 11,\n    :light_green    => 12,\n    :light_yellow   => 13,\n    :light_blue     => 14,\n    :light_magenta  => 15,\n    :light_cyan     => 16,\n    :light_white    => 17\n  }\n\n  #\n  # Modes Hash\n  #\n  MODES = {\n    :default        => 0, # Turn off all attributes\n    #:bright        => 1, # Set bright mode\n    :underline      => 4, # Set underline mode\n    :blink          => 5, # Set blink mode\n    :swap           => 7, # Exchange foreground and background colors\n    :hide           => 8  # Hide text (foreground color would be the same as background)\n  }\n\n  protected\n\n  #\n  # Set color values in new string intance\n  #\n  def set_color_parameters( params )\n    if (params.instance_of?(Hash))\n      @color = params[:color]\n      @background = params[:background]\n      @mode = params[:mode]\n      @uncolorized = params[:uncolorized]\n      self\n    else\n      nil\n    end\n  end\n\n  public\n\n  #\n  # Change color of string\n  #\n  # Examples:\n  #\n  #   puts \"This is blue\".colorize( :blue )\n  #   puts \"This is light blue\".colorize( :light_blue )\n  #   puts \"This is also blue\".colorize( :color => :blue )\n  #   puts \"This is blue with red background\".colorize( :color => :light_blue, :background => :red )\n  #   puts \"This is blue with red background\".colorize( :light_blue ).colorize( :background => :red )\n  #   puts \"This is blue text on red\".blue.on_red\n  #   puts \"This is red on blue\".colorize( :red ).on_blue\n  #   puts \"This is red on blue and underline\".colorize( :red ).on_blue.underline\n  #   puts \"This is blue text on red\".blue.on_red.blink\n  #\n  def colorize( params )\n\n    unless STDOUT.use_color\n      return self unless STDOUT.isatty\n    end\n    return self if ENV['NO_COLOR']\n\n    begin\n        require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/\n    rescue LoadError\n        raise 'You must gem install win32console to use color on Windows'\n    end\n\n    color_parameters = {}\n\n    if (params.instance_of?(Hash))\n      color_parameters[:color] = COLORS[params[:color]]\n      color_parameters[:background] = COLORS[params[:background]]\n      color_parameters[:mode] = MODES[params[:mode]]\n    elsif (params.instance_of?(Symbol))\n      color_parameters[:color] = COLORS[params]\n    end\n\n    color_parameters[:color] ||= @color || 9\n    color_parameters[:background] ||= @background || 9\n    color_parameters[:mode] ||= @mode || 0\n\n    color_parameters[:uncolorized] ||= @uncolorized || self.dup\n\n    # calculate bright mode\n    color_parameters[:color] += 50 if color_parameters[:color] > 10\n\n    color_parameters[:background] += 50 if color_parameters[:background] > 10\n\n    return \"\\033[#{color_parameters[:mode]};#{color_parameters[:color]+30};#{color_parameters[:background]+40}m#{color_parameters[:uncolorized]}\\033[0m\".set_color_parameters( color_parameters )\n  end\n\n\n  #\n  # Return uncolorized string\n  #\n  def uncolorize\n    return @uncolorized || self\n  end\n\n  #\n  # Return true if sting is colorized\n  #\n  def colorized?\n    return !@uncolorized.nil?\n  end\n\n  #\n  # Make some color and on_color methods\n  #\n  COLORS.each_key do | key |\n    eval <<-\"end_eval\"\n      def #{key.to_s}\n        return self.colorize( :color => :#{key.to_s} )\n      end\n      def on_#{key.to_s}\n        return self.colorize( :background => :#{key.to_s} )\n      end\n    end_eval\n  end\n\n  #\n  # Methods for modes\n  #\n  MODES.each_key do | key |\n    eval <<-\"end_eval\"\n      def #{key.to_s}\n        return self.colorize( :mode => :#{key.to_s} )\n      end\n    end_eval\n  end\n\n  class << self\n\n    #\n    # Return array of available modes used by colorize method\n    #\n    def modes\n      keys = []\n      MODES.each_key do | key |\n        keys << key\n      end\n      keys\n    end\n\n    #\n    # Return array of available colors used by colorize method\n    #\n    def colors\n      keys = []\n      COLORS.each_key do | key |\n        keys << key\n      end\n      keys\n    end\n\n    #\n    # Display color matrix with color names.\n    #\n    def color_matrix( txt = \"[X]\" )\n      size = String.colors.length\n      String.colors.each do | color |\n        String.colors.each do | back |\n         print txt.colorize( :color => color, :background => back )\n        end\n        puts \" < #{color}\"\n      end\n      String.colors.reverse.each_with_index do | back, index |\n        puts \"#{\"|\".rjust(txt.length)*(size-index)} < #{back}\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/ext/core.rb",
    "content": "class Object\n  def returning(value)\n    yield(value)\n    value\n  end unless Object.respond_to?(:returning)\nend\n\nclass Symbol\n  def to_proc\n    Proc.new { |*args| args.shift.__send__(self, *args) }\n  end\nend\n\nclass IO\n  attr_accessor :use_color\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/autorunner.rb",
    "content": "require 'git-style-binary/parser'\n\nmodule GitStyleBinary\nclass AutoRunner\n\n  def self.run(argv=ARGV)\n    r = new\n    r.run\n  end\n\n  def run\n    unless GitStyleBinary.run?\n      if !GitStyleBinary.current_command \n        GitStyleBinary.load_primary\n      end\n      GitStyleBinary.current_command.run\n    end\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/command.rb",
    "content": "require 'git-style-binary'\n\nmodule GitStyleBinary\n  def self.command(&block)\n    returning Command.new(:constraints => [block]) do |c|\n      c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name)\n      GitStyleBinary.known_commands[c.name] = c\n\n      if !GitStyleBinary.current_command || GitStyleBinary.current_command.is_primary?\n        GitStyleBinary.current_command = c\n      end\n    end\n  end\n\n  def self.primary(&block)\n    returning Primary.new(:constraints => [block]) do |c|\n      c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name)\n      GitStyleBinary.known_commands[c.name] = c\n\n      GitStyleBinary.primary_command = c unless GitStyleBinary.primary_command\n      GitStyleBinary.current_command = c unless GitStyleBinary.current_command\n    end\n  end\n\n  class Command\n    class << self\n      def defaults\n        lambda do\n          name_desc \"#{command.full_name}\\#{command.short_desc ? ' - ' + command.short_desc : ''}\" # eval jit\n          version_string = defined?(VERSION) ? VERSION : \"0.0.1\"\n          version \"#{version_string} (c) #{Time.now.year}\"\n          banner <<-EOS\n#{\"SYNOPSIS\".colorize(:red)}\n      #{command.full_name.colorize(:light_blue)} #{all_options_string}\n\n#{\"SUBCOMMANDS\".colorize(:red)}\n   \\#{GitStyleBinary.pretty_known_subcommands.join(\"\\n   \")}\n\n  See '#{command.full_name} help COMMAND' for more information on a specific command.\n        EOS\n\n          opt :verbose,  \"verbose\", :default => false\n        end\n      end\n    end\n\n    attr_reader :constraints\n    attr_reader :opts\n    attr_accessor :name\n\n    def initialize(o={})\n      o.each do |k,v|\n        eval \"@#{k.to_s}= v\"\n      end\n    end\n\n    def parser\n      @parser ||= begin \n                    p = Parser.new\n                    p.command = self\n                    p\n                  end\n    end\n\n    def constraints\n      @constraints ||= []\n    end\n\n    def run\n      GitStyleBinary.load_primary    unless is_primary?      \n      GitStyleBinary.load_subcommand if is_primary? && running_subcommand?\n      load_all_parser_constraints\n      @opts = process_args_with_subcmd\n      call_parser_run_block      \n      self\n    end\n\n    def running_subcommand?\n      GitStyleBinary.valid_subcommand?(GitStyleBinary.current_command_name)\n    end\n\n    def load_all_parser_constraints\n      @loaded_all_parser_constraints ||= begin\n        load_parser_default_constraints\n        load_parser_primary_constraints\n        load_parser_local_constraints\n        true\n      end\n    end\n\n    def load_parser_default_constraints\n      parser.consume_all([self.class.defaults])\n    end\n\n    def load_parser_primary_constraints\n      parser.consume_all(GitStyleBinary.primary_command.constraints)\n    end\n\n    def load_parser_local_constraints \n      cur = GitStyleBinary.current_command # see, why isn't 'this' current_command?\n\n      unless self.is_primary? && cur == self\n        # TODO TODO - the key lies in this function. figure out when you hav emore engergy\n        # soo UGLY. see #process_parser! unify with that method\n        # parser.consume_all(constraints) rescue ArgumentError\n        parser.consume_all(cur.constraints)\n      end\n    end\n\n    def call_parser_run_block\n      runs = GitStyleBinary.current_command.parser.runs\n      \n      parser.run_callbacks(:before_run, self)\n      parser.runs.last.call(self) # ... not too happy with this\n      parser.run_callbacks(:after_run, self)      \n    end\n\n    def process_args_with_subcmd(args = ARGV, *a, &b)\n      cmd = GitStyleBinary.current_command_name\n      vals = process_args(args, *a, &b)\n      parser.leftovers.shift if parser.leftovers[0] == cmd\n      vals\n    end\n\n    # TOOooootally ugly! why? bc load_parser_local_constraints doesn't work\n    # when loading the indivdual commands because it depends on\n    # #current_command. This really sucks and is UGLY. \n    # the todo is to put in 'load_all_parser_constraints' and this works\n    def process_parser!\n      # load_all_parser_constraints\n\n      load_parser_default_constraints\n      load_parser_primary_constraints\n      # load_parser_local_constraints\n      parser.consume_all(constraints)\n\n      # hack\n      parser.consume { \n        opt :version, \"Print version and exit\" if @version unless @specs[:version] || @long[\"version\"]\n        opt :help, \"Show this message\" unless @specs[:help] || @long[\"help\"]\n        resolve_default_short_options\n      } # hack\n    end\n\n    def process_args(args = ARGV, *a, &b)\n      p = parser\n      begin\n        vals = p.parse args\n        args.clear\n        p.leftovers.each { |l| args << l }\n        vals # ugly todo\n      rescue Trollop::CommandlineError => e\n        $stderr.puts \"Error: #{e.message}.\"\n        $stderr.puts \"Try --help for help.\"\n        exit(-1)\n      rescue Trollop::HelpNeeded\n        p.educate\n        exit\n      rescue Trollop::VersionNeeded\n        puts p.version\n        exit\n      end\n    end\n\n    def is_primary?\n      false\n    end\n\n    def argv\n      parser.leftovers\n    end\n\n    def short_desc \n      parser.short_desc\n    end\n\n    def full_name\n      # ugly, should be is_primary?\n      GitStyleBinary.primary_name == name ? GitStyleBinary.primary_name : GitStyleBinary.primary_name + \"-\" + name\n    end\n\n    def die arg, msg=nil\n      p = parser # create local copy\n      Trollop.instance_eval { @p = p }\n      Trollop::die(arg, msg)\n    end\n    \n    # Helper to return the option\n    def [](k)\n      opts[k]\n    end\n\n  end\n\n  class Primary < Command\n    def is_primary?\n      true\n    end\n    def primary\n      self\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/commands/help.rb",
    "content": "module GitStyleBinary\n  module Commands\n    class Help\n      # not loving this syntax, but works for now\n      GitStyleBinary.command do\n        short_desc \"get help for a specific command\"\n        run do |command|\n\n          # this is slightly ugly b/c it has to muck around in the internals to\n          # get information about commands other than itself. This isn't a\n          # typical case\n          def educate_about_command(name)\n            load_all_commands\n            if GitStyleBinary.known_commands.has_key?(name)\n              cmd = GitStyleBinary.known_commands[name]\n              cmd.process_parser!\n              cmd.parser.educate\n            else\n              puts \"Unknown command '#{name}'\"\n            end\n          end\n\n          if command.argv.size > 0\n            command.argv.first == \"help\" ? educate : educate_about_command(command.argv.first)\n          else\n            educate\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/helpers/name_resolver.rb",
    "content": "module GitStyleBinary\nmodule Helpers\n  module NameResolver\n\n    def basename(filename=zero)\n      File.basename(filename).match(/(.*?)(\\-|$)/).captures.first\n    end\n    alias_method :primary_name, :basename\n\n    # checks the bin directory for all files starting with +basename+ and\n    # returns an array of strings specifying the subcommands\n    def subcommand_names(filename=zero)\n      subfiles = Dir[File.join(binary_directory, basename + \"-*\")]\n      cmds = subfiles.collect{|file| File.basename(file).sub(/^#{basename}-/, '')}.sort\n      cmds += built_in_command_names\n      cmds.uniq\n    end\n\n    def binary_directory(filename=zero)\n      File.dirname(filename)\n    end\n\n    def built_in_commands_directory\n      File.dirname(__FILE__) + \"/../commands\"\n    end\n\n    def built_in_command_names\n      Dir[built_in_commands_directory + \"/*.rb\"].collect{|f| File.basename(f.sub(/\\.rb$/,''))}\n    end\n\n    def list_subcommands(filename=zero)\n      subcommand_names(filename).join(\", \")\n    end\n\n    # load first from users binary directory. then load built-in commands if\n    # available\n    def binary_filename_for(name)\n      user_file = File.join(binary_directory, \"#{basename}-#{name}\") \n      return user_file if File.exists?(user_file)\n      built_in = File.join(built_in_commands_directory, \"#{name}.rb\") \n      return built_in if File.exists?(built_in)\n      user_file\n    end\n\n    def current_command_name(filename=zero,argv=ARGV)\n      current = File.basename(zero)\n      first_arg = ARGV[0]\n      return first_arg if valid_subcommand?(first_arg)\n      return basename if basename == current\n      current.sub(/^#{basename}-/, '')\n    end\n\n    # returns the command name with the prefix if needed\n    def full_current_command_name(filename=zero,argv=ARGV)\n      cur = current_command_name(filename, argv)\n      subcmd = cur == basename(filename) ? false : true # is this a subcmd?\n      \"%s%s%s\" % [basename(filename), subcmd ? \"-\" : \"\", subcmd ? current_command_name(filename, argv) : \"\"]\n    end\n\n    def valid_subcommand?(name)\n      subcommand_names.include?(name)\n    end\n\n    def zero\n      $0\n    end\n\n    def pretty_known_subcommands(theme=:long)\n      GitStyleBinary.known_commands.collect do |k,cmd| \n        next if k == basename \n        cmd.process_parser!\n        (\"%-s%s%-10s\" % [basename, '-', k]).colorize(:light_blue) + (\"%s       \" % [theme == :long ? \"\\n\" : \"\"]) + (\"%s\" % [cmd.short_desc]) + \"\\n\"\n      end.compact.sort\n    end\n\n  end\nend\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/helpers/pager.rb",
    "content": "module GitStyleBinary\n  module Helpers\n    module Pager\n\n      # by Nathan Weizenbaum - http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby\n      def run_pager\n        return if RUBY_PLATFORM =~ /win32/\n        return unless STDOUT.tty?\n        STDOUT.use_color = true\n\n        read, write = IO.pipe\n\n        unless Kernel.fork # Child process\n          STDOUT.reopen(write)\n          STDERR.reopen(write) if STDERR.tty?\n          read.close\n          write.close\n          return\n        end\n\n        # Parent process, become pager\n        STDIN.reopen(read)\n        read.close\n        write.close\n\n        ENV['LESS'] = 'FSRX' # Don't page if the input is short enough\n\n        Kernel.select [STDIN] # Wait until we have input before we start the pager\n        pager = ENV['PAGER'] || 'less -erXF'\n        exec pager rescue exec \"/bin/sh\", \"-c\", pager\n      end\n\n      module_function :run_pager\n\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary/parser.rb",
    "content": "module GitStyleBinary\nclass Parser < Trollop::Parser\n  attr_reader :runs, :callbacks\n  attr_reader :short_desc\n  attr_accessor :command\n\n  def initialize *a, &b\n    super\n    @runs = []\n    setup_callbacks    \n  end\n  \n  def setup_callbacks\n    @callbacks =  {}\n    %w(run).each do |event|\n      %w(before after).each do |time|\n        @callbacks[\"#{time}_#{event}\".to_sym] = []\n        instance_eval \"def #{time}_#{event}(&block);@callbacks[:#{time}_#{event}] << block;end\"\n      end\n    end\n  end\n  \n  def run_callbacks(at, from)\n    @callbacks[at].each {|c| c.call(from) }\n  end\n\n  def banner      s=nil; @banner     = s if s; @banner     end\n  def short_desc  s=nil; @short_desc = s if s; @short_desc end\n  def name_desc   s=nil; @name_desc = s if s; @name_desc end\n\n  # Set the theme. Valid values are +:short+ or +:long+. Default +:long+\n  attr_writer :theme\n\n  def theme\n    @theme ||= :long\n  end\n \n  ## Adds text to the help display.\n  def text s; @order << [:text, s] end\n\n  def spec_names\n    @specs.collect{|name, spec| spec[:long]}\n  end\n\n  # should probably be somewhere else\n  def load_all_commands\n    GitStyleBinary.subcommand_names.each do |name|\n      cmd_file = GitStyleBinary.binary_filename_for(name)\n      GitStyleBinary.load_command_file(name, cmd_file)\n    end\n  end\n\n  ## Print the help message to 'stream'.\n  def educate(stream=$stdout)\n    load_all_commands\n    width # just calculate it now; otherwise we have to be careful not to\n          # call this unless the cursor's at the beginning of a line.\n    GitStyleBinary::Helpers::Pager.run_pager\n    self.send(\"educate_#{theme}\", stream) \n  end\n\n  def educate_long(stream=$stdout)\n    left = {}\n\n    @specs.each do |name, spec| \n      left[name] = \n        ((spec[:short] ? \"-#{spec[:short]}, \" : \"\") +\n        \"--#{spec[:long]}\" +\n        case spec[:type]\n        when :flag; \"\"\n        when :int; \"=<i>\"\n        when :ints; \"=<i+>\"\n        when :string; \"=<s>\"\n        when :strings; \"=<s+>\"\n        when :float; \"=<f>\"\n        when :floats; \"=<f+>\"\n        end).colorize(:red)\n    end\n\n    leftcol_width = left.values.map { |s| s.length }.max || 0\n    rightcol_start = leftcol_width + 6 # spaces\n    leftcol_start = 6\n    leftcol_spaces = \" \" * leftcol_start\n\n    unless @order.size > 0 && @order.first.first == :text\n\n      if @name_desc\n        stream.puts \"NAME\".colorize(:red)\n        stream.puts \"#{leftcol_spaces}\"+  colorize_known_words(eval(%Q[\"#{@name_desc}\"])) + \"\\n\"\n        stream.puts\n      end\n\n      if @version\n        stream.puts \"VERSION\".colorize(:red)\n        stream.puts \"#{leftcol_spaces}#@version\\n\"\n      end\n \n      stream.puts\n\n      banner = colorize_known_words_array(wrap(eval(%Q[\"#{@banner}\"]) + \"\\n\", :prefix => leftcol_start)) if @banner # lazy banner\n      stream.puts banner\n\n      stream.puts\n      stream.puts \"OPTIONS\".colorize(:red)\n    else\n      stream.puts \"#@banner\\n\" if @banner\n    end\n\n    @order.each do |what, opt|\n      if what == :text\n        stream.puts wrap(opt)\n        next\n      end\n\n      spec = @specs[opt]\n      stream.printf \"    %-#{leftcol_width}s\\n\", left[opt]\n      desc = spec[:desc] + \n        if spec[:default]\n          if spec[:desc] =~ /\\.$/\n            \" (Default: #{spec[:default]})\"\n          else\n            \" (default: #{spec[:default]})\"\n          end\n        else\n          \"\"\n        end\n      stream.puts wrap(\"      %s\" % [desc], :prefix => leftcol_start, :width => width - rightcol_start - 1 )\n      stream.puts\n      stream.puts\n    end\n\n  end\n\n  def educate_short(stream=$stdout)\n    left = {}\n\n    @specs.each do |name, spec| \n      left[name] = \"--#{spec[:long]}\" +\n        (spec[:short] ? \", -#{spec[:short]}\" : \"\") +\n        case spec[:type]\n        when :flag; \"\"\n        when :int; \" <i>\"\n        when :ints; \" <i+>\"\n        when :string; \" <s>\"\n        when :strings; \" <s+>\"\n        when :float; \" <f>\"\n        when :floats; \" <f+>\"\n        end\n    end\n\n    leftcol_width = left.values.map { |s| s.length }.max || 0\n    rightcol_start = leftcol_width + 6 # spaces\n    leftcol_start = 0\n\n    unless @order.size > 0 && @order.first.first == :text\n      stream.puts \"#@version\\n\" if @version\n      stream.puts colorize_known_words_array(wrap(eval(%Q[\"#{@banner}\"]) + \"\\n\", :prefix => leftcol_start)) if @banner # jit banner\n      stream.puts \"Options:\"\n    else\n      stream.puts \"#@banner\\n\" if @banner\n    end\n\n    @order.each do |what, opt|\n      if what == :text\n        stream.puts wrap(opt)\n        next\n      end\n\n      spec = @specs[opt]\n      stream.printf \"  %#{leftcol_width}s:   \", left[opt]\n      desc = spec[:desc] + \n        if spec[:default]\n          if spec[:desc] =~ /\\.$/\n            \" (Default: #{spec[:default]})\"\n          else\n            \" (default: #{spec[:default]})\"\n          end\n        else\n          \"\"\n        end\n      stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)\n    end\n\n  end\n\n\n  def colorize_known_words_array(txts)\n    txts.collect{|txt| colorize_known_words(txt)}\n  end\n\n  def colorize_known_words(txt)\n    txt = txt.gsub(/^([A-Z]+\\s*)$/, '\\1'.colorize(:red))       # all caps words on their own line\n    txt = txt.gsub(/\\b(#{bin_name})\\b/, '\\1'.colorize(:light_blue))  # the current command name\n    txt = txt.gsub(/\\[([^\\s]+)\\]/, \"[\".colorize(:magenta) + '\\1'.colorize(:green) + \"]\".colorize(:magenta)) # synopsis options\n  end\n\n  def consume(&block)\n    cloaker(&block).bind(self).call\n  end\n\n  def consume_all(blocks)\n    blocks.each {|b| consume(&b)}\n  end\n\n  def bin_name\n    GitStyleBinary.full_current_command_name\n  end\n\n  def all_options_string\n    # '#{spec_names.collect(&:to_s).collect{|name| \"[\".colorize(:magenta) + \"--\" + name + \"]\".colorize(:magenta)}.join(\" \")} COMMAND [ARGS]'\n    '#{spec_names.collect(&:to_s).collect{|name| \"[\" + \"--\" + name + \"]\"}.join(\" \")} COMMAND [ARGS]'\n  end\n\n  def run(&block)\n    @runs << block\n  end\n  \n  def action(name = :action, &block)\n    block.call(self) if block\n  end\n \nend\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/lib/git-style-binary.rb",
    "content": "$:.unshift(File.dirname(__FILE__))\nrequire 'rubygems'\n\n# Load the vendor gems\n$:.unshift(File.dirname(__FILE__) + \"/../vendor/gems\")\n%w(trollop).each do |library|\n  begin\n    require \"#{library}/lib/#{library}\"\n  rescue LoadError\n    begin\n      require 'trollop'\n    rescue LoadError\n      puts \"There was an error loading #{library}. Try running git submodule init && git submodule update to correct the problem\"\n    end\n  end\nend\n\nrequire 'ext/core'\nrequire 'ext/colorize'\nrequire 'git-style-binary/autorunner'\nDir[File.dirname(__FILE__) + \"/git-style-binary/helpers/*.rb\"].each {|f|  require f}\n\nmodule GitStyleBinary\n \n  class << self\n    include Helpers::NameResolver\n    attr_accessor :current_command\n    attr_accessor :primary_command\n    attr_writer :known_commands\n\n    # If set to false GitStyleBinary will not automatically run at exit.\n    attr_writer :run\n\n    # Automatically run at exit?\n    def run?\n      @run ||= false\n    end\n\n    def parser\n      @p ||= Parser.new\n    end\n\n    def known_commands\n      @known_commands ||= {}\n    end\n\n    def load_primary\n      unless @loaded_primary\n        @loaded_primary = true\n        primary_file = File.join(binary_directory, basename) \n        load primary_file\n\n        if !GitStyleBinary.primary_command # you still dont have a primary load a default\n          GitStyleBinary.primary do\n            run do |command|\n              educate\n            end\n          end\n        end\n      end\n    end\n\n    def load_subcommand\n      unless @loaded_subcommand\n        @loaded_subcommand = true\n        cmd_file = GitStyleBinary.binary_filename_for(GitStyleBinary.current_command_name)\n        load cmd_file\n      end\n    end\n\n    def load_command_file(name, file)\n      self.name_of_command_being_loaded = name\n      load file\n      self.name_of_command_being_loaded = nil\n    end\n\n    # UGLY eek\n    attr_accessor :name_of_command_being_loaded\n   \n  end\nend\n\nat_exit do\n  unless $! || GitStyleBinary.run?\n    command = GitStyleBinary::AutoRunner.run\n    exit 0\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/flickr",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\nVERSION=\"0.0.2\" # just to test it\nrequire 'git-style-binary/command'\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/flickr-download",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  short_desc \"download a flickr image\"\n  banner <<-EOS\nSYNOPSIS\n      #{command.full_name} #{all_options_string} url \n\nDownloads an image from flickr\n\nEOS\n  run do |command|\n    puts \"would download: #{command.argv.inspect}\"\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/wordpress",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\n\nrequire 'git-style-binary/command'\nGitStyleBinary.primary do\n  version \"0.0.1 (c) 2009 Nate Murray - local\"\n  opt :test_primary, \"test an option on the primary\", :type => String\n  \n  action do\n    @categories = [\"sports\", \"news\"]\n  end\n  \n  before_run do |cmd|\n    puts \"before_run command #{cmd}\"\n  end\n  \n  after_run do |cmd|\n    puts \"after_run command #{cmd}\"\n  end\n\n  run do |command|\n    puts \"Primary Options: #{command.opts.inspect}\"\n  end\nend\n\n# OR\n\n# require 'git-style-binary/primary'\n# command = GitStyleBinary::primary(\"wordpress\") do\n#   version \"#{$0} 0.0.1 (c) 2009 Nate Murray\"\n#   banner <<-EOS\n# usage: #{$0} #{all_options.collect(:&to_s).join(\" \")} COMMAND [ARGS]\n#\n# The wordpress subcommands commands are:\n# {subcommand_names.pretty_print}\n#\n# See 'wordpress help COMMAND' for more information on a specific command.\n# EOS\n#   opt :verbose,  \"verbose\", :default => false\n#   opt :dry,      \"dry run\", :default => false\n#   opt :test_global, \"a basic global string option\", :type => String\n# end\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/wordpress-categories",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  short_desc \"do something with categories\"\n  banner <<-EOS\nSYNOPSIS\n      #{command.full_name} #{all_options_string}\n\nDoes something with categories\n\nEOS\n  run do |command|\n    puts \"does something with categories\"\n    puts @categories.join(\" \")\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/wordpress-list",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  short_desc \"list blog postings\"\n  banner <<-EOS\nSYNOPSIS \n      #{command.full_name} #{all_options_string}\n\nLists the posts on the blog\n\nEOS\n  run do |command|\n    puts \"listing blog posts\"\n  end\nend\n\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/fixtures/wordpress-post",
    "content": "#!/usr/bin/env ruby\n$:.unshift(File.dirname(__FILE__) + \"/../../lib\")\nrequire 'git-style-binary/command'\n\nGitStyleBinary.command do\n  short_desc \"create a blog post\"\n  banner <<-EOS\nSYNOPSIS\n      #{command.full_name} #{all_options_string} {content|STDIN} \n\nEOS\n  opt :blog,     \"short name of the blog to use\", :default => 'default'\n  opt :category, \"tag/category. specify multiple times for multiple categories\", :type => String, :multi => true\n  opt :title,    \"title for the post\", :required => true, :type => String\n  opt :type,     \"type of the content [html|xhtml|text]\", :default => 'html', :type => String\n\n  run do |command|\n    command.die :type, \"type must be one of [html|xhtml|text]\" unless command.opts[:type] =~ /^(x?html|text)$/i\n\n    puts \"Subcommand name:     #{command.name.inspect}\"\n    puts \"Options:             #{command.opts.inspect}\"\n    puts \"Remaining arguments: #{command.argv.inspect}\"\n  end\nend\n\n\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/git-style-binary/command_test.rb",
    "content": "require File.dirname(__FILE__) + \"/../test_helper.rb\"\nrequire 'git-style-binary/command'\n\nclass CommandTest < Test::Unit::TestCase\n  context \"cmd\" do\n    setup do\n      @c = GitStyleBinary::Command.new\n    end\n\n    should \"be able to easily work with constraints\" do\n      assert_equal @c.constraints, []\n      @c.constraints << \"foo\"\n      assert_equal @c.constraints, [\"foo\"]\n    end\n    \n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/git_style_binary_test.rb",
    "content": "require File.dirname(__FILE__) + \"/test_helper.rb\"\n\nclass GitStyleBinariesTest < Test::Unit::TestCase\n  context \"parsing basenames\" do\n    should \"accurately parse basenames\" do\n      assert_equal \"wordpress\", GitStyleBinary.basename(\"bin/wordpress\")\n      assert_equal \"wordpress\", GitStyleBinary.basename(\"bin/wordpress-post\")\n      assert_equal \"wordpress\", GitStyleBinary.basename(\"wordpress-post\")\n    end\n\n    should \"get the current command name\" do\n      # doesn't really apply any more b/c it calls 'current' which is never the\n      # current when your running rake_test_loader.rb\n      # \n      # assert_equal \"wordpress\",  GitStyleBinary.current_command_name(\"bin/wordpress\", [\"--help\"])\n      # assert_equal \"post\", GitStyleBinary.current_command_name(\"bin/wordpress-post\", [\"--help\"])\n      # assert_equal \"post\", GitStyleBinary.current_command_name(\"bin/wordpress post\", [\"--help\"])\n      #assert_equal \"post\", GitStyleBinary.current_command_name(\"bin/wordpress post\", [])\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/running_binaries_test.rb",
    "content": "require File.dirname(__FILE__) + \"/test_helper.rb\"\n\nTHIS_YEAR=Time.now.year # todo\n\nclass RunningBinariesTest < Test::Unit::TestCase\n  include RunsBinaryFixtures\n\n  context \"when running primary\" do\n    [\"wordpress -h\", \"wordpress help\"].each do |format|\n      context \"and getting help as a '#{format}'\" do\n        setup { @stdout, @stderr = bin(format) }\n\n        should \"have the command name and short description\" do\n          unless format == \"wordpress -h\" # doesn't apply to wordpress -h\n            output_matches /NAME\\n\\s*wordpress\\-help \\- get help for a specific command/m\n          end\n        end\n\n        should \"have a local (not default) version string\" do\n          output_matches /0\\.0\\.1 \\(c\\) 2009 Nate Murray - local/\n        end\n\n        should \"get a list of subcommands\" do\n          output_matches /subcommands/mi\n        end\n\n        should \"have subcommand short descriptions\" do\n          output_matches /post\\s*create a blog post/\n          output_matches /categories\\s*do something with categories/\n          output_matches /help\\s*get help for a specific command/\n          output_matches /list\\s*list blog postings/\n        end\n\n        should \"have a usage\" do\n          output_matches /SYNOPSIS/i\n          output_matches /wordpress(\\-help)? \\[/\n        end\n\n        should \"be able to ask for help about help\"\n      end\n    end\n\n    context \"and getting help as subcommand\" do\n      # [\"wordpress -h\", \"wordpress help\"].each do |format|\n      [\"wordpress help\"].each do |format|\n        context \"'#{format}'\" do\n          should \"get help on subcommand post\"\n        end\n      end\n    end\n\n    context \"with no options\" do\n      setup { @stdout, @stderr = bin(\"wordpress\") }\n\n      should \"output the options\" do\n        output_matches /Primary Options:/\n      end\n\n      should \"have the test_primary option\" do\n        output_matches /test_primary=>nil/\n      end\n    end\n    should \"be able to require 'primary' and run just fine\"\n  end\n  \n  context \"when running with an action\" do\n    # should be the same for both formats\n    [\"wordpress-categories\", \"wordpress categories\"].each do |bin_format|\n      context \"#{bin_format}\" do\n\n        context \"with action block\" do\n          setup { @stdout, @stderr = bin(\"#{bin_format}\") }\n          should \"have the parsed action items in the help output\" do\n            output_matches /sports news/m\n          end\n        end\n      end\n    end\n  end\n  \n  context \"callbacks\" do\n    context \"on a binary\" do\n      setup { @stdout, @stderr = bin(\"wordpress\") }\n\n      %w(before after).each do |time|\n        should \"run the callback #{time}_run}\" do\n          assert @stdout.match(/#{time}_run command/)\n        end\n      end      \n    end\n    \n    context \"on help\" do\n      setup { @stdout, @stderr = bin(\"wordpress -h\") }\n\n      %w(before after).each do |time|\n        should \"not run the callback #{time}_run\" do\n          assert_nil @stdout.match(/#{time}_run command/)\n        end\n      end      \n    end\n    \n  end\n  \n\n  context \"when running the subcommand\" do\n    # should be the same for both formats\n    [\"wordpress-post\", \"wordpress post\"].each do |bin_format|\n      context \"#{bin_format}\" do\n\n        context \"with no options\" do\n          setup { @stdout, @stderr = bin(\"#{bin_format}\") }\n          should \"fail because title is required\" do\n            output_matches /Error: option 'title' must be specified.\\s*Try --help for help/m\n          end\n        end\n\n        context \"with options\" do\n          setup { @stdout, @stderr = bin(\"#{bin_format} --title='glendale'\") }\n          should \"be running the subcommand's run block\" do\n            output_matches /Subcommand name/\n          end\n          should \"have some default options\" do\n            output_matches /version=>false/\n            output_matches /help=>false/\n          end\n          should \"have some primary options\" do\n            output_matches /test_primary=>nil/\n          end\n          should \"have some local options\" do\n            output_matches /title=>\"glendale\"/\n            output_matches /type=>\"html\"/\n          end\n        end\n\n        context \"testing die statements\" do\n          setup { @stdout, @stderr = bin(\"#{bin_format} --title='glendale' --type=yaml\") }\n\n          should \"die on invalid options\"  do\n            output_matches /argument \\-\\-type type must be one of \\[html\\|xhtml\\|text\\]/\n          end\n        end\n\n      end # end bin_format\n    end # end #each\n  end\n\n  [\"wordpress help post\", \"wordpress post -h\"].each do |format| \n    context \"when calling '#{format}'\" do\n      \n      setup { @stdout, @stderr = bin(format) }\n      should \"have a description\" do\n        output_matches /create a blog post/\n      end\n\n      should \"have the proper usage line\" do\n        output_matches /SYNOPSIS\\n\\s*wordpress\\-post/m\n        output_matches /\\[--title\\]/\n      end\n\n      should \"have option flags\" do\n        output_matches /\\-\\-title(.*)<s>/\n      end\n\n      should \"have primary option flags\" do\n        output_matches /\\-\\-test-primary(.*)<s>/\n      end\n\n      should \"have default option flags\" do\n        output_matches /\\-\\-verbose/\n      end\n\n      should \"have trollop default option flags\" do\n        output_matches /\\-e, \\-\\-version/\n      end\n\n      should \"have the correct binary name and short description\" do\n        output_matches /NAME\\n\\s*wordpress\\-post \\- create a blog post/m\n      end\n\n      should \"have a the primaries version string\" do\n         output_matches /0\\.0\\.1 \\(c\\) 2009 Nate Murray - local/\n      end\n\n      should \"have options\" do\n        output_matches /Options/i\n\n        output_matches /\\-b, \\-\\-blog=<s>/\n        output_matches /short name of the blog to use/\n\n        output_matches /-i, \\-\\-title=<s>/\n        output_matches /title for the post/\n      end\n\n    end\n  end\n\n  context \"when running a bare primary\" do\n    [\"flickr -h\", \"flickr help\"].each do |format|\n      context format do\n        setup { @stdout, @stderr = bin(format) }\n\n        should \"have the name and short description\" do\n          unless format == \"flickr -h\" # hmm\n            output_matches /NAME\\n\\s*flickr\\-help \\- get help for a specific command/m\n          end\n        end\n\n        should \"have a local (not default) version string\" do\n          output_matches /0\\.0\\.2 \\(c\\) 2009/\n        end\n      end\n    end\n    [\"flickr-download -h\", \"flickr download -h\"].each do |format|\n      context format do\n       setup { @stdout, @stderr = bin(format) }\n\n       should \"match on usage\" do\n         output_matches /SYNOPSIS\\n\\s*flickr\\-download/m\n       end\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/shoulda_macros/matching_stdio.rb",
    "content": "class Test::Unit::TestCase\n  def output_should_match(regexp)\n    assert_match regexp, @stdout + @stderr\n  end\n  alias_method :output_matches, :output_should_match\n\n  def stdout_should_match(regexp)\n    assert_match regexp, @stdout \n  end\n  def stderr_should_match(regexp)\n    assert_match regexp, @stderr \n  end\nend\n"
  },
  {
    "path": "vendor/gems/git-style-binaries/test/test_helper.rb",
    "content": "require 'rubygems'\nrequire 'test/unit'\nrequire 'shoulda'\nbegin require 'redgreen'; rescue LoadError; end\nrequire 'open3'\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))\n$LOAD_PATH.unshift(File.dirname(__FILE__))\nDir[File.join(File.dirname(__FILE__), \"shoulda_macros\", \"*.rb\")].each {|f| require f}\nENV['NO_COLOR'] = \"true\"\n\nrequire 'git-style-binary'\nGitStyleBinary.run = true\n\nclass Test::Unit::TestCase\n  def FIXTURES_PATH\n    File.join(File.dirname(__FILE__), \"fixtures\")\n  end\nend\n\nmodule RunsBinaryFixtures\n  # run the specified cmd returning the string values of [stdout,stderr]\n  def bin(cmd)\n    stdin, stdout, stderr = Open3.popen3(\"#{FIXTURES_PATH}/#{cmd}\")\n    [stdout.read, stderr.read]\n  end\nend\n\n"
  },
  {
    "path": "vendor/gems/searchable_paths/.document",
    "content": "README.rdoc\nlib/**/*.rb\nbin/*\nfeatures/**/*.feature\nLICENSE\n"
  },
  {
    "path": "vendor/gems/searchable_paths/.gitignore",
    "content": "*.sw?\n.DS_Store\ncoverage\nrdoc\npkg\n"
  },
  {
    "path": "vendor/gems/searchable_paths/LICENSE",
    "content": "Copyright (c) 2009 Ari Lerner\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/gems/searchable_paths/README.rdoc",
    "content": "= searchable_paths\n\nSearchable paths\n\n== Note on Patches/Pull Requests\n \n* Fork the project.\n* Make your feature addition or bug fix.\n* Add tests for it. This is important so I don't break it in a\n  future version unintentionally.\n* Commit, do not mess with rakefile, version, or history.\n  (if you want to have your own version, that is fine but\n   bump version in a commit by itself I can ignore when I pull)\n* Send me a pull request. Bonus points for topic branches.\n\n== Copyright\n\nCopyright (c) 2009 Nate Murray, Ari Lerner. See LICENSE for details.\n"
  },
  {
    "path": "vendor/gems/searchable_paths/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"searchable_paths\"\n    gem.summary = %Q{Add path searching}\n    gem.description = %Q{Add searchable paths to any class}\n    gem.email = \"arilerner@mac.com\"\n    gem.homepage = \"http://github.com/auser/searchable_paths\"\n    gem.authors = [\"Nate Murray and Ari Lerner\"]\n    # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings\n  end\n  Jeweler::GemcutterTasks.new\nrescue LoadError\n  puts \"Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler\"\nend\n\nrequire 'rake/testtask'\nRake::TestTask.new(:test) do |test|\n  test.libs << 'lib' << 'test'\n  test.pattern = 'test/**/*_test.rb'\n  test.verbose = true\nend\n\nbegin\n  require 'rcov/rcovtask'\n  Rcov::RcovTask.new do |test|\n    test.libs << 'test'\n    test.pattern = 'test/**/*_test.rb'\n    test.verbose = true\n  end\nrescue LoadError\n  task :rcov do\n    abort \"RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov\"\n  end\nend\n\ntask :test => :check_dependencies\n\ntask :default => :test\n\nrequire 'rake/rdoctask'\nRake::RDocTask.new do |rdoc|\n  if File.exist?('VERSION')\n    version = File.read('VERSION')\n  else\n    version = \"\"\n  end\n\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title = \"searchable_paths #{version}\"\n  rdoc.rdoc_files.include('README*')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/gems/searchable_paths/lib/searchable_paths.rb",
    "content": "=begin rdoc\n=end\n\nmodule SearchablePaths\n  def self.included(mod)\n    mod.extend(ClassMethods)\n  end\n\n  module ClassMethods\n    # Specify that a particular class has methods for searchable paths.\n    # \n    # Options:\n    # * <tt>:dirs</tt>: array of directories to look in *under* the search paths. (default: <tt>[\"/\"]</tt>)\n    # * <tt>:dir</tt>: set the directory to look in *under* the search paths. Use either dir or dirs, not both. (default: +/+)\n    # * <tt>:paths</tt>: overwrite all default paths and set the paths to this array exactly\n    # * <tt>:append_paths</tt>:  append these paths to any existing paths\n    # * <tt>:prepend_paths</tt>: prepend these paths to any existing paths\n    def has_searchable_paths(opts={})\n      class_eval do\n        @searchable_paths_dirs = [opts[:dir]] if opts[:dir]\n        @searchable_paths_dirs = opts[:dirs]  if opts[:dirs]\n        @paths_override        = opts[:paths] if opts[:paths]\n        @paths_prepend         = opts[:prepend_paths] || []\n        @paths_append          = opts[:append_paths]  || []\n      end\n      extend SearchablePaths::SingletonMethods\n      include SearchablePaths::InstanceMethods\n    end\n    \n    def searchable_paths_dir;  @searchable_paths_dirs.first; end\n    def searchable_paths_dirs\n      @searchable_paths_dirs && @searchable_paths_dirs.size > 0 ? @searchable_paths_dirs : [\"/\"]\n    end\n   \n    # These are the default search paths in order:\n    # \n    # * current working directory (Dir.pwd)\n    def default_paths\n      [\n        Dir.pwd\n      ]\n    end\n\n    # returns the full set of valid searchable paths, given the options\n    def searchable_paths\n      return @paths_override if @paths_override && @paths_override.size > 0\n      @searchable_paths ||= @paths_prepend + default_paths + @paths_append\n    end\n  end\n\n  module SingletonMethods\n  end\n\n  module InstanceMethods\n\n    # Searches for +filepath+ in the <tt>searchable_paths</tt> iff +filepath+\n    # doesn't exist. e.g. +filepath+ is interpreted *first* as an absolute\n    # path, if +filepath+ doesn't exist verbatim then it looks for the file\n    # in the searchable_paths.\n    # \n    # Returns +nil+ if the file cannot be found.\n    def search_in_known_locations(filepath, additional_search_paths=[])\n      return filepath if File.exists?(filepath) # return the file if its an absolute path\n      additional_search_paths.each do |path|\n        full_path = File.expand_path(path / filepath)\n        return full_path if File.exists?(full_path)\n      end\n      self.class.searchable_paths.each do |path|\n        self.class.searchable_paths_dirs.each do |dir|\n          next if path.nil?\n          full_path = File.expand_path(path / dir / filepath)\n          return full_path if File.exists?(full_path)\n        end\n      end\n      nil\n    end\n    alias_method :find_file, :search_in_known_locations\n\n  end\n\nend"
  },
  {
    "path": "vendor/gems/searchable_paths/test/searchable_paths_test.rb",
    "content": "require \"test_helper\"\n\nPATH_TEST_ROOT = \"/tmp/poolparty\" / \"path_test\"\nPATH_ONE       = PATH_TEST_ROOT / \"one\"\nPATH_TWO       = PATH_TEST_ROOT / \"two\"\n\nclass TestFile\n  include SearchablePaths\n  has_searchable_paths(:dir => \"templates\", :paths => [PATH_ONE, PATH_TWO])\nend\n\nclass TestFile2\n  include SearchablePaths\n  has_searchable_paths(:dirs => [\"clouds\", \"/\"], :prepend_paths => [PATH_ONE, PATH_TWO])\nend\n\ndef File.write_to_file(name, content=\"\")\n  open(name, \"w\") {|f| f.print content}\nend\n\nclass SearchablePathsTest < Test::Unit::TestCase\n  def setup\n    # create path one\n    [PATH_ONE/:clouds, PATH_ONE/:templates, PATH_ONE/:foo].each {|dir| FileUtils.mkdir_p(dir) }\n    [PATH_ONE/'clouds.rb', PATH_ONE/:clouds/'special.rb', PATH_ONE/:templates/'apache.conf'].each do |f|\n      File.write_to_file(f)\n    end\n\n    # create path two\n    [PATH_TWO/:clouds, PATH_TWO/:templates, PATH_TWO/:foo].each {|dir| FileUtils.mkdir_p(dir) }\n    [PATH_TWO/'swing.rb', PATH_TWO/'clouds.rb', PATH_TWO/:clouds/'common.rb', PATH_TWO/:templates/'mysql.conf'].each do |f|\n      File.write_to_file(f)\n    end\n\n    @template = TestFile.new\n    @cloud    = TestFile2.new\n  end\n    \n  def teardown\n    FileUtils.rm_rf(PATH_TEST_ROOT)\n  end\n\n  def test_should_have_class_options_set\n    assert_equal \"templates\", TestFile.searchable_paths_dir\n    assert_equal [\"templates\"], TestFile.searchable_paths_dirs\n    assert_equal [\"clouds\", \"/\"], TestFile2.searchable_paths_dirs\n  end\n    \n  def test_should_be_able_to_find_a_template\n    assert_not_nil @template.find_file(\"apache.conf\")\n    assert_equal PATH_ONE/:templates/'apache.conf', @template.find_file(\"apache.conf\")\n    assert_equal PATH_TWO/:templates/'mysql.conf', @template.find_file(\"mysql.conf\")\n  end\n\n  def test_shouldnt_find_a_template_that_doesnt_exist\n    assert_nil @template.find_file(\"post-office.conf\")\n  end\n\n  def test_should_find_something_with_prepended_paths\n    assert_equal PATH_ONE/'clouds.rb', @cloud.find_file(\"clouds.rb\")\n    assert_equal PATH_TWO/'swing.rb', @cloud.find_file(\"swing.rb\")\n  end\n\n  def test_should_find_things_in_the_right_order\n    assert_equal PATH_ONE/'clouds.rb', @cloud.find_file(\"clouds.rb\")\n  end\n\n  def test_should_look_in_the_additional_search_paths_first\n    FileUtils.mkdir_p(PATH_ONE/'extra')                     \n    File.write_to_file(PATH_ONE/'extra'/'clouds.rb')\n    assert_equal @cloud.find_file(\"clouds.rb\", [PATH_ONE/'extra']), PATH_ONE/'extra'/'clouds.rb'\n  end\n  \nend"
  },
  {
    "path": "vendor/gems/searchable_paths/test/test_helper.rb",
    "content": "require 'rubygems'\nrequire 'test/unit'\nrequire \"fileutils\"\n\n$LOAD_PATH.unshift(File.dirname(__FILE__))\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))\nrequire 'searchable_paths'\n\nclass Test::Unit::TestCase\nend\n\nclass String\n  def /(o)\n    File.join(self, o.to_s)\n  end\nend"
  },
  {
    "path": "vendor/gems/trollop/FAQ.txt",
    "content": "Trollop FAQ\n-----------\n\nQ: Why is it called \"Trollop\"?\nA: No reason.\n\nQ: Why should I use Trollop?\nA: Because it will take you FEWER LINES OF CODE to do reasonable option parsing\n   than any other option parser out there.\n\n   Look at this:\n\n     opts = Trollop::options do\n       opt :monkey, \"Use monkey mode\"\n       opt :goat, \"Use goat mode\", :default => true\n       opt :num_limbs, \"Set number of limbs\", :default => 4\n     end\n\n   That's it. And opts is a hash and you do whatever you want with it.\n   Trivial. You don't have to mix option processing code blocks with the\n   declarations. You don't have to make a class for every option (what is this,\n   Java?). You don't have to write more than 1 line of code per option.\n\n   Plus, you get a beautiful help screen that detects your terminal width and\n   wraps appropriately. C'mon, that's hot.\n\nQ: What is the philosophy behind Trollop?\nA: Must a commandline option processor have a philosophy?\n\nQ: Seriously now. What is it?\nA: Ok, it's this: Trollop *just* does the parsing and gives you a hash table\n   of the result. So whatever fancy logic or constraints you need, you can\n   implement by operating on that hash table. Options that disable other\n   options, fancy constraints involving multiple sets of values across multiple\n   sets of options, etc. are all left for you to do manually.\n\n   (Trollop does support limited constraint setting (see #conflicts and\n   #depends), but any non-trivial program will need to get fancier.)\n\n   The result is that using Trollop is pretty simple, and whatever bizarre\n   logic you want, you can write yourself. And don't forget, you can call\n   Trollop::die to abort the program and give a fancy options-related error\n   message.\n\nQ: What happens to the other stuff on the commandline?\nA: Anything Trollop doesn't recognize as an option or as an option parameter is\n   left in ARGV for you to process.\n\nQ: Does Trollop support multiple-value arguments?\nA: Yes. If you set the :type of an option to something plural, like \":ints\",\n   \":strings\", \":doubles\", \":floats\", \":ios\", it will accept multiple arguments\n   on the commandline and the value will be an array of these.\n\nQ: Does Trollop support arguments that can be given multiple times?\nA: Yes. If you set :multi to true, then the argument can appear multiple times\n   on the commandline, and the value will be an array of the parameters.\n\nQ: Does Trollop support subcommands?\nA: Yes. You get subcommand support by adding a call #stop_on within the options\n   block, and passing the names of the subcommands to it. (See the third\n   example on the webpage.) When Trollop encounters one of these subcommands on\n   the commandline, it stops processing and returns.\n\n   ARGV at that point will contain the subcommand followed by any subcommand\n   options, since Trollop has contained the rest. So you can consume the\n   subcommand and call Trollop.options again with the particular options set\n   for that subcommand.\n\n   If you don't know the subcommands ahead of time, you can call\n   #stop_on_unknown, which will cause Trollop to stop when it encounters any\n   unknown token. This might be more trouble than its worth if you're also\n   passing filenames on the commandline.\n\n   It's probably easier to see the example on the webpage than to read all\n   that.\n\nQ: Why does Trollop disallow numeric short argument names, like '-1' and '-9'?\nA: Because it's ambiguous whether these are arguments or negative integer or\n   floating-point parameters to arguments. E.g., what about \"-f -3\".  Is that a\n   negative three parameter to -f, or two separate parameters? \n\n   I could be very clever and detect when there are no arguments that require\n   floating-point parameters, and allow such short option names in those cases,\n   but opted for simplicity and consistency.\n"
  },
  {
    "path": "vendor/gems/trollop/History.txt",
    "content": "== 1.14 / 2009-06-19\n* Make :multi arguments default to [], not nil, when not set on the commandline.\n* Minor commenting and error message improvements\n\n== 1.13 / 2009-03-16\n* Fix parsing of \"--longarg=<value with spaces>\".\n\n== 1.12 / 2009-01-30\n* Fix some unit test failures in the last release. Should be more careful.\n* Make default short options only be assigned *after* all user-specified\n  short options. Now there's a little less juggling to do when you just\n  want to specify a few short options.\n\n== 1.11 / 2009-01-29\n* Set <opt>_given keys in the results hash for options that were specified\n  on the commandline.\n\n== 1.10.2 / 2008-10-23\n* No longer try `stty size` for screen size detection. Just use curses, and\n  screen users will have to deal with the screen clearing.\n\n== 1.10.1 / 2008-10-22\n* Options hash now responds to method calls as well as standard hash lookup.\n* Default values for multi-occurrence parameters now autoboxed.\n* The relationship between multi-value, multi-occurrence, and default values\n  improved and explained.\n* Documentation improvements.\n\n== 1.10 / 2008-10-21\n* Added :io type for parameters that point to IO streams (filenames, URIs, etc).\n* For screen size detection, first try `stty size` before loading Curses.\n* Improved documentation.\n\n== 1.9 / 2008-08-20\n* Added 'stop_on_unknown' command to stop parsing on any unknown argument.\n  This is useful for handling sub-commands when you don't know the entire\n  set of commands up front. (E.g. if the initial arguments can change it.)\n* Added a :multi option for parameters, signifying that they can be specified\n  multiple times.\n* Added :ints, :strings, :doubles, and :floats option types, which can take\n  multiple arguments.\n\n== 1.8.2 / 2008-06-25\n* Bugfix for #conflicts and #depends error messages\n\n== 1.8.1 / 2008-06-24\n* Bugfix for short option autocreation\n* More aggressive documentation\n\n== 1.8 / 2008-06-16\n* Sub-command support via Parser#stop_on\n\n== 1.7.2 / 2008-01-16\n* Ruby 1.9-ify. Apparently this means replacing :'s with ;'s.\n\n== 1.7.1 / 2008-01-07\n* Documentation improvements\n\n== 1.7 / 2007-06-17\n* Fix incorrect error message for multiple missing required arguments\n  (thanks to Neill Zero)\n\n== 1.6 / 2007-04-01\n* Don't attempt curses screen-width magic unless running on a terminal.\n\n== 1.5 / 2007-03-31\n* --help and --version do the right thing even if the rest of the\n  command line is incorrect.\n* Added #conflicts and #depends to model dependencies and exclusivity\n  between arguments.\n* Minor bugfixes.\n\n== 1.4 / 2007-03-26\n* Disable short options with :short => :none.\n* Minor bugfixes and error message improvements.\n\n== 1.3 / 2007-01-31\n* Wrap at (screen width - 1) instead of screen width.\n* User can override --help and --version.\n* Bugfix in handling of -v and -h.\n* More tests to confirm the above.\n\n== 1.2 / 2007-01-31\n* Minor documentation tweaks.\n* Removed hoe dependency.\n\n== 1.1 / 2007-01-30\n* Trollop::options now passes any arguments as block arguments. Since\n  instance variables are not properly captured by the block, this\n  makes it slightly less noisy to pass them in as local variables.\n  (A real-life use for _why's cloaker!)\n* Help display now preserves original argument order.\n* Trollop::die now also has a single string form in case death is not\n  due to a single argument.\n* Parser#text now an alias for Parser#banner, and can be called\n  multiple times, with the output being placed in the right position\n  in the help text.\n* Slightly more indicative formatting for parameterized arguments.\n\n== 1.0 / 2007-01-29\n* Initial release.\n"
  },
  {
    "path": "vendor/gems/trollop/Manifest.txt",
    "content": "FAQ.txt\nHistory.txt\nManifest.txt\nREADME.txt\nRakefile\nlib/trollop.rb\ntest/test_trollop.rb\n"
  },
  {
    "path": "vendor/gems/trollop/README.txt",
    "content": "== trollop\n\nby William Morgan (wmorgan-trollop at the masanjin dot nets or http://cs.stanford.edu/~ruby)\n\nMain page: http://trollop.rubyforge.org\n\nRelease announcements and comments: http://all-thing.net/search/label/trollop\n\nDocumentation quickstart: See Trollop::options (for some reason rdoc isn't\nlinking that; it's in the top right of the screen if you're browsing online)\nand then Trollop::Parser#opt. Also see the examples at http://trollop.rubyforge.org/.\n\n== DESCRIPTION\n\nTrollop is a commandline option parser for Ruby that just gets out of your\nway. One line of code per option is all you need to write. For that, you get\na nice automatically-generated help page, robust option parsing, command\nsubcompletion, and sensible defaults for everything you don't specify.\n\n== FEATURES/PROBLEMS\n\n- Dirt-simple usage.\n- Sensible defaults. No tweaking necessary, much tweaking possible.\n- Support for long options, short options, short option bundling,\n  and automatic type validation and conversion.\n- Support for subcommands.\n- Automatic help message generation, wrapped to current screen width.\n- Lots of unit tests.\n\n== REQUIREMENTS\n\n* A burning desire to write less code.\n\n== INSTALL\n\n* gem install trollop\n\n== LICENSE\n\nCopyright (c) 2008 William Morgan. Trollop is distributed under the same terms as Ruby.\n"
  },
  {
    "path": "vendor/gems/trollop/Rakefile",
    "content": "# -*- ruby -*-\n\nrequire 'rubygems'\nrequire 'hoe'\n\n$:.unshift \"lib\"\nrequire 'trollop'\n\nclass Hoe\n  def extra_dev_deps; @extra_dev_deps.reject { |x| x[0] == \"hoe\" } end\nend\n\nHoe.new('trollop', Trollop::VERSION) do |p|\n  p.rubyforge_name = 'trollop'\n  p.author = \"William Morgan\"\n  p.summary = \"Trollop is a commandline option parser for Ruby that just gets out of your way. One line of code per option is all you need to write. For that, you get a nice automatically-generated help page, robust option parsing, command subcompletion, and sensible defaults for everything you don't specify.\"\n  p.description = p.paragraphs_of('README.txt', 4..5, 9..18).join(\"\\n\\n\").gsub(/== SYNOPSIS/, \"Synopsis\")\n  p.url = \"http://trollop.rubyforge.org\"\n  p.changes = p.paragraphs_of('History.txt', 0..0).join(\"\\n\\n\")\n  p.email = \"wmorgan-trollop@masanjin.net\"\nend\n\nWWW_FILES = FileList[\"www/*\"] + %w(README.txt FAQ.txt)\ntask :upload_webpage => WWW_FILES do |t|\n  sh \"rsync -Paz -essh #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/trollop/\"\nend\n\ntask :rdoc do |t|\n  sh \"rdoc lib README.txt History.txt -m README.txt\"\nend\n\ntask :upload_docs => :rdoc do |t|\n  sh \"rsync -az -essh doc/* wmorgan@rubyforge.org:/var/www/gforge-projects/trollop/trollop/\"\nend\n\n# vim: syntax=ruby\n"
  },
  {
    "path": "vendor/gems/trollop/lib/trollop.rb",
    "content": "## lib/trollop.rb -- trollop command-line processing library\n## Author::    William Morgan (mailto: wmorgan-trollop@masanjin.net)\n## Copyright:: Copyright 2007 William Morgan\n## License::   GNU GPL version 2\n\nrequire 'date'\n\nmodule Trollop\n\nVERSION = \"1.14\"\n\n## Thrown by Parser in the event of a commandline error. Not needed if\n## you're using the Trollop::options entry.\nclass CommandlineError < StandardError; end\n  \n## Thrown by Parser if the user passes in '-h' or '--help'. Handled\n## automatically by Trollop#options.\nclass HelpNeeded < StandardError; end\n\n## Thrown by Parser if the user passes in '-h' or '--version'. Handled\n## automatically by Trollop#options.\nclass VersionNeeded < StandardError; end\n\n## Regex for floating point numbers\nFLOAT_RE = /^-?((\\d+(\\.\\d+)?)|(\\.\\d+))$/\n\n## Regex for parameters\nPARAM_RE = /^-(-|\\.$|[^\\d\\.])/\n\n## The commandline parser. In typical usage, the methods in this class\n## will be handled internally by Trollop::options. In this case, only the\n## #opt, #banner and #version, #depends, and #conflicts methods will\n## typically be called.\n##\n## If it's necessary to instantiate this class (for more complicated\n## argument-parsing situations), be sure to call #parse to actually\n## produce the output hash.\nclass Parser\n\n  ## The set of values that indicate a flag option when passed as the\n  ## +:type+ parameter of #opt.\n  FLAG_TYPES = [:flag, :bool, :boolean]\n\n  ## The set of values that indicate a single-parameter (normal) option when\n  ## passed as the +:type+ parameter of #opt.\n  ##\n  ## A value of +io+ corresponds to a readable IO resource, including\n  ## a filename, URI, or the strings 'stdin' or '-'.\n  SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date]\n\n  ## The set of values that indicate a multiple-parameter option (i.e., that\n  ## takes multiple space-separated values on the commandline) when passed as\n  ## the +:type+ parameter of #opt.\n  MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates]\n\n  ## The complete set of legal values for the +:type+ parameter of #opt.\n  TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES\n\n  INVALID_SHORT_ARG_REGEX = /[\\d-]/ #:nodoc:\n\n  ## The values from the commandline that were not interpreted by #parse.\n  attr_reader :leftovers\n\n  ## The complete configuration hashes for each option. (Mainly useful\n  ## for testing.)\n  attr_reader :specs\n\n  ## Initializes the parser, and instance-evaluates any block given.\n  def initialize *a, &b\n    @version = nil\n    @leftovers = []\n    @specs = {}\n    @long = {}\n    @short = {}\n    @order = []\n    @constraints = []\n    @stop_words = []\n    @stop_on_unknown = false\n\n    #instance_eval(&b) if b # can't take arguments\n    cloaker(&b).bind(self).call(*a) if b\n  end\n\n  ## Define an option. +name+ is the option name, a unique identifier\n  ## for the option that you will use internally, which should be a\n  ## symbol or a string. +desc+ is a string description which will be\n  ## displayed in help messages.\n  ##\n  ## Takes the following optional arguments:\n  ##\n  ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s.\n  ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+.\n  ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given.\n  ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Trollop::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the the commandline the value will be +false+.\n  ## [+:required+] If set to +true+, the argument must be provided on the commandline.\n  ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)\n  ##\n  ## Note that there are two types of argument multiplicity: an argument\n  ## can take multiple values, e.g. \"--arg 1 2 3\". An argument can also\n  ## be allowed to occur multiple times, e.g. \"--arg 1 --arg 2\".\n  ##\n  ## Arguments that take multiple values should have a +:type+ parameter\n  ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+\n  ## value of an array of the correct type (e.g. [String]). The\n  ## value of this argument will be an array of the parameters on the\n  ## commandline.\n  ##\n  ## Arguments that can occur multiple times should be marked with\n  ## +:multi+ => +true+. The value of this argument will also be an array.\n  ## In contrast with regular non-multi options, if not specified on\n  ## the commandline, the default value will be [], not nil.\n  ##\n  ## These two attributes can be combined (e.g. +:type+ => +:strings+,\n  ## +:multi+ => +true+), in which case the value of the argument will be\n  ## an array of arrays.\n  ##\n  ## There's one ambiguous case to be aware of: when +:multi+: is true and a\n  ## +:default+ is set to an array (of something), it's ambiguous whether this\n  ## is a multi-value argument as well as a multi-occurrence argument.\n  ## In thise case, Trollop assumes that it's not a multi-value argument.\n  ## If you want a multi-value, multi-occurrence argument with a default\n  ## value, you must specify +:type+ as well.\n\n  def opt name, desc=\"\", opts={}\n    raise ArgumentError, \"you already have an argument named '#{name}'\" if @specs.member? name\n\n    ## fill in :type\n    opts[:type] = # normalize\n      case opts[:type]\n      when :boolean, :bool; :flag\n      when :integer; :int\n      when :integers; :ints\n      when :double; :float\n      when :doubles; :floats\n      when Class\n        case opts[:type].name\n        when 'TrueClass', 'FalseClass'; :flag\n        when 'String'; :string\n        when 'Integer'; :int\n        when 'Float'; :float\n        when 'IO'; :io\n        when 'Date'; :date\n        else\n          raise ArgumentError, \"unsupported argument type '#{opts[:type].class.name}'\"\n        end\n      when nil; nil\n      else\n        raise ArgumentError, \"unsupported argument type '#{opts[:type]}'\" unless TYPES.include?(opts[:type])\n        opts[:type]\n      end\n\n    ## for options with :multi => true, an array default doesn't imply\n    ## a multi-valued argument. for that you have to specify a :type\n    ## as well. (this is how we disambiguate an ambiguous situation;\n    ## see the docs for Parser#opt for details.)\n    disambiguated_default =\n      if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type]\n        opts[:default].first\n      else\n        opts[:default]\n      end\n\n    type_from_default =\n      case disambiguated_default\n      when Integer; :int\n      when Numeric; :float\n      when TrueClass, FalseClass; :flag\n      when String; :string\n      when IO; :io\n      when Date; :date\n      when Array\n        if opts[:default].empty?\n          raise ArgumentError, \"multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'\"\n        end\n        case opts[:default][0]    # the first element determines the types\n        when Integer; :ints\n        when Numeric; :floats\n        when String; :strings\n        when IO; :ios\n        when Date; :dates\n        else\n          raise ArgumentError, \"unsupported multiple argument type '#{opts[:default][0].class.name}'\"\n        end\n      when nil; nil\n      else\n        raise ArgumentError, \"unsupported argument type '#{opts[:default].class.name}'\"\n      end\n\n    raise ArgumentError, \":type specification and default type don't match (default type is #{type_from_default})\" if opts[:type] && type_from_default && opts[:type] != type_from_default\n\n    opts[:type] = opts[:type] || type_from_default || :flag\n\n    ## fill in :long\n    opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub(\"_\", \"-\")\n    opts[:long] =\n      case opts[:long]\n      when /^--([^-].*)$/\n        $1\n      when /^[^-]/\n        opts[:long]\n      else\n        raise ArgumentError, \"invalid long option name #{opts[:long].inspect}\"\n      end\n    raise ArgumentError, \"long option name #{opts[:long].inspect} is already taken; please specify a (different) :long\" if @long[opts[:long]]\n\n    ## fill in :short\n    opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none\n    opts[:short] = case opts[:short]\n      when /^-(.)$/; $1\n      when nil, :none, /^.$/; opts[:short]\n      else raise ArgumentError, \"invalid short option name '#{opts[:short].inspect}'\"\n    end\n\n    if opts[:short]\n      raise ArgumentError, \"short option name #{opts[:short].inspect} is already taken; please specify a (different) :short\" if @short[opts[:short]]\n      raise ArgumentError, \"a short option name can't be a number or a dash\" if opts[:short] =~ INVALID_SHORT_ARG_REGEX\n    end\n\n    ## fill in :default for flags\n    opts[:default] = false if opts[:type] == :flag && opts[:default].nil?\n\n    ## autobox :default for :multi (multi-occurrence) arguments\n    opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)\n\n    ## fill in :multi\n    opts[:multi] ||= false\n\n    opts[:desc] ||= desc\n    @long[opts[:long]] = name\n    @short[opts[:short]] = name if opts[:short] && opts[:short] != :none\n    @specs[name] = opts\n    @order << [:opt, name]\n  end\n\n  ## Sets the version string. If set, the user can request the version\n  ## on the commandline. Should probably be of the form \"<program name>\n  ## <version number>\".\n  def version s=nil; @version = s if s; @version end\n\n  ## Adds text to the help display. Can be interspersed with calls to\n  ## #opt to build a multi-section help page.\n  def banner s; @order << [:text, s] end\n  alias :text :banner\n\n  ## Marks two (or more!) options as requiring each other. Only handles\n  ## undirected (i.e., mutual) dependencies. Directed dependencies are\n  ## better modeled with Trollop::die.\n  def depends *syms\n    syms.each { |sym| raise ArgumentError, \"unknown option '#{sym}'\" unless @specs[sym] }\n    @constraints << [:depends, syms]\n  end\n  \n  ## Marks two (or more!) options as conflicting.\n  def conflicts *syms\n    syms.each { |sym| raise ArgumentError, \"unknown option '#{sym}'\" unless @specs[sym] }\n    @constraints << [:conflicts, syms]\n  end\n\n  ## Defines a set of words which cause parsing to terminate when\n  ## encountered, such that any options to the left of the word are\n  ## parsed as usual, and options to the right of the word are left\n  ## intact.\n  ##\n  ## A typical use case would be for subcommand support, where these\n  ## would be set to the list of subcommands. A subsequent Trollop\n  ## invocation would then be used to parse subcommand options, after\n  ## shifting the subcommand off of ARGV.\n  def stop_on *words\n    @stop_words = [*words].flatten\n  end\n\n  ## Similar to #stop_on, but stops on any unknown word when encountered\n  ## (unless it is a parameter for an argument). This is useful for\n  ## cases where you don't know the set of subcommands ahead of time,\n  ## i.e., without first parsing the global options.\n  def stop_on_unknown\n    @stop_on_unknown = true\n  end\n\n  ## Parses the commandline. Typically called by Trollop::options.\n  def parse cmdline=ARGV\n    vals = {}\n    required = {}\n\n    opt :version, \"Print version and exit\" if @version unless @specs[:version] || @long[\"version\"]\n    opt :help, \"Show this message\" unless @specs[:help] || @long[\"help\"]\n\n    @specs.each do |sym, opts|\n      required[sym] = true if opts[:required]\n      vals[sym] = opts[:default]\n      vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil\n    end\n\n    resolve_default_short_options\n\n    ## resolve symbols\n    given_args = {}\n    @leftovers = each_arg cmdline do |arg, params|\n      sym = case arg\n      when /^-([^-])$/\n        @short[$1]\n      when /^--([^-]\\S*)$/\n        @long[$1]\n      else\n        raise CommandlineError, \"invalid argument syntax: '#{arg}'\"\n      end\n      raise CommandlineError, \"unknown argument '#{arg}'\" unless sym\n\n      if given_args.include?(sym) && !@specs[sym][:multi]\n        raise CommandlineError, \"option '#{arg}' specified multiple times\"\n      end\n\n      given_args[sym] ||= {}\n\n      given_args[sym][:arg] = arg\n      given_args[sym][:params] ||= []\n\n      # The block returns the number of parameters taken.\n      num_params_taken = 0\n\n      unless params.nil?\n        if SINGLE_ARG_TYPES.include?(@specs[sym][:type])\n          given_args[sym][:params] << params[0, 1]  # take the first parameter\n          num_params_taken = 1\n        elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])\n          given_args[sym][:params] << params        # take all the parameters\n          num_params_taken = params.size\n        end\n      end\n\n      num_params_taken\n    end\n\n    ## check for version and help args\n    raise VersionNeeded if given_args.include? :version\n    raise HelpNeeded if given_args.include? :help\n\n    ## check constraint satisfaction\n    @constraints.each do |type, syms|\n      constraint_sym = syms.find { |sym| given_args[sym] }\n      next unless constraint_sym\n\n      case type\n      when :depends\n        syms.each { |sym| raise CommandlineError, \"--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}\" unless given_args.include? sym }\n      when :conflicts\n        syms.each { |sym| raise CommandlineError, \"--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}\" if given_args.include?(sym) && (sym != constraint_sym) }\n      end\n    end\n\n    required.each do |sym, val|\n      raise CommandlineError, \"option '#{sym}' must be specified\" unless given_args.include? sym\n    end\n\n    ## parse parameters\n    given_args.each do |sym, given_data|\n      arg = given_data[:arg]\n      params = given_data[:params]\n\n      opts = @specs[sym]\n      raise CommandlineError, \"option '#{arg}' needs a parameter\" if params.empty? && opts[:type] != :flag\n\n      vals[\"#{sym}_given\".intern] = true # mark argument as specified on the commandline\n\n      case opts[:type]\n      when :flag\n        vals[sym] = !opts[:default]\n      when :int, :ints\n        vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }\n      when :float, :floats\n        vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }\n      when :string, :strings\n        vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }\n      when :io, :ios\n        vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }\n      when :date, :dates\n        vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } }\n      end\n\n      if SINGLE_ARG_TYPES.include?(opts[:type])\n        unless opts[:multi]       # single parameter\n          vals[sym] = vals[sym][0][0]\n        else                      # multiple options, each with a single parameter\n          vals[sym] = vals[sym].map { |p| p[0] }\n        end\n      elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]\n        vals[sym] = vals[sym][0]  # single option, with multiple parameters\n      end\n      # else: multiple options, with multiple parameters\n    end\n\n    ## allow openstruct-style accessors\n    class << vals\n      def method_missing(m, *args)\n        self[m] || self[m.to_s]\n      end\n    end\n    vals\n  end\n\n  def parse_date_parameter param, arg #:nodoc:\n    begin\n      begin\n        time = Chronic.parse(param)\n      rescue NameError\n        # chronic is not available\n      end\n      time ? Date.new(time.year, time.month, time.day) : Date.parse(param)\n    rescue ArgumentError => e\n      raise CommandlineError, \"option '#{arg}' needs a date\"\n    end\n  end\n\n  ## Print the help message to +stream+.\n  def educate stream=$stdout\n    width # just calculate it now; otherwise we have to be careful not to\n          # call this unless the cursor's at the beginning of a line.\n\n    left = {}\n    @specs.each do |name, spec| \n      left[name] = \"--#{spec[:long]}\" +\n        (spec[:short] && spec[:short] != :none ? \", -#{spec[:short]}\" : \"\") +\n        case spec[:type]\n        when :flag; \"\"\n        when :int; \" <i>\"\n        when :ints; \" <i+>\"\n        when :string; \" <s>\"\n        when :strings; \" <s+>\"\n        when :float; \" <f>\"\n        when :floats; \" <f+>\"\n        when :io; \" <filename/uri>\"\n        when :ios; \" <filename/uri+>\"\n        when :date; \" <date>\"\n        when :dates; \" <date+>\"\n        end\n    end\n\n    leftcol_width = left.values.map { |s| s.length }.max || 0\n    rightcol_start = leftcol_width + 6 # spaces\n\n    unless @order.size > 0 && @order.first.first == :text\n      stream.puts \"#@version\\n\" if @version\n      stream.puts \"Options:\"\n    end\n\n    @order.each do |what, opt|\n      if what == :text\n        stream.puts wrap(opt)\n        next\n      end\n\n      spec = @specs[opt]\n      stream.printf \"  %#{leftcol_width}s:   \", left[opt]\n      desc = spec[:desc] + begin\n        default_s = case spec[:default]\n        when $stdout; \"<stdout>\"\n        when $stdin; \"<stdin>\"\n        when $stderr; \"<stderr>\"\n        when Array\n          spec[:default].join(\", \")\n        else\n          spec[:default].to_s\n        end\n\n        if spec[:default]\n          if spec[:desc] =~ /\\.$/\n            \" (Default: #{default_s})\"\n          else\n            \" (default: #{default_s})\"\n          end\n        else\n          \"\"\n        end\n      end\n      stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)\n    end\n  end\n\n  def width #:nodoc:\n    @width ||= if $stdout.tty?\n      begin\n        require 'curses'\n        Curses::init_screen\n        x = Curses::cols\n        Curses::close_screen\n        x\n      rescue Exception\n        80\n      end\n    else\n      80\n    end\n  end\n\n  def wrap str, opts={} # :nodoc:\n    if str == \"\"\n      [\"\"]\n    else\n      str.split(\"\\n\").map { |s| wrap_line s, opts }.flatten\n    end\n  end\n\nprivate\n\n  ## yield successive arg, parameter pairs\n  def each_arg args\n    remains = []\n    i = 0\n\n    until i >= args.length\n      if @stop_words.member? args[i]\n        remains += args[i .. -1]\n        return remains\n      end\n      case args[i]\n      when /^--$/ # arg terminator\n        remains += args[(i + 1) .. -1]\n        return remains\n      when /^--(\\S+?)=(.*)$/ # long argument with equals\n        yield \"--#{$1}\", [$2]\n        i += 1\n      when /^--(\\S+)$/ # long argument\n        params = collect_argument_parameters(args, i + 1)\n        unless params.empty?\n          num_params_taken = yield args[i], params\n          unless num_params_taken\n            if @stop_on_unknown\n              remains += args[i + 1 .. -1]\n              return remains\n            else\n              remains += params\n            end\n          end\n          i += 1 + num_params_taken\n        else # long argument no parameter\n          yield args[i], nil\n          i += 1\n        end\n      when /^-(\\S+)$/ # one or more short arguments\n        shortargs = $1.split(//)\n        shortargs.each_with_index do |a, j|\n          if j == (shortargs.length - 1)\n            params = collect_argument_parameters(args, i + 1)\n            unless params.empty?\n              num_params_taken = yield \"-#{a}\", params\n              unless num_params_taken\n                if @stop_on_unknown\n                  remains += args[i + 1 .. -1]\n                  return remains\n                else\n                  remains += params\n                end\n              end\n              i += 1 + num_params_taken\n            else # argument no parameter\n              yield \"-#{a}\", nil\n              i += 1\n            end\n          else\n            yield \"-#{a}\", nil\n          end\n        end\n      else\n        if @stop_on_unknown\n          remains += args[i .. -1]\n          return remains\n        else\n          remains << args[i]\n          i += 1\n        end\n      end\n    end\n\n    remains\n  end\n\n  def parse_integer_parameter param, arg\n    raise CommandlineError, \"option '#{arg}' needs an integer\" unless param =~ /^\\d+$/\n    param.to_i\n  end\n\n  def parse_float_parameter param, arg\n    raise CommandlineError, \"option '#{arg}' needs a floating-point number\" unless param =~ FLOAT_RE\n    param.to_f\n  end\n\n  def parse_io_parameter param, arg\n    case param\n    when /^(stdin|-)$/i; $stdin\n    else\n      require 'open-uri'\n      begin\n        open param\n      rescue SystemCallError => e\n        raise CommandlineError, \"file or url for option '#{arg}' cannot be opened: #{e.message}\"\n      end\n    end\n  end\n\n  def collect_argument_parameters args, start_at\n    params = []\n    pos = start_at\n    while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do\n      params << args[pos]\n      pos += 1\n    end\n    params\n  end\n\n  def resolve_default_short_options\n    @order.each do |type, name|\n      next unless type == :opt\n      opts = @specs[name]\n      next if opts[:short]\n\n      c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }\n      raise ArgumentError, \"can't generate a default short option name for #{opts[:long].inspect}: out of unique characters\" unless c\n\n      opts[:short] = c\n      @short[c] = name\n    end\n  end\n\n  def wrap_line str, opts={}\n    prefix = opts[:prefix] || 0\n    width = opts[:width] || (self.width - 1)\n    start = 0\n    ret = []\n    until start > str.length\n      nextt = \n        if start + width >= str.length\n          str.length\n        else\n          x = str.rindex(/\\s/, start + width)\n          x = str.index(/\\s/, start) if x && x < start\n          x || str.length\n        end\n      ret << (ret.empty? ? \"\" : \" \" * prefix) + str[start ... nextt]\n      start = nextt + 1\n    end\n    ret\n  end\n\n  ## instance_eval but with ability to handle block arguments\n  ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html\n  def cloaker &b\n    (class << self; self; end).class_eval do\n      define_method :cloaker_, &b\n      meth = instance_method :cloaker_\n      remove_method :cloaker_\n      meth\n    end\n  end\nend\n\n## The top-level entry method into Trollop. Creates a Parser object,\n## passes the block to it, then parses +args+ with it, handling any\n## errors or requests for help or version information appropriately (and\n## then exiting). Modifies +args+ in place. Returns a hash of option\n## values.\n##\n## The block passed in should contain zero or more calls to +opt+\n## (Parser#opt), zero or more calls to +text+ (Parser#text), and\n## probably a call to +version+ (Parser#version).\n##\n## The returned block contains a value for every option specified with\n## +opt+.  The value will be the value given on the commandline, or the\n## default value if the option was not specified on the commandline. For\n## every option specified on the commandline, a key \"<option\n## name>_given\" will also be set in the hash.\n##\n## Example:\n##\n##   require 'trollop'\n##   opts = Trollop::options do\n##     opt :monkey, \"Use monkey mode\"                     # a flag --monkey, defaulting to false\n##     opt :goat, \"Use goat mode\", :default => true       # a flag --goat, defaulting to true\n##     opt :num_limbs, \"Number of limbs\", :default => 4   # an integer --num-limbs <i>, defaulting to 4\n##     opt :num_thumbs, \"Number of thumbs\", :type => :int # an integer --num-thumbs <i>, defaulting to nil\n##   end\n##\n##   ## if called with no arguments\n##   p opts # => { :monkey => false, :goat => true, :num_limbs => 4, :num_thumbs => nil }\n##\n##   ## if called with --monkey\n##   p opts # => {:monkey_given=>true, :monkey=>true, :goat=>true, :num_limbs=>4, :help=>false, :num_thumbs=>nil}\n##\n## See more examples at http://trollop.rubyforge.org.\ndef options args = ARGV, *a, &b\n  @p = Parser.new(*a, &b)\n  begin\n    vals = @p.parse args\n    args.clear\n    @p.leftovers.each { |l| args << l }\n    vals\n  rescue CommandlineError => e\n    $stderr.puts \"Error: #{e.message}.\"\n    $stderr.puts \"Try --help for help.\"\n    exit(-1)\n  rescue HelpNeeded\n    @p.educate\n    exit\n  rescue VersionNeeded\n    puts @p.version\n    exit\n  end\nend\n\n## Informs the user that their usage of 'arg' was wrong, as detailed by\n## 'msg', and dies. Example:\n##\n##   options do\n##     opt :volume, :default => 0.0\n##   end\n##\n##   die :volume, \"too loud\" if opts[:volume] > 10.0\n##   die :volume, \"too soft\" if opts[:volume] < 0.1\n##\n## In the one-argument case, simply print that message, a notice\n## about -h, and die. Example:\n##\n##   options do\n##     opt :whatever # ...\n##   end\n##\n##   Trollop::die \"need at least one filename\" if ARGV.empty?\ndef die arg, msg=nil\n  if msg\n    $stderr.puts \"Error: argument --#{@p.specs[arg][:long]} #{msg}.\"\n  else\n    $stderr.puts \"Error: #{arg}.\"\n  end\n  $stderr.puts \"Try --help for help.\"\n  exit(-1)\nend\n\nmodule_function :options, :die\n\nend # module\n"
  },
  {
    "path": "vendor/gems/trollop/release-script.txt",
    "content": "Just a few simple steps to make a new release.\n\nvi lib/trollop.rb # and bump version number\nvi History.txt    # and describe changes\ngit-rank-contributors -o -h >> www/index.html\nvi www/index.html # and integrate contributors\nrake upload_webpage\nrake upload_docs\nrake release VERSION=<releasename>\ngit commit -a -m \"bump to...\"\ngit tag release-<releasename>\ngit push\ngit push --tags\n"
  },
  {
    "path": "vendor/gems/trollop/test/test_trollop.rb",
    "content": "## test/test_trollop.rb -- unit tests for trollop\n## Author::    William Morgan (mailto: wmorgan-trollop@masanjin.net)\n## Copyright:: Copyright 2007 William Morgan\n## License::   GNU GPL version 2\n\nrequire 'test/unit'\nrequire 'stringio'\nrequire 'trollop'\n\nmodule Trollop\nmodule Test\n\nclass Trollop < ::Test::Unit::TestCase\n  def setup\n    @p = Parser.new\n  end\n\n  def test_unknown_arguments\n    assert_raise(CommandlineError) { @p.parse(%w(--arg)) }\n    @p.opt \"arg\"\n    assert_nothing_raised { @p.parse(%w(--arg)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--arg2)) }\n  end\n\n  def test_syntax_check\n    @p.opt \"arg\"\n\n    assert_nothing_raised { @p.parse(%w(--arg)) }\n    assert_nothing_raised { @p.parse(%w(arg)) }\n    assert_raise(CommandlineError) { @p.parse(%w(---arg)) }\n    assert_raise(CommandlineError) { @p.parse(%w(-arg)) }\n  end\n\n  def test_required_flags_are_required\n    @p.opt \"arg\", \"desc\", :required => true\n    @p.opt \"arg2\", \"desc\", :required => false\n    @p.opt \"arg3\", \"desc\", :required => false\n\n    assert_nothing_raised { @p.parse(%w(--arg)) }\n    assert_nothing_raised { @p.parse(%w(--arg --arg2)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--arg2)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--arg2 --arg3)) }\n  end\n  \n  ## flags that take an argument error unless given one\n  def test_argflags_demand_args\n    @p.opt \"goodarg\", \"desc\", :type => String\n    @p.opt \"goodarg2\", \"desc\", :type => String\n\n    assert_nothing_raised { @p.parse(%w(--goodarg goat)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--goodarg --goodarg2 goat)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--goodarg)) }\n  end\n\n  ## flags that don't take arguments ignore them\n  def test_arglessflags_refuse_args\n    @p.opt \"goodarg\"\n    @p.opt \"goodarg2\"\n    assert_nothing_raised { @p.parse(%w(--goodarg)) }\n    assert_nothing_raised { @p.parse(%w(--goodarg --goodarg2)) }\n    opts = @p.parse %w(--goodarg a)\n    assert_equal true, opts[\"goodarg\"]\n    assert_equal [\"a\"], @p.leftovers\n  end\n\n  ## flags that require args of a specific type refuse args of other\n  ## types\n  def test_typed_args_refuse_args_of_other_types\n    assert_nothing_raised { @p.opt \"goodarg\", \"desc\", :type => :int }\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :type => :asdf }\n\n    assert_nothing_raised { @p.parse(%w(--goodarg 3)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--goodarg 4.2)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--goodarg hello)) }\n  end\n\n  ## type is correctly derived from :default\n  def test_type_correctly_derived_from_default\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :default => [] }\n\n    opts = nil\n\n    # single arg: int\n    assert_nothing_raised { @p.opt \"argsi\", \"desc\", :default => 0 }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal 0, opts[\"argsi\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argsi 4)) }\n    assert_equal 4, opts[\"argsi\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argsi 4.2)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--argsi hello)) }\n\n    # single arg: float\n    assert_nothing_raised { @p.opt \"argsf\", \"desc\", :default => 3.14 }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal 3.14, opts[\"argsf\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argsf 2.41)) }\n    assert_equal 2.41, opts[\"argsf\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argsf 2)) }\n    assert_equal 2, opts[\"argsf\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argsf hello)) }\n\n    # single arg: date\n    date = Date.today\n    assert_nothing_raised { @p.opt \"argsd\", \"desc\", :default => date }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal Date.today, opts[\"argsd\"]\n    assert_nothing_raised { opts = @p.parse(['--argsd', 'Jan 4, 2007']) }\n    assert_equal Date.civil(2007, 1, 4), opts[\"argsd\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argsd hello)) }\n\n    # single arg: string\n    assert_nothing_raised { @p.opt \"argss\", \"desc\", :default => \"foobar\" }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal \"foobar\", opts[\"argss\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argss 2.41)) }\n    assert_equal \"2.41\", opts[\"argss\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argss hello)) }\n    assert_equal \"hello\", opts[\"argss\"]\n\n    # multi args: ints\n    assert_nothing_raised { @p.opt \"argmi\", \"desc\", :default => [3, 5] }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal [3, 5], opts[\"argmi\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argmi 4)) }\n    assert_equal [4], opts[\"argmi\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argmi 4.2)) }\n    assert_raise(CommandlineError) { @p.parse(%w(--argmi hello)) }\n\n    # multi args: floats\n    assert_nothing_raised { @p.opt \"argmf\", \"desc\", :default => [3.34, 5.21] }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal [3.34, 5.21], opts[\"argmf\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argmf 2)) }\n    assert_equal [2], opts[\"argmf\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argmf 4.0)) }\n    assert_equal [4.0], opts[\"argmf\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argmf hello)) }\n\n    # multi args: dates\n    dates = [Date.today, Date.civil(2007, 1, 4)]\n    assert_nothing_raised { @p.opt \"argmd\", \"desc\", :default => dates }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal dates, opts[\"argmd\"]\n    assert_nothing_raised { opts = @p.parse(['--argmd', 'Jan 4, 2007']) }\n    assert_equal [Date.civil(2007, 1, 4)], opts[\"argmd\"]\n    assert_raise(CommandlineError) { @p.parse(%w(--argmd hello)) }\n\n    # multi args: strings\n    assert_nothing_raised { @p.opt \"argmst\", \"desc\", :default => %w(hello world) }\n    assert_nothing_raised { opts = @p.parse(\"--\") }\n    assert_equal %w(hello world), opts[\"argmst\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argmst 3.4)) }\n    assert_equal [\"3.4\"], opts[\"argmst\"]\n    assert_nothing_raised { opts = @p.parse(%w(--argmst goodbye)) }\n    assert_equal [\"goodbye\"], opts[\"argmst\"]\n  end    \n\n  ## :type and :default must match if both are specified\n  def test_type_and_default_must_match\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :type => :int, :default => \"hello\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg2\", \"desc\", :type => :String, :default => 4 }\n    assert_raise(ArgumentError) { @p.opt \"badarg2\", \"desc\", :type => :String, :default => [\"hi\"] }\n    assert_raise(ArgumentError) { @p.opt \"badarg2\", \"desc\", :type => :ints, :default => [3.14] }\n\n    assert_nothing_raised { @p.opt \"argsi\", \"desc\", :type => :int, :default => 4 }\n    assert_nothing_raised { @p.opt \"argsf\", \"desc\", :type => :float, :default => 3.14 }\n    assert_nothing_raised { @p.opt \"argsd\", \"desc\", :type => :date, :default => Date.today }\n    assert_nothing_raised { @p.opt \"argss\", \"desc\", :type => :string, :default => \"yo\" }\n    assert_nothing_raised { @p.opt \"argmi\", \"desc\", :type => :ints, :default => [4] }\n    assert_nothing_raised { @p.opt \"argmf\", \"desc\", :type => :floats, :default => [3.14] }\n    assert_nothing_raised { @p.opt \"argmd\", \"desc\", :type => :dates, :default => [Date.today] }\n    assert_nothing_raised { @p.opt \"argmst\", \"desc\", :type => :strings, :default => [\"yo\"] }\n  end\n\n  def test_long_detects_bad_names\n    assert_nothing_raised { @p.opt \"goodarg\", \"desc\", :long => \"none\" }\n    assert_nothing_raised { @p.opt \"goodarg2\", \"desc\", :long => \"--two\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :long => \"\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg2\", \"desc\", :long => \"--\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg3\", \"desc\", :long => \"-one\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg4\", \"desc\", :long => \"---toomany\" }\n  end\n\n  def test_short_detects_bad_names\n    assert_nothing_raised { @p.opt \"goodarg\", \"desc\", :short => \"a\" }\n    assert_nothing_raised { @p.opt \"goodarg2\", \"desc\", :short => \"-b\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :short => \"\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg2\", \"desc\", :short => \"-ab\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg3\", \"desc\", :short => \"--t\" }\n  end\n\n  def test_short_names_created_automatically\n    @p.opt \"arg\"\n    @p.opt \"arg2\"\n    @p.opt \"arg3\"\n    opts = @p.parse %w(-a -g)\n    assert_equal true, opts[\"arg\"]\n    assert_equal false, opts[\"arg2\"]\n    assert_equal true, opts[\"arg3\"]\n  end\n\n  def test_short_autocreation_skips_dashes_and_numbers\n    @p.opt :arg # auto: a\n    @p.opt :arg_potato # auto: r\n    @p.opt :arg_muffin # auto: g\n    assert_nothing_raised { @p.opt :arg_daisy } # auto: d (not _)!\n    assert_nothing_raised { @p.opt :arg_r2d2f } # auto: f (not 2)!\n\n    opts = @p.parse %w(-f -d)\n    assert_equal true, opts[:arg_daisy]\n    assert_equal true, opts[:arg_r2d2f]\n    assert_equal false, opts[:arg]\n    assert_equal false, opts[:arg_potato]\n    assert_equal false, opts[:arg_muffin]\n  end\n\n  def test_short_autocreation_detects_running_out\n    @p.opt :arg1 # auto: a\n    @p.opt :arg2 # auto: r\n    @p.opt :arg3 # auto: g\n    @p.opt :arg4 # auto: uh oh!\n    assert_raises(ArgumentError) { @p.parse [] }\n  end\n\n  def test_short_can_be_nothing\n    assert_nothing_raised do\n      @p.opt \"arg\", \"desc\", :short => :none\n      @p.parse []\n    end\n\n    sio = StringIO.new \"w\"\n    @p.educate sio\n    assert sio.string =~ /--arg:\\s+desc/\n\n    assert_raise(CommandlineError) { @p.parse %w(-a) }\n  end\n\n  ## two args can't have the same name\n  def test_conflicting_names_are_detected\n    assert_nothing_raised { @p.opt \"goodarg\" }\n    assert_raise(ArgumentError) { @p.opt \"goodarg\" }\n  end\n\n  ## two args can't have the same :long\n  def test_conflicting_longs_detected\n    assert_nothing_raised { @p.opt \"goodarg\", \"desc\", :long => \"--goodarg\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :long => \"--goodarg\" }\n  end  \n\n  ## two args can't have the same :short\n  def test_conflicting_shorts_detected\n    assert_nothing_raised { @p.opt \"goodarg\", \"desc\", :short => \"-g\" }\n    assert_raise(ArgumentError) { @p.opt \"badarg\", \"desc\", :short => \"-g\" }\n  end  \n\n  def test_flag_defaults\n    @p.opt \"defaultfalse\", \"desc\"\n    @p.opt \"defaulttrue\", \"desc\", :default => true\n    opts = @p.parse []\n    assert_equal false, opts[\"defaultfalse\"]\n    assert_equal true, opts[\"defaulttrue\"]\n\n    opts = @p.parse %w(--defaultfalse --defaulttrue)\n    assert_equal true, opts[\"defaultfalse\"]\n    assert_equal false, opts[\"defaulttrue\"]\n  end\n\n  def test_special_flags_work\n    @p.version \"asdf fdas\"\n    assert_raise(VersionNeeded) { @p.parse(%w(-v)) }\n    assert_raise(HelpNeeded) { @p.parse(%w(-h)) }\n  end\n\n  def test_short_options_combine\n    @p.opt :arg1, \"desc\", :short => \"a\"\n    @p.opt :arg2, \"desc\", :short => \"b\"\n    @p.opt :arg3, \"desc\", :short => \"c\", :type => :int\n\n    opts = nil\n    assert_nothing_raised { opts = @p.parse %w(-a -b) }\n    assert_equal true, opts[:arg1]\n    assert_equal true, opts[:arg2]\n    assert_equal nil, opts[:arg3]\n\n    assert_nothing_raised { opts = @p.parse %w(-ab) }\n    assert_equal true, opts[:arg1]\n    assert_equal true, opts[:arg2]\n    assert_equal nil, opts[:arg3]\n\n    assert_nothing_raised { opts = @p.parse %w(-ac 4 -b) }\n    assert_equal true, opts[:arg1]\n    assert_equal true, opts[:arg2]\n    assert_equal 4, opts[:arg3]\n\n    assert_raises(CommandlineError) { @p.parse %w(-cab 4) }\n    assert_raises(CommandlineError) { @p.parse %w(-cba 4) }\n  end\n\n  def test_version_only_appears_if_set\n    @p.opt \"arg\"\n    assert_raise(CommandlineError) { @p.parse %w(-v) }\n    @p.version \"trollop 1.2.3.4\"\n    assert_raise(VersionNeeded) { @p.parse %w(-v) }\n  end\n\n  def test_doubledash_ends_option_processing\n    @p.opt :arg1, \"desc\", :short => \"a\", :default => 0\n    @p.opt :arg2, \"desc\", :short => \"b\", :default => 0\n    opts = nil\n    assert_nothing_raised { opts = @p.parse %w(-- -a 3 -b 2) }\n    assert_equal opts[:arg1], 0\n    assert_equal opts[:arg2], 0\n    assert_equal %w(-a 3 -b 2), @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(-a 3 -- -b 2) }\n    assert_equal opts[:arg1], 3\n    assert_equal opts[:arg2], 0\n    assert_equal %w(-b 2), @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(-a 3 -b 2 --) }\n    assert_equal opts[:arg1], 3\n    assert_equal opts[:arg2], 2\n    assert_equal %w(), @p.leftovers\n  end\n\n  def test_wrap\n    assert_equal [\"\"], @p.wrap(\"\")\n    assert_equal [\"a\"], @p.wrap(\"a\")\n    assert_equal [\"one two\", \"three\"], @p.wrap(\"one two three\", :width => 8)\n    assert_equal [\"one two three\"], @p.wrap(\"one two three\", :width => 80)\n    assert_equal [\"one\", \"two\", \"three\"], @p.wrap(\"one two three\", :width => 3)\n    assert_equal [\"onetwothree\"], @p.wrap(\"onetwothree\", :width => 3)\n    assert_equal [\n      \"Test is an awesome program that does something very, very important.\",\n      \"\",\n      \"Usage:\",\n      \"  test [options] <filenames>+\",\n      \"where [options] are:\"], @p.wrap(<<EOM, :width => 100)\nTest is an awesome program that does something very, very important.\n\nUsage:\n  test [options] <filenames>+\nwhere [options] are:\nEOM\n  end\n\n  def test_floating_point_formatting\n    @p.opt :arg, \"desc\", :type => :float, :short => \"f\"\n    opts = nil\n    assert_nothing_raised { opts = @p.parse %w(-f 1) }\n    assert_equal 1.0, opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(-f 1.0) }\n    assert_equal 1.0, opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(-f 0.1) }\n    assert_equal 0.1, opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(-f .1) }\n    assert_equal 0.1, opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(-f .99999999999999999999) }\n    assert_equal 1.0, opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(-f -1) }\n    assert_equal(-1.0, opts[:arg])\n    assert_nothing_raised { opts = @p.parse %w(-f -1.0) }\n    assert_equal(-1.0, opts[:arg])\n    assert_nothing_raised { opts = @p.parse %w(-f -0.1) }\n    assert_equal(-0.1, opts[:arg])\n    assert_nothing_raised { opts = @p.parse %w(-f -.1) }\n    assert_equal(-0.1, opts[:arg])\n    assert_raises(CommandlineError) { @p.parse %w(-f a) }\n    assert_raises(CommandlineError) { @p.parse %w(-f 1a) }\n    assert_raises(CommandlineError) { @p.parse %w(-f 1.a) }\n    assert_raises(CommandlineError) { @p.parse %w(-f a.1) }\n    assert_raises(CommandlineError) { @p.parse %w(-f 1.0.0) }\n    assert_raises(CommandlineError) { @p.parse %w(-f .) }\n    assert_raises(CommandlineError) { @p.parse %w(-f -.) }\n  end\n\n  def test_date_formatting\n    @p.opt :arg, \"desc\", :type => :date, :short => 'd'\n    opts = nil\n    assert_nothing_raised { opts = @p.parse(['-d', 'Jan 4, 2007']) }\n    assert_equal Date.civil(2007, 1, 4), opts[:arg]\n    begin\n      require 'chronic'\n      assert_nothing_raised { opts = @p.parse(['-d', 'today']) }\n      assert_equal Date.today, opts[:arg]\n    rescue LoadError\n      # chronic is not available\n    end\n  end\n\n  def test_short_options_cant_be_numeric\n    assert_raises(ArgumentError) { @p.opt :arg, \"desc\", :short => \"-1\" }\n    @p.opt :a1b, \"desc\"\n    @p.opt :a2b, \"desc\"\n    assert_not_equal \"2\", @p.specs[:a2b][:short]\n  end\n\n  def test_short_options_can_be_weird\n    assert_nothing_raised { @p.opt :arg1, \"desc\", :short => \"#\" }\n    assert_nothing_raised { @p.opt :arg2, \"desc\", :short => \".\" }\n    assert_raises(ArgumentError) { @p.opt :arg3, \"desc\", :short => \"-\" }\n  end\n\n  def test_options_cant_be_set_multiple_times_if_not_specified\n    @p.opt :arg, \"desc\", :short => \"-x\"\n    assert_nothing_raised { @p.parse %w(-x) }\n    assert_raises(CommandlineError) { @p.parse %w(-x -x) }\n    assert_raises(CommandlineError) { @p.parse %w(-xx) }\n  end\n\n  def test_options_can_be_set_multiple_times_if_specified\n    assert_nothing_raised do\n      @p.opt :arg, \"desc\", :short => \"-x\", :multi => true\n    end\n    assert_nothing_raised { @p.parse %w(-x) }\n    assert_nothing_raised { @p.parse %w(-x -x) }\n    assert_nothing_raised { @p.parse %w(-xx) }\n  end\n\n  def test_short_options_with_multiple_options\n    opts = nil\n\n    assert_nothing_raised do\n       @p.opt :xarg, \"desc\", :short => \"-x\", :type => String, :multi => true\n    end\n    assert_nothing_raised { opts = @p.parse %w(-x a -x b) }\n    assert_equal %w(a b), opts[:xarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def short_options_with_multiple_options_does_not_affect_flags_type\n    opts = nil\n\n    assert_nothing_raised do\n      @p.opt :xarg, \"desc\", :short => \"-x\", :type => :flag, :multi => true\n    end\n\n    assert_nothing_raised { opts = @p.parse %w(-x a) }\n    assert_equal true, opts[:xarg]\n    assert_equal %w(a), @p.leftovers\n\n    assert_nothing_raised { opts = @p.parse %w(-x a -x b) }\n    assert_equal true, opts[:xarg]\n    assert_equal %w(a b), @p.leftovers\n\n    assert_nothing_raised { opts = @p.parse %w(-xx a -x b) }\n    assert_equal true, opts[:xarg]\n    assert_equal %w(a b), @p.leftovers\n  end\n\n  def test_short_options_with_multiple_arguments\n    opts = nil\n\n    @p.opt :xarg, \"desc\", :type => :ints\n    assert_nothing_raised { opts = @p.parse %w(-x 3 4 0) }\n    assert_equal [3, 4, 0], opts[:xarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :yarg, \"desc\", :type => :floats\n    assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 0.66) }\n    assert_equal [3.14, 4.21, 0.66], opts[:yarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :zarg, \"desc\", :type => :strings\n    assert_nothing_raised { opts = @p.parse %w(-z a b c) }\n    assert_equal %w(a b c), opts[:zarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def test_short_options_with_multiple_options_and_arguments\n    opts = nil\n\n    @p.opt :xarg, \"desc\", :type => :ints, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(-x 3 4 5 -x 6 7) }\n    assert_equal [[3, 4, 5], [6, 7]], opts[:xarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :yarg, \"desc\", :type => :floats, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 5.66 -y 6.99 7.01) }\n    assert_equal [[3.14, 4.21, 5.66], [6.99, 7.01]], opts[:yarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :zarg, \"desc\", :type => :strings, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(-z a b c -z d e) }\n    assert_equal [%w(a b c), %w(d e)], opts[:zarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def test_combined_short_options_with_multiple_arguments\n    @p.opt :arg1, \"desc\", :short => \"a\"\n    @p.opt :arg2, \"desc\", :short => \"b\"\n    @p.opt :arg3, \"desc\", :short => \"c\", :type => :ints\n    @p.opt :arg4, \"desc\", :short => \"d\", :type => :floats\n\n    opts = nil\n\n    assert_nothing_raised { opts = @p.parse %w(-abc 4 6 9) }\n    assert_equal true, opts[:arg1]\n    assert_equal true, opts[:arg2]\n    assert_equal [4, 6, 9], opts[:arg3]\n\n    assert_nothing_raised { opts = @p.parse %w(-ac 4 6 9 -bd 3.14 2.41) }\n    assert_equal true, opts[:arg1]\n    assert_equal true, opts[:arg2]\n    assert_equal [4, 6, 9], opts[:arg3]\n    assert_equal [3.14, 2.41], opts[:arg4]\n\n    assert_raises(CommandlineError) { opts = @p.parse %w(-abcd 3.14 2.41) }\n  end\n\n  def test_long_options_with_multiple_options\n    @p.opt :xarg, \"desc\", :type => String, :multi => true\n    opts = nil\n    assert_nothing_raised { opts = @p.parse %w(--xarg=a --xarg=b) }\n    assert_equal %w(a b), opts[:xarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--xarg a --xarg b) }\n    assert_equal %w(a b), opts[:xarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def test_long_options_with_multiple_arguments\n    opts = nil\n\n    @p.opt :xarg, \"desc\", :type => :ints\n    assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5) }\n    assert_equal [3, 2, 5], opts[:xarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--xarg=3) }\n    assert_equal [3], opts[:xarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :yarg, \"desc\", :type => :floats\n    assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.41 5.66) }\n    assert_equal [3.14, 2.41, 5.66], opts[:yarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--yarg=3.14) }\n    assert_equal [3.14], opts[:yarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :zarg, \"desc\", :type => :strings\n    assert_nothing_raised { opts = @p.parse %w(--zarg a b c) }\n    assert_equal %w(a b c), opts[:zarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--zarg=a) }\n    assert_equal %w(a), opts[:zarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def test_long_options_with_multiple_options_and_arguments\n    opts = nil\n\n    @p.opt :xarg, \"desc\", :type => :ints, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5 --xarg 2 1) }\n    assert_equal [[3, 2, 5], [2, 1]], opts[:xarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--xarg=3 --xarg=2) }\n    assert_equal [[3], [2]], opts[:xarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :yarg, \"desc\", :type => :floats, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.72 5 --yarg 2.41 1.41) }\n    assert_equal [[3.14, 2.72, 5], [2.41, 1.41]], opts[:yarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--yarg=3.14 --yarg=2.41) }\n    assert_equal [[3.14], [2.41]], opts[:yarg]\n    assert_equal [], @p.leftovers\n\n    @p.opt :zarg, \"desc\", :type => :strings, :multi => true\n    assert_nothing_raised { opts = @p.parse %w(--zarg a b c --zarg d e) }\n    assert_equal [%w(a b c), %w(d e)], opts[:zarg]\n    assert_equal [], @p.leftovers\n    assert_nothing_raised { opts = @p.parse %w(--zarg=a --zarg=d) }\n    assert_equal [%w(a), %w(d)], opts[:zarg]\n    assert_equal [], @p.leftovers\n  end\n\n  def test_long_options_also_take_equals\n    @p.opt :arg, \"desc\", :long => \"arg\", :type => String, :default => \"hello\"\n    opts = nil\n    assert_nothing_raised { opts = @p.parse %w() }\n    assert_equal \"hello\", opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(--arg goat) }\n    assert_equal \"goat\", opts[:arg]\n    assert_nothing_raised { opts = @p.parse %w(--arg=goat) }\n    assert_equal \"goat\", opts[:arg]\n    ## actually, this next one is valid. empty string for --arg, and goat as a\n    ## leftover.\n    ## assert_raises(CommandlineError) { opts = @p.parse %w(--arg= goat) }\n  end\n\n  def test_auto_generated_long_names_convert_underscores_to_hyphens\n    @p.opt :hello_there\n    assert_equal \"hello-there\", @p.specs[:hello_there][:long]\n  end\n\n  def test_arguments_passed_through_block\n    @goat = 3\n    boat = 4\n    Parser.new(@goat) do |goat|\n      boat = goat\n    end\n    assert_equal @goat, boat\n  end\n\n  def test_help_has_default_banner\n    @p = Parser.new\n    sio = StringIO.new \"w\"\n    @p.parse []\n    @p.educate sio\n    help = sio.string.split \"\\n\"\n    assert help[0] =~ /options/i\n    assert_equal 2, help.length # options, then -h\n\n    @p = Parser.new\n    @p.version \"my version\"\n    sio = StringIO.new \"w\"\n    @p.parse []\n    @p.educate sio\n    help = sio.string.split \"\\n\"\n    assert help[0] =~ /my version/i\n    assert_equal 4, help.length # version, options, -h, -v\n\n    @p = Parser.new\n    @p.banner \"my own banner\"\n    sio = StringIO.new \"w\"\n    @p.parse []\n    @p.educate sio\n    help = sio.string.split \"\\n\"\n    assert help[0] =~ /my own banner/i\n    assert_equal 2, help.length # banner, -h\n  end\n\n  def test_help_preserves_positions\n    @p.opt :zzz, \"zzz\"\n    @p.opt :aaa, \"aaa\"\n    sio = StringIO.new \"w\"\n    @p.educate sio\n\n    help = sio.string.split \"\\n\"\n    assert help[1] =~ /zzz/\n    assert help[2] =~ /aaa/\n  end\n\n  def test_version_and_help_short_args_can_be_overridden\n    @p.opt :verbose, \"desc\", :short => \"-v\"\n    @p.opt :hello, \"desc\", :short => \"-h\"\n    @p.version \"version\"\n\n    assert_nothing_raised { @p.parse(%w(-v)) }\n    assert_raises(VersionNeeded) { @p.parse(%w(--version)) }\n    assert_nothing_raised { @p.parse(%w(-h)) }\n    assert_raises(HelpNeeded) { @p.parse(%w(--help)) }\n  end\n\n  def test_version_and_help_long_args_can_be_overridden\n    @p.opt :asdf, \"desc\", :long => \"help\"\n    @p.opt :asdf2, \"desc2\", :long => \"version\"\n    assert_nothing_raised { @p.parse %w() }\n    assert_nothing_raised { @p.parse %w(--help) }\n    assert_nothing_raised { @p.parse %w(--version) }\n    assert_nothing_raised { @p.parse %w(-h) }\n    assert_nothing_raised { @p.parse %w(-v) }\n  end\n\n  def test_version_and_help_override_errors\n    @p.opt :asdf, \"desc\", :type => String\n    @p.version \"version\"\n    assert_nothing_raised { @p.parse %w(--asdf goat) }\n    assert_raises(CommandlineError) { @p.parse %w(--asdf) }\n    assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }\n    assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }\n  end\n\n  def test_conflicts\n    @p.opt :one\n    assert_raises(ArgumentError) { @p.conflicts :one, :two }\n    @p.opt :two\n    assert_nothing_raised { @p.conflicts :one, :two }\n    assert_nothing_raised { @p.parse %w(--one) }\n    assert_nothing_raised { @p.parse %w(--two) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--one --two) }\n\n    @p.opt :hello\n    @p.opt :yellow\n    @p.opt :mellow\n    @p.opt :jello\n    @p.conflicts :hello, :yellow, :mellow, :jello\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello --yellow --mellow --jello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }\n\n    assert_nothing_raised { opts = @p.parse %w(--hello) }\n    assert_nothing_raised { opts = @p.parse %w(--jello) }\n    assert_nothing_raised { opts = @p.parse %w(--yellow) }\n    assert_nothing_raised { opts = @p.parse %w(--mellow) }\n\n    assert_nothing_raised { opts = @p.parse %w(--mellow --one) }\n    assert_nothing_raised { opts = @p.parse %w(--mellow --two) }\n\n    assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--one --mellow --two --jello) }\n  end\n\n  def test_conflict_error_messages\n    @p.opt :one\n    @p.opt \"two\"\n    @p.conflicts :one, \"two\"\n\n    begin\n      @p.parse %w(--one --two)\n      flunk \"no error thrown\"\n    rescue CommandlineError => e\n      assert_match(/--one/, e.message)\n      assert_match(/--two/, e.message)\n    end\n  end\n\n  def test_depends\n    @p.opt :one\n    assert_raises(ArgumentError) { @p.depends :one, :two }\n    @p.opt :two\n    assert_nothing_raised { @p.depends :one, :two }\n    assert_nothing_raised { opts = @p.parse %w(--one --two) }\n    assert_raises(CommandlineError) { @p.parse %w(--one) }\n    assert_raises(CommandlineError) { @p.parse %w(--two) }\n\n    @p.opt :hello\n    @p.opt :yellow\n    @p.opt :mellow\n    @p.opt :jello\n    @p.depends :hello, :yellow, :mellow, :jello\n    assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }\n\n    assert_raises(CommandlineError) { opts = @p.parse %w(--hello) }\n    assert_raises(CommandlineError) { opts = @p.parse %w(--mellow) }\n\n    assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two) }\n    assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two a b c) }\n\n    assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello --one) }\n  end\n\n  def test_depend_error_messages\n    @p.opt :one\n    @p.opt \"two\"\n    @p.depends :one, \"two\"\n\n    assert_nothing_raised { @p.parse %w(--one --two) }\n\n    begin\n      @p.parse %w(--one)\n      flunk \"no error thrown\"\n    rescue CommandlineError => e\n      assert_match(/--one/, e.message)\n      assert_match(/--two/, e.message)\n    end\n\n    begin\n      @p.parse %w(--two)\n      flunk \"no error thrown\"\n    rescue CommandlineError => e\n      assert_match(/--one/, e.message)\n      assert_match(/--two/, e.message)\n    end\n  end\n\n  ## courtesy neill zero\n  def test_two_required_one_missing_accuses_correctly\n    @p.opt \"arg1\", \"desc1\", :required => true\n    @p.opt \"arg2\", \"desc2\", :required => true\n\n    begin\n      @p.parse(%w(--arg1))\n      flunk \"should have failed on a missing req\"\n    rescue CommandlineError => e\n      assert e.message =~ /arg2/, \"didn't mention arg2 in the error msg: #{e.message}\"\n    end\n\n    begin\n      @p.parse(%w(--arg2))\n      flunk \"should have failed on a missing req\"\n    rescue CommandlineError => e\n      assert e.message =~ /arg1/, \"didn't mention arg1 in the error msg: #{e.message}\"\n    end\n\n    assert_nothing_raised { @p.parse(%w(--arg1 --arg2)) }\n  end\n\n  def test_stopwords_mixed\n    @p.opt \"arg1\", :default => false\n    @p.opt \"arg2\", :default => false\n    @p.stop_on %w(happy sad)\n\n    opts = @p.parse %w(--arg1 happy --arg2)\n    assert_equal true, opts[\"arg1\"]\n    assert_equal false, opts[\"arg2\"]\n\n    ## restart parsing\n    @p.leftovers.shift\n    opts = @p.parse @p.leftovers\n    assert_equal false, opts[\"arg1\"]\n    assert_equal true, opts[\"arg2\"]\n  end\n\n  def test_stopwords_no_stopwords\n    @p.opt \"arg1\", :default => false\n    @p.opt \"arg2\", :default => false\n    @p.stop_on %w(happy sad)\n\n    opts = @p.parse %w(--arg1 --arg2)\n    assert_equal true, opts[\"arg1\"]\n    assert_equal true, opts[\"arg2\"]\n\n    ## restart parsing\n    @p.leftovers.shift\n    opts = @p.parse @p.leftovers\n    assert_equal false, opts[\"arg1\"]\n    assert_equal false, opts[\"arg2\"]\n  end\n\n  def test_stopwords_multiple_stopwords\n    @p.opt \"arg1\", :default => false\n    @p.opt \"arg2\", :default => false\n    @p.stop_on %w(happy sad)\n\n    opts = @p.parse %w(happy sad --arg1 --arg2)\n    assert_equal false, opts[\"arg1\"]\n    assert_equal false, opts[\"arg2\"]\n\n    ## restart parsing\n    @p.leftovers.shift\n    opts = @p.parse @p.leftovers\n    assert_equal false, opts[\"arg1\"]\n    assert_equal false, opts[\"arg2\"]\n\n    ## restart parsing again\n    @p.leftovers.shift\n    opts = @p.parse @p.leftovers\n    assert_equal true, opts[\"arg1\"]\n    assert_equal true, opts[\"arg2\"]\n  end\n\n  def test_stopwords_with_short_args\n    @p.opt :global_option, \"This is a global option\", :short => \"-g\"\n    @p.stop_on %w(sub-command-1 sub-command-2)\n\n    global_opts = @p.parse %w(-g sub-command-1 -c)\n    cmd = @p.leftovers.shift\n\n    @q = Parser.new\n    @q.opt :cmd_option, \"This is an option only for the subcommand\", :short => \"-c\"\n    cmd_opts = @q.parse @p.leftovers\n\n    assert_equal true, global_opts[:global_option]\n    assert_nil global_opts[:cmd_option]\n\n    assert_equal true, cmd_opts[:cmd_option]\n    assert_nil cmd_opts[:global_option]\n\n    assert_equal cmd, \"sub-command-1\"\n    assert_equal @q.leftovers, []\n  end\n\n  def assert_parses_correctly(parser, commandline, expected_opts,\n                              expected_leftovers)\n    opts = parser.parse commandline\n    assert_equal expected_opts, opts\n    assert_equal expected_leftovers, parser.leftovers\n  end\n\n  def test_unknown_subcommand\n    @p.opt :global_flag, \"Global flag\", :short => \"-g\", :type => :flag\n    @p.opt :global_param, \"Global parameter\", :short => \"-p\", :default => 5\n    @p.stop_on_unknown\n\n    expected_opts = { :global_flag => true, :help => false, :global_param => 5, :global_flag_given => true }\n    expected_leftovers = [ \"my_subcommand\", \"-c\" ]\n\n    assert_parses_correctly @p, %w(--global-flag my_subcommand -c), \\\n      expected_opts, expected_leftovers\n    assert_parses_correctly @p, %w(-g my_subcommand -c), \\\n      expected_opts, expected_leftovers\n\n    expected_opts = { :global_flag => false, :help => false, :global_param => 5, :global_param_given => true }\n    expected_leftovers = [ \"my_subcommand\", \"-c\" ]\n\n    assert_parses_correctly @p, %w(-p 5 my_subcommand -c), \\\n      expected_opts, expected_leftovers\n    assert_parses_correctly @p, %w(--global-param 5 my_subcommand -c), \\\n      expected_opts, expected_leftovers\n  end\n\n  def test_alternate_args\n    args = %w(-a -b -c)\n\n    opts = ::Trollop.options(args) do\n      opt :alpher, \"Ralph Alpher\", :short => \"-a\"\n      opt :bethe, \"Hans Bethe\", :short => \"-b\"\n      opt :gamow, \"George Gamow\", :short => \"-c\"\n    end\n\n    physicists_with_humor = [:alpher, :bethe, :gamow]\n    physicists_with_humor.each do |physicist|\n      assert_equal true, opts[physicist]\n    end\n  end\n\n  def test_io_arg_type\n    @p.opt :arg, \"desc\", :type => :io\n    @p.opt :arg2, \"desc\", :type => IO\n    @p.opt :arg3, \"desc\", :default => $stdout\n\n    opts = nil\n    assert_nothing_raised { opts = @p.parse() }\n    assert_equal $stdout, opts[:arg3]\n\n    assert_nothing_raised { opts = @p.parse %w(--arg /dev/null) }\n    assert_kind_of File, opts[:arg]\n    assert_equal \"/dev/null\", opts[:arg].path\n\n    #TODO: move to mocks\n    #assert_nothing_raised { opts = @p.parse %w(--arg2 http://google.com/) }\n    #assert_kind_of StringIO, opts[:arg2]\n\n    assert_nothing_raised { opts = @p.parse %w(--arg3 stdin) }\n    assert_equal $stdin, opts[:arg3]\n\n    assert_raises(CommandlineError) { opts = @p.parse %w(--arg /fdasfasef/fessafef/asdfasdfa/fesasf) }\n  end\n\n  def test_openstruct_style_access\n    @p.opt \"arg1\", \"desc\", :type => :int\n    @p.opt :arg2, \"desc\", :type => :int\n\n    opts = @p.parse(%w(--arg1 3 --arg2 4))\n\n    assert_nothing_raised { opts.arg1 }\n    assert_nothing_raised { opts.arg2 }\n    assert_equal 3, opts.arg1\n    assert_equal 4, opts.arg2\n  end\n\n  def test_multi_args_autobox_defaults\n    @p.opt :arg1, \"desc\", :default => \"hello\", :multi => true\n    @p.opt :arg2, \"desc\", :default => [\"hello\"], :multi => true\n\n    opts = @p.parse\n    assert_equal [\"hello\"], opts[:arg1]\n    assert_equal [\"hello\"], opts[:arg2]\n\n    opts = @p.parse %w(--arg1 hello)\n    assert_equal [\"hello\"], opts[:arg1]\n    assert_equal [\"hello\"], opts[:arg2]\n\n    opts = @p.parse %w(--arg1 hello --arg1 there)\n    assert_equal [\"hello\", \"there\"], opts[:arg1]\n  end\n\n  def test_ambigious_multi_plus_array_default_resolved_as_specified_by_documentation\n    @p.opt :arg1, \"desc\", :default => [\"potato\"], :multi => true\n    @p.opt :arg2, \"desc\", :default => [\"potato\"], :multi => true, :type => :strings\n    @p.opt :arg3, \"desc\", :default => [\"potato\"]\n    @p.opt :arg4, \"desc\", :default => [\"potato\", \"rhubarb\"], :short => :none, :multi => true\n\n    ## arg1 should be multi-occurring but not multi-valued\n    opts = @p.parse %w(--arg1 one two)\n    assert_equal [\"one\"], opts[:arg1]\n    assert_equal [\"two\"], @p.leftovers\n\n    opts = @p.parse %w(--arg1 one --arg1 two)\n    assert_equal [\"one\", \"two\"], opts[:arg1]\n    assert_equal [], @p.leftovers\n\n    ## arg2 should be multi-valued and multi-occurring\n    opts = @p.parse %w(--arg2 one two)\n    assert_equal [[\"one\", \"two\"]], opts[:arg2]\n    assert_equal [], @p.leftovers\n\n    ## arg3 should be multi-valued but not multi-occurring\n    opts = @p.parse %w(--arg3 one two)\n    assert_equal [\"one\", \"two\"], opts[:arg3]\n    assert_equal [], @p.leftovers\n\n    ## arg4 should be multi-valued but not multi-occurring\n    opts = @p.parse %w()\n    assert_equal [\"potato\", \"rhubarb\"], opts[:arg4]\n  end\n\n  def test_given_keys\n    @p.opt :arg1\n    @p.opt :arg2\n\n    opts = @p.parse %w(--arg1)\n    assert opts[:arg1_given]\n    assert !opts[:arg2_given]\n\n    opts = @p.parse %w(--arg2)\n    assert !opts[:arg1_given]\n    assert opts[:arg2_given]\n\n    opts = @p.parse []\n    assert !opts[:arg1_given]\n    assert !opts[:arg2_given]\n\n    opts = @p.parse %w(--arg1 --arg2)\n    assert opts[:arg1_given]\n    assert opts[:arg2_given]\n  end\n\n  def test_default_shorts_assigned_only_after_user_shorts\n    @p.opt :aab, \"aaa\" # should be assigned to -b\n    @p.opt :ccd, \"bbb\" # should be assigned to -d\n    @p.opt :user1, \"user1\", :short => 'a'\n    @p.opt :user2, \"user2\", :short => 'c'\n\n    opts = @p.parse %w(-a -b)\n    assert opts[:user1]\n    assert !opts[:user2]\n    assert opts[:aab]\n    assert !opts[:ccd]\n\n    opts = @p.parse %w(-c -d)\n    assert !opts[:user1]\n    assert opts[:user2]\n    assert !opts[:aab]\n    assert opts[:ccd]\n  end\n\n  def test_accepts_arguments_with_spaces\n    @p.opt :arg1, \"arg\", :type => String\n    @p.opt :arg2, \"arg2\", :type => String\n\n    opts = @p.parse [\"--arg1\", \"hello there\", \"--arg2=hello there\"]\n    assert_equal \"hello there\", opts[:arg1]\n    assert_equal \"hello there\", opts[:arg2]\n    assert_equal 0, @p.leftovers.size\n  end\n\n  def test_multi_args_default_to_empty_array\n    @p.opt :arg1, \"arg\", :multi => true\n    opts = @p.parse \"\"\n    assert_equal [], opts[:arg1]\n  end\nend\n\nend\nend\n"
  },
  {
    "path": "vendor/gems/trollop/www/index.html",
    "content": "<html>\n<head>\n<title>Trollop</title>\n<style type=\"text/css\">\n.ruby { background: #111122; padding: 10px; color: #228822; width: 70em; }\n.ruby .normal { color: #fff; }\n.ruby .comment { color: #99f }\n.ruby .keyword { color: #A44; font-weight: bold; }\n.ruby .method { color: #44f; }\n.ruby .class { color: #0c4; }\n.ruby .module { color: #050; }\n.ruby .punct { color: #FF0; font-weight: bold; }\n.ruby .symbol { color: #ff0; }\n.ruby .string { color: #4f4 }\n.ruby .char { color: #F07; }\n.ruby .ident { color: #fff; }\n.ruby .constant { color: #0c4; }\n.ruby .regex { color: #B66; background: #444; }\n.ruby .number { color: #F99; }\n.ruby .attribute { color: #fc4; }\n.ruby .global { color: #7FB; }\n.ruby .expr { color: #827; }\n.ruby .escape { color: #277; }\n</style>\n</head>\n\n<body>\n\n<h1>Trollop</h1>\n\n<p style=\"border: solid 1px black; background: #ccc; padding: 0.5em;\">\nCurrent project news: see the <a href=\"http://all-thing.net/label/trollop\">blog</a>.\n</p>\n\n<p>Trollop is a commandline option parser for Ruby that <i>gets out of your\nway</i>. One line of code per option is all you need to write. For that, you get\na nice automatically-generated help page (fit to your screen size!), robust\noption parsing, command subcompletion, and sensible defaults for everything you\ndon't specify.</p>\n\n<p> Reasons to use Trollop:\n<ol>\n<li> It requires <i>fewer lines of code</i> than any other option out there. </li>\n<li> It doesn't require you to subclass some shit just to use a damn option parser.</li>\n</li>\n<li> It's a single file. You don't even need to make it a dependency. Just throw it in <code>lib/</code>.</li>\n<li> This gradient-free webpage. Fight the candy! </li>\n</ol>\n</p>\n\n<p> To install, you have three options:\n<ul>\n<li>Trollop is a single file with no dependencies. You can <a href=\"http://gitorious.org/trollop/mainline/blobs/raw/master/lib/trollop.rb\">just download it</a> and throw it in your code directory.</li>\n<li>You can use rubygems and command your computer to <code>gem install trollop</gem>.</li>\n<li>You can download the tarball (why?) from the <a href=\"http://rubyforge.org/projects/trollop/\">Trollop Rubyforge page</a>.</p>\n</ul>\n\n<p> To hack, command your computer to <code>git clone git://gitorious.org/trollop/mainline.git</code>, or see the <a href=\"http://gitorious.org/projects/trollop\">Trollop Gitorious page</a>.</p>\n\n<p>To understand, read the examples below, the <a href=\"FAQ.txt\">FAQ</a>, and the <a href=\"trollop/\">API docs</a>.\n\n<h2>Examples</h2>\n<h3>Simple</h3>\n<pre class=\"ruby\"><span class=\"ident\">require</span> <span class=\"punct\">'</span><span class=\"string\">trollop</span><span class=\"punct\">'</span>\n<span class=\"ident\">opts</span> <span class=\"punct\">=</span> <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">options</span> <span class=\"keyword\">do</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:monkey</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Use monkey mode</span><span class=\"punct\">&quot;</span>                     <span class=\"comment\"># a flag --monkey, defaulting to false</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:goat</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Use goat mode</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:default</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">true</span>       <span class=\"comment\"># a flag --goat, defaulting to true</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:num_limbs</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Number of limbs</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:default</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">4</span>   <span class=\"comment\"># an integer --num-limbs &lt;i&gt;, defaulting to 4</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:num_thumbs</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Number of thumbs</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:type</span> <span class=\"punct\">=&gt;</span> <span class=\"symbol\">:int</span> <span class=\"comment\"># an integer --num-thumbs &lt;i&gt;, defaulting to nil</span>\n<span class=\"keyword\">end</span>\n\n<span class=\"ident\">p</span> <span class=\"ident\">opts</span> <span class=\"comment\"># a hash: { :monkey =&gt; false, :goat =&gt; true, :num_limbs =&gt; 4, :num_thumbs =&gt; nil }</span>\n</pre>\n\n<p>\n<ul>\n<li><tt>Trollop::options</tt> returns a hash of values. That's all the output you get.</li>\n<li>Underscores are converted to dashes. <tt>opt :hello_there</tt> corresponds to an option <tt>--hello-there</tt>.\n<li>All options are taken to be boolean flags, defaulting to false, unless you specify a default or a type. The type will be inferred from the default if given, so no need to specify both.</li>\n<li>Short (one-character) option names are created automatically. You can set them manually with <tt>:short</tt>.\n</ul>\n</p>\n\n<h3>Medium</h3>\n<pre class=\"ruby\">\n<span class=\"ident\">require</span> <span class=\"punct\">'</span><span class=\"string\">trollop</span><span class=\"punct\">'</span>\n<span class=\"ident\">opts</span> <span class=\"punct\">=</span> <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">options</span> <span class=\"keyword\">do</span>\n  <span class=\"ident\">version</span> <span class=\"punct\">&quot;</span><span class=\"string\">test 1.2.3 (c) 2008 William Morgan</span><span class=\"punct\">&quot;</span>\n  <span class=\"ident\">banner</span> <span class=\"punct\">&lt;&lt;-</span><span class=\"constant\">EOS</span><span class=\"string\">\nTest is an awesome program that does something very, very important.\n\nUsage:\n       test [options] &lt;filenames&gt;+\nwhere [options] are:\n</span><span class=\"constant\">EOS</span>\n\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:ignore</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Ignore incorrect values</span><span class=\"punct\">&quot;</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:file</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Extra data filename to read in, with a very long option description like this one</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:type</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">String</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:volume</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Volume level</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:default</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">3.0</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:iters</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Number of iterations</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:default</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">5</span>\n<span class=\"keyword\">end</span>\n<span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">die</span> <span class=\"symbol\">:volume</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">must be non-negative</span><span class=\"punct\">&quot;</span> <span class=\"keyword\">if</span> <span class=\"ident\">opts</span><span class=\"punct\">[</span><span class=\"symbol\">:volume</span><span class=\"punct\">]</span> <span class=\"punct\">&lt;</span> <span class=\"number\">0</span>\n<span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">die</span> <span class=\"symbol\">:file</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">must exist</span><span class=\"punct\">&quot;</span> <span class=\"keyword\">unless</span> <span class=\"constant\">File</span><span class=\"punct\">.</span><span class=\"ident\">exist?</span><span class=\"punct\">(</span><span class=\"ident\">opts</span><span class=\"punct\">[</span><span class=\"symbol\">:file</span><span class=\"punct\">])</span> <span class=\"keyword\">if</span> <span class=\"ident\">opts</span><span class=\"punct\">[</span><span class=\"symbol\">:file</span><span class=\"punct\">]</span>\n</pre>\n\n<p>\n<ul>\n<li>You can specify a version and some banner text for the help message. <tt>--help</tt> and <tt>--version</tt> are defined for you.</li>\n<li>Any special error-checking is done by you, on the option hash. You can call <tt>Trollop::die</tt> to die with a nice message.</li>\n</ul>\n</p>\n\n<h3>Sub-commands, a la SVN and Git</h3>\n<pre class=\"ruby\"><span class=\"ident\">require</span> <span class=\"punct\">'</span><span class=\"string\">trollop</span><span class=\"punct\">'</span>\n\n<span class=\"comment\">## Here's a program called &quot;magic&quot;. We want this behavior:</span>\n<span class=\"comment\">##</span>\n<span class=\"comment\">##   magic delete &lt;fn&gt; =&gt; deletes a file</span>\n<span class=\"comment\">##   magic copy &lt;fn&gt;   =&gt; copies a file</span>\n<span class=\"comment\">##</span>\n<span class=\"comment\">## So 'delete' and 'copy' are subcommands.</span>\n<span class=\"comment\">##</span>\n<span class=\"comment\">## There are some global options, which appear to the left of the subcommand.</span>\n<span class=\"comment\">## There are some subcommand options, which appear to the right.</span>\n<span class=\"comment\">##</span>\n<span class=\"comment\">## Subcommand options can be specific to the subcommand. 'delete' might take</span>\n<span class=\"comment\">## different options from 'copy'.</span>\n<span class=\"comment\">##</span>\n<span class=\"comment\">## We do this by calling Trollop twice; one for the global options and once for</span>\n<span class=\"comment\">## the subcommand options. We need to tell Trollop what the subcommands are, so</span>\n<span class=\"comment\">## that it stops processing the global options when it encounters one of them.</span>\n\n<span class=\"constant\">SUB_COMMANDS</span> <span class=\"punct\">=</span> <span class=\"punct\">%w(</span><span class=\"string\">delete copy</span><span class=\"punct\">)</span>\n<span class=\"ident\">global_opts</span> <span class=\"punct\">=</span> <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">options</span> <span class=\"keyword\">do</span>\n  <span class=\"ident\">banner</span> <span class=\"punct\">&quot;</span><span class=\"string\">magic file deleting and copying utility</span><span class=\"punct\">&quot;</span>\n  <span class=\"ident\">opt</span> <span class=\"symbol\">:dry_run</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Don't actually do anything</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:short</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">-n</span><span class=\"punct\">&quot;</span>\n  <span class=\"ident\">stop_on</span> <span class=\"constant\">SUB_COMMANDS</span>\n<span class=\"keyword\">end</span>\n\n<span class=\"ident\">cmd</span> <span class=\"punct\">=</span> <span class=\"constant\">ARGV</span><span class=\"punct\">.</span><span class=\"ident\">shift</span> <span class=\"comment\"># get the subcommand</span>\n<span class=\"ident\">cmd_opts</span> <span class=\"punct\">=</span> <span class=\"keyword\">case</span> <span class=\"ident\">cmd</span>\n  <span class=\"keyword\">when</span> <span class=\"punct\">&quot;</span><span class=\"string\">delete</span><span class=\"punct\">&quot;</span> <span class=\"comment\"># parse delete options</span>\n    <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">options</span> <span class=\"keyword\">do</span>\n      <span class=\"ident\">opt</span> <span class=\"symbol\">:force</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Force deletion</span><span class=\"punct\">&quot;</span>\n    <span class=\"keyword\">end</span>\n  <span class=\"keyword\">when</span> <span class=\"punct\">&quot;</span><span class=\"string\">copy</span><span class=\"punct\">&quot;</span>  <span class=\"comment\"># parse copy options</span>\n    <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">options</span> <span class=\"keyword\">do</span>\n      <span class=\"ident\">opt</span> <span class=\"symbol\">:double</span><span class=\"punct\">,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Copy twice for safety's sake</span><span class=\"punct\">&quot;</span>\n    <span class=\"keyword\">end</span>\n  <span class=\"keyword\">else</span>\n    <span class=\"constant\">Trollop</span><span class=\"punct\">::</span><span class=\"ident\">die</span> <span class=\"punct\">&quot;</span><span class=\"string\">unknown subcommand <span class=\"expr\">#{cmd.inspect}</span></span><span class=\"punct\">&quot;</span>\n  <span class=\"keyword\">end</span>\n\n<span class=\"ident\">puts</span> <span class=\"punct\">&quot;</span><span class=\"string\">Global options: <span class=\"expr\">#{global_opts.inspect}</span></span><span class=\"punct\">&quot;</span>\n<span class=\"ident\">puts</span> <span class=\"punct\">&quot;</span><span class=\"string\">Subcommand: <span class=\"expr\">#{cmd.inspect}</span></span><span class=\"punct\">&quot;</span>\n<span class=\"ident\">puts</span> <span class=\"punct\">&quot;</span><span class=\"string\">Subcommand options: <span class=\"expr\">#{cmd_opts.inspect}</span></span><span class=\"punct\">&quot;</span>\n<span class=\"ident\">puts</span> <span class=\"punct\">&quot;</span><span class=\"string\">Remaining arguments: <span class=\"expr\">#{ARGV.inspect}</span></span><span class=\"punct\">&quot;</span>\n\n</pre>\n\n<h2> Contributors </h2>\n\n<p>Trollop is brought to you by <a href=\"http://cs.stanford.edu/~ruby/\">William Morgan</a> and by:\n<ul>\n<li>Tuomas Kareinen &lt;tkareine at the gmail dot coms&gt;</li>\n<li>Ohad Lutzky &lt;ohad at the lutzky dot nets&gt;</li>\n<li>Erik Ostrom &lt;erik at the echographia dot coms&gt;</li>\n</ul>\n</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/gems/xml-simple/lib/xmlsimple.rb",
    "content": "# = XmlSimple\n#\n# Author::    Maik Schmidt <contact@maik-schmidt.de>\n# Copyright:: Copyright (c) 2003-2009 Maik Schmidt\n# License::   Distributes under the same terms as Ruby.\n#\nrequire 'rexml/document'\nrequire 'stringio'\n\n# Easy API to maintain XML (especially configuration files).\nclass XmlSimple\n  include REXML\n\n  @@VERSION = '1.0.12'\n\n  # A simple cache for XML documents that were already transformed\n  # by xml_in.\n  class Cache\n    # Creates and initializes a new Cache object.\n    def initialize\n      @mem_share_cache = {}\n      @mem_copy_cache  = {}\n    end\n\n    # Saves a data structure into a file.\n    # \n    # data::\n    #   Data structure to be saved.\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def save_storable(data, filename)\n      cache_file = get_cache_filename(filename)\n      File.open(cache_file, \"w+\") { |f| Marshal.dump(data, f) }\n    end\n\n    # Restores a data structure from a file. If restoring the data\n    # structure failed for any reason, nil will be returned.\n    #\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def restore_storable(filename)\n      cache_file = get_cache_filename(filename)\n      return nil unless File::exist?(cache_file)\n      return nil unless File::mtime(cache_file).to_i > File::mtime(filename).to_i\n      data = nil\n      File.open(cache_file) { |f| data = Marshal.load(f) }\n      data\n    end\n\n    # Saves a data structure in a shared memory cache.\n    #\n    # data::\n    #   Data structure to be saved.\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def save_mem_share(data, filename)\n      @mem_share_cache[filename] = [Time::now.to_i, data]\n    end\n\n    # Restores a data structure from a shared memory cache. You\n    # should consider these elements as \"read only\". If restoring\n    # the data structure failed for any reason, nil will be\n    # returned.\n    #\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def restore_mem_share(filename)\n      get_from_memory_cache(filename, @mem_share_cache)\n    end\n\n    # Copies a data structure to a memory cache.\n    #\n    # data::\n    #   Data structure to be copied.\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def save_mem_copy(data, filename)\n      @mem_share_cache[filename] = [Time::now.to_i, Marshal.dump(data)]\n    end\n\n    # Restores a data structure from a memory cache. If restoring\n    # the data structure failed for any reason, nil will be\n    # returned.\n    #\n    # filename::\n    #   Name of the file belonging to the data structure.\n    def restore_mem_copy(filename)\n      data = get_from_memory_cache(filename, @mem_share_cache)\n      data = Marshal.load(data) unless data.nil?\n      data\n    end\n\n    private\n\n    # Returns the \"cache filename\" belonging to a filename, i.e.\n    # the extension '.xml' in the original filename will be replaced\n    # by '.stor'. If filename does not have this extension, '.stor'\n    # will be appended.\n    #\n    # filename::\n    #   Filename to get \"cache filename\" for.\n    def get_cache_filename(filename)\n      filename.sub(/(\\.xml)?$/, '.stor')\n    end\n\n    # Returns a cache entry from a memory cache belonging to a\n    # certain filename. If no entry could be found for any reason,\n    # nil will be returned.\n    #\n    # filename::\n    #   Name of the file the cache entry belongs to.\n    # cache::\n    #   Memory cache to get entry from.\n    def get_from_memory_cache(filename, cache)\n      return nil unless cache[filename]\n      return nil unless cache[filename][0] > File::mtime(filename).to_i\n      return cache[filename][1]\n    end\n  end\n\n  # Create a \"global\" cache.\n  @@cache = Cache.new\n\n  # Creates and intializes a new XmlSimple object.\n  # \n  # defaults::\n  #   Default values for options.\n  def initialize(defaults = nil)\n    unless defaults.nil? || defaults.instance_of?(Hash)\n      raise ArgumentError, \"Options have to be a Hash.\"\n    end\n    @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq)\n    @options = Hash.new\n    @_var_values = nil\n  end\n\n  # Converts an XML document in the same way as the Perl module XML::Simple.\n  #\n  # string::\n  #   XML source. Could be one of the following:\n  #\n  #   - nil: Tries to load and parse '<scriptname>.xml'.\n  #   - filename: Tries to load and parse filename.\n  #   - IO object: Reads from object until EOF is detected and parses result.\n  #   - XML string: Parses string.\n  #   \n  # options::\n  #   Options to be used.\n  def xml_in(string = nil, options = nil)\n    handle_options('in', options)\n\n    # If no XML string or filename was supplied look for scriptname.xml.\n    if string.nil?\n      string = File::basename($0).dup\n      string.sub!(/\\.[^.]+$/, '')\n      string += '.xml'\n\n      directory = File::dirname($0)\n      @options['searchpath'].unshift(directory) unless directory.nil?\n    end\n\n    if string.instance_of?(String)\n      if string =~ /<.*?>/m\n        @doc = parse(string)\n      elsif string == '-'\n        @doc = parse($stdin.read)\n      else\n        filename = find_xml_file(string, @options['searchpath'])\n\n        if @options.has_key?('cache')\n          @options['cache'].each { |scheme|\n            case(scheme)\n            when 'storable'\n              content = @@cache.restore_storable(filename)\n            when 'mem_share'\n              content = @@cache.restore_mem_share(filename)\n            when 'mem_copy'\n              content = @@cache.restore_mem_copy(filename)\n            else\n              raise ArgumentError, \"Unsupported caching scheme: <#{scheme}>.\"\n            end\n            return content if content\n          }\n        end\n        \n        @doc = load_xml_file(filename)\n      end\n    elsif string.kind_of?(IO) || string.kind_of?(StringIO) || string.kind_of?(Zlib::GzipReader)\n      @doc = parse(string.read)\n    else\n      raise ArgumentError, \"Could not parse object of type: <#{string.type}>.\"\n    end\n\n    result = collapse(@doc.root)\n    result = @options['keeproot'] ? merge({}, @doc.root.name, result) : result\n    put_into_cache(result, filename)\n    result\n  end\n\n  # This is the functional version of the instance method xml_in.\n  def XmlSimple.xml_in(string = nil, options = nil)\n    xml_simple = XmlSimple.new\n    xml_simple.xml_in(string, options)\n  end\n  \n  # Converts a data structure into an XML document.\n  #\n  # ref::\n  #   Reference to data structure to be converted into XML.\n  # options::\n  #   Options to be used.\n  def xml_out(ref, options = nil)\n    handle_options('out', options)\n    if ref.instance_of?(Array)\n      ref = { @options['anonymoustag'] => ref }\n    end\n\n    if @options['keeproot']\n      keys = ref.keys\n      if keys.size == 1\n        ref = ref[keys[0]]\n        @options['rootname'] = keys[0]\n      end\n    elsif @options['rootname'] == ''\n      if ref.instance_of?(Hash)\n        refsave = ref\n        ref = {}\n        refsave.each { |key, value|\n          if !scalar(value)\n            ref[key] = value\n          else\n            ref[key] = [ value.to_s ]\n          end\n        }\n      end\n    end\n\n    @ancestors = []\n    xml = value_to_xml(ref, @options['rootname'], '')\n    @ancestors = nil\n\n    if @options['xmldeclaration']\n      xml = @options['xmldeclaration'] + \"\\n\" + xml\n    end\n\n    if @options.has_key?('outputfile')\n      if @options['outputfile'].kind_of?(IO)\n        return @options['outputfile'].write(xml)\n      else\n        File.open(@options['outputfile'], \"w\") { |file| file.write(xml) }\n      end\n    end\n    xml\n  end\n\n  # This is the functional version of the instance method xml_out.\n  def XmlSimple.xml_out(hash, options = nil)\n    xml_simple = XmlSimple.new\n    xml_simple.xml_out(hash, options)\n  end\n  \n  private\n\n  # Declare options that are valid for xml_in and xml_out.\n  KNOWN_OPTIONS = {\n    'in'  => %w(\n      keyattr keeproot forcecontent contentkey noattr\n      searchpath forcearray suppressempty anonymoustag\n      cache grouptags normalisespace normalizespace\n      variables varattr keytosymbol attrprefix\n    ),\n    'out' => %w(\n      keyattr keeproot contentkey noattr rootname\n      xmldeclaration outputfile noescape suppressempty\n      anonymoustag indent grouptags noindent attrprefix\n    )\n  }\n\n  # Define some reasonable defaults.\n  DEF_KEY_ATTRIBUTES  = []\n  DEF_ROOT_NAME       = 'opt'\n  DEF_CONTENT_KEY     = 'content'\n  DEF_XML_DECLARATION = \"<?xml version='1.0' standalone='yes'?>\"\n  DEF_ANONYMOUS_TAG   = 'anon'\n  DEF_FORCE_ARRAY     = true\n  DEF_INDENTATION     = '  '\n  DEF_KEY_TO_SYMBOL   = false\n  \n  # Normalizes option names in a hash, i.e., turns all\n  # characters to lower case and removes all underscores.\n  # Additionally, this method checks, if an unknown option\n  # was used and raises an according exception.\n  #\n  # options::\n  #   Hash to be normalized.\n  # known_options::\n  #   List of known options.\n  def normalize_option_names(options, known_options)\n    return nil if options.nil?\n    result = Hash.new\n    options.each { |key, value|\n      lkey = key.downcase\n      lkey.gsub!(/_/, '')\n      if !known_options.member?(lkey)\n        raise ArgumentError, \"Unrecognised option: #{lkey}.\"\n      end\n      result[lkey] = value\n    }\n    result\n  end\n  \n  # Merges a set of options with the default options.\n  # \n  # direction::\n  #  'in':  If options should be handled for xml_in.\n  #  'out': If options should be handled for xml_out.\n  # options::\n  #   Options to be merged with the default options.\n  def handle_options(direction, options)\n    @options = options || Hash.new\n\n    raise ArgumentError, \"Options must be a Hash!\" unless @options.instance_of?(Hash)\n\n    unless KNOWN_OPTIONS.has_key?(direction)\n      raise ArgumentError, \"Unknown direction: <#{direction}>.\"\n    end\n\n    known_options = KNOWN_OPTIONS[direction]\n    @options = normalize_option_names(@options, known_options)\n\n    unless @default_options.nil?\n      known_options.each { |option|\n        unless @options.has_key?(option)\n          if @default_options.has_key?(option)\n            @options[option] = @default_options[option]\n          end\n        end\n      }\n    end\n\n    unless @options.has_key?('noattr')\n        @options['noattr'] = false\n    end\n\n    if @options.has_key?('rootname')\n      @options['rootname'] = '' if @options['rootname'].nil?\n    else\n      @options['rootname'] = DEF_ROOT_NAME\n    end\n\n    if @options.has_key?('xmldeclaration') && @options['xmldeclaration'] == true\n      @options['xmldeclaration'] = DEF_XML_DECLARATION\n    end\n\n    @options['keytosymbol'] = DEF_KEY_TO_SYMBOL unless @options.has_key?('keytosymbol')\n\n    if @options.has_key?('contentkey')\n      if @options['contentkey'] =~ /^-(.*)$/\n        @options['contentkey']    = $1\n        @options['collapseagain'] = true\n      end\n    else\n      @options['contentkey'] = DEF_CONTENT_KEY\n    end\n\n    unless @options.has_key?('normalisespace')\n      @options['normalisespace'] = @options['normalizespace']\n    end\n    @options['normalisespace'] = 0 if @options['normalisespace'].nil?\n\n    if @options.has_key?('searchpath')\n      unless @options['searchpath'].instance_of?(Array)\n        @options['searchpath'] = [ @options['searchpath'] ]\n      end\n    else\n      @options['searchpath'] = []\n    end\n\n    if @options.has_key?('cache') && scalar(@options['cache'])\n      @options['cache'] = [ @options['cache'] ]\n    end\n\n    @options['anonymoustag'] = DEF_ANONYMOUS_TAG unless @options.has_key?('anonymoustag')\n\n    if !@options.has_key?('indent') || @options['indent'].nil?\n      @options['indent'] = DEF_INDENTATION\n    end\n\n    @options['indent'] = '' if @options.has_key?('noindent')\n\n    # Special cleanup for 'keyattr' which could be an array or\n    # a hash or left to default to array.\n    if @options.has_key?('keyattr')\n      if !scalar(@options['keyattr'])\n        # Convert keyattr => { elem => '+attr' }\n        #      to keyattr => { elem => ['attr', '+'] }\n        if @options['keyattr'].instance_of?(Hash)\n          @options['keyattr'].each { |key, value|\n            if value =~ /^([-+])?(.*)$/\n              @options['keyattr'][key] = [$2, $1 ? $1 : '']\n            end\n          }\n        elsif !@options['keyattr'].instance_of?(Array)\n          raise ArgumentError, \"'keyattr' must be String, Hash, or Array!\"\n        end\n      else\n        @options['keyattr'] = [ @options['keyattr'] ]\n      end\n    else\n      @options['keyattr'] = DEF_KEY_ATTRIBUTES\n    end\n\n    if @options.has_key?('forcearray')\n      if @options['forcearray'].instance_of?(Regexp)\n        @options['forcearray'] = [ @options['forcearray'] ]\n      end\n\n      if @options['forcearray'].instance_of?(Array)\n        force_list = @options['forcearray']\n        unless force_list.empty?\n          @options['forcearray'] = {}\n          force_list.each { |tag|\n            if tag.instance_of?(Regexp)\n              unless @options['forcearray']['_regex'].instance_of?(Array)\n                @options['forcearray']['_regex'] = []\n              end\n              @options['forcearray']['_regex'] << tag\n            else\n              @options['forcearray'][tag] = true\n            end\n          }\n        else\n          @options['forcearray'] = false\n        end\n      else\n        @options['forcearray'] = @options['forcearray'] ? true : false\n      end\n    else\n      @options['forcearray'] = DEF_FORCE_ARRAY\n    end\n\n    if @options.has_key?('grouptags') && !@options['grouptags'].instance_of?(Hash)\n      raise ArgumentError, \"Illegal value for 'GroupTags' option - expected a Hash.\"\n    end\n\n    if @options.has_key?('variables') && !@options['variables'].instance_of?(Hash)\n      raise ArgumentError, \"Illegal value for 'Variables' option - expected a Hash.\"\n    end\n\n    if @options.has_key?('variables')\n      @_var_values = @options['variables']\n    elsif @options.has_key?('varattr')\n      @_var_values = {}\n    end\n  end\n\n  # Actually converts an XML document element into a data structure.\n  #\n  # element::\n  #   The document element to be collapsed.\n  def collapse(element)\n    result = @options['noattr'] ? {} : get_attributes(element)\n\n    if @options['normalisespace'] == 2\n      result.each { |k, v| result[k] = normalise_space(v) }\n    end\n\n    if element.has_elements?\n      element.each_element { |child|\n        value = collapse(child)\n        if empty(value) && (element.attributes.empty? || @options['noattr'])\n          next if @options.has_key?('suppressempty') && @options['suppressempty'] == true\n        end\n        result = merge(result, child.name, value)\n      }\n      if has_mixed_content?(element)\n        # normalisespace?\n        content = element.texts.map { |x| x.to_s }\n        content = content[0] if content.size == 1\n        result[@options['contentkey']] = content\n      end\n    elsif element.has_text? # i.e. it has only text.\n      return collapse_text_node(result, element)\n    end\n\n    # Turn Arrays into Hashes if key fields present.\n    count = fold_arrays(result)\n\n    # Disintermediate grouped tags.\n    if @options.has_key?('grouptags')\n      result.each { |key, value|\n        next unless (value.instance_of?(Hash) && (value.size == 1))\n        child_key, child_value = value.to_a[0]\n        if @options['grouptags'][key] == child_key\n          result[key] = child_value\n        end\n      }\n    end\n    \n    # Fold Hashes containing a single anonymous Array up into just the Array.\n    if count == 1 \n      anonymoustag = @options['anonymoustag']\n      if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array)\n        return result[anonymoustag]\n      end\n    end\n\n    if result.empty? && @options.has_key?('suppressempty')\n      return @options['suppressempty'] == '' ? '' : nil\n    end\n\n    result\n  end\n\n  # Collapses a text node and merges it with an existing Hash, if\n  # possible.\n  # Thanks to Curtis Schofield for reporting a subtle bug.\n  #\n  # hash::\n  #   Hash to merge text node value with, if possible.\n  # element::\n  #   Text node to be collapsed.\n  def collapse_text_node(hash, element)\n    value = node_to_text(element)\n    if empty(value) && !element.has_attributes?\n      return {}\n    end\n\n    if element.has_attributes? && !@options['noattr']\n      return merge(hash, @options['contentkey'], value)\n    else\n      if @options['forcecontent']\n        return merge(hash, @options['contentkey'], value)\n      else\n        return value\n      end\n    end\n  end\n\n  # Folds all arrays in a Hash.\n  # \n  # hash::\n  #   Hash to be folded.\n  def fold_arrays(hash)\n    fold_amount = 0\n    keyattr = @options['keyattr']\n    if (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash))\n      hash.each { |key, value|\n        if value.instance_of?(Array)\n          if keyattr.instance_of?(Array)\n            hash[key] = fold_array(value)\n          else\n            hash[key] = fold_array_by_name(key, value)\n          end\n          fold_amount += 1\n        end\n      }\n    end\n    fold_amount\n  end\n\n  # Folds an Array to a Hash, if possible. Folding happens\n  # according to the content of keyattr, which has to be\n  # an array.\n  #\n  # array::\n  #   Array to be folded.\n  def fold_array(array)\n    hash = Hash.new\n    array.each { |x|\n      return array unless x.instance_of?(Hash)\n      key_matched = false\n      @options['keyattr'].each { |key|\n        if x.has_key?(key)\n          key_matched = true\n          value = x[key]\n          return array if value.instance_of?(Hash) || value.instance_of?(Array)\n          value = normalise_space(value) if @options['normalisespace'] == 1\n          x.delete(key)\n          hash[value] = x\n          break\n        end\n      }\n      return array unless key_matched\n    }\n    hash = collapse_content(hash) if @options['collapseagain']\n    hash\n  end\n  \n  # Folds an Array to a Hash, if possible. Folding happens\n  # according to the content of keyattr, which has to be\n  # a Hash.\n  #\n  # name::\n  #   Name of the attribute to be folded upon.\n  # array::\n  #   Array to be folded.\n  def fold_array_by_name(name, array)\n    return array unless @options['keyattr'].has_key?(name)\n    key, flag = @options['keyattr'][name]\n\n    hash = Hash.new\n    array.each { |x|\n      if x.instance_of?(Hash) && x.has_key?(key)\n        value = x[key]\n        return array if value.instance_of?(Hash) || value.instance_of?(Array)\n        value = normalise_space(value) if @options['normalisespace'] == 1\n        hash[value] = x\n        hash[value][\"-#{key}\"] = hash[value][key] if flag == '-'\n        hash[value].delete(key) unless flag == '+'\n      else\n        $stderr.puts(\"Warning: <#{name}> element has no '#{key}' attribute.\")\n        return array\n      end\n    }\n    hash = collapse_content(hash) if @options['collapseagain']\n    hash\n  end\n\n  # Tries to collapse a Hash even more ;-)\n  #\n  # hash::\n  #   Hash to be collapsed again.\n  def collapse_content(hash)\n    content_key = @options['contentkey']\n    hash.each_value { |value|\n      return hash unless value.instance_of?(Hash) && value.size == 1 && value.has_key?(content_key)\n      hash.each_key { |key| hash[key] = hash[key][content_key] }\n    }\n    hash\n  end\n  \n  # Adds a new key/value pair to an existing Hash. If the key to be added\n  # does already exist and the existing value associated with key is not\n  # an Array, it will be converted into an Array. Then the new value is\n  # appended to that Array.\n  #\n  # hash::\n  #   Hash to add key/value pair to.\n  # key::\n  #   Key to be added.\n  # value::\n  #   Value to be associated with key.\n  def merge(hash, key, value)\n    if value.instance_of?(String)\n      value = normalise_space(value) if @options['normalisespace'] == 2\n\n      # do variable substitutions\n      unless @_var_values.nil? || @_var_values.empty?\n        value.gsub!(/\\$\\{(\\w+)\\}/) { |x| get_var($1) }\n      end\n      \n      # look for variable definitions\n      if @options.has_key?('varattr')\n        varattr = @options['varattr']\n        if hash.has_key?(varattr)\n          set_var(hash[varattr], value)\n        end\n      end\n    end\n    \n    #patch for converting keys to symbols\n    if @options.has_key?('keytosymbol')\n      if @options['keytosymbol'] == true\n        key = key.to_s.downcase.to_sym\n      end\n    end\n    \n    if hash.has_key?(key)\n      if hash[key].instance_of?(Array)\n        hash[key] << value\n      else\n        hash[key] = [ hash[key], value ]\n      end\n    elsif value.instance_of?(Array) # Handle anonymous arrays.\n      hash[key] = [ value ]\n    else\n      if force_array?(key)\n        hash[key] = [ value ]\n      else\n        hash[key] = value\n      end\n    end\n    hash\n  end\n  \n  # Checks, if the 'forcearray' option has to be used for\n  # a certain key.\n  def force_array?(key)\n    return false if key == @options['contentkey']\n    return true if @options['forcearray'] == true\n    forcearray = @options['forcearray']\n    if forcearray.instance_of?(Hash)\n      return true if forcearray.has_key?(key) \n      return false unless forcearray.has_key?('_regex')\n      forcearray['_regex'].each { |x| return true if key =~ x }\n    end\n    return false\n  end\n  \n  # Converts the attributes array of a document node into a Hash.\n  # Returns an empty Hash, if node has no attributes.\n  #\n  # node::\n  #   Document node to extract attributes from.\n  def get_attributes(node)\n    attributes = {}\n    if @options['attrprefix']\n      node.attributes.each { |n,v| attributes[\"@\" + n] = v }\n    else\n      node.attributes.each { |n,v| attributes[n] = v }\n    end\n    attributes\n  end\n  \n  # Determines, if a document element has mixed content.\n  #\n  # element::\n  #   Document element to be checked.\n  def has_mixed_content?(element)\n    if element.has_text? && element.has_elements?\n      return true if element.texts.join('') !~ /^\\s*$/s\n    end\n    false\n  end\n  \n  # Called when a variable definition is encountered in the XML.\n  # A variable definition looks like\n  #    <element attrname=\"name\">value</element>\n  # where attrname matches the varattr setting.\n  def set_var(name, value)\n    @_var_values[name] = value\n  end\n\n  # Called during variable substitution to get the value for the\n  # named variable.\n  def get_var(name)\n    if @_var_values.has_key?(name)\n      return @_var_values[name]\n    else\n      return \"${#{name}}\"\n    end\n  end\n  \n  # Recurses through a data structure building up and returning an\n  # XML representation of that structure as a string.\n  #\n  # ref::\n  #   Reference to the data structure to be encoded.\n  # name::\n  #   The XML tag name to be used for this item.\n  # indent::\n  #   A string of spaces for use as the current indent level.\n  def value_to_xml(ref, name, indent)\n    named = !name.nil? && name != ''\n    nl    = @options.has_key?('noindent') ? '' : \"\\n\"\n\n    if !scalar(ref)\n      if @ancestors.member?(ref)\n        raise ArgumentError, \"Circular data structures not supported!\"\n      end\n      @ancestors << ref\n    else\n      if named\n        return [indent, '<', name, '>', @options['noescape'] ? ref.to_s : escape_value(ref.to_s), '</', name, '>', nl].join('')\n      else\n        return ref.to_s + nl\n      end\n    end\n\n    # Unfold hash to array if possible.\n    if ref.instance_of?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != ''\n      ref = hash_to_array(name, ref)\n    end\n\n    result = []\n    if ref.instance_of?(Hash)\n      # Reintermediate grouped values if applicable.\n      if @options.has_key?('grouptags')\n        ref.each { |key, value|\n          if @options['grouptags'].has_key?(key)\n            ref[key] = { @options['grouptags'][key] => value }\n          end\n        }\n      end\n      \n      nested = []\n      text_content = nil\n      if named\n        result << indent << '<' << name\n      end\n\n      if !ref.empty?\n        ref.each { |key, value|\n          next if !key.nil? && key[0, 1] == '-'\n          if value.nil?\n            unless @options.has_key?('suppressempty') && @options['suppressempty'].nil?\n              raise ArgumentError, \"Use of uninitialized value!\"\n            end\n            value = {}\n          end\n\n          # Check for the '@' attribute prefix to allow separation of attributes and elements\n          if @options['noattr'] ||\n             (@options['attrprefix'] && !(key =~ /^@(.*)/)) ||\n             !scalar(value)\n            nested << value_to_xml(value, key, indent + @options['indent'])\n          else\n            value = value.to_s\n            value = escape_value(value) unless @options['noescape']\n            if key == @options['contentkey']\n              text_content = value\n            else\n              result << ' ' << ($1||key) << '=\"' << value << '\"'\n            end\n          end\n        }\n      else\n        text_content = ''\n      end\n\n      if !nested.empty? || !text_content.nil?\n        if named\n          result << '>'\n          if !text_content.nil?\n            result << text_content\n            nested[0].sub!(/^\\s+/, '') if !nested.empty?\n          else\n            result << nl\n          end\n          if !nested.empty?\n            result << nested << indent\n          end\n          result << '</' << name << '>' << nl\n        else\n          result << nested\n        end\n      else\n        result << ' />' << nl\n      end\n    elsif ref.instance_of?(Array)\n      ref.each { |value|\n        if scalar(value)\n          result << indent << '<' << name << '>'\n          result << (@options['noescape'] ? value.to_s : escape_value(value.to_s))\n          result << '</' << name << '>' << nl\n        elsif value.instance_of?(Hash)\n          result << value_to_xml(value, name, indent)\n        else\n          result << indent << '<' << name << '>' << nl\n          result << value_to_xml(value, @options['anonymoustag'], indent + @options['indent'])\n          result << indent << '</' << name << '>' << nl\n        end\n      }\n    else\n      # Probably, this is obsolete.\n      raise ArgumentError, \"Can't encode a value of type: #{ref.type}.\"\n    end\n    @ancestors.pop if !scalar(ref)\n    result.join('')\n  end\n  \n  # Checks, if a certain value is a \"scalar\" value. Whatever\n  # that will be in Ruby ... ;-)\n  # \n  # value::\n  #   Value to be checked.\n  def scalar(value)\n    return false if value.instance_of?(Hash) || value.instance_of?(Array)\n    return true\n  end\n\n  # Attempts to unfold a hash of hashes into an array of hashes. Returns\n  # a reference to th array on success or the original hash, if unfolding\n  # is not possible.\n  # \n  # parent::\n  #   \n  # hashref::\n  #   Reference to the hash to be unfolded.\n  def hash_to_array(parent, hashref)\n    arrayref = []\n    hashref.each { |key, value|\n      return hashref unless value.instance_of?(Hash)\n\n      if @options['keyattr'].instance_of?(Hash)\n        return hashref unless @options['keyattr'].has_key?(parent)\n        arrayref << { @options['keyattr'][parent][0] => key }.update(value)\n      else\n        arrayref << { @options['keyattr'][0] => key }.update(value)\n      end\n    }\n    arrayref\n  end\n  \n  # Replaces XML markup characters by their external entities.\n  #\n  # data::\n  #   The string to be escaped.\n  def escape_value(data)\n    Text::normalize(data)\n  end\n  \n  # Removes leading and trailing whitespace and sequences of\n  # whitespaces from a string.\n  #\n  # text::\n  #   String to be normalised.\n  def normalise_space(text)\n    text.strip.gsub(/\\s\\s+/, ' ')\n  end\n\n  # Checks, if an object is nil, an empty String or an empty Hash.\n  # Thanks to Norbert Gawor for a bugfix.\n  #\n  # value::\n  #   Value to be checked for emptyness.\n  def empty(value)\n    case value\n      when Hash\n        return value.empty?\n      when String\n        return value !~ /\\S/m\n      else\n        return value.nil?\n    end\n  end\n  \n  # Converts a document node into a String.\n  # If the node could not be converted into a String\n  # for any reason, default will be returned.\n  #\n  # node::\n  #   Document node to be converted.\n  # default::\n  #   Value to be returned, if node could not be converted.\n  def node_to_text(node, default = nil)\n    if node.instance_of?(REXML::Element) \n      node.texts.map { |t| t.value }.join('')\n    elsif node.instance_of?(REXML::Attribute)\n      node.value.nil? ? default : node.value.strip\n    elsif node.instance_of?(REXML::Text)\n      node.value.strip\n    else\n      default\n    end\n  end\n\n  # Parses an XML string and returns the according document.\n  #\n  # xml_string::\n  #   XML string to be parsed.\n  #\n  # The following exception may be raised:\n  #\n  # REXML::ParseException::\n  #   If the specified file is not wellformed.\n  def parse(xml_string)\n    Document.new(xml_string)\n  end\n  \n  # Searches in a list of paths for a certain file. Returns\n  # the full path to the file, if it could be found. Otherwise,\n  # an exception will be raised.\n  #\n  # filename::\n  #   Name of the file to search for.\n  # searchpath::\n  #   List of paths to search in.\n  def find_xml_file(file, searchpath)\n    filename = File::basename(file)\n\n    if filename != file\n      return file if File::file?(file)\n    else\n      searchpath.each { |path|\n        full_path = File::join(path, filename)\n        return full_path if File::file?(full_path)\n      }\n    end\n\n    if searchpath.empty?\n      return file if File::file?(file)\n      raise ArgumentError, \"File does not exist: #{file}.\"\n    end\n    raise ArgumentError, \"Could not find <#{filename}> in <#{searchpath.join(':')}>\"\n  end\n  \n  # Loads and parses an XML configuration file.\n  #\n  # filename::\n  #   Name of the configuration file to be loaded.\n  #\n  # The following exceptions may be raised:\n  # \n  # Errno::ENOENT::\n  #   If the specified file does not exist.\n  # REXML::ParseException::\n  #   If the specified file is not wellformed.\n  def load_xml_file(filename)\n    parse(IO::read(filename))\n  end\n\n  # Caches the data belonging to a certain file.\n  #\n  # data::\n  #   Data to be cached.\n  # filename::\n  #   Name of file the data was read from.\n  def put_into_cache(data, filename)\n    if @options.has_key?('cache')\n      @options['cache'].each { |scheme|\n        case(scheme)\n        when 'storable'\n          @@cache.save_storable(data, filename)\n        when 'mem_share'\n          @@cache.save_mem_share(data, filename)\n        when 'mem_copy'\n          @@cache.save_mem_copy(data, filename)\n        else\n          raise ArgumentError, \"Unsupported caching scheme: <#{scheme}>.\"\n        end\n      }\n    end\n  end\nend\n\n# vim:sw=2\n"
  }
]