------------wXkDTjTmcKHHO5WXuKtn0q
Content-Type: text/plain; format=flowed; delsp=yes; charset=iso-8859-15
Content-Transfer-Encoding: 8bit

This was really a very nice quiz. I actually had bookmarked this tutorial,  
but this quiz finally motivated me to read it.

I did two versions: The first versions is an almost literal translation of  
the lisp code (see attachment). It uses Hashes instead of Arrays for some  
stuff and describe_path has a different interface but other than that it's  
very similar to the original. I also used method_missing to allow the user  
to write "pickup bucket" instead of "pickup :bucket".

The second versions (see below and attachment) is still near the lisp  
version but object oriented and more ruby-like.

And thanks to Brian Schröäer and his thread "Eval and block problems" (and  
of course to everybody, who replied): I had a bug in my game_action  
method, I used "block.call" instead of "instance_eval &block". I wouldn't  
have found this without the thread because it actually worked because of  
my method_missing trick...

Here is a walkthrough (spoiler alert ;-):

$ irb --prompt simple -r lispgame.rb
>> WizardGame.start_irb_game
nil
>> help
[describe_floor, describe_location, describe_paths, dunk, get, go, h,  
help, i, inventory, l, look, pickup, pickup_object, splash, take, w, walk,  
walk_direction, weld]
>> l
you are in the living-room of a wizard's house. there is a wizard  
snoring loudly on the couch.
there is a door going west from here. there is a stairway going upstairs  
 from here.
you see a whiskey_bottle on the floor. you see a bucket on the floor.
>> take bucket
you are now carrying the bucket
>> go west
you are in a beautiful garden. there is a well in front of you.
there is a door going east from here.
you see a frog on the floor. you see a chain on the floor.
>> dunk bucket, well
the water level is too low to reach.
>> pickup chain
you are now carrying the chain
>> w east
you are in the living-room of a wizard's house. there is a wizard  
snoring loudly on the couch.
there is a door going west from here. there is a stairway going upstairs  
 from here.
you see a whiskey_bottle on the floor.
>> i
[bucket, chain]
>> w upstairs
you are in the attic of the abandoned house. there is a giant welding  
torch in the corner.
there is a stairway going downstairs from here.

>> weld chain, bucket
the chain is now securely welded to the bucket.
>> w downstairs
you are in the living-room of a wizard's house. there is a wizard  
snoring loudly on the couch.
there is a door going west from here. there is a stairway going upstairs  
 from here.
you see a whiskey_bottle on the floor.
>> w west
you are in a beautiful garden. there is a well in front of you.
there is a door going east from here.
you see a frog on the floor.
>> dunk bucket, well
the bucket is now full of water.
>> w east
you are in the living-room of a wizard's house. there is a wizard  
snoring loudly on the couch.
there is a door going west from here. there is a stairway going upstairs  
 from here.
you see a whiskey_bottle on the floor.
>> splash bucket, wizard
the wizard awakens from his slumber and greets you warmly. he hands you  
the magic low-carb donut- you win! the end.

Dominik


The code of the second version:

class TextAdventureEngine

   Location  truct.new(:description, :paths)
   Path  truct.new(:description, :destination)

   def describe_location
     @map[@location].description
   end

   def describe_paths
     paths  map[@location].paths
     paths.keys.map { |dir|
       "there is a #{paths[dir].description} going #{dir} from here."
     }.join(" ")
   end

   def is_at?(object, location)
     @object_locations[object] location
   end

   def describe_floor
     @objects.find_all { |obj| is_at?(obj, @location) }.map { |obj|
       "you see a #{obj} on the floor."
     }.join(" ")
   end

   def look
     [describe_location, describe_paths, describe_floor].join("\n")
   end

   alias :l :look

   def walk_direction(direction)
     next_loc  map[@location].paths[direction]
     if next_loc
       @location  ext_loc.destination
       look
     else
       "you can't go that way."
     end
   end

   alias :walk :walk_direction
   alias :go :walk_direction
   alias :w :walk_direction

   def pickup_object(object)
     if is_at?(object, @location)
       @object_locations[object]  body
       "you are now carrying the #{object}"
     else
       "you cannot get that."
     end
   end

   alias :pickup :pickup_object
   alias :take :pickup_object
   alias :get :pickup_object

   def inventory
     @objects.find_all { |obj|
       is_at?(obj, :body)
     }.map { |o| o.to_s }
   end

   alias :i :inventory

   def have?(object)
     is_at?(object, :body)
   end

   def help
     (methods - Object.instance_methods).reject { |m| m\?$/ }.sort
   end

   alias :h :help

   def self.game_action(command, subj, obj, place, &block)
     define_method(command) { |subject, object|
       if @location place && subject subj && object obj &&  
have?(subj)
         instance_eval &block
       else
         "i can't #{command} like that."
       end
     }
   end

   def self.start_irb_game
     $irb_ta  elf.new
     Object.class_eval {
       # send missing methods to $irb_ta or return their name as symbol
       def method_missing(m, *a, &b)
         if $irb_ta.respond_to? m
           $irb_ta.send(m, *a, &b)
         elsif (a.empty? && !b)
           m
         else
           super
         end
       end
     }
     String.class_eval {
       # nicer output
       def inspect
         self
       end
     }
   end

end


class WizardGame < TextAdventureEngine

   def initialize
     @objects  :whiskey_bottle, :bucket, :frog, :chain]

     @map  
       :living_room Location.new(
       "you are in the living-room of a wizard's house. there is a wizard  
snoring loudly on the couch.",
       {:west Path.new("door", :garden), :upstairs  
Path.new("stairway", :attic)}
       ),
       :garden Location.new(
       "you are in a beautiful garden. there is a well in front of you.",
       {:east Path.new("door", :living_room)}
       ),
       :attic Location.new(
       "you are in the attic of the abandoned house. there is a giant  
welding torch in the corner.",
       {:downstairs Path.new("stairway", :living_room)}
       )
     }

     @object_locations  
       :whiskey_bottle :living_room,
       :bucket :living_room,
       :chain :garden,
       :frog :garden
     }

     @location  living_room
   end

   game_action(:weld, :chain, :bucket, :attic) {
     if have?(:bucket)
       @chain_welded  rue
       "the chain is now securely welded to the bucket."
     else
       "you do not have a bucket."
     end
   }

   game_action(:dunk, :bucket, :well, :garden) {
     if @chain_welded
       @bucket_filled  rue
       "the bucket is now full of water."
     else
       "the water level is too low to reach."
     end
   }

   game_action(:splash, :bucket, :wizard, :living_room) {
     if not @bucket_filled
       "the bucket has nothing in it."
     elsif have?(:frog)
       "the wizard awakens and sees that you stole his frog. he is so upset  
he banishes you to the netherworlds- you lose! the end."
     else
       "the wizard awakens from his slumber and greets you warmly. he hands  
you the magic low-carb donut- you win! the end."
     end
   }

end
------------wXkDTjTmcKHHO5WXuKtn0q
Content-Disposition: attachment; filename=lispgame.rb
Content-Type: application/octet-stream; name=lispgame.rb
Content-Transfer-Encoding: Base64

CmNsYXNzIFRleHRBZHZlbnR1cmVFbmdpbmUKCglMb2NhdGlvbiA9IFN0cnVjdC5u
ZXcoOmRlc2NyaXB0aW9uLCA6cGF0aHMpCglQYXRoID0gU3RydWN0Lm5ldyg6ZGVz
Y3JpcHRpb24sIDpkZXN0aW5hdGlvbikKCglkZWYgZGVzY3JpYmVfbG9jYXRpb24K
CQlAbWFwW0Bsb2NhdGlvbl0uZGVzY3JpcHRpb24KCWVuZAoKCWRlZiBkZXNjcmli
ZV9wYXRocwoJCXBhdGhzID0gQG1hcFtAbG9jYXRpb25dLnBhdGhzCgkJcGF0aHMu
a2V5cy5tYXAgeyB8ZGlyfAoJCQkidGhlcmUgaXMgYSAje3BhdGhzW2Rpcl0uZGVz
Y3JpcHRpb259IGdvaW5nICN7ZGlyfSBmcm9tIGhlcmUuIgoJCX0uam9pbigiICIp
CgllbmQKCglkZWYgaXNfYXQ/KG9iamVjdCwgbG9jYXRpb24pCgkJQG9iamVjdF9s
b2NhdGlvbnNbb2JqZWN0XSA9PSBsb2NhdGlvbgoJZW5kCgoJZGVmIGRlc2NyaWJl
X2Zsb29yCgkJQG9iamVjdHMuZmluZF9hbGwgeyB8b2JqfCBpc19hdD8ob2JqLCBA
bG9jYXRpb24pIH0ubWFwIHsgfG9ianwKCQkJInlvdSBzZWUgYSAje29ian0gb24g
dGhlIGZsb29yLiIKCQl9LmpvaW4oIiAiKQoJZW5kCgoJZGVmIGxvb2sKCQlbZGVz
Y3JpYmVfbG9jYXRpb24sIGRlc2NyaWJlX3BhdGhzLCBkZXNjcmliZV9mbG9vcl0u
am9pbigiXG4iKQoJZW5kCgoJYWxpYXMgOmwgOmxvb2sKCglkZWYgd2Fsa19kaXJl
Y3Rpb24oZGlyZWN0aW9uKQoJCW5leHRfbG9jID0gQG1hcFtAbG9jYXRpb25dLnBh
dGhzW2RpcmVjdGlvbl0KCQlpZiBuZXh0X2xvYwoJCQlAbG9jYXRpb24gPSBuZXh0
X2xvYy5kZXN0aW5hdGlvbgoJCQlsb29rCgkJZWxzZQoJCQkieW91IGNhbid0IGdv
IHRoYXQgd2F5LiIKCQllbmQKCWVuZAoKCWFsaWFzIDp3YWxrIDp3YWxrX2RpcmVj
dGlvbgoJYWxpYXMgOmdvIDp3YWxrX2RpcmVjdGlvbgoJYWxpYXMgOncgOndhbGtf
ZGlyZWN0aW9uCgoJZGVmIHBpY2t1cF9vYmplY3Qob2JqZWN0KQoJCWlmIGlzX2F0
PyhvYmplY3QsIEBsb2NhdGlvbikKCQkJQG9iamVjdF9sb2NhdGlvbnNbb2JqZWN0
XSA9IDpib2R5CgkJCSJ5b3UgYXJlIG5vdyBjYXJyeWluZyB0aGUgI3tvYmplY3R9
IgoJCWVsc2UKCQkJInlvdSBjYW5ub3QgZ2V0IHRoYXQuIgoJCWVuZAoJZW5kCgoJ
YWxpYXMgOnBpY2t1cCA6cGlja3VwX29iamVjdAoJYWxpYXMgOnRha2UgOnBpY2t1
cF9vYmplY3QKCWFsaWFzIDpnZXQgOnBpY2t1cF9vYmplY3QKCglkZWYgaW52ZW50
b3J5CgkJQG9iamVjdHMuZmluZF9hbGwgeyB8b2JqfAoJCQlpc19hdD8ob2JqLCA6
Ym9keSkKCQl9Lm1hcCB7IHxvfCBvLnRvX3MgfQoJZW5kCgoJYWxpYXMgOmkgOmlu
dmVudG9yeQoKCWRlZiBoYXZlPyhvYmplY3QpCgkJaXNfYXQ/KG9iamVjdCwgOmJv
ZHkpCgllbmQKCglkZWYgaGVscAoJCShtZXRob2RzIC0gT2JqZWN0Lmluc3RhbmNl
X21ldGhvZHMpLnJlamVjdCB7IHxtfCBtPX4vXD8kLyB9LnNvcnQKCWVuZAoKCWFs
aWFzIDpoIDpoZWxwCgoJZGVmIHNlbGYuZ2FtZV9hY3Rpb24oY29tbWFuZCwgc3Vi
aiwgb2JqLCBwbGFjZSwgJmJsb2NrKQoJCWRlZmluZV9tZXRob2QoY29tbWFuZCkg
eyB8c3ViamVjdCwgb2JqZWN0fAoJCQlpZiBAbG9jYXRpb24gPT0gcGxhY2UgJiYg
c3ViamVjdCA9PSBzdWJqICYmIG9iamVjdCA9PSBvYmogJiYgaGF2ZT8oc3ViaikK
CQkJCWluc3RhbmNlX2V2YWwgJmJsb2NrCgkJCWVsc2UKCQkJCSJpIGNhbid0ICN7
Y29tbWFuZH0gbGlrZSB0aGF0LiIKCQkJZW5kCgkJfQoJZW5kCgoJZGVmIHNlbGYu
c3RhcnRfaXJiX2dhbWUKCQkkaXJiX3RhID0gc2VsZi5uZXcKCQlPYmplY3QuY2xh
c3NfZXZhbCB7CgkJCSMgc2VuZCBtaXNzaW5nIG1ldGhvZHMgdG8gJGlyYl90YSBv
ciByZXR1cm4gdGhlaXIgbmFtZSBhcyBzeW1ib2wKCQkJZGVmIG1ldGhvZF9taXNz
aW5nKG0sICphLCAmYikKCQkJCWlmICRpcmJfdGEucmVzcG9uZF90bz8gbQoJCQkJ
CSRpcmJfdGEuc2VuZChtLCAqYSwgJmIpCgkJCQllbHNpZiAoYS5lbXB0eT8gJiYg
IWIpCgkJCQkJbQoJCQkJZWxzZQoJCQkJCXN1cGVyCgkJCQllbmQKCQkJZW5kCgkJ
fQoJCVN0cmluZy5jbGFzc19ldmFsIHsKCQkJIyBuaWNlciBvdXRwdXQKCQkJZGVm
IGluc3BlY3QKCQkJCXNlbGYKCQkJZW5kCgkJfQoJZW5kCgplbmQKCgpjbGFzcyBX
aXphcmRHYW1lIDwgVGV4dEFkdmVudHVyZUVuZ2luZQoKCWRlZiBpbml0aWFsaXpl
CgkJQG9iamVjdHMgPSBbOndoaXNrZXlfYm90dGxlLCA6YnVja2V0LCA6ZnJvZywg
OmNoYWluXQoKCQlAbWFwID0gewoJCQk6bGl2aW5nX3Jvb20gPT4gTG9jYXRpb24u
bmV3KAoJCQkieW91IGFyZSBpbiB0aGUgbGl2aW5nLXJvb20gb2YgYSB3aXphcmQn
cyBob3VzZS4gdGhlcmUgaXMgYSB3aXphcmQgc25vcmluZyBsb3VkbHkgb24gdGhl
IGNvdWNoLiIsCgkJCXs6d2VzdCA9PiBQYXRoLm5ldygiZG9vciIsIDpnYXJkZW4p
LCA6dXBzdGFpcnMgPT4gUGF0aC5uZXcoInN0YWlyd2F5IiwgOmF0dGljKX0KCQkJ
KSwKCQkJOmdhcmRlbiA9PiBMb2NhdGlvbi5uZXcoCgkJCSJ5b3UgYXJlIGluIGEg
YmVhdXRpZnVsIGdhcmRlbi4gdGhlcmUgaXMgYSB3ZWxsIGluIGZyb250IG9mIHlv
dS4iLAoJCQl7OmVhc3QgPT4gUGF0aC5uZXcoImRvb3IiLCA6bGl2aW5nX3Jvb20p
fQoJCQkpLAoJCQk6YXR0aWMgPT4gTG9jYXRpb24ubmV3KAoJCQkieW91IGFyZSBp
biB0aGUgYXR0aWMgb2YgdGhlIGFiYW5kb25lZCBob3VzZS4gdGhlcmUgaXMgYSBn
aWFudCB3ZWxkaW5nIHRvcmNoIGluIHRoZSBjb3JuZXIuIiwKCQkJezpkb3duc3Rh
aXJzID0+IFBhdGgubmV3KCJzdGFpcndheSIsIDpsaXZpbmdfcm9vbSl9CgkJCSkK
CQl9CgoJCUBvYmplY3RfbG9jYXRpb25zID0gewoJCQk6d2hpc2tleV9ib3R0bGUg
PT4gOmxpdmluZ19yb29tLAoJCQk6YnVja2V0ID0+IDpsaXZpbmdfcm9vbSwKCQkJ
OmNoYWluID0+IDpnYXJkZW4sCgkJCTpmcm9nID0+IDpnYXJkZW4KCQl9CgoJCUBs
b2NhdGlvbiA9IDpsaXZpbmdfcm9vbQoJZW5kCgoJZ2FtZV9hY3Rpb24oOndlbGQs
IDpjaGFpbiwgOmJ1Y2tldCwgOmF0dGljKSB7CgkJaWYgaGF2ZT8oOmJ1Y2tldCkK
CQkJQGNoYWluX3dlbGRlZCA9IHRydWUKCQkJInRoZSBjaGFpbiBpcyBub3cgc2Vj
dXJlbHkgd2VsZGVkIHRvIHRoZSBidWNrZXQuIgoJCWVsc2UKCQkJInlvdSBkbyBu
b3QgaGF2ZSBhIGJ1Y2tldC4iCgkJZW5kCgl9CgoJZ2FtZV9hY3Rpb24oOmR1bmss
IDpidWNrZXQsIDp3ZWxsLCA6Z2FyZGVuKSB7CgkJaWYgQGNoYWluX3dlbGRlZAoJ
CQlAYnVja2V0X2ZpbGxlZCA9IHRydWUKCQkJInRoZSBidWNrZXQgaXMgbm93IGZ1
bGwgb2Ygd2F0ZXIuIgoJCWVsc2UKCQkJInRoZSB3YXRlciBsZXZlbCBpcyB0b28g
bG93IHRvIHJlYWNoLiIKCQllbmQKCX0KCglnYW1lX2FjdGlvbig6c3BsYXNoLCA6
YnVja2V0LCA6d2l6YXJkLCA6bGl2aW5nX3Jvb20pIHsKCQlpZiBub3QgQGJ1Y2tl
dF9maWxsZWQKCQkJInRoZSBidWNrZXQgaGFzIG5vdGhpbmcgaW4gaXQuIgoJCWVs
c2lmIGhhdmU/KDpmcm9nKQoJCQkidGhlIHdpemFyZCBhd2FrZW5zIGFuZCBzZWVz
IHRoYXQgeW91IHN0b2xlIGhpcyBmcm9nLiBoZSBpcyBzbyB1cHNldCBoZSBiYW5p
c2hlcyB5b3UgdG8gdGhlIG5ldGhlcndvcmxkcy0geW91IGxvc2UhIHRoZSBlbmQu
IgoJCWVsc2UKCQkJInRoZSB3aXphcmQgYXdha2VucyBmcm9tIGhpcyBzbHVtYmVy
IGFuZCBncmVldHMgeW91IHdhcm1seS4gaGUgaGFuZHMgeW91IHRoZSBtYWdpYyBs
b3ctY2FyYiBkb251dC0geW91IHdpbiEgdGhlIGVuZC4iCgkJZW5kCgl9CgplbmQK

------------wXkDTjTmcKHHO5WXuKtn0q
Content-Disposition: attachment; filename=lispgame_literal.rb
Content-Type: application/octet-stream; name=lispgame_literal.rb
Content-Transfer-Encoding: Base64

CiRvYmplY3RzID0gWzp3aGlza2V5X2JvdHRsZSwgOmJ1Y2tldCwgOmZyb2csIDpj
aGFpbl0KCiRtYXAgPSB7Cgk6bGl2aW5nX3Jvb20gPT4gWyJ5b3UgYXJlIGluIHRo
ZSBsaXZpbmctcm9vbSBvZiBhIHdpemFyZCdzIGhvdXNlLiB0aGVyZSBpcyBhIHdp
emFyZCBzbm9yaW5nIGxvdWRseSBvbiB0aGUgY291Y2guIiwKCQl7Ondlc3QgPT4g
WyJkb29yIiwgOmdhcmRlbl0sIDp1cHN0YWlycyA9PiBbInN0YWlyd2F5IiwgOmF0
dGljXX1dLAoJOmdhcmRlbiA9PiBbInlvdSBhcmUgaW4gYSBiZWF1dGlmdWwgZ2Fy
ZGVuLiB0aGVyZSBpcyBhIHdlbGwgaW4gZnJvbnQgb2YgeW91LiIsCgkJezplYXN0
ID0+IFsiZG9vciIsIDpsaXZpbmdfcm9vbV19XSwKCTphdHRpYyA9PiBbInlvdSBh
cmUgaW4gdGhlIGF0dGljIG9mIHRoZSBhYmFuZG9uZWQgaG91c2UuIHRoZXJlIGlz
IGEgZ2lhbnQgd2VsZGluZyB0b3JjaCBpbiB0aGUgY29ybmVyLiIsCgkJezpkb3du
c3RhaXJzID0+IFsic3RhaXJ3YXkiLCA6bGl2aW5nX3Jvb21dfV0KfQoKJG9iamVj
dF9sb2NhdGlvbnMgPSB7Cgk6d2hpc2tleV9ib3R0bGUgPT4gOmxpdmluZ19yb29t
LAoJOmJ1Y2tldCA9PiA6bGl2aW5nX3Jvb20sCgk6Y2hhaW4gPT4gOmdhcmRlbiwK
CTpmcm9nID0+IDpnYXJkZW4KfQoKJGxvY2F0aW9uID0gOmxpdmluZ19yb29tCgpk
ZWYgZGVzY3JpYmVfbG9jYXRpb24obG9jYXRpb24sIG1hcCkKCW1hcFtsb2NhdGlv
bl1bMF0KZW5kCgpkZWYgZGVzY3JpYmVfcGF0aChwYXRocywgZGlyZWN0aW9uKQoJ
InRoZXJlIGlzIGEgI3twYXRoc1tkaXJlY3Rpb25dWzBdfSBnb2luZyAje2RpcmVj
dGlvbn0gZnJvbSBoZXJlLiIKZW5kCgpkZWYgZGVzY3JpYmVfcGF0aHMobG9jYXRp
b24sIG1hcCkKCXBhdGhzID0gbWFwW2xvY2F0aW9uXVsxXQoJcGF0aHMua2V5cy5t
YXAgeyB8ZGlyfCBkZXNjcmliZV9wYXRoKHBhdGhzLCBkaXIpIH0uam9pbigiICIp
CmVuZAoKZGVmIGlzX2F0KG9iaiwgbG9jLCBvYmpfbG9jKQoJb2JqX2xvY1tvYmpd
ID09IGxvYwplbmQKCmRlZiBkZXNjcmliZV9mbG9vcihsb2MsIG9ianMsIG9ial9s
b2MpCglvYmpzLmZpbmRfYWxsIHsgfG9ianwgaXNfYXQob2JqLCBsb2MsIG9ial9s
b2MpIH0ubWFwIHsgfG9ianwKCQkieW91IHNlZSBhICN7b2JqfSBvbiB0aGUgZmxv
b3IuIgoJfS5qb2luKCIgIikKZW5kCgpkZWYgbG9vawoJWwoJZGVzY3JpYmVfbG9j
YXRpb24oJGxvY2F0aW9uLCAkbWFwKSwKCWRlc2NyaWJlX3BhdGhzKCRsb2NhdGlv
biwgJG1hcCksCglkZXNjcmliZV9mbG9vcigkbG9jYXRpb24sICRvYmplY3RzLCAk
b2JqZWN0X2xvY2F0aW9ucykKCV0uam9pbigiICIpCmVuZAoKZGVmIHdhbGtfZGly
ZWN0aW9uKGRpcmVjdGlvbikKCW5leHRfbG9jID0gJG1hcFskbG9jYXRpb25dWzFd
W2RpcmVjdGlvbl0KCWlmIG5leHRfbG9jCgkJJGxvY2F0aW9uID0gbmV4dF9sb2Nb
MV0KCQlsb29rCgllbHNlCgkJInlvdSBjYW4ndCBnbyB0aGF0IHdheS4iCgllbmQK
ZW5kCgojIG1hcCBhbGwgbWlzc2luZyBtZXRob2RzIHdpdGhvdXQgYXJndW1lbnRz
IHRvIHRoZXJlIG5hbWUgYXMgc3ltYm9sLCBzbyB0aGUKIyBwbGF5ZXIgY2FuIHdy
aXRlIGJ1Y2tldCBpbnN0ZWFkIG9mIDpidWNrZXQKZGVmIG1ldGhvZF9taXNzaW5n
KG0sICphLCAmYikKCWEuZW1wdHk/ID8gbSA6IHN1cGVyCmVuZAoKYWxpYXMgOndh
bGsgOndhbGtfZGlyZWN0aW9uCgpkZWYgcGlja3VwX29iamVjdChvYmplY3QpCglp
ZiBpc19hdChvYmplY3QsICRsb2NhdGlvbiwgJG9iamVjdF9sb2NhdGlvbnMpCgkJ
JG9iamVjdF9sb2NhdGlvbnNbb2JqZWN0XSA9IDpib2R5CgkJInlvdSBhcmUgbm93
IGNhcnJ5aW5nIHRoZSAje29iamVjdH0iCgllbHNlCgkJInlvdSBjYW5ub3QgZ2V0
IHRoYXQuIgoJZW5kCmVuZAoKYWxpYXMgOnBpY2t1cCA6cGlja3VwX29iamVjdAoK
ZGVmIGludmVudG9yeQoJJG9iamVjdHMuZmluZF9hbGwgeyB8b2JqfAoJCWlzX2F0
KG9iaiwgOmJvZHksICRvYmplY3RfbG9jYXRpb25zKQoJfQplbmQKCmRlZiBoYXZl
KG9iamVjdCkKCWludmVudG9yeS5pbmNsdWRlPyBvYmplY3QKZW5kCgpkZWYgZ2Ft
ZV9hY3Rpb24oY29tbWFuZCwgc3Viaiwgb2JqLCBwbGFjZSwgJmJsb2NrKQoJc2Vs
Zi5jbGFzcy5jbGFzc19ldmFsIHsKCQlkZWZpbmVfbWV0aG9kKGNvbW1hbmQpIHsg
fHN1YmplY3QsIG9iamVjdHwKCQkJaWYgJGxvY2F0aW9uID09IHBsYWNlICYmIHN1
YmplY3QgPT0gc3ViaiAmJiBvYmplY3QgPT0gb2JqICYmIGhhdmUoc3ViaikKCQkJ
CWluc3RhbmNlX2V2YWwgJmJsb2NrCgkJCWVsc2UKCQkJCSJpIGNhbid0ICN7Y29t
bWFuZH0gbGlrZSB0aGF0LiIKCQkJZW5kCgkJfQoJfQplbmQKCiRjaGFpbl93ZWxk
ZWQgPT0gZmFsc2UKJGJ1Y2tldF9maWxsZWQgPT0gZmFsc2UKCmdhbWVfYWN0aW9u
KDp3ZWxkLCA6Y2hhaW4sIDpidWNrZXQsIDphdHRpYykgewoJaWYgaGF2ZSg6YnVj
a2V0KSAmJiAoJGNoYWluX3dlbGRlZCA9IHRydWUpCgkJInRoZSBjaGFpbiBpcyBu
b3cgc2VjdXJlbHkgd2VsZGVkIHRvIHRoZSBidWNrZXQuIgoJZWxzZQoJCSJ5b3Ug
ZG8gbm90IGhhdmUgYSBidWNrZXQuIgoJZW5kCn0KCmdhbWVfYWN0aW9uKDpkdW5r
LCA6YnVja2V0LCA6d2VsbCwgOmdhcmRlbikgewoJaWYgJGNoYWluX3dlbGRlZAoJ
CSRidWNrZXRfZmlsbGVkID0gdHJ1ZQoJCSJ0aGUgYnVja2V0IGlzIG5vdyBmdWxs
IG9mIHdhdGVyLiIKCWVsc2UKCQkidGhlIHdhdGVyIGxldmVsIGlzIHRvbyBsb3cg
dG8gcmVhY2guIgoJZW5kCn0KCmdhbWVfYWN0aW9uKDpzcGxhc2gsIDpidWNrZXQs
IDp3aXphcmQsIDpsaXZpbmdfcm9vbSkgewoJaWYgISRidWNrZXRfZmlsbGVkCgkJ
InRoZSBidWNrZXQgaGFzIG5vdGhpbmcgaW4gaXQuIgoJZWxzaWYgaGF2ZSg6ZnJv
ZykKCQkidGhlIHdpemFyZCBhd2FrZW5zIGFuZCBzZWVzIHRoYXQgeW91IHN0b2xl
IGhpcyBmcm9nLiBoZSBpcyBzbyB1cHNldCBoZSBiYW5pc2hlcyB5b3UgdG8gdGhl
IG5ldGhlcndvcmxkcy0geW91IGxvc2UhIHRoZSBlbmQuIgoJZWxzZQoJCSJ0aGUg
d2l6YXJkIGF3YWtlbnMgZnJvbSBoaXMgc2x1bWJlciBhbmQgZ3JlZXRzIHlvdSB3
YXJtbHkuIGhlIGhhbmRzIHlvdSB0aGUgbWFnaWMgbG93LWNhcmIgZG9udXQtIHlv
dSB3aW4hIHRoZSBlbmQuIgoJZW5kCn0K
------------wXkDTjTmcKHHO5WXuKtn0q--