```Here is my solution. As a side note, it was probably not the best idea to
stick to the benchmarking code in the quiz, as it forced not the best design
decisions (I'd rather not have default constructor for Rope, and for sure -
no normalizing 'in place'). But - what's done is done.
For slice variants I've decided to have two argument ones in #slice, and one
arg  - in #[]

Results:
String

Build:   0.188000   0.032000   0.220000 (  0.219000)
Sort:   1.578000   0.843000   2.421000 (  2.422000)

Rope

Build:   0.031000   0.000000   0.031000 (  0.031000)
Sort:   0.203000   0.000000   0.203000 (  0.234000)

Code:
-------------------------------------------------------------------------------------------------------------------------
class NilClass
def length; 0; end
end

class String
def shift
return nil if empty?
res=self[0]
self[0]=""
res
end
end

class Rope
attr_reader :length, :left, :right

def initialize(left=nil,right=nil)
@left=left if left
@right=right if right
@length=left.length+right.length
end

def append(what)
len=what.length
if (len>0)
@left=self.dup if @right.length>0
@right=what
@length+=len
end
self
end

alias << append

def prepend(what)
len=what.length
if (len>0)
@right=self.dup if @left.length>0
@left=what
@length+=len
end
self
end

def to_s
@left.to_s+@right.to_s
end

def [](i)
return i.match(self.to_s)[0] if i.kind_of? Regexp
if i.kind_of? Range
pos,last=i.first,i.last
pos=@length+pos if pos<0
last=@length+last if last<0
return nil if pos<0 || last<0
return slice(pos,last-pos+1)
end
i=@length+i if i<0
return nil if i<0 || i>@length-1
llen=@left.length
i<llen ? @left[i] : @right[i-llen]
end

def []=(i,val)
#fixnum only
i=@length+i if i<0
""[i]=0 if i<0 || i>@length-1
@length+=val.length-1
llen=@left.length
i<llen ? @left[i]=val : @right[i-llen]=val
end

def slice(pos,len)
return pos.match(self.to_s)[len] if pos.kind_of? Regexp
pos=@length+pos if pos<0
return nil if pos<0 || len<0 || pos>@length-1
llen=@left.length
return @left.slice(pos,len) if pos+len<=llen
return @right.slice(pos-llen, len) if pos>=llen
Rope.new(@left.slice(pos,len),@right.slice(0,len+pos-llen))
end

def shift
return nil if @length==0
@length-=1
res=@left.length>0 ? @left.shift : @right.shift
@left=nil if @left.length==0
@right=nil if @right.length==0
res
end

def normalize
r=Rebalancer.new(@length)
self.traverse { |str| r.append(str) }
@left,@right=r.get_ropes
end

def traverse(&blck)
@left.kind_of?(String) ? yield(@left) : @left.traverse(&blck) if @left
@right.kind_of?(String) ? yield(@right) : @right.traverse(&blck) if
@right
end

end

class Rebalancer
def initialize len
@limits=[1,2]
@slots=[]
n=2
@limits<<n=@limits[-2]+@limits[-1] while n<len
end

def append str
@slots[0]=@slots[0] ? Rope.new(@slots[0],str) : str
i=0
while @slots[i].length>@limits[i]
@slots[i+1]=@slots[i+1] ? Rope.new(@slots[i+1],@slots[i]) : @slots[i]
@slots[i]=nil
i+=1
end
end

def get_ropes
@slots.compact!
(@slots.length-1).times { |i|
@slots[i+1]=@slots[i+1] ? Rope.new(@slots[i+1],@slots[i]) : @slots[i]
@slots[i]=nil
i+=1
}
[@slots[-1].left,@slots[-1].right]
end
end

```