About Hashes
	- Empty hashes are created using the literal {} or using Hash.new
	- An empty hash has the size 0
	- Hashes keys and values collections are arrays
	- Accessing a non existent key in a hash using the [] operator will not break, rather nil will be returned; if you want a safer way to do thing, however, you should use Hash#fetch method, this  one will throw if the key is not found
	- Use Hash#merge function to combine two hashes together and return a new one. Keys in the new hash (the passed-in parameter) will override the old ones.
	- Hashes are unorderd and the order of keys will not affect equality comparison
	- When using the Hash#new metho, you can choose to supply a default value, this value will be returned when accessing any hash key that is not specifically initialized. Understandably, this default value will an object shared across all keys (e.g. if the default value is an array or some other object that is considered a reference type, then any modification to this default object will reflect across all uninitizlied keys) .. take the following example:
		hash = Hash.new([]) # the [] array is shared
		hash[:one] << 'one'
		hash[:two] << 'two'
		hash[:one] == hash[:two] == hash[:any_uninitialized_object] == ['one','two'] == true
	- To avoid sharing the default object across all hash keys, you could define a hash with a block like so:
		hash = Hash.new { |ha, key| h[key] = []}
the progress track
changes in progress