text:
module RightAws

  # = RightAWS::EC2 -- RightScale Amazon EC2 interface
  # The RightAws::EC2 class provides a complete interface to Amazon's
  # Elastic Compute Cloud service, as well as the associated EBS (Elastic Block
  # Store).
  # For explanations of the semantics
  # of each call, please refer to Amazon's documentation at
  # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
  #
  # Examples:
  #
  # Create an EC2 interface handle:
  #
  #   @ec2   = RightAws::Ec2.new(aws_access_key_id,
  #                               aws_secret_access_key)
  # Create a new SSH key pair:
  #  @key   = 'right_ec2_awesome_test_key'
  #  new_key = @ec2.create_key_pair(@key)
  #  keys = @ec2.describe_key_pairs
  #
  # Create a security group:
  #  @group = 'right_ec2_awesome_test_security_group'
  #  @ec2.create_security_group(@group,'My awesome test group')
  #  group = @ec2.describe_security_groups([@group])[0]
  #
  # Configure a security group:
  #  @ec2.authorize_security_group_named_ingress(@group, account_number, 'default')
  #  @ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
  #
  # Describe the available images:
  #  images = @ec2.describe_images
  #
  # Launch an instance:
  #  ec2.run_instances('ami-9a9e7bf3', 1, 1, ['default'], @key, 'SomeImportantUserData', 'public')
  #
  #
  # Describe running instances:
  #  @ec2.describe_instances
  #
  # Error handling: all operations raise an RightAws::AwsError in case
  # of problems. Note that transient errors are automatically retried.

  class Ec2 < RightAwsBase
    include RightAwsBaseInterface

    # Amazon EC2 API version being used
    API_VERSION       = "2008-12-01"
    DEFAULT_HOST      = "ec2.amazonaws.com"
    DEFAULT_PATH      = '/'
    DEFAULT_PROTOCOL  = 'https'
    DEFAULT_PORT      = 443

    # Default addressing type (public=NAT, direct=no-NAT) used when launching instances.
    DEFAULT_ADDRESSING_TYPE =  'public'
    DNS_ADDRESSING_SET      = ['public','direct']

    # Amazon EC2 Instance Types : http://www.amazon.com/b?ie=UTF8&node=370375011
    # Default EC2 instance type (platform)
    DEFAULT_INSTANCE_TYPE   =  'm1.small'
    INSTANCE_TYPES          = ['m1.small','c1.medium','m1.large','m1.xlarge','c1.xlarge']

    @@bench = AwsBenchmarkingBlock.new
    def self.bench_xml
      @@bench.xml
    end
    def self.bench_ec2
      @@bench.service
    end

     # Current API version (sometimes we have to check it outside the GEM).
    @@api = ENV['EC2_API_VERSION'] || API_VERSION
    def self.api
      @@api
    end

    # Create a new handle to an EC2 account. All handles share the same per process or per thread
    # HTTP connection to Amazon EC2. Each handle is for a specific account. The params have the
    # following options:
    # * <tt>:endpoint_url</tt> a fully qualified url to Amazon API endpoint (this overwrites: :server, :port, :service, :protocol and :region). Example: 'https://eu-west-1.ec2.amazonaws.com/'
    # * <tt>:server</tt>: EC2 service host, default: DEFAULT_HOST
    # * <tt>:region</tt>: EC2 region (North America by default)
    # * <tt>:port</tt>: EC2 service port, default: DEFAULT_PORT
    # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
    # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
    # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
    # * <tt>:signature_version</tt>:  The signature version : '0' or '1'(default)
    # * <tt>:cache</tt>: true/false: caching for: ec2_describe_images, describe_instances,
    # describe_images_by_owner, describe_images_by_executable_by, describe_availability_zones,
    # describe_security_groups, describe_key_pairs, describe_addresses,
    # describe_volumes, describe_snapshots methods, default: false.
    #
    def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
      init({ :name             => 'EC2',
             :default_host     => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).host   : DEFAULT_HOST,
             :default_port     => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).port   : DEFAULT_PORT,
             :default_service  => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).path   : DEFAULT_PATH,
             :default_protocol => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).scheme : DEFAULT_PROTOCOL },
           aws_access_key_id    || ENV['AWS_ACCESS_KEY_ID'] ,
           aws_secret_access_key|| ENV['AWS_SECRET_ACCESS_KEY'],
           params)
      # EC2 doesn't really define any transient errors to retry, and in fact,
      # when they return a 503 it is usually for 'request limit exceeded' which
      # we most certainly should not retry.  So let's pare down the list of
      # retryable errors to InternalError only (see RightAwsBase for the default
      # list)
      amazon_problems = ['InternalError']
    end

    def generate_request(action, params={}) #:nodoc:
      service_hash = {"Action"         => action,
                      "AWSAccessKeyId" => @aws_access_key_id,
                      "Version"        => @@api }
      service_hash.update(params)
      service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], @params[:service])

      # use POST method if the length of the query string is too large
      if service_params.size > 2000
        if signature_version == '2'
          # resign the request because HTTP verb is included into signature
          service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], @params[:service])
        end
        request      = Net::HTTP::Post.new(service)
        request.body = service_params
        request['Content-Type'] = 'application/x-www-form-urlencoded'
      else
        request        = Net::HTTP::Get.new("#{@params[:service]}?#{service_params}")
      end
        # prepare output hash
      { :request  => request,
        :server   => @params[:server],
        :port     => @params[:port],
        :protocol => @params[:protocol] }
    end

      # Sends request to Amazon and parses the response
      # Raises AwsError if any banana happened
    def request_info(request, parser)  #:nodoc:
      thread = @params[:multi_thread] ? Thread.current : Thread.main
      thread[:ec2_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError, :logger => @logger)
      request_info_impl(thread[:ec2_connection], @@bench, request, parser)
    end

    def hash_params(prefix, list) #:nodoc:
      groups = {}
      list.each_index{|i| groups.update("#{prefix}.#{i+1}"=>list[i])} if list
      return groups
    end

  #-----------------------------------------------------------------
  #      Images
  #-----------------------------------------------------------------

    # params:
    #   { 'ImageId'      => ['id1', ..., 'idN'],
    #     'Owner'        => ['self', ..., 'userN'],
    #     'ExecutableBy' => ['self', 'all', ..., 'userN']
    #   }
    def ec2_describe_images(params={}, image_type=nil, cache_for=nil) #:nodoc:
      request_hash = {}
      params.each do |list_by, list|
        request_hash.merge! hash_params(list_by, list.to_a)
      end
      request_hash['ImageType'] = image_type if image_type
      link = generate_request("DescribeImages", request_hash)
      request_cache_or_info cache_for, link,  QEc2DescribeImagesParser, @@bench, cache_for
    rescue Exception
      on_exception
    end

      # Retrieve a list of images. Returns array of hashes describing the images or an exception:
      # +image_type+ = 'machine' || 'kernel' || 'ramdisk'
      #
      #  ec2.describe_images #=>
      #    [{:aws_owner => "522821470517",
      #      :aws_id => "ami-e4b6538d",
      #      :aws_state => "available",
      #      :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
      #      :aws_is_public => true,
      #      :aws_architecture => "i386",
      #      :aws_image_type => "machine"},
      #     {...},
      #     {...} ]
      #
      # If +list+ param is set, then retrieve information about the listed images only:
      #
      #  ec2.describe_images(['ami-e4b6538d']) #=>
      #    [{:aws_owner => "522821470517",
      #      :aws_id => "ami-e4b6538d",
      #      :aws_state => "available",
      #      :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
      #      :aws_is_public => true,
      #      :aws_architecture => "i386",
      #      :aws_image_type => "machine"}]
      #
    def describe_images(list=[], image_type=nil)
      list = list.to_a
      cache_for = list.empty? && !image_type ? :describe_images : nil
      ec2_describe_images({ 'ImageId' => list }, image_type, cache_for)
    end

      #
      #  Example:
      #
      #   ec2.describe_images_by_owner('522821470517')
      #   ec2.describe_images_by_owner('self')
      #
    def describe_images_by_owner(list=['self'], image_type=nil)
      list = list.to_a
      cache_for = list==['self'] && !image_type ? :describe_images_by_owner : nil
      ec2_describe_images({ 'Owner' => list }, image_type, cache_for)
    end

      #
      #  Example:
      #
      #   ec2.describe_images_by_executable_by('522821470517')
      #   ec2.describe_images_by_executable_by('self')
      #   ec2.describe_images_by_executable_by('all')
      #
    def describe_images_by_executable_by(list=['self'], image_type=nil)
      list = list.to_a
      cache_for = list==['self'] && !image_type ? :describe_images_by_executable_by : nil
      ec2_describe_images({ 'ExecutableBy' => list }, image_type, cache_for)
    end

      # Register new image at Amazon.
      # Returns new image id or an exception.
      #
      #  ec2.register_image('bucket/key/manifest') #=> 'ami-e444444d'
      #
    def register_image(image_location)
      link = generate_request("RegisterImage",
                              'ImageLocation' => image_location.to_s)
      request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Deregister image at Amazon. Returns +true+ or an exception.
      #
      #  ec2.deregister_image('ami-e444444d') #=> true
      #
    def deregister_image(image_id)
      link = generate_request("DeregisterImage",
                              'ImageId' => image_id.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Describe image attributes. Currently 'launchPermission', 'productCodes', 'kernel', 'ramdisk' and 'blockDeviceMapping'  are supported.
      #
      #  ec2.describe_image_attribute('ami-e444444d') #=> {:groups=>["all"], :users=>["000000000777"]}
      #
    def describe_image_attribute(image_id, attribute='launchPermission')
      link = generate_request("DescribeImageAttribute",
                              'ImageId'   => image_id,
                              'Attribute' => attribute)
      request_info(link, QEc2DescribeImageAttributeParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Reset image attribute. Currently, only 'launchPermission' is supported. Returns +true+ or an exception.
      #
      #  ec2.reset_image_attribute('ami-e444444d') #=> true
      #
    def reset_image_attribute(image_id, attribute='launchPermission')
      link = generate_request("ResetImageAttribute",
                              'ImageId'   => image_id,
                              'Attribute' => attribute)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Modify an image's attributes. It is recommended that you use
      # modify_image_launch_perm_add_users, modify_image_launch_perm_remove_users, etc.
      # instead of modify_image_attribute because the signature of
      # modify_image_attribute may change with EC2 service changes.
      #
      #  attribute      : currently, only 'launchPermission' is supported.
      #  operation_type : currently, only 'add' & 'remove' are supported.
      #  vars:
      #    :user_group  : currently, only 'all' is supported.
      #    :user_id
      #    :product_code
    def modify_image_attribute(image_id, attribute, operation_type = nil, vars = {})
      params =  {'ImageId'   => image_id,
                 'Attribute' => attribute}
      params['OperationType'] = operation_type if operation_type
      params.update(hash_params('UserId',      vars[:user_id].to_a))    if vars[:user_id]
      params.update(hash_params('UserGroup',   vars[:user_group].to_a)) if vars[:user_group]
      params.update(hash_params('ProductCode', vars[:product_code]))    if vars[:product_code]
      link = generate_request("ModifyImageAttribute", params)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Grant image launch permissions to users.
      # Parameter +userId+ is a list of user AWS account ids.
      # Returns +true+ or an exception.
      #
      #  ec2.modify_image_launch_perm_add_users('ami-e444444d',['000000000777','000000000778']) #=> true
    def modify_image_launch_perm_add_users(image_id, user_id=[])
      modify_image_attribute(image_id, 'launchPermission', 'add', :user_id => user_id.to_a)
    end

      # Revokes image launch permissions for users. +userId+ is a list of users AWS accounts ids. Returns +true+ or an exception.
      #
      #  ec2.modify_image_launch_perm_remove_users('ami-e444444d',['000000000777','000000000778']) #=> true
      #
    def modify_image_launch_perm_remove_users(image_id, user_id=[])
      modify_image_attribute(image_id, 'launchPermission', 'remove', :user_id => user_id.to_a)
    end

      # Add image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
      # Returns +true+ or an exception.
      #
      #  ec2.modify_image_launch_perm_add_groups('ami-e444444d') #=> true
      #
    def modify_image_launch_perm_add_groups(image_id, user_group=['all'])
      modify_image_attribute(image_id, 'launchPermission', 'add', :user_group => user_group.to_a)
    end

      # Remove image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
      #
      #  ec2.modify_image_launch_perm_remove_groups('ami-e444444d') #=> true
      #
    def modify_image_launch_perm_remove_groups(image_id, user_group=['all'])
      modify_image_attribute(image_id, 'launchPermission', 'remove', :user_group => user_group.to_a)
    end

      # Add product code to image
      #
      #  ec2.modify_image_product_code('ami-e444444d','0ABCDEF') #=> true
      #
    def modify_image_product_code(image_id, product_code=[])
      modify_image_attribute(image_id, 'productCodes', nil, :product_code => product_code.to_a)
    end

  #-----------------------------------------------------------------
  #      Instances
  #-----------------------------------------------------------------

    def get_desc_instances(instances)  # :nodoc:
      result = []
      instances.each do |reservation|
        reservation[:instances_set].each do |instance|
          # Parse and remove timestamp from the reason string. The timestamp is of
          # the request, not when EC2 took action, thus confusing & useless...
          instance[:aws_reason]         = instance[:aws_reason].sub(/\(\d[^)]*GMT\) */, '')
          instance[:aws_owner]          = reservation[:aws_owner]
          instance[:aws_reservation_id] = reservation[:aws_reservation_id]
          instance[:aws_groups]         = reservation[:aws_groups]
          result << instance
        end
      end
      result
    rescue Exception
      on_exception
    end

      # Retrieve information about EC2 instances. If +list+ is omitted then returns the
      # list of all instances.
      #
      #  ec2.describe_instances #=>
      #    [{:aws_image_id       => "ami-e444444d",
      #      :aws_reason         => "",
      #      :aws_state_code     => "16",
      #      :aws_owner          => "000000000888",
      #      :aws_instance_id    => "i-123f1234",
      #      :aws_reservation_id => "r-aabbccdd",
      #      :aws_state          => "running",
      #      :dns_name           => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
      #      :ssh_key_name       => "staging",
      #      :aws_groups         => ["default"],
      #      :private_dns_name   => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
      #      :aws_instance_type  => "m1.small",
      #      :aws_launch_time    => "2008-1-1T00:00:00.000Z"},
      #      :aws_availability_zone => "us-east-1b",
      #      :aws_kernel_id      => "aki-ba3adfd3",
      #      :aws_ramdisk_id     => "ari-badbad00",
      #       ..., {...}]
      #
    def describe_instances(list=[])
      link = generate_request("DescribeInstances", hash_params('InstanceId',list.to_a))
      request_cache_or_info(:describe_instances, link,  QEc2DescribeInstancesParser, @@bench, list.blank?) do |parser|
        get_desc_instances(parser.result)
      end
    rescue Exception
      on_exception
    end

      # Return the product code attached to instance or +nil+ otherwise.
      #
      #  ec2.confirm_product_instance('ami-e444444d','12345678') #=> nil
      #  ec2.confirm_product_instance('ami-e444444d','00001111') #=> "000000000888"
      #
    def confirm_product_instance(instance, product_code)
      link = generate_request("ConfirmProductInstance", { 'ProductCode' => product_code,
                                'InstanceId'  => instance })
      request_info(link, QEc2ConfirmProductInstanceParser.new(:logger => @logger))
    end

      # Launch new EC2 instances. Returns a list of launched instances or an exception.
      #
      #  ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', 'public') #=>
      #   [{:aws_image_id       => "ami-e444444d",
      #     :aws_reason         => "",
      #     :aws_state_code     => "0",
      #     :aws_owner          => "000000000888",
      #     :aws_instance_id    => "i-123f1234",
      #     :aws_reservation_id => "r-aabbccdd",
      #     :aws_state          => "pending",
      #     :dns_name           => "",
      #     :ssh_key_name       => "my_awesome_key",
      #     :aws_groups         => ["my_awesome_group"],
      #     :private_dns_name   => "",
      #     :aws_instance_type  => "m1.small",
      #     :aws_launch_time    => "2008-1-1T00:00:00.000Z"
      #     :aws_ramdisk_id     => "ari-8605e0ef"
      #     :aws_kernel_id      => "aki-9905e0f0",
      #     :ami_launch_index   => "0",
      #     :aws_availability_zone => "us-east-1b"
      #     }]
      #
    def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='',
                      addressing_type = nil, instance_type = nil,
                      kernel_id = nil, ramdisk_id = nil, availability_zone = nil,
                      block_device_mappings = nil)
 	    launch_instances(image_id, { :min_count       => min_count,
 	                                 :max_count       => max_count,
 	                                 :user_data       => user_data,
                                   :group_ids       => group_ids,
                                   :key_name        => key_name,
                                   :instance_type   => instance_type,
                                   :addressing_type => addressing_type,
                                   :kernel_id       => kernel_id,
                                   :ramdisk_id      => ramdisk_id,
                                   :availability_zone     => availability_zone,
                                   :block_device_mappings => block_device_mappings
                                 })
    end

      # Launch new EC2 instances. Returns a list of launched instances or an exception.
      #
      # +lparams+ keys (default values in parenthesis):
      #  :min_count              fixnum, (1)
      #  :max_count              fixnum, (1)
      #  :group_ids              array or string ([] == 'default')
      #  :instance_type          string (DEFAULT_INSTACE_TYPE)
      #  :addressing_type        string (DEFAULT_ADDRESSING_TYPE
      #  :key_name               string
      #  :kernel_id              string
      #  :ramdisk_id             string
      #  :availability_zone      string
      #  :block_device_mappings  string
      #  :user_data              string
      #
      #  ec2.launch_instances('ami-e444444d', :group_ids => 'my_awesome_group',
      #                                       :user_data => "Woohoo!!!",
      #                                       :addressing_type => "public",
      #                                       :key_name => "my_awesome_key",
      #                                       :availability_zone => "us-east-1c") #=>
      #   [{:aws_image_id       => "ami-e444444d",
      #     :aws_reason         => "",
      #     :aws_state_code     => "0",
      #     :aws_owner          => "000000000888",
      #     :aws_instance_id    => "i-123f1234",
      #     :aws_reservation_id => "r-aabbccdd",
      #     :aws_state          => "pending",
      #     :dns_name           => "",
      #     :ssh_key_name       => "my_awesome_key",
      #     :aws_groups         => ["my_awesome_group"],
      #     :private_dns_name   => "",
      #     :aws_instance_type  => "m1.small",
      #     :aws_launch_time    => "2008-1-1T00:00:00.000Z",
      #     :aws_ramdisk_id     => "ari-8605e0ef"
      #     :aws_kernel_id      => "aki-9905e0f0",
      #     :ami_launch_index   => "0",
      #     :aws_availability_zone => "us-east-1c"
      #     }]
      #
    def launch_instances(image_id, lparams={})
      @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, " +
                   "key: #{lparams[:key_name]}, groups: #{(lparams[:group_ids]).to_a.join(',')}")
      # careful: keyName and securityGroups may be nil
      params = hash_params('SecurityGroup', lparams[:group_ids].to_a)
      params.update( {'ImageId'        => image_id,
                      'MinCount'       => (lparams[:min_count] || 1).to_s,
                      'MaxCount'       => (lparams[:max_count] || 1).to_s,
                      'AddressingType' => lparams[:addressing_type] || DEFAULT_ADDRESSING_TYPE,
                      'InstanceType'   => lparams[:instance_type]   || DEFAULT_INSTANCE_TYPE })
      # optional params
      params['KeyName']                    = lparams[:key_name]              unless lparams[:key_name].blank?
      params['KernelId']                   = lparams[:kernel_id]             unless lparams[:kernel_id].blank?
      params['RamdiskId']                  = lparams[:ramdisk_id]            unless lparams[:ramdisk_id].blank?
      params['Placement.AvailabilityZone'] = lparams[:availability_zone]     unless lparams[:availability_zone].blank?
      params['BlockDeviceMappings']        = lparams[:block_device_mappings] unless lparams[:block_device_mappings].blank?
      unless lparams[:user_data].blank?
        lparams[:user_data].strip!
          # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
          # Amazon 169.254.169.254 does not like escaped symbols!
          # And it doesn't like "\n" inside of encoded string! Grrr....
          # Otherwise, some of UserData symbols will be lost...
        params['UserData'] = Base64.encode64(lparams[:user_data]).delete("\n").strip unless lparams[:user_data].blank?
      end
      link = generate_request("RunInstances", params)
        #debugger
      instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
      get_desc_instances(instances)
    rescue Exception
      on_exception
    end

      # Terminates EC2 instances. Returns a list of termination params or an exception.
      #
      #  ec2.terminate_instances(['i-f222222d','i-f222222e']) #=>
      #    [{:aws_shutdown_state      => "shutting-down",
      #      :aws_instance_id         => "i-f222222d",
      #      :aws_shutdown_state_code => 32,
      #      :aws_prev_state          => "running",
      #      :aws_prev_state_code     => 16},
      #     {:aws_shutdown_state      => "shutting-down",
      #      :aws_instance_id         => "i-f222222e",
      #      :aws_shutdown_state_code => 32,
      #      :aws_prev_state          => "running",
      #      :aws_prev_state_code     => 16}]
      #
    def terminate_instances(list=[])
      link = generate_request("TerminateInstances", hash_params('InstanceId',list.to_a))
      request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Retreive EC2 instance OS logs. Returns a hash of data or an exception.
      #
      #  ec2.get_console_output('i-f222222d') =>
      #    {:aws_instance_id => 'i-f222222d',
      #     :aws_timestamp   => "2007-05-23T14:36:07.000-07:00",
      #     :timestamp       => Wed May 23 21:36:07 UTC 2007,          # Time instance
      #     :aws_output      => "Linux version 2.6.16-xenU (builder@patchbat.amazonsa) (gcc version 4.0.1 20050727 ..."
    def get_console_output(instance_id)
      link = generate_request("GetConsoleOutput", { 'InstanceId.1' => instance_id })
      request_info(link, QEc2GetConsoleOutputParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Reboot an EC2 instance. Returns +true+ or an exception.
      #
      #  ec2.reboot_instances(['i-f222222d','i-f222222e']) #=> true
      #
    def reboot_instances(list)
      link = generate_request("RebootInstances", hash_params('InstanceId', list.to_a))
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Instances: Windows addons
  #-----------------------------------------------------------------

      # Get initial Windows Server setup password from an instance console output.
      #
      #  my_awesome_key = ec2.create_key_pair('my_awesome_key') #=>
      #    {:aws_key_name    => "my_awesome_key",
      #     :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
      #     :aws_material    => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
      #
      #  my_awesome_instance = ec2.run_instances('ami-a000000a',1,1,['my_awesome_group'],'my_awesome_key', 'WindowsInstance!!!') #=>
      #   [{:aws_image_id       => "ami-a000000a",
      #     :aws_instance_id    => "i-12345678",
      #     ...
      #     :aws_availability_zone => "us-east-1b"
      #     }]
      #
      #  # wait until instance enters 'operational' state and get it's initial password
      #
      #  puts ec2.get_initial_password(my_awesome_instance[:aws_instance_id], my_awesome_key[:aws_material]) #=> "MhjWcgZuY6"
      #
    def get_initial_password(instance_id, private_key)
      console_output = get_console_output(instance_id)
      crypted_password = console_output[:aws_output][%r{<Password>(.+)</Password>}m] && $1
      unless crypted_password
        raise AwsError.new("Initial password was not found in console output for #{instance_id}")
      else
        OpenSSL::PKey::RSA.new(private_key).private_decrypt(Base64.decode64(crypted_password))
      end
    rescue Exception
      on_exception
    end

    # Bundle a Windows image.
    # Internally, it queues the bundling task and shuts down the instance.
    # It then takes a snapshot of the Windows volume bundles it, and uploads it to
    # S3. After bundling completes, Rightaws::Ec2#register_image may be used to
    # register the new Windows AMI for subsequent launches.
    #
    #   ec2.bundle_instance('i-e3e24e8a', 'my-awesome-bucket', 'my-win-image-1') #=>
    #    [{:aws_update_time => "2008-10-16T13:58:25.000Z",
    #      :s3_bucket       => "kd-win-1",
    #      :s3_prefix       => "win2pr",
    #      :aws_state       => "pending",
    #      :aws_id          => "bun-26a7424f",
    #      :aws_instance_id => "i-878a25ee",
    #      :aws_start_time  => "2008-10-16T13:58:02.000Z"}]
    #
    def bundle_instance(instance_id, s3_bucket, s3_prefix,
                        s3_owner_aws_access_key_id=nil, s3_owner_aws_secret_access_key=nil,
                        s3_expires = S3Interface::DEFAULT_EXPIRES_AFTER,
                        s3_upload_policy='ec2-bundle-read')
      # S3 access and signatures
      s3_owner_aws_access_key_id     ||= @aws_access_key_id
      s3_owner_aws_secret_access_key ||= @aws_secret_access_key
      s3_expires = Time.now.utc + s3_expires if s3_expires.is_a?(Fixnum) && (s3_expires < S3Interface::ONE_YEAR_IN_SECONDS)
      # policy
      policy = { 'expiration' => s3_expires.strftime('%Y-%m-%dT%H:%M:%SZ'),
                 'conditions' => [ { 'bucket' => s3_bucket },
                                   { 'acl'    => s3_upload_policy },
                                   [ 'starts-with', '$key', s3_prefix ] ] }.to_json
      policy64        = Base64.encode64(policy).gsub("\n","")
      signed_policy64 = AwsUtils.sign(s3_owner_aws_secret_access_key, policy64)
      # fill request params
      params = { 'InstanceId'                       => instance_id,
                 'Storage.S3.AWSAccessKeyId'        => s3_owner_aws_access_key_id,
                 'Storage.S3.UploadPolicy'          => policy64,
                 'Storage.S3.UploadPolicySignature' => signed_policy64,
                 'Storage.S3.Bucket'                => s3_bucket,
                 'Storage.S3.Prefix'                => s3_prefix,
                 }
      link = generate_request("BundleInstance", params)
      request_info(link, QEc2BundleInstanceParser.new)
    rescue Exception
      on_exception
    end

      # Describe the status of the Windows AMI bundlings.
      # If +list+ is omitted the returns the whole list of tasks.
      #
      #  ec2.describe_bundle_tasks(['bun-4fa74226']) #=>
      #    [{:s3_bucket         => "my-awesome-bucket"
      #      :aws_id            => "bun-0fa70206",
      #      :s3_prefix         => "win1pr",
      #      :aws_start_time    => "2008-10-14T16:27:57.000Z",
      #      :aws_update_time   => "2008-10-14T16:37:10.000Z",
      #      :aws_error_code    => "Client.S3Error",
      #      :aws_error_message =>
      #       "AccessDenied(403)- Invalid according to Policy: Policy Condition failed: [\"eq\", \"$acl\", \"aws-exec-read\"]",
      #      :aws_state         => "failed",
      #      :aws_instance_id   => "i-e3e24e8a"}]
      #
    def describe_bundle_tasks(list=[])
      link = generate_request("DescribeBundleTasks", hash_params('BundleId', list.to_a))
      request_info(link, QEc2DescribeBundleTasksParser.new)
    rescue Exception
      on_exception
    end

      # Cancel an in‐progress or pending bundle task by id.
      #
      #  ec2.cancel_bundle_task('bun-73a7421a') #=>
      #   [{:s3_bucket         => "my-awesome-bucket"
      #     :aws_id            => "bun-0fa70206",
      #     :s3_prefix         => "win02",
      #     :aws_start_time    => "2008-10-14T13:00:29.000Z",
      #     :aws_error_message => "User has requested bundling operation cancellation",
      #     :aws_state         => "failed",
      #     :aws_update_time   => "2008-10-14T13:01:31.000Z",
      #     :aws_error_code    => "Client.Cancelled",
      #     :aws_instance_id   => "i-e3e24e8a"}
      #
    def cancel_bundle_task(bundle_id)
      link = generate_request("CancelBundleTask", { 'BundleId' => bundle_id })
      request_info(link, QEc2BundleInstanceParser.new)
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Security groups
  #-----------------------------------------------------------------

      # Retrieve Security Group information. If +list+ is omitted the returns the whole list of groups.
      #
      #  ec2.describe_security_groups #=>
      #    [{:aws_group_name  => "default-1",
      #      :aws_owner       => "000000000888",
      #      :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
      #      :aws_perms       =>
      #        [{:owner => "000000000888", :group => "default"},
      #         {:owner => "000000000888", :group => "default-1"},
      #         {:to_port => "-1",  :protocol => "icmp", :from_port => "-1",  :cidr_ips => "0.0.0.0/0"},
      #         {:to_port => "22",  :protocol => "tcp",  :from_port => "22",  :cidr_ips => "0.0.0.0/0"},
      #         {:to_port => "80",  :protocol => "tcp",  :from_port => "80",  :cidr_ips => "0.0.0.0/0"},
      #         {:to_port => "443", :protocol => "tcp",  :from_port => "443", :cidr_ips => "0.0.0.0/0"}]},
      #    ..., {...}]
      #
    def describe_security_groups(list=[])
      link = generate_request("DescribeSecurityGroups", hash_params('GroupName',list.to_a))
      request_cache_or_info( :describe_security_groups, link,  QEc2DescribeSecurityGroupsParser, @@bench, list.blank?) do |parser|
        result = []
        parser.result.each do |item|
          perms = []
          item.ipPermissions.each do |perm|
            perm.groups.each do |ngroup|
              perms << {:group => ngroup.groupName,
                        :owner => ngroup.userId}
            end
            perm.ipRanges.each do |cidr_ip|
              perms << {:from_port => perm.fromPort,
                        :to_port   => perm.toPort,
                        :protocol  => perm.ipProtocol,
                        :cidr_ips  => cidr_ip}
            end
          end

             # delete duplication
          perms.each_index do |i|
            (0...i).each do |j|
              if perms[i] == perms[j] then perms[i] = nil; break; end
            end
          end
          perms.compact!

          result << {:aws_owner       => item.ownerId,
                     :aws_group_name  => item.groupName,
                     :aws_description => item.groupDescription,
                     :aws_perms       => perms}

        end
        result
      end
    rescue Exception
      on_exception
    end

      # Create new Security Group. Returns +true+ or an exception.
      #
      #  ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=> true
      #
    def create_security_group(name, description)
      # EC2 doesn't like an empty description...
      description = " " if description.blank?
      link = generate_request("CreateSecurityGroup",
                              'GroupName'        => name.to_s,
                              'GroupDescription' => description.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Remove Security Group. Returns +true+ or an exception.
      #
      #  ec2.delete_security_group('default-1') #=> true
      #
    def delete_security_group(name)
      link = generate_request("DeleteSecurityGroup",
                              'GroupName' => name.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Authorize named ingress for security group. Allows instances that are member of someone
      # else's security group to open connections to instances in my group.
      #
      #  ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
      #
    def authorize_security_group_named_ingress(name, owner, group)
      link = generate_request("AuthorizeSecurityGroupIngress",
                              'GroupName'                  => name.to_s,
                                'SourceSecurityGroupName'    => group.to_s,
                              'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Revoke named ingress for security group.
      #
      #  ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
      #
    def revoke_security_group_named_ingress(name, owner, group)
      link = generate_request("RevokeSecurityGroupIngress",
                              'GroupName'                  => name.to_s,
                              'SourceSecurityGroupName'    => group.to_s,
                              'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
      #
      #  ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
      #  ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
      #
    def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
      link = generate_request("AuthorizeSecurityGroupIngress",
                              'GroupName'  => name.to_s,
                              'IpProtocol' => protocol.to_s,
                              'FromPort'   => from_port.to_s,
                              'ToPort'     => to_port.to_s,
                              'CidrIp'     => cidr_ip.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
      #
      #  ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
      #
    def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
      link = generate_request("RevokeSecurityGroupIngress",
                              'GroupName'  => name.to_s,
                              'IpProtocol' => protocol.to_s,
                              'FromPort'   => from_port.to_s,
                              'ToPort'     => to_port.to_s,
                              'CidrIp'     => cidr_ip.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Keys
  #-----------------------------------------------------------------

      # Retrieve a list of SSH keys. Returns an array of keys or an exception. Each key is
      # represented as a two-element hash.
      #
      #  ec2.describe_key_pairs #=>
      #    [{:aws_fingerprint=> "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03", :aws_key_name=>"key-1"},
      #     {:aws_fingerprint=> "1e:29:30:47:58:6d:7b:8c:9f:08:11:20:3c:44:52:69:74:80:97:08", :aws_key_name=>"key-2"},
      #      ..., {...} ]
      #
    def describe_key_pairs(list=[])
      link = generate_request("DescribeKeyPairs", hash_params('KeyName',list.to_a))
      request_cache_or_info :describe_key_pairs, link,  QEc2DescribeKeyPairParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

      # Create new SSH key. Returns a hash of the key's data or an exception.
      #
      #  ec2.create_key_pair('my_awesome_key') #=>
      #    {:aws_key_name    => "my_awesome_key",
      #     :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
      #     :aws_material    => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
      #
    def create_key_pair(name)
      link = generate_request("CreateKeyPair",
                              'KeyName' => name.to_s)
      request_info(link, QEc2CreateKeyPairParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

      # Delete a key pair. Returns +true+ or an exception.
      #
      #  ec2.delete_key_pair('my_awesome_key') #=> true
      #
    def delete_key_pair(name)
      link = generate_request("DeleteKeyPair",
                              'KeyName' => name.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Elastic IPs
  #-----------------------------------------------------------------

    # Acquire a new elastic IP address for use with your account.
    # Returns allocated IP address or an exception.
    #
    #  ec2.allocate_address #=> '75.101.154.140'
    #
    def allocate_address
      link = generate_request("AllocateAddress")
      request_info(link, QEc2AllocateAddressParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Associate an elastic IP address with an instance.
    # Returns +true+ or an exception.
    #
    #  ec2.associate_address('i-d630cbbf', '75.101.154.140') #=> true
    #
    def associate_address(instance_id, public_ip)
      link = generate_request("AssociateAddress",
                              "InstanceId" => instance_id.to_s,
                              "PublicIp"   => public_ip.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # List elastic IP addresses assigned to your account.
    # Returns an array of 2 keys (:instance_id and :public_ip) hashes:
    #
    #  ec2.describe_addresses  #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"},
    #                               {:instance_id=>nil, :public_ip=>"75.101.154.141"}]
    #
    #  ec2.describe_addresses('75.101.154.140') #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"}]
    #
    def describe_addresses(list=[])
      link = generate_request("DescribeAddresses",
                              hash_params('PublicIp',list.to_a))
      request_cache_or_info :describe_addresses, link,  QEc2DescribeAddressesParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

    # Disassociate the specified elastic IP address from the instance to which it is assigned.
    # Returns +true+ or an exception.
    #
    #  ec2.disassociate_address('75.101.154.140') #=> true
    #
    def disassociate_address(public_ip)
      link = generate_request("DisassociateAddress",
                              "PublicIp" => public_ip.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Release an elastic IP address associated with your account.
    # Returns +true+ or an exception.
    #
    #  ec2.release_address('75.101.154.140') #=> true
    #
    def release_address(public_ip)
      link = generate_request("ReleaseAddress",
                              "PublicIp" => public_ip.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Availability zones
  #-----------------------------------------------------------------

    # Describes availability zones that are currently available to the account and their states.
    # Returns an array of 2 keys (:zone_name and :zone_state) hashes:
    #
    #  ec2.describe_availability_zones  #=> [{:region_name=>"us-east-1",
    #                                         :zone_name=>"us-east-1a",
    #                                         :zone_state=>"available"}, ... ]
    #
    #  ec2.describe_availability_zones('us-east-1c') #=> [{:region_name=>"us-east-1",
    #                                                      :zone_state=>"available",
    #                                                      :zone_name=>"us-east-1c"}]
    #
    def describe_availability_zones(list=[])
      link = generate_request("DescribeAvailabilityZones",
                              hash_params('ZoneName',list.to_a))
      request_cache_or_info :describe_availability_zones, link,  QEc2DescribeAvailabilityZonesParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      Regions
  #-----------------------------------------------------------------

    # Describe regions.
    #
    #  ec2.describe_regions  #=> ["eu-west-1", "us-east-1"]
    #
    def describe_regions(list=[])
      link = generate_request("DescribeRegions",
                              hash_params('RegionName',list.to_a))
      request_cache_or_info :describe_regions, link,  QEc2DescribeRegionsParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      EBS: Volumes
  #-----------------------------------------------------------------

    # Describe all EBS volumes.
    #
    #  ec2.describe_volumes #=>
    #      [{:aws_size              => 94,
    #        :aws_device            => "/dev/sdc",
    #        :aws_attachment_status => "attached",
    #        :zone                  => "merlot",
    #        :snapshot_id           => nil,
    #        :aws_attached_at       => Wed Jun 18 08:19:28 UTC 2008,
    #        :aws_status            => "in-use",
    #        :aws_id                => "vol-60957009",
    #        :aws_created_at        => Wed Jun 18 08:19:20s UTC 2008,
    #        :aws_instance_id       => "i-c014c0a9"},
    #       {:aws_size       => 1,
    #        :zone           => "merlot",
    #        :snapshot_id    => nil,
    #        :aws_status     => "available",
    #        :aws_id         => "vol-58957031",
    #        :aws_created_at => Wed Jun 18 08:19:21 UTC 2008,}, ... ]
    #
    def describe_volumes(list=[])
      link = generate_request("DescribeVolumes",
                              hash_params('VolumeId',list.to_a))
      request_cache_or_info :describe_volumes, link,  QEc2DescribeVolumesParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

    # Create new EBS volume based on previously created snapshot.
    # +Size+ in Gigabytes.
    #
    #  ec2.create_volume('snap-000000', 10, zone) #=>
    #      {:snapshot_id    => "snap-e21df98b",
    #       :aws_status     => "creating",
    #       :aws_id         => "vol-fc9f7a95",
    #       :zone           => "merlot",
    #       :aws_created_at => Tue Jun 24 18:13:32 UTC 2008,
    #       :aws_size       => 94}
    #
    def create_volume(snapshot_id, size, zone)
      link = generate_request("CreateVolume",
                              "SnapshotId"        => snapshot_id.to_s,
                              "Size"              => size.to_s,
                              "AvailabilityZone"  => zone.to_s )
      request_info(link, QEc2CreateVolumeParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Delete the specified EBS volume.
    # This does not deletes any snapshots created from this volume.
    #
    #  ec2.delete_volume('vol-b48a6fdd') #=> true
    #
    def delete_volume(volume_id)
      link = generate_request("DeleteVolume",
                              "VolumeId" => volume_id.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Attach the specified EBS volume to a specified instance, exposing the
    # volume using the specified device name.
    #
    #  ec2.attach_volume('vol-898a6fe0', 'i-7c905415', '/dev/sdh') #=>
    #    { :aws_instance_id => "i-7c905415",
    #      :aws_device      => "/dev/sdh",
    #      :aws_status      => "attaching",
    #      :aws_attached_at => "2008-03-28T14:14:39.000Z",
    #      :aws_id          => "vol-898a6fe0" }
    #
    def attach_volume(volume_id, instance_id, device)
      link = generate_request("AttachVolume",
                              "VolumeId"   => volume_id.to_s,
                              "InstanceId" => instance_id.to_s,
                              "Device"     => device.to_s)
      request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Detach the specified EBS volume from the instance to which it is attached.
    #
    #   ec2.detach_volume('vol-898a6fe0') #=>
    #     { :aws_instance_id => "i-7c905415",
    #       :aws_device      => "/dev/sdh",
    #       :aws_status      => "detaching",
    #       :aws_attached_at => "2008-03-28T14:38:34.000Z",
    #       :aws_id          => "vol-898a6fe0"}
    #
    def detach_volume(volume_id, instance_id=nil, device=nil, force=nil)
      hash = { "VolumeId" => volume_id.to_s }
      hash["InstanceId"] = instance_id.to_s unless instance_id.blank?
      hash["Device"]     = device.to_s      unless device.blank?
      hash["Force"]      = 'true'           if     force
      #
      link = generate_request("DetachVolume", hash)
      request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      EBS: Snapshots
  #-----------------------------------------------------------------

     # Describe all EBS snapshots.
     #
     # ec2.describe_snapshots #=>
     #   [ { :aws_progress   => "100%",
     #       :aws_status     => "completed",
     #       :aws_id         => "snap-72a5401b",
     #       :aws_volume_id  => "vol-5582673c",
     #       :aws_started_at => "2008-02-23T02:50:48.000Z"},
     #     { :aws_progress   => "100%",
     #       :aws_status     => "completed",
     #       :aws_id         => "snap-75a5401c",
     #       :aws_volume_id  => "vol-5582673c",
     #       :aws_started_at => "2008-02-23T16:23:19.000Z" },...]
     #
    def describe_snapshots(list=[])
      link = generate_request("DescribeSnapshots",
                              hash_params('SnapshotId',list.to_a))
      request_cache_or_info :describe_snapshots, link,  QEc2DescribeSnapshotsParser, @@bench, list.blank?
    rescue Exception
      on_exception
    end

    # Create a snapshot of specified volume.
    #
    #  ec2.create_snapshot('vol-898a6fe0') #=>
    #      {:aws_volume_id  => "vol-fd9f7a94",
    #       :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
    #       :aws_progress   => "",
    #       :aws_status     => "pending",
    #       :aws_id         => "snap-d56783bc"}
    #
    def create_snapshot(volume_id)
      link = generate_request("CreateSnapshot",
                              "VolumeId" => volume_id.to_s)
      request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

    # Create a snapshot of specified volume, but with the normal retry algorithms disabled.
    # This method will return immediately upon error.  The user can specify connect and read timeouts (in s)
    # for the connection to AWS.  If the user does not specify timeouts, try_create_snapshot uses the default values
    # in Rightscale::HttpConnection.
    #
    #  ec2.try_create_snapshot('vol-898a6fe0') #=>
    #      {:aws_volume_id  => "vol-fd9f7a94",
    #       :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
    #       :aws_progress   => "",
    #       :aws_status     => "pending",
    #       :aws_id         => "snap-d56783bc"}
    #
    def try_create_snapshot(volume_id, connect_timeout = nil, read_timeout = nil)
      # For safety in the ensure block...we don't want to restore values
      # if we never read them in the first place
      orig_reiteration_time = nil
      orig_http_params = nil

      orig_reiteration_time = RightAws::AWSErrorHandler::reiteration_time
      RightAws::AWSErrorHandler::reiteration_time = 0

      orig_http_params = Rightscale::HttpConnection::params()
      new_http_params = orig_http_params.dup
      new_http_params[:http_connection_retry_count] = 0
      new_http_params[:http_connection_open_timeout] = connect_timeout if !connect_timeout.nil?
      new_http_params[:http_connection_read_timeout] = read_timeout if !read_timeout.nil?
      Rightscale::HttpConnection::params = new_http_params

      link = generate_request("CreateSnapshot",
                              "VolumeId" => volume_id.to_s)
      request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))

    rescue Exception
      on_exception
    ensure
      RightAws::AWSErrorHandler::reiteration_time = orig_reiteration_time if orig_reiteration_time
      Rightscale::HttpConnection::params = orig_http_params if orig_http_params
    end

    # Delete the specified snapshot.
    #
    #  ec2.delete_snapshot('snap-55a5403c') #=> true
    #
    def delete_snapshot(snapshot_id)
      link = generate_request("DeleteSnapshot",
                              "SnapshotId" => snapshot_id.to_s)
      request_info(link, RightBoolResponseParser.new(:logger => @logger))
    rescue Exception
      on_exception
    end

  #-----------------------------------------------------------------
  #      PARSERS: Boolean Response Parser
  #-----------------------------------------------------------------

    class RightBoolResponseParser < RightAWSParser #:nodoc:
      def tagend(name)
        @result = @text=='true' ? true : false if name == 'return'
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Key Pair
  #-----------------------------------------------------------------

    class QEc2DescribeKeyPairParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @item = {} if name == 'item'
      end
      def tagend(name)
        case name
          when 'keyName'        then @item[:aws_key_name]    = @text
          when 'keyFingerprint' then @item[:aws_fingerprint] = @text
          when 'item'           then @result                << @item
        end
      end
      def reset
        @result = [];
      end
    end

    class QEc2CreateKeyPairParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @result = {} if name == 'CreateKeyPairResponse'
      end
      def tagend(name)
        case name
          when 'keyName'        then @result[:aws_key_name]    = @text
          when 'keyFingerprint' then @result[:aws_fingerprint] = @text
          when 'keyMaterial'    then @result[:aws_material]    = @text
        end
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Security Groups
  #-----------------------------------------------------------------

    class QEc2UserIdGroupPairType #:nodoc:
      attr_accessor :userId
      attr_accessor :groupName
    end

    class QEc2IpPermissionType #:nodoc:
      attr_accessor :ipProtocol
      attr_accessor :fromPort
      attr_accessor :toPort
      attr_accessor :groups
      attr_accessor :ipRanges
    end

    class QEc2SecurityGroupItemType #:nodoc:
      attr_accessor :groupName
      attr_accessor :groupDescription
      attr_accessor :ownerId
      attr_accessor :ipPermissions
    end

    class QEc2DescribeSecurityGroupsParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        case name
          when 'item'
            if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
              @group = QEc2SecurityGroupItemType.new
              @group.ipPermissions = []
            elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
              @perm = QEc2IpPermissionType.new
              @perm.ipRanges = []
              @perm.groups   = []
            elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
              @sgroup = QEc2UserIdGroupPairType.new
            end
        end
      end
      def tagend(name)
        case name
          when 'ownerId'          then @group.ownerId   = @text
          when 'groupDescription' then @group.groupDescription = @text
          when 'groupName'
            if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item'
              @group.groupName  = @text
            elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups/item'
              @sgroup.groupName = @text
            end
          when 'ipProtocol'       then @perm.ipProtocol = @text
          when 'fromPort'         then @perm.fromPort   = @text
          when 'toPort'           then @perm.toPort     = @text
          when 'userId'           then @sgroup.userId   = @text
          when 'cidrIp'           then @perm.ipRanges  << @text
          when 'item'
            if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
              @perm.groups << @sgroup
            elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
              @group.ipPermissions << @perm
            elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
              @result << @group
            end
        end
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Images
  #-----------------------------------------------------------------

    class QEc2DescribeImagesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        if name == 'item' && @xmlpath[%r{.*/imagesSet$}]
          @image = {}
        end
      end
      def tagend(name)
        case name
          when 'imageId'       then @image[:aws_id]       = @text
          when 'imageLocation' then @image[:aws_location] = @text
          when 'imageState'    then @image[:aws_state]    = @text
          when 'imageOwnerId'  then @image[:aws_owner]    = @text
          when 'isPublic'      then @image[:aws_is_public]= @text == 'true' ? true : false
          when 'productCode'   then (@image[:aws_product_codes] ||= []) << @text
          when 'architecture'  then @image[:aws_architecture] = @text
          when 'imageType'     then @image[:aws_image_type] = @text
          when 'kernelId'      then @image[:aws_kernel_id]  = @text
          when 'ramdiskId'     then @image[:aws_ramdisk_id] = @text
          when 'item'          then @result << @image if @xmlpath[%r{.*/imagesSet$}]
        end
      end
      def reset
        @result = []
      end
    end

    class QEc2RegisterImageParser < RightAWSParser #:nodoc:
      def tagend(name)
        @result = @text if name == 'imageId'
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Image Attribute
  #-----------------------------------------------------------------

    class QEc2DescribeImageAttributeParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        case name
          when 'launchPermission'
            @result[:groups] = []
            @result[:users]  = []
          when 'productCodes'
            @result[:aws_product_codes] = []
        end
      end
      def tagend(name)
          # right now only 'launchPermission' is supported by Amazon.
          # But nobody know what will they xml later as attribute. That is why we
          # check for 'group' and 'userId' inside of 'launchPermission/item'
        case name
          when 'imageId'            then @result[:aws_id] = @text
          when 'group'              then @result[:groups] << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
          when 'userId'             then @result[:users]  << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
          when 'productCode'        then @result[:aws_product_codes] << @text
          when 'kernel'             then @result[:aws_kernel]  = @text
          when 'ramdisk'            then @result[:aws_ramdisk] = @text
          when 'blockDeviceMapping' then @result[:block_device_mapping] = @text
        end
      end
      def reset
        @result = {}
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Instances
  #-----------------------------------------------------------------

    class QEc2DescribeInstancesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
           # DescribeInstances property
        if (name == 'item' && @xmlpath == 'DescribeInstancesResponse/reservationSet') ||
           # RunInstances property
           (name == 'RunInstancesResponse')
            @reservation = { :aws_groups    => [],
                             :instances_set => [] }

        elsif (name == 'item') &&
                # DescribeInstances property
              ( @xmlpath=='DescribeInstancesResponse/reservationSet/item/instancesSet' ||
               # RunInstances property
                @xmlpath=='RunInstancesResponse/instancesSet' )
              # the optional params (sometimes are missing and we dont want them to be nil)
            @instance = { :aws_reason       => '',
                          :dns_name         => '',
                          :private_dns_name => '',
                          :ami_launch_index => '',
                          :ssh_key_name     => '',
                          :aws_state        => '',
                          :aws_product_codes => [] }
        end
      end
      def tagend(name)
        case name
          # reservation
          when 'reservationId'    then @reservation[:aws_reservation_id] = @text
          when 'ownerId'          then @reservation[:aws_owner]          = @text
          when 'groupId'          then @reservation[:aws_groups]        << @text
          # instance
          when 'instanceId'       then @instance[:aws_instance_id]    = @text
          when 'imageId'          then @instance[:aws_image_id]       = @text
          when 'dnsName'          then @instance[:dns_name]           = @text
          when 'privateDnsName'   then @instance[:private_dns_name]   = @text
          when 'reason'           then @instance[:aws_reason]         = @text
          when 'keyName'          then @instance[:ssh_key_name]       = @text
          when 'amiLaunchIndex'   then @instance[:ami_launch_index]   = @text
          when 'code'             then @instance[:aws_state_code]     = @text
          when 'name'             then @instance[:aws_state]          = @text
          when 'productCode'      then @instance[:aws_product_codes] << @text
          when 'instanceType'     then @instance[:aws_instance_type]  = @text
          when 'launchTime'       then @instance[:aws_launch_time]    = @text
          when 'kernelId'         then @instance[:aws_kernel_id]      = @text
          when 'ramdiskId'        then @instance[:aws_ramdisk_id]     = @text
          when 'platform'         then @instance[:aws_platform]       = @text
          when 'availabilityZone' then @instance[:aws_availability_zone] = @text
          when 'item'
            if @xmlpath == 'DescribeInstancesResponse/reservationSet/item/instancesSet' || # DescribeInstances property
               @xmlpath == 'RunInstancesResponse/instancesSet'            # RunInstances property
              @reservation[:instances_set] << @instance
            elsif @xmlpath=='DescribeInstancesResponse/reservationSet'    # DescribeInstances property
              @result << @reservation
            end
          when 'RunInstancesResponse' then @result << @reservation            # RunInstances property
        end
      end
      def reset
        @result = []
      end
    end

    class QEc2ConfirmProductInstanceParser < RightAWSParser #:nodoc:
      def tagend(name)
        @result = @text if name == 'ownerId'
      end
    end

    class QEc2TerminateInstancesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @instance = {} if name == 'item'
      end
      def tagend(name)
        case name
        when 'instanceId' then @instance[:aws_instance_id] = @text
        when 'code'
          if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
               @instance[:aws_shutdown_state_code] = @text.to_i
          else @instance[:aws_prev_state_code]     = @text.to_i end
        when 'name'
          if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
               @instance[:aws_shutdown_state] = @text
          else @instance[:aws_prev_state]     = @text end
        when 'item'       then @result << @instance
        end
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Console
  #-----------------------------------------------------------------

    class QEc2GetConsoleOutputParser < RightAWSParser #:nodoc:
      def tagend(name)
        case name
        when 'instanceId' then @result[:aws_instance_id] = @text
        when 'timestamp'  then @result[:aws_timestamp]   = @text
                               @result[:timestamp]       = (Time.parse(@text)).utc
        when 'output'     then @result[:aws_output]      = Base64.decode64(@text)
        end
      end
      def reset
        @result = {}
      end
    end

  #-----------------------------------------------------------------
  #      Instances: Wondows related part
  #-----------------------------------------------------------------
    class QEc2DescribeBundleTasksParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @bundle = {} if name == 'item'
      end
      def tagend(name)
        case name
#        when 'requestId'  then @bundle[:request_id]    = @text
        when 'instanceId' then @bundle[:aws_instance_id]   = @text
        when 'bundleId'   then @bundle[:aws_id]            = @text
        when 'bucket'     then @bundle[:s3_bucket]         = @text
        when 'prefix'     then @bundle[:s3_prefix]         = @text
        when 'startTime'  then @bundle[:aws_start_time]    = @text
        when 'updateTime' then @bundle[:aws_update_time]   = @text
        when 'state'      then @bundle[:aws_state]         = @text
        when 'progress'   then @bundle[:aws_progress]      = @text
        when 'code'       then @bundle[:aws_error_code]    = @text
        when 'message'    then @bundle[:aws_error_message] = @text
        when 'item'       then @result                    << @bundle
        end
      end
      def reset
        @result = []
      end
    end

    class QEc2BundleInstanceParser < RightAWSParser #:nodoc:
      def tagend(name)
        case name
#        when 'requestId'  then @result[:request_id]    = @text
        when 'instanceId' then @result[:aws_instance_id]   = @text
        when 'bundleId'   then @result[:aws_id]            = @text
        when 'bucket'     then @result[:s3_bucket]         = @text
        when 'prefix'     then @result[:s3_prefix]         = @text
        when 'startTime'  then @result[:aws_start_time]    = @text
        when 'updateTime' then @result[:aws_update_time]   = @text
        when 'state'      then @result[:aws_state]         = @text
        when 'progress'   then @result[:aws_progress]      = @text
        when 'code'       then @result[:aws_error_code]    = @text
        when 'message'    then @result[:aws_error_message] = @text
        end
      end
      def reset
        @result = {}
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Elastic IPs
  #-----------------------------------------------------------------

    class QEc2AllocateAddressParser < RightAWSParser #:nodoc:
      def tagend(name)
        @result = @text if name == 'publicIp'
      end
    end

    class QEc2DescribeAddressesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @address = {} if name == 'item'
      end
      def tagend(name)
        case name
        when 'instanceId' then @address[:instance_id] = @text.blank? ? nil : @text
        when 'publicIp'   then @address[:public_ip]   = @text
        when 'item'       then @result << @address
        end
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: AvailabilityZones
  #-----------------------------------------------------------------

    class QEc2DescribeAvailabilityZonesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @zone = {} if name == 'item'
      end
      def tagend(name)
        case name
        when 'regionName' then @zone[:region_name] = @text
        when 'zoneName'   then @zone[:zone_name]   = @text
        when 'zoneState'  then @zone[:zone_state]  = @text
        when 'item'      then @result << @zone
        end
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: Regions
  #-----------------------------------------------------------------

    class QEc2DescribeRegionsParser < RightAWSParser #:nodoc:
      def tagend(name)
        @result << @text if name == 'regionName'
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: EBS - Volumes
  #-----------------------------------------------------------------

    class QEc2CreateVolumeParser < RightAWSParser #:nodoc:
      def tagend(name)
        case name
          when 'volumeId'         then @result[:aws_id]         = @text
          when 'status'           then @result[:aws_status]     = @text
          when 'createTime'       then @result[:aws_created_at] = Time.parse(@text)
          when 'size'             then @result[:aws_size]       = @text.to_i ###
          when 'snapshotId'       then @result[:snapshot_id]    = @text.blank? ? nil : @text ###
          when 'availabilityZone' then @result[:zone]           = @text ###
        end
      end
      def reset
        @result = {}
      end
    end

    class QEc2AttachAndDetachVolumeParser < RightAWSParser #:nodoc:
      def tagend(name)
        case name
          when 'volumeId'   then @result[:aws_id]                = @text
          when 'instanceId' then @result[:aws_instance_id]       = @text
          when 'device'     then @result[:aws_device]            = @text
          when 'status'     then @result[:aws_attachment_status] = @text
          when 'attachTime' then @result[:aws_attached_at]       = Time.parse(@text)
        end
      end
      def reset
        @result = {}
      end
    end

    class QEc2DescribeVolumesParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        case name
        when 'item'
          case @xmlpath
            when 'DescribeVolumesResponse/volumeSet' then @volume = {}
          end
        end
      end
      def tagend(name)
        case name
          when 'volumeId'
            case @xmlpath
            when 'DescribeVolumesResponse/volumeSet/item' then @volume[:aws_id] = @text
            end
          when 'status'
            case @xmlpath
            when 'DescribeVolumesResponse/volumeSet/item' then @volume[:aws_status] = @text
            when 'DescribeVolumesResponse/volumeSet/item/attachmentSet/item' then @volume[:aws_attachment_status] = @text
            end
          when 'size'             then @volume[:aws_size]        = @text.to_i
          when 'createTime'       then @volume[:aws_created_at]  = Time.parse(@text)
          when 'instanceId'       then @volume[:aws_instance_id] = @text
          when 'device'           then @volume[:aws_device]      = @text
          when 'attachTime'       then @volume[:aws_attached_at] = Time.parse(@text)
          when 'snapshotId'       then @volume[:snapshot_id]     = @text.blank? ? nil : @text
          when 'availabilityZone' then @volume[:zone]            = @text
          when 'item'
            case @xmlpath
            when 'DescribeVolumesResponse/volumeSet' then @result << @volume
            end
        end
      end
      def reset
        @result = []
      end
    end

  #-----------------------------------------------------------------
  #      PARSERS: EBS - Snapshots
  #-----------------------------------------------------------------

    class QEc2DescribeSnapshotsParser < RightAWSParser #:nodoc:
      def tagstart(name, attributes)
        @snapshot = {} if name == 'item'
      end
      def tagend(name)
        case name
          when 'volumeId'   then @snapshot[:aws_volume_id]  = @text
          when 'snapshotId' then @snapshot[:aws_id]         = @text
          when 'status'     then @snapshot[:aws_status]     = @text
          when 'startTime'  then @snapshot[:aws_started_at] = Time.parse(@text)
          when 'progress'   then @snapshot[:aws_progress]   = @text
          when 'item'       then @result                   << @snapshot
        end
      end
      def reset
        @result = []
      end
    end

    class QEc2CreateSnapshotParser < RightAWSParser #:nodoc:
      def tagend(name)
        case name
          when 'volumeId'   then @result[:aws_volume_id]  = @text
          when 'snapshotId' then @result[:aws_id]         = @text
          when 'status'     then @result[:aws_status]     = @text
          when 'startTime'  then @result[:aws_started_at] = Time.parse(@text)
          when 'progress'   then @result[:aws_progress]   = @text
        end
      end
      def reset
        @result = {}
      end
    end

  end

end


text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Fakturace_2009.StorageEngines;
using Fakturace_2009.Backbone;

namespace Fakturace_2009.GUI
{
    public partial class StatisticsForm : Form
    {
        FakturaceStorage Storage;

        private bool loaded = false;

        public StatisticsForm(FakturaceStorage storage)
        {
            InitializeComponent();
            Storage = storage;

            List<FakturaFingerprint> faktury = Storage.FakturaGetFprints();
            if (faktury.Count > 0)
            {
                DateTime first = DateTime.Now;
                DateTime last = DateTime.Now;

                foreach (FakturaFingerprint f in faktury)
                {
                    if (f.datumVytvoreni.CompareTo(first) < 0)
                        first = f.datumVytvoreni;
                    if (f.datumVytvoreni.CompareTo(last) > 0)
                        last = f.datumVytvoreni;
                }

                PocatekDate.MinDate = first;
                PocatekDate.Value = first;
                KonecDate.MaxDate = last;
                KonecDate.Value = last;

                loaded = true;

                labelPocet.Text = faktury.Count.ToString();

            }
            else
            {
                PocatekDate.Enabled = false;
                KonecDate.Enabled = false;
            }

            foreach (PolozkaFakturyTyp t in Storage.TypyPolozekGet())
            {
                comboBoxTyp.Items.Add(t.Nazev);
            }
        }

        Faktura[] vybraneFaktury;

        private bool UpdateVybraneFaktury()
        {
            try
            {
                vybraneFaktury = Storage.FakturaGetRange(PocatekDate.Value, KonecDate.Value);
                return true;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Chyba pøi získávání statistik", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.ResumeLayout();
                this.Cursor = Cursors.Default;
                return false;
            }
        }

        private void VypocitatZaObdobi()
        {
            if (vybraneFaktury == null) return;

            decimal celkem = 0, celkemDPH = 0, celkemTyp = 0;
            int pocetFaktur = 0, pocetPolozek = 0;

            this.Cursor = Cursors.WaitCursor;
            this.SuspendLayout();

            foreach (Faktura f in vybraneFaktury)
            {
                celkem += f.CenaCelkem;
                celkemDPH += f.CenaDPH;
                pocetPolozek += f.PolozkyNaFakture.Count;

                if (comboBoxTyp.Text != "")
                {
                    celkemTyp += f.CenaCelkemTypu(comboBoxTyp.Text );
                }
            }

            pocetFaktur = vybraneFaktury.Length;

            this.ResumeLayout();
            this.Cursor = Cursors.Default;

            labelCelkDPH.Text = celkemDPH.ToString("C");
            labelCelkSDPH.Text = (celkem + celkemDPH).ToString("C");
            labelPolCelk.Text = celkem.ToString("C");
            labelPocet.Text = pocetFaktur.ToString();
            labelPolozek.Text = pocetPolozek.ToString();
            labelAvgFak.Text = ((celkem + celkemDPH) / pocetFaktur).ToString("C");
            labelAvgPol.Text = (celkem / pocetPolozek).ToString("C");
            labelCelkemTyp.Text = celkemTyp.ToString("C");
        }

        private void PocatekDate_ValueChanged(object sender, EventArgs e)
        {
            if (!loaded) return;
            //KonecDate.MinDate = PocatekDate.Value;
            if (UpdateVybraneFaktury())
                VypocitatZaObdobi();
        }

        private void KonecDate_ValueChanged(object sender, EventArgs e)
        {
            if (!loaded) return;
            //PocatekDate.MaxDate = KonecDate.Value;
            if (UpdateVybraneFaktury())
                VypocitatZaObdobi();
        }

        private void comboBoxTyp_TextUpdate(object sender, EventArgs e)
        {
            VypocitatZaObdobi();
        }

        private void buttonRecomp_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            UpdateVybraneFaktury();

            VypocitatZaObdobi();

            this.Cursor = Cursors.Arrow;
        }

        private void comboBoxTyp_SelectedValueChanged(object sender, EventArgs e)
        {
            VypocitatZaObdobi();
        }

        private void StatisticsForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                this.DialogResult = DialogResult.Cancel;
                this.Close();
            }
        }

    }
}

redpajama_set_name: RedPajamaGithub


text:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Characters.FirstPerson;

public class FlashbackMoveToPos : MonoBehaviour {

    public FlashbackController flashback;
    public FirstPersonController fpc;
    public bool go = false;
    public StarGazing1_StarMap star1;
    public StarMapOverlay overlay;
    public StarGazing2_Telescope star2;

    void OnTriggerEnter(Collider col)
    {
        if (col.gameObject.tag == "Player" && go)
        {
            if (flashback)
            {
                flashback.movePlayer = false;
            }
            else if (star1)
            {
                star1.movePlayer = false;
                FindObjectOfType<SceneTransitions>().UpdateSceneState(subSceneState.STARGAZING1);
            }
            else if (star2)
            {
                star2.movePlayer = false;
                star2.StartCoroutine(star2.telescope());
            }

            go = false;
        }
    }

    private void OnTriggerStay(Collider col)
    {
        if (col.gameObject.tag == "Player" && go)
        {
            if (flashback)
            {
                flashback.movePlayer = false;
            }
            else if (star1)
            {
                star1.movePlayer = false;
                overlay.Overlay();
            }
            else if (star2)
            {
                star2.movePlayer = false;
                star2.StartCoroutine(star2.telescope());
            }

            go = false;
        }
    }
}


text:
#ifndef HOOLANG_DECLARATIONSTATEMENT_HH
#define HOOLANG_DECLARATIONSTATEMENT_HH

#include <hoo/ast/Declaration.hh>
#include <hoo/ast/Statement.hh>

#include <memory>

namespace hoo {
    namespace ast {
        class DeclarationStatement : public Statement {
        private:
            std::shared_ptr<Declaration> _declaration;

        public:
            explicit DeclarationStatement(std::shared_ptr<Declaration> declaration);

        public:
            std::shared_ptr<Declaration> GetDeclaration();
        };
    }
}

#endif //HOOLANG_DECLARATIONSTATEMENT_HH


text:
<?php
// Copyright 2017 DAIMTO ([Linda Lawton](https://twitter.com/LindaLawtonDK)) :  [www.daimto.com](http://www.daimto.com/)
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by DAIMTO-Google-apis-Sample-generator 1.0.0
//     Template File Name:  methodTemplate.tt
//     Build date: 2017-10-08
//     PHP generator version: 1.0.0
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
// About
//
// Unofficial sample for the safebrowsing v4 API for PHP.
// This sample is designed to be used with the Google PHP client library. (https://github.com/google/google-api-php-client)
//
// API Description: Enables client applications to check web resources (most commonly URLs) against Google-generated lists of unsafe web resources.
// API Documentation Link https://developers.google.com/safe-browsing/
//
// Discovery Doc  https://www.googleapis.com/discovery/v1/apis/safebrowsing/v4/rest
//
//------------------------------------------------------------------------------
// Installation
//
// The preferred method is via https://getcomposer.org. Follow the installation instructions https://getcomposer.org/doc/00-intro.md
// if you do not already have composer installed.
//
// Once composer is installed, execute the following command in your project root to install this library:
//
// composer require google/apiclient:^2.0
//
//------------------------------------------------------------------------------
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
session_start();

/***************************************************
* Include this line for service account authencation.  Note: Not all APIs support service accounts.
//require_once __DIR__ . '/ServiceAccount.php';
* Include the following four lines Oauth2 authencation.
* require_once __DIR__ . '/Oauth2Authentication.php';
* $_SESSION['mainScript'] = basename($_SERVER['PHP_SELF']);   // Oauth2callback.php will return here.
* $client = getGoogleClient();
* $service = new Google_Service_Safebrowsing($client);
****************************************************/

// Option paramaters can be set as needed.
 $optParams = array(
  'fields' => '*'
);
// Single Request.
$results = threatListUpdatesFetchExample($service, $optParams);

/**
* Fetches the most recent threat list updates. A client can request updatesfor multiple lists at once.
* @service Authenticated Safebrowsing service.
* @optParams Optional paramaters are not required by a request.
* @return FetchThreatListUpdatesResponse
*/
function threatListUpdatesFetchExample($service, $optParams)
{
	try
	{
		// Parameter validation.
		if ($service == null)
			throw new Exception("service is required.");
		if ($optParams == null)
			throw new Exception("optParams is required.");
		// Make the request and return the results.
		return $service->threatListUpdates->FetchThreatListUpdates($optParams);
	}
	catch (Exception $e)
	{
		print "An error occurred: " . $e->getMessage();
	}
}
?>


text:
package com.cleeng.api.domain.async;

import com.cleeng.api.AsyncRequestCallback;
import com.cleeng.api.domain.FlowDescription;

public class AsyncGenerateCheckoutUrlRequest extends AsyncRequest {

    public String publisherToken;

    public String customerEmail;

    public FlowDescription flowDescription;

    public AsyncGenerateCheckoutUrlRequest(String publisherToken,
                                           String customerEmail,
                                           FlowDescription flowDescription,
                                           AsyncRequestCallback callback) {
        super();

        this.callback = callback;
        this.publisherToken = publisherToken;
        this.customerEmail = customerEmail;
        this.flowDescription = flowDescription;
    }
}


text:
/**
 * \file
 * \brief Standard headers for kernel code.
 *
 * All C source in the kernel should include this file first.
 * This file should contain only definitions and prototypes that are
 * required for the majority of kernel code.
 */

/*
 * Copyright (c) 2007, 2008, 2009, 2010, 2016, ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

#ifndef __KERNEL_H
#define __KERNEL_H

#include <assert.h>
#include <stddef.h>
#include <stdio.h> // printf for debug
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <barrelfish_kpi/types.h>
#include <barrelfish_kpi/cpu.h>
#include <barrelfish_kpi/registers_arch.h>
#include <errors/errno.h>
#include <bitmacros.h>
#include <debug.h>
#include <offsets.h> /* XXX */
#include <schedule.h>
#include <logging.h>

extern const char *kernel_command_line;
extern coreid_t my_core_id;

bool arch_core_is_bsp(void);

/*
 * Utility macros.
 * FIXME: should we move these elsewhere?
 */

/** Macro to return the number of entries in a statically-allocated array. */
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))

/// Round up n to the next multiple of size
#define ROUND_UP(n, size)           ((((n) + (size) - 1)) & (~((size) - 1)))

#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif

/**
 * \brief Align block at base_addr with size n to power of two
 * alignable at its size
 *
 * Compute the highest exponent x of n so that 2^x \< n _and_
 * the base_addr is aligned at its size.
 * For example: n = 20, base_addr = 4 => size can be 1, 2 or 4.
 * Biggest possible block is 4 => x = 2
 *
 * \param n         Size of the block to split in bytes
 * \param base_addr Base address of the block to split
 *
 * \return Highest exponent (bits) for the blocksize to use next
 */

/// Computes the floor of log_2 of the given number
static inline uint8_t log2flr(uintptr_t num)
{
    uint8_t l = 0;
    uintptr_t n;
    for (n = num; n > 1; n >>= 1, l++);
    return l;
}

/// Computes the ceiling of log_2 of the given number
static inline uint8_t log2cl(uintptr_t num)
{
    uint8_t l = log2flr(num);
    if (num == ((uintptr_t)1) << l) { /* fencepost case */
        return l;
    } else {
        return l + 1;
    }
}

static inline int bitaddralign(size_t n, lpaddr_t base_addr)
{
    int exponent = sizeof(size_t) * NBBY - 1;

    if(n == 0) {
        return 0;
    }

    while ((exponent > 0) && ((base_addr % (1UL << exponent)) != 0)){
        exponent--;
    }
    return((1UL << exponent) > n ? log2flr(n) : exponent);
}

void wait_cycles(uint64_t duration);
void kernel_startup_early(void);
void kernel_startup(void) __attribute__ ((noreturn));

/**
 * kernel timeslice in system ticks
 */
extern systime_t kernel_timeslice;

/**
 * command-line option for kernel timeslice in milliseconds
 */
extern unsigned int config_timeslice;

/**
 * variable for gating timer interrupts.
 */
extern bool kernel_ticks_enabled;

extern lvaddr_t kernel_trace_buf;

extern struct capability monitor_ep;

/*
 * Variant based on Padraig Brady's implementation
 * http://www.pixelbeat.org/programming/gcc/static_assert.html
 */
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)

/* These can't be used after statements in c89. */
#ifdef __COUNTER__
  /* Microsoft compiler. */
  #define STATIC_ASSERT(e,m) \
    enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }
#else
  /* This can't be used twice on the same line so ensure if using in headers
   * that the headers are not included twice (by wrapping in #ifndef...#endif)
   * Note it doesn't cause an issue when used on same line of separate modules
   * compiled with gcc -combine -fwhole-program.  */
  #define STATIC_ASSERT(e,m) \
    enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
#endif

#define STATIC_ASSERT_SIZEOF(tname,n)                   \
    STATIC_ASSERT(sizeof(tname) == n,                   \
        ASSERT_CONCAT("Size mismatch:", tname)          \
        )

#define sa_offsetof(x,y) ((size_t)(((void*)&(((x*)0)->y)) - (void*)(x*)0))

#define STATIC_ASSERT_OFFSETOF(tname, field, offset)    \
    STATIC_ASSERT(sa_offsetof(tname, field) == offset,    \
        ASSERT_CONCAT("Offset mismatch:", field)        \
        )

#endif // __KERNEL_H


text:
// (c) Copyright 2015 Cloudera, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.cloudera.director.spi.v1.model;

/**
 *
Represents the status of an instance in a provider-agnostic way.

 *

 *
Note that for a given provider, some statuses may be unreachable, and some may correspond to
 * multiple distinct provider-specific instance states.

 */
public enum InstanceStatus {

  /**
   * The instance has been requested (initially or after being stopped), but is not yet known to be available.
   */
  PENDING,

  /**
   * The instance is running, although it may not be accessible.
   */
  RUNNING,

  /**
   * The instance is stopping, and may be restarted later.
   */
  STOPPING,

  /**
   * The instance is stopped, and may be restarted.
   */
  STOPPED,

  /**
   * The instance is being removed permanently.
   */
  DELETING,

  /**
   * The instance has been removed permanently.
   */
  DELETED,

  /**
   * The instance has failed, and cannot be reused.
   */
  FAILED,

  /**
   * The instance state cannot be determined.
   */
  UNKNOWN
}


text:
<?php

namespace spec\BenGorUser\User\Application\Command\Remove;

use BenGorUser\User\Application\Command\Remove\RemoveUserCommand;
use BenGorUser\User\Application\Command\Remove\RemoveUserHandler;
use BenGorUser\User\Domain\Model\Exception\UserDoesNotExistException;
use BenGorUser\User\Domain\Model\User;
use BenGorUser\User\Domain\Model\UserId;
use BenGorUser\User\Domain\Model\UserRepository;
use PhpSpec\ObjectBehavior;

/**
 * Spec file of RemoveUserCommand class.
 *
 * @author Beñat Espiña <benatespina@gmail.com>
 * @author Gorka Laucirica <gorka.lauzirika@gmail.com>
 */
class RemoveUserHandlerSpec extends ObjectBehavior
{
    function let(UserRepository $repository)
    {
        $this->beConstructedWith($repository);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType(RemoveUserHandler::class);
    }

    function it_does_not_remove_because_user_does_no_exist(RemoveUserCommand $command, UserRepository $repository)
    {
        $command->id()->shouldBeCalled()->willReturn('non-exist-user-id');
        $repository->userOfId(new UserId('non-exist-user-id'))->shouldBeCalled()->willReturn(null);

        $this->shouldThrow(UserDoesNotExistException::class)->during__invoke($command);
    }

    function it_removes_user(RemoveUserCommand $command, UserRepository $repository, User $user)
    {
        $command->id()->shouldBeCalled()->willReturn('user-id');

        $repository->userOfId(new UserId('user-id'))->shouldBeCalled()->willReturn($user);
        $repository->remove($user)->shouldBeCalled();

        $this->__invoke($command);
    }
}


text:
package org.pikater.core.ontology.subtrees.openml;

import jade.content.AgentAction;

public class ExportDataset implements AgentAction {

	private static final long serialVersionUID = 8475049934695874698L;

	private String path;

	private String name;
	private String description;
	private String type;

	public String getPath() {
		return path;
	}
	/**
	 * Sets the path to the file in the local file system, that should be uploaded to OpenMl.org .
	 * @param path
	 */
	public void setPath(String path) {
		this.path = path;
	}
	public String getName() {
		return name;
	}
	/**
	 * Sets the name of the dataset, that will appear in the repository of OpenML.org
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
}


text:
package newsletter

// [START utility_example_1]
import (
	"testing"

	"google.golang.org/appengine/aetest"
)

func TestWithContext(t *testing.T) {
	ctx, done, err := aetest.NewContext()
	if err != nil {
		t.Fatal(err)
	}
	defer done()

	// Run code and tests requiring the context.Context using ctx.
	// [START_EXCLUDE]
	check(t, ctx)
	// [END_EXCLUDE]
}

// [END utility_example_1]

func check(t *testing.T, ctx interface{}) {
}


text:
@interface LaunchViewController : UIViewController

- (IBAction)startNewGame:(id)sender;

@end


text:
Template.contentMeetup.helpers({
    formatTime: function(time) {
        return moment(time).format('MMMM Do YYYY');
    },

    round: function(value) {
        return Math.round(value);
    }
});


text:
<?php

namespace AlphaLabs\Pagination\Provider;

use AlphaLabs\Pagination\PaginatedCollection\PaginatedCollectionRequestInterface;

interface PaginatedCollectionRequestProviderInterface
{
    /**
     * Provide the current pagination request
     *
     * Returns null if the current context does not provide any pagination information.
     *
     * @return PaginatedCollectionRequestInterface|null
     */
    public function getPaginatedCollectionRequest();
}


text:
This is just a braindump wishlist:

# Type Info Wishlist

* Dequalify qualified names, and somehow visually make it apparent that this
  happened? Hovering over the portion would tell you the full name.

* Explanations for builtin type syntax.  For example, explanations of
forall, (=>), tuples, lists, etc.  These could also be made into links
to relevant documentation, though that might bug advanced users (could
make this a setting).

  - Would also apply to highlighted expressions etc, could possibly
  also apply to code in the editor.

* Highlighting of AST nodes of the type on hover.  This lets the user
know the structure of the type's AST, and can aid in learning Haskell
syntax.  Unfortunately, this is not possible to do perfectly with our
current information, because we need fixities.  Even for advanced
users, this will be helpful for understanding types that involve infix
operators.

  - For expressions within the editor, the above is already given by type
  info.

* Allow type synonyms to be replaced by definitions and vice versa.

  - The equivalent in expressions would be inlining and abstraction
  refactorings.

I think the best implementation strategy for the items above is to
expose annotated ASTs from ide-backend, possibly involving
modifications of GHC itself.  Until then, we'll stick to the
haskell-src-exts / autocomplete map annotation of type info.

# Identifier info

* Fall back on hoogle when identifier info fails.  Might be best to implement
this at the stack-ide level so that all clients can benefit.


text:
class Calculator {

  constructor(screen="calc__total") {
    this.val = [];
    this.operator = "";
    this.screen = document.getElementsByClassName(screen)[0];
  }

  init() {
    this.setScreen();
    this.setNumKeyListeners();
    this.setOperatorKeyListeners();
    this.setBackspaceKeyListeners();
  }

  setScreen() {
    this.screen.innerHTML = (this.val.length == 0) ? "" : this.val.join('');
    console.log(this);
  }

  setNumKeyListeners() {
    let numKeys = document.getElementsByClassName("calc__int");

    for (let i = 0; i < numKeys.length; i++) {
      numKeys[i].addEventListener('click', (event) => {
        return this.pushScreenValue(event.target.innerHTML);
      });
    }
  }

  setOperatorKeyListeners() {
    let operatorKeys = document.getElementsByClassName("calc__operator");
    // let operators = ["/","*","-","+","="];

    for (let i = 0; i < operatorKeys.length; i++) {
      operatorKeys[i].addEventListener('click', (event) => {
        console.log(event.target.innerHTML);
      });
    }
  }

  setBackspaceKeyListeners() {
    let backspace = document.getElementsByClassName("calc__backspace");
    backspace[0].addEventListener('click', () => this.popScreenValue());
  }

  pushScreenValue(value) {
    this.val.push(value);
    this.setScreen();
  }

  popScreenValue(value) {
    (this.val.length == 1) ? this.clear() : this.val.pop();
    this.setScreen();
  }

  add(value) {
    return this.val += value;
  }

  subtract(value) {
    return this.val -= value;
  }

  multiply(value) {
    return this.val *= value;
  }

  divide(value) {
    return this.val /= value;
  }

  clear() {
    return this.val = [];
  }

}

export default Calculator;