# File lib/net/ssh/transport/algorithm-negotiator.rb, line 101
        def negotiate( session, options )
          prepare_preferred_algorithms options

          # first, discover what the server can do
          type, buffer = session.wait_for_message
          raise Net::SSH::Exception, "expected KEXINIT" unless type == KEXINIT

          server_algorithm_packet = buffer.content

          cookie = buffer.read( 16 )
          kex_algorithms = buffer.read_string
          server_host_key_algorithms = buffer.read_string
          encryption_algorithms_client_to_server = buffer.read_string
          encryption_algorithms_server_to_client = buffer.read_string
          mac_algorithms_client_to_server = buffer.read_string
          mac_algorithms_server_to_client = buffer.read_string
          compression_algorithms_client_to_server = buffer.read_string
          compression_algorithms_server_to_client = buffer.read_string
          languages_client_to_server = buffer.read_string
          languages_server_to_client = buffer.read_string
          first_kex_packet_follows = buffer.read_bool
          zero = buffer.read_long

          # TODO: if first_kex_packet_follows, we need to try to skip the
          # actual kexinit stuff and try to guess what the server is doing...
          # need to read more about this scenario.

          # next, tell the server what we can do

          my_kex = @algorithms[ :kex ].join( "," )
          my_server_host_key_algorithms = @algorithms[ :host_key ].join( "," )
          my_encryption_algorithms = @algorithms[ :encryption ].join( "," )
          my_mac_algorithms = @algorithms[ :hmac ].join( "," )
          my_compression_algorithms = @algorithms[ :compression ].join( "," )
          my_languages = @algorithms[ :languages ].join( "," )

          msg = @buffers.writer
          msg.write_byte KEXINIT
          msg.write_long rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF),
            rand(0xFFFFFFFF)
          msg.write_string my_kex, my_server_host_key_algorithms
          msg.write_string my_encryption_algorithms, my_encryption_algorithms
          msg.write_string my_mac_algorithms, my_mac_algorithms
          msg.write_string my_compression_algorithms, my_compression_algorithms
          msg.write_string my_languages, my_languages
          msg.write_bool false
          msg.write_long 0

          client_algorithm_packet = msg.to_s
          session.send_message msg

          # negotiate algorithms

          kex_algorithm = first_matching_element( @algorithms[ :kex ],
            kex_algorithms )
          raise Net::SSH::Exception,
            "could not settle on kex algorithm" unless kex_algorithm
          @logger.debug "kex algorithm: #{kex_algorithm}" if @logger.debug?

          host_key_algorithm = first_matching_element(
            @algorithms[ :host_key ], server_host_key_algorithms )
          raise Net::SSH::Exception,
            "could not settle on host key algorithm" unless host_key_algorithm
          if @logger.debug?
            @logger.debug "host key algorithm: #{host_key_algorithm}"
          end

          encryption_algorithm_c2s = first_matching_element(
            @algorithms[ :encryption ], encryption_algorithms_client_to_server )
          unless encryption_algorithm_c2s
            raise Net::SSH::Exception,
              "could not settle on client-to-server encryption algorithm"
          end
          if @logger.debug?
            @logger.debug "encryption algorithm (client-to-server): " +
              encryption_algorithm_c2s
          end

          encryption_algorithm_s2c = first_matching_element(
            @algorithms[ :encryption ], encryption_algorithms_server_to_client )
          unless encryption_algorithm_s2c
            raise Net::SSH::Exception,
              "could not settle on server-to-client encryption algorithm"
          end
          if @logger.debug?
            @logger.debug "encryption algorithm (server-to-client): " +
              encryption_algorithm_s2c
          end

          mac_algorithm_c2s = first_matching_element(
            @algorithms[ :hmac ], mac_algorithms_client_to_server )
          unless mac_algorithm_c2s
            raise Net::SSH::Exception,
              "could not settle on client-to-server HMAC algorithm"
          end
          if @logger.debug?
            @logger.debug "hmac algorithm (client-to-server): " +
              mac_algorithm_c2s
          end

          mac_algorithm_s2c = first_matching_element( @algorithms[ :hmac ],
            mac_algorithms_server_to_client )
          unless mac_algorithm_s2c
            raise Net::SSH::Exception,
              "could not settle on server-to-client HMAC algorithm"
          end
          if @logger.debug?
            @logger.debug "hmac algorithm (server-to-client): " +
              mac_algorithm_s2c
          end

          compression_algorithm_c2s = first_matching_element(
            @algorithms[ :compression ],
            compression_algorithms_client_to_server )
          unless compression_algorithm_c2s
            raise Net::SSH::Exception,
              "could not settle on client-to-server compression algorithm"
          end
          if @logger.debug?
            @logger.debug "compression algorithm (client-to-server): " +
              compression_algorithm_c2s
          end

          compression_algorithm_s2c = first_matching_element(
            @algorithms[ :compression ],
            compression_algorithms_server_to_client )
          unless compression_algorithm_s2c
            raise Net::SSH::Exception,
              "could not settle on server-to-client compression algorithm"
          end
          if @logger.debug?
            @logger.debug "compression algorithm (server-to-client): " +
              compression_algorithm_s2c
          end

          language_c2s = first_matching_element( @algorithms[ :languages ],
            languages_client_to_server ) || ""
          if @logger.debug?
            @logger.debug "language (client-to-server): #{language_c2s}"
          end

          language_s2c = first_matching_element( @algorithms[ :languages ],
            languages_server_to_client ) || ""
          if @logger.debug?
            @logger.debug "language (server-to-client): #{language_s2c}"
          end

          return Algorithms.new( server_algorithm_packet,
                                 client_algorithm_packet,
                                 kex_algorithm,
                                 host_key_algorithm,
                                 encryption_algorithm_c2s,
                                 encryption_algorithm_s2c,
                                 mac_algorithm_c2s,
                                 mac_algorithm_s2c,
                                 compression_algorithm_c2s,
                                 compression_algorithm_s2c,
                                 language_c2s,
                                 language_s2c,
                                 @compression_level )
        end