Index: /pyyaml-legacy/tags/PyYaml_0.32/profileYaml.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/profileYaml.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/profileYaml.py	(revision 75)
@@ -0,0 +1,23 @@
+import profile
+import pstats
+import yaml
+import glob
+
+def loadAllFiles():
+    testFiles = glob.glob('TestingSuite/*.yml')
+    for file in testFiles:
+        docs = yaml.loadFile(file)
+        for doc in docs:
+            exercise(doc)
+
+def exercise(doc):                
+    if 'python' in doc:
+        if 'yaml' in doc:
+            for subDoc in yaml.load(doc['yaml']):
+                pass
+print dir(profile)
+profile.run('loadAllFiles()', 'profileResults')
+
+p = pstats.Stats('profileResults')
+file = open("profile.out", "w")
+p.sort_stats('time').print_stats(25)
Index: /pyyaml-legacy/tags/PyYaml_0.32/here.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/here.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/here.py	(revision 75)
@@ -0,0 +1,14 @@
+import re
+from string import split, join
+
+def flushLeft(s):
+    lines = split(s,'\n')
+    lastLine = lines.pop()
+    if re.match(r"\S", lastLine):
+        raise "bad last line"
+    indent = len(lastLine)
+    ret = []
+    for line in lines[1:]:
+        ret.append(line[indent:] + '\n')
+    return join(ret,'')
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/demo.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/demo.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/demo.py	(revision 75)
@@ -0,0 +1,92 @@
+import yaml, string
+
+####### RUNNING YAML AGAINST THE README AND CHANGELOG
+
+readme = yaml.loadFile("README")
+print "README"
+for item in readme.next():
+    print item
+print "\n\nCONTRIBUTORS"
+for person in readme.next()['contributors']:
+    print "===%s===" % person['who']
+    print person['why?']
+    print
+print "\n\n"
+print "CHANGELOG:\n"
+print list(yaml.loadFile("CHANGELOG"))
+print "\n\n"
+
+######## USING YAML INSIDE YOUR PROGRAM
+
+testData = \
+"""
+program: PyYaml
+author: Steve Howell
+---
+shopping list:
+ - apple
+ - banana
+todo:
+ - eat more fruit:
+     - especially bananas!
+     - good for you
+ - write a better demo
+"""
+
+print "YAML INSIDE YOUR PROGRAM"
+for x in yaml.load(testData):
+   print repr(x)
+print "\n\n"
+
+
+######### YPATH STUFF
+
+try:
+    print "YPATH EXPERIMENTATION"
+    data = yaml.load(testData)
+    print yaml.ypath("/author",data.next()).next()
+    print yaml.dump(yaml.ypath("/todo/0",data.next()).next())
+except NotImplementedError:
+    print "Experimental YPATH requires Python 2.2"
+
+######### YAML DUMPER 
+
+class Person:
+    def __init__(self, fname, lname, salary, children):
+        self.fname = fname
+        self.lname = lname
+        self.salary = salary
+        self.children = children
+        # private variables
+        self._fullname = fname + ' ' + lname
+        if salary:
+            self._sal_per_month = salary / 12.0
+        self._num_children = len(children)
+    def to_yaml(self):
+        return ({
+            'first name': self.fname,
+            'last name':  self.lname,
+            'salary':     self.salary
+        }, '!!Person')
+
+mrBarson = Person('Foo', 'Barson', 20, ['ex', 'theomatic'])
+mrDoe = Person('John', 'Doe', None, [])
+print yaml.dump([mrBarson, mrDoe])
+
+print "\n\nANOTHER WAY TO STDOUT:\n"
+import sys
+yaml.dumpToFile(sys.stdout, [mrBarson, mrDoe])
+
+print "\n\nDUMP MULTIPLE DOCS TO A FILE:\n"
+file = open('DEMO_OUTPUT.TXT', 'w')
+yaml.dumpToFile(file, 
+    {'source': "Demo output from demo.py"},
+    [
+        'apple',
+        'banana',
+    ],
+    'Third document'      
+)
+file.close()
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestYpath.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestYpath.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestYpath.py	(revision 75)
@@ -0,0 +1,20 @@
+import yaml
+from test import assertEquals
+
+try:    
+    for test in yaml.loadFile("./TestingSuite/ypath.yml"):
+        if not test.has_key('ignore'):
+            expr = test['ypath']
+            pth = yaml.ypath(expr,cntx=1)
+            lst = [] 
+            for x in pth.apply(test['data']):
+                lst.append(str(x))
+            exp = test['expected']
+            if test.has_key('unordered'):
+               lst.sort()
+               exp.sort()
+            assertEquals(lst,exp,expr + " => " + str(pth))
+
+    print "Experimental YPATH OK"
+except NotImplementedError: 
+    print "Experimental YPATH requires Python 2.2"
Index: /pyyaml-legacy/tags/PyYaml_0.32/Makefile
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/Makefile	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/Makefile	(revision 75)
@@ -0,0 +1,23 @@
+test:
+	@for n in YamlTest TestYpath TestClasses TestFileNamesInErrors; do \
+		echo $$n.py; \
+		python2.1 $$n.py; \
+		python2.2 $$n.py; done
+	python TestPluggableDictionary.py
+
+clean:
+	rm -f *.pyc
+	rm -f yaml/*.pyc
+	rm -rf build
+	rm -f DEMO*.TXT
+	rm -f profileResults
+
+profile:
+	python profileYaml.py > profile.out
+
+install:
+	python setup.py install
+
+build:
+	python setup.py build
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TESTING
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TESTING	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TESTING	(revision 75)
@@ -0,0 +1,12 @@
+--- >
+As of July 2002, PyYaml shares its YAML-based testing suite with 
+other YAML implementations, starting with YamlForRuby.  Many
+thanks to Why The Lucky Stuff, the author of YamlForRuby, for
+setting this up.
+
+When you check code out of Perforce, please set up your client
+to check out TestingSuite as a subfolder of PyYaml.
+
+Thanks,
+
+Steve
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestYamlBasics.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestYamlBasics.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestYamlBasics.py	(revision 75)
@@ -0,0 +1,163 @@
+import YamlTest
+from here import *
+from test import assertEquals
+from yaml.load import l
+from yaml.dump import d
+
+class Test(YamlTest.YamlTest):
+    def setUp(self):
+        # print '>>>>>>>>>>>>>>>'
+        pass
+
+    def testNoLineFeed(self):
+        from yaml.stream import noLineFeed
+        assertEquals("foo", noLineFeed("foo\n"))
+        assertEquals("bar", noLineFeed("bar\n"))
+        assertEquals("bar", noLineFeed("bar\r\n"))
+        assertEquals("", noLineFeed("\r\n"))
+
+    def XXXtest9(self):
+        # XXX - not sure how this gets handled now
+        self.verify(
+            """
+            - foo: 1
+                bar: 2
+            """,
+            [ {'foo': 1, '  bar': 2}])
+
+    def testOutlineSnippet(self):
+        self.verify(
+            """
+            - YAML ToDo:
+                - y2outline
+                - support generic transfers
+                - work on YAML.py:
+                    - work on Store
+            """,
+            [ {'YAML ToDo': [   
+                'y2outline',
+                'support generic transfers',
+                { 'work on YAML.py': ['work on Store'] }
+                ]
+              }
+            ])
+
+    def testQuotedString(self):
+        self.verify(
+            """
+            ---
+            foo: 'key: value'
+            """,
+            {'foo': "key: value"}
+            )
+
+    def testFloatRedHerring(self):
+        self.verify(
+            """
+            ---
+            - 'Version: 0.18.0'
+            """,
+            [ 'Version: 0.18.0' ]
+            )
+
+    def testDashInQuotes(self):
+        self.verify(
+            """
+            ---
+            title: 'Perspective Broker - twisted.spread'
+            """,
+            {'title': 'Perspective Broker - twisted.spread'}
+            )
+
+    def testQuestionMarks(self):
+        self.verify(
+            """
+            ---
+            hello: you there?
+            foo:
+                - ok?
+                - sure?
+            bar:
+                - for here or to go?
+                - more sugar?
+            """,
+            {   
+                'hello': 'you there?',
+                'foo': ['ok?', 'sure?'],
+                'bar': ['for here or to go?', 'more sugar?']
+            }
+            )
+
+    def testDoubleQuoteEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            "I'm escaped!": simple
+            """,
+            { "I'm escaped!": 'simple' }
+            )
+
+    def testColonsInsideEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            'aaa: bbbb': simple
+            """,
+            { 'aaa: bbbb': 'simple' }
+            )
+
+    def testControlChars(self):
+        self.verify(
+            r"""
+            control: "\b1998\t1999\t2000\n"
+            """,
+            { 'control': "\b1998\t1999\t2000\n" }
+        )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.verify(
+                r'''
+                unicode: "Sosa did fine.\u263A"
+                ''',
+                { 'unicode': u"Sosa did fine.\u263A"}
+            )
+
+    def testMultiLineScalar(self):
+        self.verify(
+            """
+            plain: This unquoted
+                   scalar spans
+                   many lines.
+            """,
+            { 'plain': 'This unquoted scalar spans many lines.' }
+        )
+
+    def testDomainType(self):
+        class MyYamlConfig:
+            def resolveType(self, data, url):
+                if url == '!!name':
+                    return 'Foo ' + data
+                elif url == '!!coords':
+                    return { 'x': data[0], 'y': data[1]}
+                else:
+                    raise 'url not passed in correctly'
+        data = YamlTest.loadFlushLeft("""
+            name: !!name Barson
+            coords: !!coords
+              - 10
+              - 20
+            """, 
+            MyYamlConfig())
+        self.assertEquals(data[0], 
+            {'name': 'Foo Barson',
+            'coords': { 'x': 10, 'y': 20 } }
+        )
+
+    def testQuickInterfaces(self):
+        assertEquals(l("--- foo"), "foo")
+        assertEquals(d({'foo': 'bar'}), "---\nfoo: bar\n")
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestPluggableDictionary.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestPluggableDictionary.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestPluggableDictionary.py	(revision 75)
@@ -0,0 +1,25 @@
+import yaml
+from yaml.ordered_dict import OrderedDict
+from yaml.redump import redump
+from test import assertEquals
+
+stream = """\
+---
+zzz: 0
+yyy: 1
+xxx: 2
+alpha: 3
+---
+-
+    foo: 1
+    bar: 2
+-
+    z: 1
+    y: 2
+"""
+
+my_dict = yaml.loadOrdered(stream).next()
+assertEquals(my_dict.keys(), ['zzz', 'yyy', 'xxx', 'alpha'])
+
+assertEquals(redump(stream), stream)
+   
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestPullParser.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestPullParser.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestPullParser.py	(revision 75)
@@ -0,0 +1,116 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals
+from TestPushDumper import mockEvents
+from yaml import load
+
+"""
+This is experimental code.  I am moving toward a rewrite of the YAML 
+parser so that it uses a pull interface.  I am using a mock object
+to emulate the parser, so that I can experiment with the interface a bit,
+and also to sketch out some ideas for schema-driven parsing.
+"""
+
+class MockParser:
+    def __init__(self, events):
+        self.events = events
+        self.index = 0
+
+    def __getattr__(self, name):
+        (nextName, value) = self.events[self.index]
+        if name != nextName:
+            raise "Improper mocking for event %d (%s vs. %s)" % \
+                (self.index, name, nextName)
+        self.index += 1
+        return lambda: value
+
+class Loader:
+    def __init__(self, parser):
+        self.parser = parser
+
+    def load(self, data):
+        typ = self.parser.getType()
+        return self._load(typ)
+
+    def _load(self, typ):
+        if typ == 'seq':
+            return self._loadSeq()
+        elif typ == 'map':
+            return self._loadMap()
+        else:
+            return self._loadScalar()
+
+    def _loadSeq(self):
+        results = []
+        def itemFunc(self, results, typ):
+            results.append(self._load(typ))
+        return self.iterateItems(results, itemFunc)
+
+    def _loadMap(self):
+        results = {}
+        def itemFunc(self, results, typ):
+            key = self._load(typ)
+            valTyp = self.parser.getType()
+            value = self._load(typ)
+            results[key] = value
+        return self.iterateItems(results, itemFunc)
+
+    def iterateItems(self, results, func):
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                func(self, results, typ)
+
+    def _loadScalar(self):
+        return self.parser.getScalar()
+
+def mockParser(data):
+    events = mockEvents(data)
+    return MockParser(events)
+
+def mockLoad(data):
+    loader = Loader(mockParser(data))
+    return loader.load(None) # None for data cause events are all mocked 
+
+def testRoundTrip(data):
+    obj = mockLoad(data)
+    assertEquals(obj, data)
+
+class Test(YamlTest.YamlTest):
+
+    def testMock(self):
+        parser = MockParser( [
+            ('getScalar', 'foo'),
+            ('getArray', [1,2,3]),
+            ('getScalar', None),
+        ])
+        assertEquals(parser.getScalar(), 'foo')
+        assertEquals(parser.getArray(), [1,2,3])
+        assertEquals(parser.getScalar(), None)
+
+    def testList(self):
+        testRoundTrip([1,2,3])
+
+    def testDict(self):
+        testRoundTrip({'foo': 'bar'})
+
+    def testListDict(self):
+        testRoundTrip( [ [1,2,3], {'foo': 'bar'} ] )
+
+    def testComplexStructure(self):
+        data = load(flushLeft(
+            """
+            list:
+                - {foo: bar}
+                - [1, 2, 3]
+            dict:
+                name: steve
+                games: [hoops, pool]
+            """))
+        testRoundTrip(data)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestClasses.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestClasses.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestClasses.py	(revision 75)
@@ -0,0 +1,140 @@
+import yaml
+from test import assertEquals
+from here import flushLeft
+from math import sqrt
+
+"""
+DUMPING OBJECTS: > 
+    YAML has several ways of persisting objects.  One view of an 
+    object is that it's nothing more than it's dictionary.  By 
+    default, YAML emits self.__dict__ from objects.
+"""
+
+class SimpleObject:
+    def __init__(self):
+        self.x = 100
+        self.y = 20
+    
+    def xyz(self):
+        return self.x + self.y + self.z
+
+def testDumpingDictionary():
+    obj = SimpleObject()
+    obj.z = 3
+    output = yaml.dump(obj)
+    expected = simpleObjectYaml()
+    assertEquals(output, expected)
+
+def simpleObjectYaml():
+    return flushLeft("""
+        --- !!__main__.SimpleObject
+        x: 100
+        y: 20
+        z: 3
+        """)
+    
+
+testDumpingDictionary()
+
+"""
+LOADING OBJECTS: > 
+    Of course, we would expect to be able to load that
+    YAML right back into Python, and we can.  You get 
+    back an object of the intended class, with all of 
+    the normal methods.  Be aware, though, that if your 
+    class creates methods on the fly, or if it does 
+    other trickery, then you might get unexpected results.
+"""
+
+def testLoadingDictionary():
+    obj = yaml.load(simpleObjectYaml()).next()
+    assertEquals(obj.xyz(), 123)
+
+testLoadingDictionary()
+
+"""
+CUSTOM DUMPING: >
+    Some times you want more control over how you dump
+    objects in YAML.  You might not want to dump all 
+    members of the object, for example.  Also, you may 
+    not want to export the module name.
+"""
+
+class Triangle:
+    def __init__(self,x,y):
+        self.x = x
+        self.y = y
+        self._hypotneuse = sqrt(x*x + y*y)
+
+    def to_yaml(self):
+        # hide the hypotneuse attribute, it's private;
+        # also use inches instead of feet
+        view = {
+            'x_inches': self.x * 12,
+            'y_inches': self.y * 12
+        }
+        return (view, '!!triangle_in_inches')
+
+def testDumpTriangle():
+    triangle = Triangle(3,4)
+    assertEquals(yaml.dump(triangle), triangleYaml())
+
+def triangleYaml():
+    return flushLeft("""
+        --- !!triangle_in_inches
+        x_inches: 36
+        y_inches: 48
+        """)
+
+testDumpTriangle()
+
+"""
+CUSTOM LOADING: >
+    You have control over the YAML load process too.  Normally
+    YAML resolves private types for you automatically, but you
+    can override its behavior.
+"""
+
+class MyResolver:
+    def resolveType(self, data, typestring):
+        if typestring == '!!triangle_in_inches':
+            x = data['x_inches'] / 12
+            y = data['y_inches'] / 12
+            return Triangle(x,y)
+        else:
+            raise 'Private type %s not supported' % typestring
+
+def testCustomLoad():
+    obj = yaml.load(triangleYaml(),MyResolver()).next()
+    assertEquals(obj._hypotneuse, 5.0)
+
+testCustomLoad()
+
+"""
+USING FROM_YAML(): >
+    Another way to customize the YAML loading process is to 
+    supply a from_yaml() method.  For example, you might want
+    the loading of an object to have some kind of a side effect.
+    Or, you may need to calculate some value that is not part of 
+    the attribute.
+"""
+
+class TestConfig:
+    lastTester = None
+    def from_yaml(self, args):
+        self.tester = args['tester']
+        self.hitcount = args['hitcount'] + 1
+        TestConfig.lastTester = self.tester
+        return self
+
+def testFromYaml():
+    yamlData = flushLeft("""
+        --- !!__main__.TestConfig
+        tester: showell
+        hitcount: 42
+        """)
+    obj = yaml.load(yamlData).next()
+    assertEquals(obj.hitcount, 43)
+    assertEquals(TestConfig.lastTester, 'showell')
+
+testFromYaml()
Index: /pyyaml-legacy/tags/PyYaml_0.32/__init__.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/__init__.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/__init__.py	(revision 75)
@@ -0,0 +1,1 @@
+# 
Index: /pyyaml-legacy/tags/PyYaml_0.32/setup.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/setup.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/setup.py	(revision 75)
@@ -0,0 +1,4 @@
+from distutils.core import setup
+setup (name = "yaml",
+       version = "0.25",
+       packages = ["yaml"])
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/foldedScalar.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/foldedScalar.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/foldedScalar.yml	(revision 71)
@@ -0,0 +1,216 @@
+--- #YAML:1.0
+test: Single ending newline
+brief: >
+    A pipe character, followed by an indented
+    block of text is treated as a literal
+    block, in which newlines are preserved
+    throughout the block, including the final
+    newline.
+yaml: |
+    ---
+    this: |
+        Foo
+        Bar
+
+ruby: |
+    { 'this' => "Foo\nBar\n" }
+python: |
+    [ 
+        { 'this': "Foo\nBar\n" }
+    ]
+---
+test: The '+' indicator
+brief: >
+    The '+' indicator says to keep newlines at the end of text
+    blocks.
+yaml: |
+    normal: |
+      extra new lines not kept
+
+    preserving: |+
+      extra new lines are kept
+
+
+    dummy: value
+ruby: |
+    {
+        'normal' => "extra new lines not kept\n",
+        'preserving' => "extra new lines are kept\n\n\n",
+        'dummy' => 'value'
+    }
+python: |
+    [ {
+        'normal': "extra new lines not kept\n",
+        'preserving': "extra new lines are kept\n\n\n",
+        'dummy': 'value'
+    } ]
+---
+test: Three trailing newlines in literals
+brief: >
+    To give you more control over how space
+    is preserved in text blocks, YAML has
+    the keep '+' and chomp '-' indicators.
+    The keep indicator will preserve all
+    ending newlines, while the chomp indicator
+    will strip all ending newlines.
+yaml: |
+    clipped: |
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: |-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: |+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+not_yet_in_python: |
+    [
+    { 
+      'clipped': "This has one newline.\n",
+      'same as "clipped" above': "This has one newline.\n",
+      'stripped': 'This has no newline.',
+      'same as "stripped" above': 'This has no newline.',
+      'kept': "This has four newlines.\n\n\n\n",
+      'same as "kept" above': "This has four newlines.\n\n\n\n"
+    }
+    ]
+
+---
+test: Extra trailing newlines with spaces
+brief: >
+    Normally, only a single newline is kept
+    from the end of a literal block, unless the
+    keep '+' character is used in combination
+    with the pipe.  The following example
+    will preserve all ending whitespace
+    since the last line of both literal blocks
+    contains spaces which extend past the indentation
+    level.
+yaml: |
+    ---
+    this: |
+        Foo
+
+          
+    kept: |+
+        Foo
+
+          
+ruby: |
+    { 'this' => "Foo\n\n  \n", 
+      'kept' => "Foo\n\n  \n" }
+
+---
+test: Folded Block in a Sequence
+brief: >
+    A greater-then character, followed by an indented
+    block of text is treated as a folded block, in
+    which lines of text separated by a single newline
+    are concatenated as a single line.
+yaml: |
+    ---
+    - apple
+    - banana
+    - >
+        can't you see
+        the beauty of yaml?
+        hmm
+    - dog
+python: |
+    [
+        [
+            'apple', 
+            'banana', 
+            "can't you see the beauty of yaml? hmm\n",
+            'dog'
+        ]
+    ]
+ruby: |
+    [
+        'apple', 
+        'banana', 
+        "can't you see the beauty of yaml? hmm\n",
+        'dog'
+    ]
+---
+test: Folded Block as a Mapping Value
+brief: >
+    Both literal and folded blocks can be
+    used in collections, as values in a 
+    sequence or a mapping.
+yaml: |
+    --- 
+    quote: >
+        Mark McGwire's
+        year was crippled
+        by a knee injury.
+    source: espn
+python: |
+    [
+        { 
+            'quote': "Mark McGwire's year was crippled by a knee injury.\n",
+            'source': 'espn'
+        }
+    ]
+ruby: |
+    { 
+        'quote' => "Mark McGwire's year was crippled by a knee injury.\n",
+        'source' => 'espn'
+    }
+
+---
+test: Three trailing newlines in folded blocks
+brief: >
+    The keep and chomp indicators can also
+    be applied to folded blocks.
+yaml: |
+    clipped: >
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: >-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: >+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/types.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/types.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/types.yml	(revision 71)
@@ -0,0 +1,239 @@
+--- #YAML:1.0
+test: Strings
+brief: >
+    Any group of characters beginning with an
+    alphabetic or numeric character is a string,
+    unless it belongs to one of the groups below
+    (such as an Integer or Time).  
+yaml: |
+    String
+ruby: |
+    'String'
+
+---
+test: String characters
+brief: >
+    A string can contain any alphabetic or
+    numeric character, along with many
+    punctuation characters, including the
+    period, dash, space, quotes, exclamation, and
+    question mark.
+yaml: |
+    - What's Yaml?
+    - It's for writing data structures in plain text.
+    - And?
+    - And what? That's not good enough for you?
+    - No, I mean, "And what about Yaml?"
+    - Oh, oh yeah. Uh.. Yaml for Ruby.
+ruby: |
+    [
+      "What's Yaml?",
+      "It's for writing data structures in plain text.",
+      "And?",
+      "And what? That's not good enough for you?",
+      "No, I mean, \"And what about Yaml?\"",
+      "Oh, oh yeah. Uh.. Yaml for Ruby."
+    ]
+
+---
+test: Indicators in Strings
+brief: >
+    Be careful using indicators in strings.  In particular,
+    the comma, colon, and pound sign must be used carefully.
+yaml: |
+    the colon followed by space is an indicator: but is a string:right here
+    same for the pound sign: here we have it#in a string
+    the comma can, honestly, be used in most cases: [ but not in, inline collections ]
+ruby: |
+    {
+      'the colon followed by space is an indicator' => 'but is a string:right here',
+      'same for the pound sign' => 'here we have it#in a string',
+      'the comma can, honestly, be used in most cases' => [ 'but not in', 'inline collections' ]
+    }
+
+---
+test: Forcing Strings
+brief: >
+    Any YAML type can be forced into a string using the
+    explicit !str method.
+yaml: |
+    date string: !str 2001-08-01
+    number string: !str 192
+ruby: |
+    {
+      'date string' => '2001-08-01',
+      'number string' => '192'
+    }
+
+---
+test: Single-quoted Strings
+brief: >
+    You can also enclose your strings within single quotes,
+    which allows use of slashes, colons, and other indicators
+    freely.  Inside single quotes, you can represent a single
+    quote in your string by using two single quotes next to
+    each other.
+yaml: |
+    all my favorite symbols: '#:!/%.)'
+    a few i hate: '&(*'
+    why do i hate them?: 'it''s very hard to explain'
+ruby: |
+    {
+      'all my favorite symbols' => '#:!/%.)',
+      'a few i hate' => '&(*',
+      'why do i hate them?' => 'it\'s very hard to explain'
+    }
+
+---
+test: Double-quoted Strings
+brief: >
+    Enclosing strings in double quotes allows you
+    to use escapings to represent ASCII and
+    Unicode characters.
+yaml: |
+    i know where i want my line breaks: "one here\nand another here\n"
+ruby: |
+    {
+      'i know where i want my line breaks' => "one here\nand another here\n"
+    }
+
+---
+test: Multi-line Quoted Strings
+brief: >
+    Both single- and double-quoted strings may be
+    carried on to new lines in your YAML document.
+    They must be indented a step and indentation
+    is interpreted as a single space.
+yaml: |
+    i want a long string: "so i'm going to
+      let it go on and on to other lines
+      until i end it with a quote."
+ruby: |
+    { 'i want a long string' => "so i'm going to " +
+         "let it go on and on to other lines " +
+         "until i end it with a quote."
+    }
+
+---
+test: Null
+brief: >
+    You can use the tilde '~' character for a null value.
+yaml: |
+    name: Mr. Show
+    hosted by: Bob and David
+    date of next season: ~
+ruby: |
+    {
+      'name' => 'Mr. Show',
+      'hosted by' => 'Bob and David',
+      'date of next season' => nil
+    }
+
+---
+test: Boolean
+brief: >
+    You can use the plus sign '+' and the negative
+    sign '-' for True and False.
+yaml: |
+    Is Gus a Liar?: +
+    Do I rely on Gus for Sustenance?: -
+ruby: |
+    {
+      'Is Gus a Liar?' => true,
+      'Do I rely on Gus for Sustenance?' => false
+    }
+
+---
+test: Integers
+brief: >
+    An integer is a series of numbers, optionally
+    starting with a positive or negative sign.  Integers
+    may also contain commas for readability.
+yaml: |
+    zero: 0
+    simple: 12
+    one-thousand: 1,000
+    negative one-thousand: -1,000
+ruby: |
+    {
+      'zero' => 0,
+      'simple' => 12,
+      'one-thousand' => 1000,
+      'negative one-thousand' => -1000
+    }
+python: |
+    [ 
+        {
+            'zero': 0,
+            'simple': 12,
+            'one-thousand': 1000,
+            'negative one-thousand': -1000,
+        }
+    ]
+---
+test: Integers as Map Keys
+brief: >
+    An integer can be used a dictionary key.
+yaml: |
+    1: one
+    2: two
+    3: three
+python: |
+    [
+        {
+            1: 'one',
+            2: 'two',
+            3: 'three',
+        }
+    ]       
+ruby: |
+    {
+        1 => 'one',
+        2 => 'two',
+        3 => 'three'
+    }
+
+---
+test: Floats
+brief: >
+     Floats are represented by numbers with decimals,
+     allowing for scientific notation, as well as
+     positive and negative infinity and "not a number."
+yaml: |
+     a simple float: 2.00
+     larger float: 1,000.09
+     scientific notation: 1.00009e+3
+ruby: |
+     {
+       'a simple float' => 2.0,
+       'larger float' => 1000.09,
+       'scientific notation' => 1000.09
+     }
+
+---
+test: Time
+brief: >
+    You can represent timestamps by using
+    ISO8601 format, or a variation which
+    allows spaces between the date, time and
+    time zone.
+yaml: |
+    iso8601: 2001-12-14t21:59:43.10-05:00
+    space seperated: 2001-12-14 21:59:43.10 -05:00
+ruby: |
+    {
+      'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+      'space seperated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" )
+    }
+
+---
+test: Date
+brief: >
+    A date can be represented by its year,
+    month and day in ISO8601 order.
+yaml: |
+    1976-07-31
+ruby: |
+    Date.new( 1976, 7, 31 )
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ypath.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ypath.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ypath.yml	(revision 75)
@@ -0,0 +1,221 @@
+data:
+  apple: red
+ypath: /
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: .
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: /*
+expected:
+ - /apple
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /*
+expected:
+ - /apple
+ - /lemon
+unordered: 1
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: //.
+expected:
+  - /
+  - /fruit
+  - /fruit/banana
+  - /vegetable
+  - /vegetable/carrot
+unordered: 1
+---
+data:
+  one:
+    two: xxx
+ypath: //two/..
+expected:
+ - /one
+---
+data:
+  apple: red
+ypath: /apple
+expected:
+ - /apple
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /"lemon"
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /'lemon'
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /lemon
+expected:
+ - /lemon
+----
+data:
+  - apple
+  - lemon
+ypath: /0
+expected:
+ - /0
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /orange
+expected: []
+----
+data:
+  apple: red
+ypath: ./.
+expected:
+ - /
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: /fruit/banana
+expected:
+ - /fruit/banana
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: fruit/banana
+expected:
+ - /fruit/banana
+---
+data:
+  names:
+    - Steve Howell
+    - Clark Evans
+ypath: /names/0
+expected:
+ - /names/0
+---
+data:
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/1/first
+expected:
+  - /names/1/first
+----
+data:
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/*/first
+expected:
+  - /names/0/first
+  - /names/1/first
+---
+data:
+  names:
+    python-heads:
+      - first: Clark
+        last:  Evans
+      - first: Steve
+        last:  Howell
+    perl-heads:
+      - first: Brian
+        last:  Ingerson
+ypath: names//first
+expected:
+  - /names/python-heads/0/first
+  - /names/python-heads/1/first
+  - /names/perl-heads/0/first
+---
+data:
+    task:
+       - name: wake
+         foo: bar
+       - name: eat
+         task:
+            - name: veggies
+            - name: meats
+       - name: sleep
+ypath: //task
+expected:
+  - /task
+  - /task/1/task
+---
+data:
+  - one:
+      name: xxx
+  - two:
+      name: yyy
+  - three:
+      name: zzz
+ypath: /*/one/name|//three/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  apple: red
+ypath: .|/apple|apple|/|.
+expected:
+ - /
+ - /apple
+---
+data:
+  - one:
+      name: xxx
+  - two:
+      name: yyy
+  - three:
+      name: zzz
+ypath: /*/(one|three)/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  - one: xxx
+  - two: yyy
+  - one: zzz
+ypath: /*[one]
+expected:
+  - /0
+  - /2
+---
+data:
+ - food: Hamburger
+   calories: 900
+ - food: Fries
+   calories: 650
+ - food: Soft Drink
+   calories: 350
+ypath: //food[.=Fries]
+expected:
+  - /1/food
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/nullsAndEmpties.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/nullsAndEmpties.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/nullsAndEmpties.yml	(revision 71)
@@ -0,0 +1,66 @@
+--- #YAML:1.0
+test: Empty Sequence
+brief: >
+    You can represent the empty sequence
+    with an empty inline sequence.
+yaml: |
+    empty: []
+python: |
+    [
+        { 'empty': [] }
+    ]
+ruby: |
+    { 'empty' => [] }
+
+---
+test: Empty Mapping
+brief: >
+    You can represent the empty mapping
+    with an empty inline mapping.
+yaml: |
+    empty: {}
+python: |
+    [
+        { 'empty': {} }
+    ]
+ruby: |
+    { 'empty' => {} }
+
+---
+test: Empty Sequence as Entire Document
+yaml: |
+    --- []
+python: |
+    [ [] ]
+ruby: |
+    []
+
+---
+test: Empty Mapping as Entire Document
+yaml: |
+    --- {}
+python: |
+    [ {} ]
+ruby: |
+    {}
+
+--- 
+test: Null as Document
+yaml: |
+    --- ~
+python: |
+    [ None ]
+ruby: |
+    nil
+
+---
+test: Empty String
+brief: >
+    You can represent an empty string
+    with a pair of quotes.
+yaml: |
+    --- ''
+python: |
+    [ '' ]
+ruby: |
+    ''
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/alias.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/alias.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/alias.yml	(revision 75)
@@ -0,0 +1,61 @@
+--- #YAML:1.0
+test: Simple Alias Example
+brief: >
+    If you need to refer to the same item of data twice,
+    you can give that item an alias.  The alias is a plain
+    string, starting with an ampersand.  The item may then
+    be referred to by the alias throughout your document
+    by using an asterisk before the name of the alias.
+    This is called an anchor.
+yaml: |
+    - &showell Steve
+    - Clark
+    - Brian
+    - Oren
+    - *showell
+python: |
+    [
+        [ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve']
+    ]
+ruby-setup: |
+    showell = 'Steve'
+ruby: |
+    [ showell, 'Clark', 'Brian', 'Oren', showell ]
+
+---
+test: Alias of a Mapping
+brief: >
+    An alias can be used on any item of data, including
+    sequences, mappings, and other complex data types.
+yaml: |
+    - &hello
+        Meat: pork
+        Starch: potato
+    - banana
+    - *hello
+python: |
+    [
+        [ 
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+            'banana',
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+        ]
+    ]
+ruby-setup: |
+    hello = { 'Meat' => 'pork', 'Starch' => 'potato' }
+ruby: |
+    [ 
+      hello, 
+      'banana',
+      hello
+    ]
+---
+test: Liberal Asterisk Handling
+brief: >
+    We need to allow strings to begin with asterisks.
+yaml: |
+    - * Bulleted item
+python: |
+    [
+        [ '* Bulleted item' ]
+    ]
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/error.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/error.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/error.yml	(revision 75)
@@ -0,0 +1,67 @@
+--- #YAML:1.0
+test: Missing value for hash item
+brief: >
+    Third item in this hash doesn't have a value
+yaml: |
+    okay: value
+    also okay: ~
+    causes error because no value specified
+    last key: value okay here too
+error:
+    python: |
+        bad key for map:
+        near line 3:
+        causes error because no value specified
+---
+test: Not indenting enough
+brief: >
+    There was a bug in PyYaml where it was off by one
+    in the indentation check.  It was allowing the YAML 
+    below.
+yaml: |
+    foo:
+    firstline: 1
+    secondline: 2
+error:
+    python: |
+        Inadequate indentation:
+        near line 2:
+        firstline: 1
+---
+test: Duplicate keys
+brief: >
+    YAML should complain when you have duplicate
+    dictionary keys, rather than silently overwriting them.
+yaml: |
+    foo: 1
+    foo: 2
+error:
+    python: |
+        Duplicate key foo:
+        near line 2:
+        foo: 2
+---
+test: Duplicate keys w/complex children
+brief: >
+    same thing for complex keys
+yaml: |
+    foo:
+        yo: 1
+    foo:
+        bar: 1
+error:
+    python: |
+        Duplicate key foo:
+        near line 3:
+        foo:
+---
+test: Complain about trailing spaces
+brief: >
+    root of all evil
+yaml: |
+    foo: bar 
+error:
+    python: |
+        Trailing spaces not allowed without quotes.:
+        near line 1:
+        foo: bar 
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/inlineCollection.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/inlineCollection.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/inlineCollection.yml	(revision 71)
@@ -0,0 +1,74 @@
+---
+test: Simple Inline Array
+brief: >
+    Sequences can be contained on a
+    single line, using the inline syntax.
+    Separate each entry with commas and
+    enclose in square brackets.
+yaml: |
+    --- 
+    seq: [ a, b, c ]
+python: |
+    [
+        { 'seq': [ 'a', 'b', 'c' ] }
+    ]
+ruby: |
+    { 'seq' => [ 'a', 'b', 'c' ] }
+
+---
+test: Simple Inline Hash
+brief: >
+    Mapping can also be contained on
+    a single line, using the inline
+    syntax.  Each key-value pair is
+    separated by a colon, with a comma
+    between each entry in the mapping.
+    Enclose with curly braces.
+yaml: |
+    ---
+    hash: { name: Steve, foo: bar }
+python: |
+    [
+        { 'hash': {'name': 'Steve', 'foo': 'bar'} }
+    ]
+ruby: |
+    { 'hash' => { 'name' => 'Steve', 'foo' => 'bar' } }
+
+---
+test: Multi-line Inline Collections
+brief: >
+    Both inline sequences and inline mappings
+    can span multiple lines, provided that you
+    indent the additional lines.
+yaml: |
+    languages: [ Ruby,
+                 Perl,
+                 Python ]
+    websites: { YAML: yaml.org,
+                Ruby: ruby-lang.org,
+                Python: python.org,
+                Perl: use.perl.org }
+ruby: |
+    { 'languages' => [ 'Ruby', 'Perl', 'Python' ],
+      'websites' => {
+        'YAML' => 'yaml.org',
+        'Ruby' => 'ruby-lang.org',
+        'Python' => 'python.org',
+        'Perl' => 'use.perl.org' 
+      }
+    }
+---
+test: Commas in Values
+brief: >
+    List items in collections are delimited by commas, but 
+    there must be a space after each comma.  This allows you
+    to add numbers without quoting.
+yaml: |
+    attendances: [ 45,123, 70,000, 17,222 ]
+python: |
+    [
+        {'attendances': [ 45123, 70000, 17222 ]}
+    ]
+ruby: |
+    { 'attendances' => [ 45123, 70000, 17222 ] }
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/spec.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/spec.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/spec.yml	(revision 75)
@@ -0,0 +1,1576 @@
+--- #YAML:1.0
+test: Sequence of scalars
+spec: A1
+yaml: |
+  - Mark McGwire
+  - Sammy Sosa
+  - Ken Griffey
+perl: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+python: |
+  [ ['Mark McGwire', 'Sammy Sosa', 'Ken Griffey'] ]
+ruby: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Mapping of scalars to scalars
+spec: A2
+yaml: |
+  hr:  65
+  avg: 0.278
+  rbi: 147
+perl: |
+  { hr => 65, avg => 0.278, rbi => 147 }
+python: |
+  [ {'hr': 65, 'avg': .278, 'rbi': 147} ]
+ruby: |
+  { 'hr' => 65, 'avg' => 0.278, 'rbi' => 147 }
+
+---
+test: Mapping of scalars to sequences
+spec: A3
+yaml: |
+    american:
+       - Boston Red Sox
+       - Detroit Tigers
+       - New York Yankees
+       - Texas Rangers
+    national:
+       - New York Mets
+       - Chicago Cubs
+       - Atlanta Braves
+       - Montreal Expos
+perl: |
+    { american => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      national =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+python: |
+    [
+    {
+    'american': 
+        ['Boston Red Sox', 'Detroit Tigers', 
+        'New York Yankees', 'Texas Rangers'],
+    'national':
+        ['New York Mets', 'Chicago Cubs',
+        'Atlanta Braves', 'Montreal Expos']
+    }
+    ]
+ruby: |
+    { 'american' => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      'national' =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+
+---
+test: Sequence of mappings
+spec: A4
+yaml: |
+    - 
+      name: Mark McGwire
+      hr:   65
+      avg:  0.278
+      rbi:  147
+    - 
+      name: Sammy Sosa
+      hr:   63
+      avg:  0.288
+      rbi:  141
+perl: |
+    [
+      {name => 'Mark McGwire', hr => 65, avg => 0.278, rbi => 147},
+      {name => 'Sammy Sosa',   hr => 63, avg => 0.288, rbi => 141}
+    ]
+python: |
+    [[ 
+        {
+        'name': 'Mark McGwire',
+        'hr': 65,
+        'avg': 0.278,
+        'rbi': 147
+        },
+        {
+        'name': 'Sammy Sosa',
+        'hr': 63,
+        'avg': 0.288,
+        'rbi': 141
+        }
+    ]]
+ruby: |
+    [
+      {'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278, 'rbi' => 147},
+      {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288, 'rbi' => 141}
+    ]
+
+---
+test: Legacy A5
+spec: legacy_A5
+yaml: |
+    ?
+        - New York Yankees
+        - Atlanta Braves
+    :
+      - 2001-07-02
+      - 2001-08-12
+      - 2001-08-14
+    ?
+        - Detroit Tigers
+        - Chicago Cubs
+    :
+      - 2001-07-23
+perl-busted: >
+    YAML.pm will be able to emulate this behavior soon. In this regard
+    it may be somewhat more correct than Python's native behaviour which
+    can only use tuples as mapping keys. PyYAML will also need to figure
+    out some clever way to roundtrip structured keys. Not sure how full
+    featured Ruby is in this regard.
+python: |
+    [
+    {
+        ('New York Yankees', 'Atlanta Braves'):
+            [yaml.timestamp('2001-07-02'), 
+             yaml.timestamp('2001-08-12'),
+             yaml.timestamp('2001-08-14')],
+        ('Detroit Tigers', 'Chicago Cubs'):
+        [yaml.timestamp('2001-07-23')]
+    }
+    ]
+ruby: |
+    {
+      [ 'New York Yankees', 'Atlanta Braves' ] =>
+        [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ],
+      [ 'Detroit Tigers', 'Chicago Cubs' ] =>
+        [ Date.new( 2001, 7, 23 ) ]
+    }
+
+
+---
+test: Sequence of sequences
+spec: A5
+yaml: |
+  - [ name         , hr , avg   ]
+  - [ Mark McGwire , 65 , 0.278 ]
+  - [ Sammy Sosa   , 63 , 0.288 ]
+perl: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ],
+  ]
+python: |
+  [[
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]]
+ruby: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]
+
+---
+test: Mapping of mappings
+spec: A6
+yaml: |
+  Mark McGwire: {hr: 65, avg: 0.278} 
+  Sammy Sosa:   {hr: 63,
+                 avg: 0.288}
+perl: |
+  { 
+    'Mark McGwire' => { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' => { 'hr' => 63, 'avg' => 0.288 },
+  }
+not_yet_in_python: |
+  [{ 
+    'Mark McGwire': 
+      { 'hr': 65, 'avg': 0.278 },
+    'Sammy Sosa':
+      { 'hr': 63, 'avg': 0.288 }
+  }]
+ruby: |
+  { 
+    'Mark McGwire' =>
+      { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' =>
+      { 'hr' => 63, 'avg' => 0.288 }
+  }
+
+---
+test: Two documents, one stream
+spec: B1
+yaml: |
+  ---
+  name: Mark McGwire
+  hr:   65
+  avg:  0.278
+  ---
+  name: Sammy Sosa
+  hr:   63
+  avg:  0.288
+python: |
+  [
+    { 'name': 'Mark McGwire', 'hr': 65, 'avg': 0.278 },
+    { 'name': 'Sammy Sosa', 'hr': 63, 'avg': 0.288 }
+  ]
+ruby: |
+  y = Stream.new
+  y.add( { 'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278 } )
+  y.add( { 'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288 } )
+documents: 2
+
+---
+test: Document with leading comment
+spec: B2
+yaml: |
+   # Ranking of players by
+   # 1998 season home runs.
+   ---
+      - Mark McGwire
+      - Sammy Sosa
+      - Ken Griffey
+python: |
+   [[ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]]
+ruby: |
+   [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Single document with two comments
+spec: B3
+yaml: |
+  hr: # 1998 hr ranking
+    - Mark McGwire
+    - Sammy Sosa
+  rbi:
+    # 1998 rbi ranking
+    - Sammy Sosa
+    - Ken Griffey
+python: |
+  [{ 
+    'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi': [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }]
+ruby: |
+  { 
+    'hr' => [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }
+
+---
+test: Node for Sammy Sosa appears twice in this document
+spec: B4
+yaml: |
+   hr:
+      - Mark McGwire
+      # Following node labeled SS
+      - &SS Sammy Sosa
+   rbi:
+      - *SS # Subsequent occurance
+      - Ken Griffey
+python: |
+   [{ 
+      'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi': [ 'Sammy Sosa', 'Ken Griffey' ]
+   }]
+ruby: |
+   { 
+      'hr' =>
+         [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi' =>
+         [ 'Sammy Sosa', 'Ken Griffey' ]
+   }
+
+---
+test: Mapping between sequences
+spec: B5
+yaml: |
+   ? # PLAY SCHEDULE
+     - Detroit Tigers
+     - Chicago Cubs
+   :  
+     - 2001-07-23
+   
+   ? [ New York Yankees,
+       Atlanta Braves ]
+   : [ 2001-07-02, 2001-08-12, 
+       2001-08-14 ]
+ruby: |
+   { 
+      [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
+      [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ]
+   }
+
+---
+test: Sequence key shortcut
+spec: B6
+yaml: |
+   invoice: 34843
+   date   : 2001-01-23
+   bill-to: Chris Dumars
+   product:
+      - item    : Super Hoop
+        quantity: 1
+      - item    : Basketball
+        quantity: 4
+      - item    : Big Shoes
+        quantity: 1
+ruby: |
+   { 
+      'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+      'bill-to' => 'Chris Dumars', 'product' =>
+      [ 
+         { 'item' => 'Super Hoop', 'quantity' => 1 },
+         { 'item' => 'Basketball', 'quantity' => 4 },
+         { 'item' => 'Big Shoes', 'quantity' => 1 } 
+      ] 
+   }
+python: |
+    [{
+        'invoice': 34843,
+        'date': yaml.timestamp('2001-01-23'),
+        'bill-to': 'Chris Dumars',
+        'product': [
+             { 'item': 'Super Hoop', 'quantity': 1 },
+             { 'item': 'Basketball', 'quantity': 4 },
+             { 'item': 'Big Shoes',  'quantity': 1 } 
+        ]
+    }]
+
+---
+test: Literal perserves newlines
+spec: C1
+yaml: |
+  --- |
+      \/|\/|
+      / |  |_
+ruby: |
+  "\\/|\\/|\n/ |  |_\n"
+python: |
+    [
+        flushLeft(
+        """
+        \/|\/|
+        / |  |_
+        """
+        )
+    ]
+
+---
+test: Folded treats newlines as a space
+spec: C2
+yaml: |
+  --- >
+      Mark McGwire's
+      year was crippled
+      by a knee injury.
+ruby: |
+  "Mark McGwire's year was crippled by a knee injury.\n"
+python: |
+    [ "Mark McGwire's year was crippled by a knee injury.\n" ]
+
+---
+test: Newlines preserved for indented and blank lines
+spec: C3
+yaml: |
+  --- >
+   Sammy Sosa completed another
+   fine season with great stats.
+  
+     63 Home Runs
+     0.288 Batting Average
+  
+   What a year!
+ruby: |
+  "Sammy Sosa completed another fine season with great stats.\n\n  63 Home Runs\n  0.288 Batting Average\n\nWhat a year!\n"
+python: |
+    [
+        flushLeft(
+        """
+        Sammy Sosa completed another fine season with great stats.
+
+          63 Home Runs
+          0.288 Batting Average
+
+        What a year!
+        """
+        )
+    ]
+
+
+---
+test: Indentation determines scope
+spec: C4
+yaml: |
+  name: Mark McGwire
+  accomplishment: >
+     Mark set a major league
+     home run record in 1998.
+  stats: |
+     65 Home Runs
+     0.278 Batting Average
+ruby: |
+  { 
+    'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n",
+    'stats' => "65 Home Runs\n0.278 Batting Average\n"
+  }
+python: |
+    [
+        {
+        'name': 'Mark McGwire',
+        'accomplishment': 
+            'Mark set a major league home run record in 1998.\n',
+        'stats': "65 Home Runs\n0.278 Batting Average\n"
+        }
+    ]
+
+---
+test: Quoted scalars
+spec: C5
+yaml: |
+  unicode: "Sosa did fine.\u263A"
+  control: "\b1998\t1999\t2000\n"
+  hexesc:  "\x0D\x0A is \r\n"
+  
+  single: '"Howdy!" he cried.'
+  quoted: ' # not a ''comment''.'
+  tie-fighter: '|\-*-/|'
+ruby: |
+  {
+    "tie-fighter" => "|\\-*-/|",
+    "control"=>"\0101998\t1999\t2000\n",
+    "unicode"=>"Sosa did fine." + ["263A".hex ].pack('U*'),
+    "quoted"=>" # not a 'comment'.",
+    "single"=>"\"Howdy!\" he cried.",
+    "hexesc"=>"\r\n is \r\n"
+  }
+python: |
+    [ {
+        'unicode': u"Sosa did fine.\u263A",
+        'control': "\b1998\t1999\t2000\n", 
+        'hexesc':  "\x0D\x0A is \r\n",
+        'single': '"Howdy!" he cried.',
+        'quoted': ' # not a \'comment\'.',
+        'tie-fighter': '|\-*-/|',
+    } ]
+
+
+---
+test: Multiline flow scalars
+spec: C6
+yaml: |
+  plain: This unquoted
+         scalar spans
+         many lines.
+  quoted: "\
+    So does this quoted
+    scalar.\n"
+ruby: |
+  { 
+    'plain' => 'This unquoted scalar spans many lines.',
+    'quoted' => "So does this quoted scalar.\n"
+  }
+python: |
+    [ {
+        'plain': 'This unquoted scalar spans many lines.',
+        'quoted': 'So does this quoted scalar.\n'
+      }
+    ]
+
+---
+test: Integers
+spec: D1
+yaml: |
+  canonical: 12345
+  decimal: +12,345
+  octal: 014
+  hexadecimal: 0xC
+ruby: |
+  { 
+    'canonical' => 12345, 
+    'decimal' => 12345, 
+    'octal' => '014'.oct, 
+    'hexadecimal' => '0xC'.hex 
+  }
+python: |
+    [ {
+        'canonical': 12345,
+        'decimal': 12345,
+        'octal': 014,
+        'hexadecimal': 0xC
+    } ]
+
+---
+test: Floating point
+spec: D2
+yaml: |
+  canonical: 1.23015e+3
+  exponential: 12.3015e+02
+  fixed: 1,230.15
+  negative infinity: (-inf)
+  not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+python: |
+    [ {
+        'canonical': 1.23015e+3,
+        'exponential': 1.23015e+3,
+        'fixed': 1230.15,
+        'negative infinity': '(-inf)',
+        'not a number': '(NaN)',
+    } ]
+
+---
+test: Miscellaneous
+spec: D3
+yaml: |
+  null: ~
+  true: +
+  false: -
+  string: '12345'
+ruby: |
+  { 
+    'null' => nil, 
+    'true' => true, 
+    'false' => false, 
+    'string' => '12345' 
+  }
+python: |
+    [ {
+        'null': None,
+        'true': 1,
+        'false': 0,
+        'string': '12345',
+    } ]
+
+---
+test: Timestamps
+spec: D4
+yaml: |
+  canonical: 2001-12-15T02:59:43.1Z
+  iso8601:  2001-12-14t21:59:43.10-05:00
+  spaced:  2001-12-14 21:59:43.10 -05:00
+  date:   2002-12-14 # Time is noon UTC 
+ruby: |
+  {
+    'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+    'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'date' => Date.new( 2002, 12, 14 )
+  }
+---
+test: legacy Timestamps test
+spec: legacy D4
+yaml: |
+    canonical: 2001-12-15T02:59:43.00Z
+    iso8601:  2001-02-28t21:59:43.00-05:00
+    spaced:  2001-12-14 21:59:43.00 -05:00
+    date:   2002-12-14
+python: |
+    [ {
+        'canonical': yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'iso8601':   yaml.timestamp('2001-03-01T02:59:43.00Z'),
+        'spaced':    yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'date':      yaml.timestamp('2002-12-14T00:00:00.00Z')
+    } ]
+ruby: |
+   {
+     'canonical' => Time::utc( 2001, 12, 15, 2, 59, 43, 0 ),
+     'iso8601' => YAML::mktime( 2001, 2, 28, 21, 59, 43, 0, "-05:00" ),
+     'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0, "-05:00" ),
+     'date' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Various explicit families
+spec: D5
+yaml: |
+  not-date: !str 2002-04-28
+  picture: !binary|base64 |
+   R0lGODlhDAAMAIQAAP//9/X
+   17unp5WZmZgAAAOfn515eXv
+   Pz7Y6OjuDg4J+fn5OTk6enp
+   56enmleECcgggoBADs=
+  
+  hmm: !somewhere.com,2002/type |
+   family above is short for
+   tag:somewhere.com,2002:type
+
+ruby-setup: |
+  YAML.add_domain_type( "somewhere.com,2002", /^type$/ ) { |type, val|
+    return "SOMEWHERE: #{val}"
+  }
+ruby: |
+  { 
+    'not-date' => '2002-04-28',
+    'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 
+    'hmm' => "SOMEWHERE: family above is short for\ntag:somewhere.com,2002:type\n" 
+  }
+
+---
+test: Application specific family
+spec: D6
+yaml: |
+  --- !clarkevans.com,2002/graph/^shape
+  - !^circle
+    center: &ORIGIN {x: 73, y: 129}
+    radius: 7
+  - !^line # !clarkevans.com,2002/graph/line
+    start: *ORIGIN
+    finish: { x: 89, y: 102 }
+  - !^text
+    start: *ORIGIN
+    color: 0xFFEEBB
+    value: Pretty vector drawing.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/shape/ ) { |type, val|
+    if val.type == Array
+      val << "Shape Container"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  one_shape_proc = Proc.new { |type, val|
+    if val.is_a? Kernel::Hash
+      val['TYPE'] = "Shape: #{type}"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/circle/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/line/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/text/, &one_shape_proc )
+ruby: |
+  [
+    { 
+      "radius" => 7, 
+      "center"=>
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "TYPE" => "Shape: graph/circle"
+    }, {
+      "finish" => 
+      {
+        "x" => 89, 
+        "y" => 102
+      }, 
+      "TYPE" => "Shape: graph/line", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }
+    }, {
+      "TYPE" => "Shape: graph/text", 
+      "value" => "Pretty vector drawing.", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "color" => 16772795
+    }, 
+    "Shape Container"
+  ]
+
+---
+test: Invoice
+spec: E1
+yaml: |
+  --- !clarkevans.com,2002/^invoice
+  invoice: 34843
+  date   : 2001-01-23
+  bill-to: &id001
+    given  : Chris
+    family : Dumars
+    address:
+      lines: |
+        458 Walkman Dr.
+        Suite #292
+      city    : Royal Oak
+      state   : MI
+      postal  : 48046
+  ship-to: *id001
+  product:
+    - sku         : BL394D
+      quantity    : 4
+      description : Basketball
+      price       : 450.00
+    - sku         : BL4438H
+      quantity    : 1
+      description : Super Hoop
+      price       : 2392.00
+  tax  : 251.42
+  total: 4443.52
+  comments: >
+    Late afternoon is best.
+    Backup contact is Nancy
+    Billsmer @ 338-4338.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", "invoice" ) { |type, val| val }
+  id001 = { 'given' => 'Chris', 'family' => 'Dumars', 'address' =>
+  { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak',
+    'state' => 'MI', 'postal' => 48046 } }
+ruby: |
+  { 
+     'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+     'bill-to' => id001, 'ship-to' => id001, 'product' =>
+       [ { 'sku' => 'BL394D', 'quantity' => 4,
+           'description' => 'Basketball', 'price' => 450.00 },
+         { 'sku' => 'BL4438H', 'quantity' => 1,
+           'description' => 'Super Hoop', 'price' => 2392.00 } ],
+     'tax' => 251.42, 'total' => 4443.52,
+     'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }
+
+---
+test: Log file
+spec: E2
+yaml: |
+  ---
+  Time: 2001-11-23 15:01:42 -05:00
+  User: ed
+  Warning: >
+    This is an error message
+    for the log file
+  ---
+  Time: 2001-11-23 15:02:31 -05:00
+  User: ed
+  Warning: >
+    A slightly different error
+    message.
+  ---
+  Date: 2001-11-23 15:03:17 -05:00
+  User: ed
+  Fatal: >
+    Unknown variable "bar"
+  Stack:
+    - file: TopClass.py
+      line: 23
+      code: |
+        x = MoreObject("345\n")
+    - file: MoreClass.py
+      line: 58
+      code: |-
+        foo = bar
+ruby: |
+  y = Stream.new
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
+  y.add( { 'Date' => YAML::mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
+           'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
+           'Stack' => [
+           { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
+           { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
+documents: 3
+
+---
+test: Throwaway comments
+yaml: |
+   ### These are four throwaway comment  ###
+   
+   ### lines (the second line is empty). ###
+   this: |   # Comments may trail lines.
+      contains three lines of text.
+      The third one starts with a
+      # character. This isn't a comment.
+   
+   # These are three throwaway comment
+   # lines (the first line is empty).
+ruby: |
+   {
+     'this' => "contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"
+   }
+
+---
+test: Document with a single value
+yaml: |
+   --- >
+   This YAML stream contains a single text value.
+   The next stream is a log file - a sequence of
+   log entries. Adding an entry to the log is a
+   simple matter of appending it at the end.
+ruby: |
+   "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n"
+
+---
+test: Document stream
+yaml: |
+   ---
+   at: 2001-08-12 09:25:00.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/index.html'
+   ---
+   at: 2001-08-12 09:25:10.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/toc.html'
+ruby: |
+   y = Stream.new
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 00 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/index.html'
+   } )
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 10 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/toc.html'
+   } )
+documents: 2
+
+---
+test: Top level mapping
+yaml: |
+   # This stream is an example of a top-level mapping.
+   invoice : 34843
+   date    : 2001-01-23
+   total   : 4443.52
+ruby: |
+   {
+      'invoice' => 34843,
+      'date' => Date.new( 2001, 1, 23 ),
+      'total' => 4443.52
+   }
+
+---
+test: Single-line documents
+yaml: |
+  # The following is a sequence of three documents.
+  # The first contains an empty mapping, the second
+  # an empty sequence, and the last an empty string.
+  --- {}
+  --- [ ]
+  --- ''
+ruby: |
+  y = Stream.new
+  y.add( {} )
+  y.add( [] )
+  y.add( '' )
+documents: 3
+
+---
+test: Document with pause
+yaml: |
+  # A communication channel based on a YAML stream.
+  ---
+  sent at: 2002-06-06 11:46:25.10 Z
+  payload: Whatever
+  # Receiver can process this as soon as the following is sent:
+  ...
+  # Even if the next message is sent long after:
+  ---
+  sent at: 2002-06-06 12:05:53.47 Z
+  payload: Whatever
+  ...
+ruby: |
+  y = Stream.new
+  y.add(
+    { 'sent at' => YAML::mktime( 2002, 6, 6, 11, 46, 25, .10 ),
+      'payload' => 'Whatever' }
+  )
+  y.add( 
+    { "payload" => "Whatever", "sent at" => YAML::mktime( 2002, 6, 6, 12, 5, 53, .47 ) }
+  )
+  y.add( nil )
+documents: 3
+
+---
+test: Explicit typing
+yaml: |
+   integer: 12
+   also int: ! "12"
+   string: !str 12
+ruby: |
+   { 'integer' => 12, 'also int' => 12, 'string' => '12' }
+
+---
+test: Private types
+yaml: |
+  # Both examples below make use of the 'x-private:ball'
+  # type family URI, but with different semantics.
+  ---
+  pool: !!ball
+    number: 8
+    color: black
+  ---
+  bearing: !!ball
+    material: steel
+ruby: |
+  y = Stream.new
+  y.add( { 'pool' =>
+    PrivateType.new( 'ball',
+      { 'number' => 8, 'color' => 'black' } ) }
+  )
+  y.add( { 'bearing' => 
+    PrivateType.new( 'ball',
+      { 'material' => 'steel' } ) }
+  )
+documents: 2
+
+---
+test: Type family under yaml.org
+yaml: |
+  # The URI is 'tag:yaml.org,2002:str'
+  - !str a Unicode string
+python: |
+  [ [ 'a Unicode string' ] ]
+ruby: |
+  [ 'a Unicode string' ]
+
+---
+test: Type family under perl.yaml.org
+yaml: |
+  # The URI is 'tag:perl.yaml.org,2002:Text::Tabs'
+  - !perl/Text::Tabs {}
+ruby: |
+  DomainType.new( 'perl.yaml.org,2002', 'Text::Tabs', {} )
+
+---
+test: Type family under clarkevans.com
+yaml: |
+  # The URI is 'tag:clarkevans.com,2003-02:timesheet'
+  - !clarkevans.com,2003-02/timesheet
+ruby: |
+  DomainType.new( 'clarkevans.com,2003-02', 'timesheet', {} )
+
+---
+test: URI Escaping
+yaml: |
+  same:
+    - !domain.tld,2002/type%30%10 value
+    - !domain.tld,2002/type\0x30\n value
+  different: # As far as the YAML parser is concerned
+    - !domain.tld,2002/type0%10 value
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", "type%30%10" ) { |type, val|
+    "ONE: #{val}"
+  }
+  YAML.add_domain_type( "domain.tld,2002", "type0%10" ) { |type, val|
+    "TWO: #{val}"
+  }
+ruby: |
+  { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }
+
+---
+test: URI Prefixing
+yaml: |
+  # 'tag:domain.tld,2002:invoice' is some type family.
+  invoice: !domain.tld,2002/^invoice
+    # 'seq' is shorthand for 'tag:yaml.org,2002:seq'.
+    # This does not effect '^customer' below
+    # because it is does not specify a prefix.
+    customers: !seq
+      # '^customer' is shorthand for the full
+      # notation 'tag:domain.tld,2002:customer'.
+      - !^customer
+        given : Chris
+        family : Dumars
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", /(invoice|customer)/ ) { |type, val|
+    if val.is_a? Kernel::Hash
+      val['type'] = "domain #{type}"
+      return val
+    else
+      raise YAML::Error, "Not a Hash in domain.tld/invoice: " + val.inspect
+    end
+  }
+ruby: |
+  { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }
+
+---
+test: Overriding anchors
+yaml: |
+  anchor : &A001 This scalar has an anchor.
+  override : &A001 >
+   The alias node below is a
+   repeated use of this value.
+  alias : *A001
+ruby: |
+  { 'anchor' => 'This scalar has an anchor.', 
+    'override' => "The alias node below is a repeated use of this value.\n", 
+    'alias' => "The alias node below is a repeated use of this value.\n" }
+
+---
+test: Flow and block formatting
+yaml: |
+  empty: []
+  flow: [ one, two, three # May span lines,
+           , four,           # indentation is
+             five ]          # mostly ignored.
+  block:
+   - First item in top sequence
+   -
+    - Subordinate sequence entry
+   - >
+    A folded sequence entry
+   - Sixth item in top sequence
+ruby: |
+  { 'empty' => [], 'flow' => [ 'one', 'two', 'three', 'four', 'five' ],
+    'block' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
+    "A folded sequence entry\n", 'Sixth item in top sequence' ] }
+
+---
+test: Complete mapping test
+yaml: |
+ empty: {}
+ flow: { one: 1, two: 2 }
+ spanning: { one: 1,
+    two: 2 }
+ block:
+  first : First entry
+  second:
+   key: Subordinate mapping
+  third:
+   - Subordinate sequence
+   - { }
+   - Previous mapping is empty.
+   - A key: value pair in a sequence.
+     A second: key:value pair.
+   - The previous entry is equal to the following one.
+   -
+    A key: value pair in a sequence.
+    A second: key:value pair.
+  !float 12 : This key is a float.
+  ? >
+   ?
+  : This key had to be protected.
+  "\a" : This key had to be escaped.
+  ? >
+   This is a
+   multi-line
+   folded key
+  : Whose value is
+    also multi-line.
+  ? this also works as a key
+  : with a value at the next line.
+  ?
+   - This key
+   - is a sequence
+  :
+   - With a sequence value.
+  ?
+   This: key
+   is a: mapping
+  :
+   with a: mapping value.
+ruby: |
+  { 'empty' => {}, 'flow' => { 'one' => 1, 'two' => 2 },
+    'spanning' => { 'one' => 1, 'two' => 2 },
+    'block' => { 'first' => 'First entry', 'second' =>
+    { 'key' => 'Subordinate mapping' }, 'third' =>
+      [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
+        'The previous entry is equal to the following one.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
+    12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
+    "\a" => 'This key had to be escaped.',
+    "This is a multi-line folded key\n" => "Whose value is also multi-line.",
+    'this also works as a key' => 'with a value at the next line.',
+    [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }
+  # Couldn't recreate map exactly, so we'll do a detailed check to be sure it's entact
+  obj_y['block'].keys.each { |k|
+    if k.type == Hash
+      v = obj_y['block'][k]
+      if k['This'] == 'key' and k['is a'] == 'mapping' and v['with a'] == 'mapping value.'
+         obj_r['block'][k] = v
+      end
+    end
+  }
+no-round-trip:
+  - ruby
+
+---
+test: Literal explicit indentation
+yaml: |
+   # Explicit indentation must
+   # be given in all the three
+   # following cases.
+   leading spaces: |2
+         This value starts with four spaces.
+   
+   leading line break: |2
+   
+     This value starts with a line break.
+   
+   leading comment indicator: |2
+     # first line starts with a
+     # character.
+   
+   # Explicit indentation may
+   # also be given when it is
+   # not required.
+   redundant: |2
+     This value is indented 2 spaces.
+ruby: |
+   {
+      'leading spaces' => "    This value starts with four spaces.\n",
+      'leading line break' => "\nThis value starts with a line break.\n",
+      'leading comment indicator' => "# first line starts with a\n# character.\n",
+      'redundant' => "This value is indented 2 spaces.\n"
+   }
+
+---
+test: Chomping and keep modifiers
+yaml: |
+    clipped: |
+        This has one newline.
+    
+    same as "clipped" above: "This has one newline.\n"
+    
+    stripped: |-
+        This has no newline.
+    
+    same as "stripped" above: "This has no newline."
+    
+    kept: |+
+        This has two newlines.
+    
+    same as "kept" above: "This has two newlines.\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has two newlines.\n\n",
+      'same as "kept" above' => "This has two newlines.\n\n"
+    }
+
+---
+test: Literal combinations
+yaml: |
+   empty: |
+   
+   literal: |
+    The \ ' " characters may be
+    freely used. Leading white
+       space is significant.
+    
+    Line breaks are significant.
+    Thus this value contains one
+    empty line and ends with a
+    single line break, but does
+    not start with one.
+    
+   is equal to: "The \\ ' \" characters may \
+    be\nfreely used. Leading white\n   space \
+    is significant.\n\nLine breaks are \
+    significant.\nThus this value contains \
+    one\nempty line and ends with a\nsingle \
+    line break, but does\nnot start with one.\n"
+   
+   # Comments may follow a block
+   # scalar value. They must be
+   # less indented.
+   
+   # Modifiers may be combined in any order.
+   indented and chomped: |2-
+       This has no newline.
+   
+   also written as: |-2
+       This has no newline.
+   
+   both are equal to: "  This has no newline."
+ruby: |
+   {
+     'empty' => '',
+     'literal' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'is equal to' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'indented and chomped' => '  This has no newline.',
+     'also written as' => '  This has no newline.',
+     'both are equal to' => '  This has no newline.'
+   }
+
+---
+test: Folded combinations
+yaml: |
+   empty: >
+   
+   one paragraph: >
+    Line feeds are converted
+    to spaces, so this value
+    contains no line breaks
+    except for the final one.
+   
+   multiple paragraphs: >2
+   
+     An empty line, either
+     at the start or in
+     the value:
+   
+     Is interpreted as a
+     line break. Thus this
+     value contains three
+     line breaks.
+   
+   indented text: >
+       This is a folded
+       paragraph followed
+       by a list:
+        * first entry
+        * second entry
+       Followed by another
+       folded paragraph,
+       another list:
+   
+        * first entry
+   
+        * second entry
+    
+       And a final folded
+       paragraph.
+   
+   above is equal to: |
+       This is a folded paragraph followed by a list:
+        * first entry
+        * second entry
+       Followed by another folded paragraph, another list:
+   
+        * first entry
+
+        * second entry
+    
+       And a final folded paragraph.
+   
+   # Explicit comments may follow
+   # but must be less indented.
+ruby: |
+   {
+     'empty' => '',
+     'one paragraph' => 'Line feeds are converted to spaces, so this value' +
+       " contains no line breaks except for the final one.\n",
+     'multiple paragraphs' => "\nAn empty line, either at the start or in the value:\n" +
+       "Is interpreted as a line break. Thus this value contains three line breaks.\n",
+     'indented text' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n",
+     'above is equal to' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n"
+   }
+
+---
+test: Single quotes
+yaml: |
+   empty: ''
+   second: '! : \ etc. can be used freely.'
+   third: 'a single quote '' must be escaped.'
+   span: 'this contains
+         six spaces
+   
+         and one
+         line break'
+   is same as: "this contains six spaces\nand one line break"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : \\ etc. can be used freely.',
+     'third' => "a single quote ' must be escaped.",
+     'span' => "this contains six spaces\nand one line break",
+     'is same as' => "this contains six spaces\nand one line break"
+   }
+
+---
+test: Double quotes
+yaml: |
+   empty: ""
+   second: "! : etc. can be used freely."
+   third: "a \" or a \\ must be escaped."
+   fourth: "this value ends with an LF.\n"
+   span: "this contains
+     four  \
+         spaces"
+   is equal to: "this contains four  spaces"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : etc. can be used freely.',
+     'third' => 'a " or a \\ must be escaped.',
+     'fourth' => "this value ends with an LF.\n",
+     'span' => "this contains four  spaces",
+     'is equal to' => "this contains four  spaces"
+   }
+
+---
+test: Unquoted strings
+yaml: |
+   first: There is no unquoted empty string.
+   
+   second: 12          ## This is an integer.
+   
+   boolean: -          ## This is (false).
+   
+   third: !str 12      ## This is a string.
+   
+   span: this contains
+         six spaces
+   
+         and one
+         line break
+   
+   indicators: this has no comments.
+               #:foo and bar# are
+               both text.
+   
+   flow: [ can span
+              lines, # comment
+              like
+              this ]
+   
+   note: { one-line keys: but
+           multi-line values }
+   
+ruby: |
+   {
+     'first' => 'There is no unquoted empty string.',
+     'second' => 12,
+     'boolean' => false,
+     'third' => '12',
+     'span' => "this contains six spaces\nand one line break",
+     'indicators' => "this has no comments. #:foo and bar# are both text.",
+     'flow' => [ 'can span lines', 'like this' ],
+     'note' => { 'one-line keys' => 'but multi-line values' }
+   }
+
+---
+test: Spanning sequences
+yaml: |
+   # The following are equal seqs
+   # with different identities.
+   flow: [ one, two ]
+   spanning: [ one,
+        two ]
+   block:
+     - one
+     - two
+ruby: |
+   {
+     'flow' => [ 'one', 'two' ],
+     'spanning' => [ 'one', 'two' ],
+     'block' => [ 'one', 'two' ]
+   }
+
+---
+test: Flow mappings
+yaml: |
+   # The following are equal maps
+   # with different identities.
+   flow: { one: 1, two: 2 }
+   block:
+       one: 1
+       two: 2
+ruby: |
+   {
+     'flow' => { 'one' => 1, 'two' => 2 },
+     'block' => { 'one' => 1, 'two' => 2 }
+   }
+
+---
+test: Representations of 12
+yaml: |
+   - 12 # An integer
+   # The following scalars
+   # are loaded to the
+   # string value '1' '2'.
+   - !str 12
+   - '12'
+   - "12"
+   - "\
+    1\
+    2\
+    "
+   # Strings containing paths and regexps can be unquoted:
+   - /foo/bar
+   - d:/foo/bar
+   - foo/bar
+   - /a.*b/
+ruby: |
+   [ 12, '12', '12', '12', '12', '/foo/bar', 'd:/foo/bar', 'foo/bar', '/a.*b/' ]
+
+---
+test: Null
+yaml: |
+   canonical: ~
+   
+   english: (null)
+   
+   # This sequence has four
+   # entries, two with values.
+   sparse:
+     - ~
+     - 2nd entry
+     - (nil)
+     - 4th entry
+   
+   four: This mapping has four keys,
+         only two with values.
+ruby: |
+   {
+     'canonical' => nil,
+     'english' => nil,
+     'sparse' => [ nil, '2nd entry', nil, '4th entry' ],
+     'four' => 'This mapping has four keys, only two with values.'
+   }
+
+---
+test: Boolean
+yaml: |
+   - : used as key  # Does not indicate a sequence.
+   canonical: +
+   logical:  (true)
+   informal: (no)
+ruby: |
+   {
+     false => 'used as key',
+     'canonical' => true,
+     'logical' => true,
+     'informal' => false
+   }
+
+---
+test: Integer
+yaml: |
+   canonical: 12345
+   decimal: +12,345
+   octal: 014
+   hexadecimal: 0xC
+ruby: |
+   {
+     'canonical' => 12345,
+     'decimal' => 12345,
+     'octal' => 12,
+     'hexadecimal' => 12 
+   }
+
+---
+test: Float
+yaml: |
+   canonical: 1.23015e+3
+   exponential: 12.3015e+02
+   fixed: 1,230.15
+   negative infinity: (-inf)
+   not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+no-round-trip:
+  - ruby
+
+---
+test: Timestamp
+yaml: |
+   canonical:       2001-12-15T02:59:43.1Z
+   valid iso8601:   2001-12-14t21:59:43.10-05:00
+   space separated: 2001-12-14 21:59:43.10 -05:00
+   date (noon UTC): 2002-12-14
+ruby: |
+   {
+     'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+     'valid iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'space separated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'date (noon UTC)' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Binary
+yaml: |
+   canonical: !binary "\
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf\
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW\
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++\
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg\
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN\
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww\
+    EeECcgggoBADs="
+   base64: !binary |
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww
+    EeECcgggoBADs=
+   description: >
+    The binary value above is a tiny arrow
+    encoded as a gif image.
+ruby-setup: |
+   arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005,  \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
+ruby: |
+   {
+     'canonical' => arrow_gif,
+     'base64' => arrow_gif,
+     'description' => "The binary value above is a tiny arrow encoded as a gif image.\n"
+   }
+
+---
+test: Default key
+yaml: |
+   ---     # Old schema
+   link with: 
+     - library1.dll
+     - library2.dll
+   ---     # New schema
+   link with:
+     - = : library1.dll
+       version: 1.2
+     - = : library2.dll
+       version: 2.3
+ruby: |
+   y = Stream.new
+   y.add( { 'link with' => [ 'library1.dll', 'library2.dll' ] } )
+   obj_h = YAML::SpecialHash[ 'version' => 1.2 ]
+   obj_h.default = 'library1.dll'
+   obj_h2 = YAML::SpecialHash[ 'version' => 2.3 ]
+   obj_h2.default = 'library2.dll'
+   y.add( { 'link with' => [ obj_h, obj_h2 ] } )
+documents: 2
+
+---
+test: Special keys
+yaml: |
+   "!": These three keys
+   "&": had to be quoted
+   "=": and are normal strings.
+   # NOTE: the following node should NOT be serialized this way.
+   encoded node :
+    !special '!' : '!type'
+    !special|canonical '&' : 12
+    = : value
+   # The proper way to serialize the above node is as follows:
+   node : !!type &12 value
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/docSep.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/docSep.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/docSep.yml	(revision 71)
@@ -0,0 +1,103 @@
+--- #YAML:1.0
+test: Trailing Document Separator
+brief: >
+    You can separate YAML documents
+    with a string of three dashes.
+yaml: |
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: Leading Document Separator
+brief: >
+    You can explicity give an opening
+    document separator to your YAML stream.
+yaml: |
+    ---
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: YAML Header
+brief: >
+    The opening separator can contain directives
+    to the YAML parser, such as the version
+    number.
+yaml: |
+    --- #YAML:1.0
+    foo: 1
+    bar: 2
+python: |
+    [
+        { 'foo': 1, 'bar': 2 }
+    ]
+ruby: |
+    y = Stream.new
+    y.add( { 'foo' => 1, 'bar' => 2 } )
+documents: 1
+
+---
+test: Red Herring Document Separator
+brief: >
+    Separators included in blocks or strings
+    are treated as blocks or strings, as the
+    document separator should have no indentation
+    preceding it.
+yaml: |
+    foo: |
+        ---
+python: |
+    [
+        { 'foo': "---\n" }
+    ]
+ruby: |
+    { 'foo' => "---\n" }
+
+---
+test: Multiple Document Separators in Block
+brief: >
+    This technique allows you to embed other YAML
+    documents within literal blocks.
+yaml: |
+    foo: |
+        ---
+        foo: bar
+        ---
+        yo: baz
+    bar: |
+        fooness
+python: |
+    [
+        {  'foo': flushLeft("""
+            ---
+            foo: bar
+            ---
+            yo: baz
+            """),
+           'bar': "fooness\n"
+        }
+    ]
+ruby: |
+    {  
+       'foo' => "---\nfoo: bar\n---\nyo: baz\n",
+       'bar' => "fooness\n"
+    }
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/basic.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/basic.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/basic.yml	(revision 71)
@@ -0,0 +1,242 @@
+--- #YAML:1.0
+test: Simple Sequence
+brief: >
+    You can specify a list in YAML by placing each
+    member of the list on a new line with an opening
+    dash. These lists are called sequences.
+yaml: |
+    - apple
+    - banana
+    - carrot
+perl: |
+    ['apple', 'banana', 'carrot'] 
+python: |
+    [ 
+        ['apple', 'banana', 'carrot'] 
+    ]
+ruby: |
+    ['apple', 'banana', 'carrot'] 
+
+---
+test: Nested Sequences
+brief: >
+    You can include a sequence within another
+    sequence by giving the sequence an empty
+    dash, followed by an indented list.
+yaml: |
+    -
+     - foo
+     - bar
+     - baz
+perl: |
+    [['foo', 'bar', 'baz']]
+python: |
+    [
+        [['foo', 'bar', 'baz']]
+    ]
+ruby: |
+    [['foo', 'bar', 'baz']]
+
+---
+test: Mixed Sequences
+brief: >
+    Sequences can contain any YAML data,
+    including strings and other sequences.
+yaml: |
+    - apple
+    -
+     - foo
+     - bar
+     - x123
+    - banana
+    - carrot
+perl: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+python: |
+    [
+        ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+    ]
+ruby: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+
+---
+test: Deeply Nested Sequences
+brief: >
+    Sequences can be nested even deeper, with each
+    level of indentation representing a level of
+    depth.
+yaml: |
+    -
+     -
+      - uno
+      - dos
+perl: |
+    [[['uno', 'dos']]]
+python: |
+    [
+        [[['uno', 'dos']]]
+    ]
+ruby: |
+    [[['uno', 'dos']]]
+
+---
+test: Simple Mapping
+brief: >
+    You can add a keyed list (also known as a dictionary or
+    hash) to your document by placing each member of the
+    list on a new line, with a colon seperating the key
+    from its value.  In YAML, this type of list is called
+    a mapping.
+yaml: |
+    foo: whatever
+    bar: stuff
+perl: |
+    { foo => 'whatever', bar => 'stuff' }
+python: |
+    [
+        {'foo': 'whatever', 'bar': 'stuff'}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => 'stuff' }
+
+---
+test: Sequence in a Mapping
+brief: >
+    A value in a mapping can be a sequence.
+yaml: |
+    foo: whatever
+    bar:
+     - uno
+     - dos
+perl: |
+    { foo => 'whatever', bar => [ 'uno', 'dos' ] }
+python: |
+    [
+        {'foo': 'whatever', 'bar': ['uno', 'dos']}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => [ 'uno', 'dos' ] }
+
+---
+test: Nested Mappings
+yaml: |
+    foo: whatever
+    bar:
+     fruit: apple
+     name: steve
+     sport: baseball
+brief: >
+    A value in a mapping can be another mapping.
+perl: |
+    { foo => 'whatever', 
+      bar => {
+         fruit => 'apple', 
+         name => 'steve',
+         sport => 'baseball'
+       }
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': {
+            'fruit': 'apple', 
+            'name': 'steve',
+            'sport': 'baseball'
+            }
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => {
+         'fruit' => 'apple', 
+         'name' => 'steve',
+         'sport' => 'baseball'
+       }
+    }
+
+---
+test: Mixed Mapping
+brief: >
+    A mapping can contain any assortment
+    of mappings and sequences as values.
+yaml: |
+    foo: whatever
+    bar:
+     -
+      fruit: apple
+      name: steve
+      sport: baseball
+     - more
+     -
+      python: rocks
+      perl: papers
+      ruby: scissorses
+perl: |
+    { foo => 'whatever', 
+      bar => [
+        {
+            fruit => 'apple', 
+            name => 'steve',
+            sport => 'baseball'
+        },
+        'more',
+        {
+            python => 'rocks',
+            perl => 'papers',
+            ruby => 'scissorses'
+        }
+      ]
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': [
+            {
+                'fruit': 'apple', 
+                'name': 'steve',
+                'sport': 'baseball'
+            },
+            'more',
+            {
+                'python': 'rocks',
+                'perl':  'papers',
+                'ruby': 'scissorses'
+            }
+         ]
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => [
+        {
+            'fruit' => 'apple', 
+            'name' => 'steve',
+            'sport' => 'baseball'
+        },
+        'more',
+        {
+            'python' => 'rocks',
+            'perl' => 'papers',
+            'ruby' => 'scissorses'
+        }
+      ]
+    }
+
+---
+test: Sequence-Mapping Shortcut
+brief: >
+     If you are adding a mapping to a sequence, you
+     can place the mapping on the same line as the
+     dash as a shortcut.
+yaml: |
+     - work on YAML.py:
+        - work on Store
+perl: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+python: |
+    [
+        [ {'work on YAML.py': ['work on Store']} ]
+    ]
+ruby: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ruby.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ruby.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestingSuite/ruby.yml	(revision 75)
@@ -0,0 +1,222 @@
+--- #YAML:1.0
+test: Symbols
+brief: >
+    Ruby Symbols can be simply serialized using
+    the !ruby/symbol transfer method, or the
+    abbreviated !ruby/sym.
+yaml: |
+    simple symbol: !ruby/symbol Simple
+    shortcut syntax: !ruby/sym Simple
+    symbols in seqs:
+      - !ruby/symbol ValOne
+      - !ruby/symbol ValTwo
+      - !ruby/symbol ValThree
+    symbols in maps:
+      !ruby/symbol MapKey: !ruby/symbol MapValue
+ruby: |
+    { 'simple symbol' => :Simple,
+      'shortcut syntax' => :Simple,
+      'symbols in seqs' => [ :ValOne, :ValTwo, :ValThree ],
+      'symbols in maps' => { :MapKey => :MapValue }
+    }
+
+---
+test: Ranges
+brief: >
+    Ranges are serialized with the !ruby/range
+    type family.
+yaml: |
+    normal range: !ruby/range 10..20
+    exclusive range: !ruby/range 11...20
+    negative range: !ruby/range -1..-5
+    ? !ruby/range 0..40
+    : range as a map key
+ruby: |
+    { 'normal range' => (10..20),
+      'exclusive range' => (11...20),
+      'negative range' => (-1..-5),
+      (0..40) => 'range as a map key'
+    }
+
+---
+test: Regexps
+brief: >
+    Regexps may be serialized to YAML, both its
+    syntax and any modifiers.
+yaml: |
+    case-insensitive: !ruby/regexp "/George McFly/i"
+    complex: !ruby/regexp "/\\A\"((?:[^\"]|\\\")+)\"/"
+    simple: !ruby/regexp '/a.b/'
+ruby: |
+    { 'simple' => /a.b/, 'complex' => /\A"((?:[^"]|\")+)"/,
+      'case-insensitive' => /George McFly/i }
+
+---
+test: Perl Regexps
+brief: >
+    Regexps may also be imported from serialized
+    Perl.
+yaml: |
+    --- !perl/regexp:
+      REGEXP: "R[Uu][Bb][Yy]$"
+      MODIFIERS: i
+ruby: |
+    /R[Uu][Bb][Yy]$/i
+
+---
+test: Struct class
+brief: >
+    The Ruby Struct class is registered as a YAML
+    builtin type through Ruby, so it can safely 
+    be serialized.  To use it, first make sure you
+    define your Struct with Struct::new.  Then,
+    you are able to serialize with Struct#to_yaml
+    and unserialize from a YAML stream.
+yaml: |
+    --- !ruby/struct:BookStruct
+      author: Yukihiro Matsumoto
+      title: Ruby in a Nutshell
+      year: 2002
+      isbn: 0-596-00214-9
+ruby-setup: |
+    book_struct = Struct::new( "BookStruct", :author, :title, :year, :isbn )
+ruby: |
+    book_struct.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" )
+
+---
+test: Nested Structs
+brief: >
+    As with other YAML builtins, you may nest the
+    Struct inside of other Structs or other data
+    types.
+yaml: |
+    - !ruby/struct:FoodStruct
+      name: Nachos
+      ingredients:
+        - Mission Chips
+        - !ruby/struct:FoodStruct
+          name: Tostitos Nacho Cheese
+          ingredients:
+            - Milk and Enzymes
+            - Jack Cheese
+            - Some Volatile Chemicals
+          taste: Angelic
+        - Sour Cream
+      taste: Zesty
+    - !ruby/struct:FoodStruct
+      name: Banana Cream Pie
+      ingredients:
+        - Bananas
+        - Creamy Stuff
+        - And Such
+      taste: Puffy
+ruby-setup: |
+    food_struct = Struct::new( "FoodStruct", :name, :ingredients, :taste )
+ruby: |
+    [
+      food_struct.new( 'Nachos', [ 'Mission Chips',
+        food_struct.new( 'Tostitos Nacho Cheese', [ 'Milk and Enzymes', 'Jack Cheese', 'Some Volatile Chemicals' ], 'Angelic' ),
+        'Sour Cream' ], 'Zesty' ),
+      food_struct.new( 'Banana Cream Pie', [ 'Bananas', 'Creamy Stuff', 'And Such' ], 'Puffy' )
+    ]
+
+---
+test: Objects
+brief: >
+    YAML has generic support for serializing objects
+    from any class available in Ruby.  If using the
+    generic object serialization, no extra code is
+    needed.
+yaml: |
+    --- !ruby/object:YAML::Zoolander
+      name: Derek
+      look: Blue Steel
+ruby-setup: |
+    class Zoolander
+      attr_accessor :name, :look
+      def initialize( look )
+        @name = "Derek"
+        @look = look
+      end
+      def ==( z )
+        self.name == z.name and self.look == z.look
+      end
+    end
+ruby: |
+    Zoolander.new( "Blue Steel" )
+
+---
+test: Extending Kernel::Array
+brief: >
+    When extending the Array class, your instances
+    of such a class will dump as YAML sequences,
+    tagged with a class name.
+yaml: |
+    --- !ruby/array:YAML::MyArray
+    - jacket
+    - sweater
+    - windbreaker
+ruby-setup: |
+    class MyArray < Kernel::Array; end
+ruby: |
+    outerwear = MyArray.new
+    outerwear << 'jacket'
+    outerwear << 'sweater'
+    outerwear << 'windbreaker'
+    outerwear
+
+---
+test: Extending Kernel::Hash
+brief: >
+    When extending the Hash class, your instances
+    of such a class will dump as YAML maps, tagged
+    with a class name.
+yaml: |
+    --- !ruby/hash:YAML::MyHash
+    Black Francis: Frank Black
+    Kim Deal: Breeders
+    Joey Santiago: Martinis
+ruby-setup: |
+    # Note that the @me attribute isn't dumped
+    # because the default to_yaml is trained
+    # to dump as a regular Hash.
+    class MyHash < Kernel::Hash
+      attr_accessor :me
+      def initialize
+        @me = "Why"
+      end
+    end
+ruby: |
+    pixies = MyHash.new
+    pixies['Black Francis'] = 'Frank Black'
+    pixies['Kim Deal'] = 'Breeders'
+    pixies['Joey Santiago'] = 'Martinis'
+    pixies
+
+---
+test: YAML::Pairs
+brief: >
+    The sequence-mapping shortcut in YAML allows you to 
+    place the first line of the mapping on the same line 
+    as the dash for the entry containing the mapping. 
+    The !ruby/pairs type takes advantage of this shortcut 
+    to create (instead of a sequence including maps) a 
+    single object of pairs which can be accessed like an 
+    ordered hash. Entries in which the last value in the 
+    pair is null can simply show the first value in the pair.
+yaml: |
+    --- !ruby/pairs
+    - Minh Thai: 22.95
+    - Guus Razous-Schultz: 24.32
+    - Zoltan Labas Hungary: 24.49
+    - Lars Petrus
+    - Ken`ichi Ueno Japan
+ruby: |
+    winners = YAML::Pairs.new
+    winners[ 'Minh Thai' ] = 22.95
+    winners[ 'Guus Razous-Schultz' ] = 24.32
+    winners[ 'Zoltan Labas Hungary' ] = 24.49
+    winners[ 'Lars Petrus' ] = nil
+    winners[ 'Ken`ichi Ueno Japan' ] = nil
+    winners
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/patches/stream.py.patch
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/patches/stream.py.patch	(revision 72)
+++ /pyyaml-legacy/tags/PyYaml_0.32/patches/stream.py.patch	(revision 72)
@@ -0,0 +1,53 @@
+--- yaml/stream.py	2002-12-26 09:53:42.000000000 -0800
++++ yaml/stream.py	2003-12-04 13:14:41.000000000 -0800
+@@ -94,12 +94,15 @@
+         return self.commentEater.lastLineRead()
+ 
+     def reset(self):
+         self.indentLevel = 0
+         self.oldIndents = [0]
++        self.empty = 0
+ 
+     def peek(self):
++        if self.empty:
++            return
+         nextLine = self.commentEater.peek()
+         if nextLine is not None:
+             if indentLevel(nextLine) >= self.indentLevel:
+                 return nextLine[self.indentLevel:]
+             elif nextLine == '':
+@@ -107,10 +110,11 @@
+ 
+     def pop(self):
+         line = self.peek()
+         if line is None:
+             self.indentLevel = self.oldIndents.pop()
++            self.empty = 0
+             return
+         self.commentEater.pop()
+         return line
+ 
+     def popNestedLines(self):
+@@ -128,19 +132,20 @@
+ 
+     def nestToNextLine(self):
+         line = self.commentEater.peek()
+         indentation = indentLevel(line)
+         if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+-            self.error("Inadequate indentation", line)
++            self.empty = 1
++            #self.error("Inadequate indentation", line)
+         self.setNewIndent(indentation)
+ 
+     def nestBySpecificAmount(self, adjust):
+         self.setNewIndent(self.indentLevel + adjust)
+         
+     def setNewIndent(self, indentLevel):
+         self.oldIndents.append(self.indentLevel)
+-        self.indentLevel = indentLevel    
++        self.indentLevel = indentLevel
+ 
+ class YamlLoaderException(Exception):
+     def __init__(self, *args):
+         (self.msg, self.lineNum, self.line, self.filename) = args
+ 
Index: /pyyaml-legacy/tags/PyYaml_0.32/patches/load.py.patch
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/patches/load.py.patch	(revision 72)
+++ /pyyaml-legacy/tags/PyYaml_0.32/patches/load.py.patch	(revision 72)
@@ -0,0 +1,103 @@
+--- yaml/load.py	2002-12-26 08:38:51.000000000 -0800
++++ yaml/load.py	2003-10-02 15:53:06.000000000 -0700
+@@ -45,10 +45,13 @@
+             if ok:
+                 return (1, result)
+ 
+ def dumpDictionary(): return {}
+ 
++_STRIP = 1
++_KEEP = 2
++
+ class Parser:
+     def __init__(self, stream, typeResolver=None):
+         try:
+             self.dictionary = dict
+         except:
+@@ -167,19 +170,16 @@
+         if alias:
+             self.aliases[alias] = value
+         return value          
+ 
+     def parse_unaliased_value(self, value):
+-        match = re.match(r"(!\S*)(.*)", value)
++        match = re.match(r"(!\S*) (.*)", value)
+         if match:
+             (url, value) = match.groups()
+-            value = self.parse_untyped_value(value)
+             if url[:2] == '!!':
+                 return self.typeResolver.resolveType(value, url)
+-            else:
+-                # XXX - allows syntax, but ignores it
+-                return value
++            return self.parse_untyped_value(value)
+         return self.parse_untyped_value(value)
+ 
+     def parseInlineArray(self, value):        
+         if re.match("\s*\[", value):
+             return self.parseInline([], value, ']', 
+@@ -231,36 +231,54 @@
+ 
+     def parseNative(self, value):
+         return (1, convertImplicit(value))
+ 
+     def parseMultiLineScalar(self, value):
++        # XXX does not handle indentation ex. >2, or |2
+         if value == '>':
+             return (1, self.parseFolded())
++        elif value == '>-':
++            return (1, self.parseFolded(_STRIP))
++        elif value == '>+':
++            return (1, self.parseFolded(_KEEP))
+         elif value == '|':
+-            return (1, joinLiteral(self.parseBlock()))
++            return (1, self.parseBlock())
++        elif value == '|-':
++            return (1, self.parseBlock(_STRIP))
+         elif value == '|+':
+-            return (1, joinLiteral(self.unprunedBlock()))
++            return (1, self.parseBlock(_KEEP))
+ 
+-    def parseFolded(self):
+-        data = self.parseBlock()
++    def parseFolded(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
+         i = 0
+         resultString = ''
+         while i < len(data)-1:
+-            resultString = resultString + data[i]
+-            resultString = resultString + foldChar(data[i], data[i+1])
+-            i = i + 1
+-        return resultString + data[-1] + "\n"        
++            resultString += data[i]
++            resultString += foldChar(data[i], data[i+1])
++            i += 1
++        resultString += data[-1]
++        if chomping ==_STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def unprunedBlock(self):
+         self.nestedDocs.nestToNextLine()
+         data = []
+         while self.nestPop():
+             data.append(self.line)
+         return data
+ 
+-    def parseBlock(self):
+-        return pruneTrailingEmpties(self.unprunedBlock())
++    def parseBlock(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
++        resultString = string.join(data, "\n")
++        if chomping == _STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def testForAlias(self, value):
+         match = re.match("&(\S*)\s*(.*)", value)
+         if match:
+             return match.groups()
Index: /pyyaml-legacy/tags/PyYaml_0.32/CHANGELOG
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/CHANGELOG	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/CHANGELOG	(revision 75)
@@ -0,0 +1,71 @@
+---
+- version: 0.32
+  date: 2002-12-26
+  changes:
+    - report filenames in loadFile exceptions
+    - added loadOrdered() method
+---
+- version: 0.31
+  date: 2002-11-17
+  changes:
+    - dumper doesn't quote strings just because they have dashes
+    - dumper does quote strings that look like negative numbers
+    - dumper does quote strings w/*, &, and white space on edges
+    - dumper doesn't quote strings starting with "* "
+    - loader can tolerate "* " unquoted
+    - complain about duplicate keys in dictionary
+    - complain about trailing spaces
+    - l() and d() convenience methods
+    - applied Tim Hochberg's FLOAT/SCIENTIFIC patch
+    - sync __version__ to CHANGELOG
+---
+- version: 0.30
+  date: 2002-11-06
+  changes:
+    - bunch of changes for 2.1 support
+    - fully tested on 2.1.3 and 2.2
+    - added YamlLoaderException
+    - pluggable dictionaries (2.2 only)
+    - simplified iterator interface (deprecated getNextDocument)
+    - single quote &foo properly
+    - quote "foo'bar properly
+---
+- version: 0.29
+  date: 2002-11-03
+  changes:
+    - support |+ syntax
+---
+- version: 0.28
+  date: 2002-09-25
+  changes:
+    - use compiled regexes for speed
+    - streamlined stream.py for speed
+    - added profileYaml.py
+---
+- version: 0.27
+  date: 2002-09-24
+  changes:
+    - better error handling
+    - removed spurious spaces from specs.yml
+    - use a true FileStream class vs. reading in entire file up front
+---
+- version: 0.26
+  date: 2002-09-23
+  changes:
+    - support to_yaml() when you inherit from Python's dict class
+    - move implicit and inline logic into own modules
+    - require space after comma for inline collections (Brian Dorsey)
+    - only call user's resolver for !!private types
+    - don't choke on !str, etc. (but doesn't yet respect them)
+    - fixed bugs in loader/dumper related to integer dict keys (Joel Shprentz)
+---
+- version: 0.25
+  date: 2002-08-21
+  changes:
+    - extensive refactorings on dumper
+    - Dumper class made public
+    - new interface for setIndent and setSort
+    - added Dave Kuhlman's XmlYaml stuff
+    - limiting support to Python 2.2 and above
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/YamlTest.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/YamlTest.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/YamlTest.py	(revision 75)
@@ -0,0 +1,118 @@
+import unittest, sys, string
+import yaml
+from here import flushLeft
+import re
+import glob
+from test import assertEquals, assertError
+from yaml.klass import makeClass
+
+try:
+   unicode('')
+   hasUnicode = 1
+except:
+   hasUnicode = 0
+
+
+def loadFlushLeft(stream, typeResolver=None):
+    return list(yaml.load(flushLeft(stream), typeResolver))
+
+class YamlTest(unittest.TestCase):
+
+    def runTest(self):
+        # reinvent the wheel, instead of trying to 
+        # understand unittest's braindead interface
+        for name in dir(self.__class__):
+            if re.match('test', name):
+                exec('self.%s()' % name)
+
+    def verify(self, stream, results):
+        self.verifyMany(stream, [results])
+
+    def verifyMany(self, stream, expected):
+        results = loadFlushLeft(stream)
+        assertEquals(results, expected)
+
+class ClassForRuntime:
+    def __init__(self):
+        self.foo = 1
+        self.bar = 2
+
+class YamlLoader:
+    # XXX python 2.1 has weak lambda support
+    def __init__(self, doc):
+        self.doc = doc
+    def __call__(self):
+        return list(yaml.load(self.doc['yaml']))
+
+class TestFromSpec(YamlTest):
+    def testFromYaml(self):
+        testFiles = glob.glob('TestingSuite/*.yml')
+        for file in testFiles:
+            # print "\n\n\n\n", file
+            try:
+                docs = yaml.loadFile(file)
+            except IOError:
+                raise "See TESTING for how to set up TestingSuite"
+            for doc in docs:
+                if doc.has_key('python'):
+                    self.verifyOneDoc(doc)
+                if doc.has_key('error') and doc['error'].has_key('python'):
+                    assertError(YamlLoader(doc), doc['error']['python'])
+
+    def verifyOneDoc(self, doc):
+        if doc.has_key('python_setup'):
+            exec(doc['python_setup'])
+        data = eval(doc['python'])
+        # print data
+        assertEquals(list(yaml.load(doc['yaml'])), data)
+        if not doc.has_key('NO_ROUND_TRIP'):
+            self.assertRoundTrip(data)
+
+    def assertRoundTrip(self, data):
+        # XXX - A5 won't round trip when enclosed by 
+        # an array...need to investigate
+        for item in data:
+            # print dump(item)
+            assertEquals(item, 
+                yaml.load(yaml.dump(item)).next(), 'roundtrip')
+
+
+class TestUtils(YamlTest):    
+    class Dummy:
+        pass
+
+    def testMakeClass(self):
+        self.assertEquals(42,
+            makeClass('YamlTest', 'TestUtils.Dummy', 
+                {'a': 27, 'b': 42}).b)
+
+    class FromYaml:
+        def from_yaml(self, dict):
+            self.sum = dict['a'] + dict['b']
+            return self
+
+    def testMakeClassFromYaml(self):
+        self.assertEquals(6,
+            makeClass('YamlTest', 'TestUtils.FromYaml',
+                {'a': 2, 'b': 4}).sum)
+
+
+def testVersion():
+    from yaml import __version__
+    assertEquals(__version__, str(yaml.loadFile('CHANGELOG').next()[0]['version']))
+
+if __name__ == '__main__':
+    import TestYamlBasics
+    import TestNestedText
+    import TestInlineTokenizer
+    import TestDumper
+    ts = unittest.TestSuite()
+    ts.addTest(TestYamlBasics.Test())
+    ts.addTest(TestNestedText.Test())
+    ts.addTest(TestInlineTokenizer.Test())
+    ts.addTest(TestDumper.Test())
+    ts.addTest(TestFromSpec())
+    ts.addTest(TestUtils())
+    unittest.TextTestRunner().run(ts)
+    yaml.dumpToFile(sys.stdout, {'TESTING dumpToFile': 'ok'})
+    testVersion()
Index: /pyyaml-legacy/tags/PyYaml_0.32/insert.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/insert.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/insert.py	(revision 75)
@@ -0,0 +1,20 @@
+from PyYaml import yaml
+from test import assertEquals
+from ypath import Ypath
+import re
+
+def Insert(data, command):
+    if command.has_key('ypath'):
+        Ypath(data, command['ypath']).append(command['value'])
+        return data
+    return data + [command['value']]
+
+def TestInsert(data, command, expected):
+    assertEquals(Insert(data, command), expected)    
+
+doc = yaml.loadFile("insert.yml")[0]
+for test in doc['tests']:
+    if not test.has_key('ignore'):
+        TestInsert(test['data'], test['command'], test['expected'])
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/query.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/query.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/query.py	(revision 75)
@@ -0,0 +1,66 @@
+import yaml
+from test import assertEquals
+import re
+
+def Query(query, doc):
+    results = []
+    for row in yaml.ypath(query['from'],doc):
+        data = {}
+        if Where(row, query):
+            for field in query['select']:
+                data[field] = yaml.ypath(field,row).next()
+            if query.has_key('order'):
+                data['__row__'] = row
+            results.append(data)
+    return Order(results, query)
+
+def Where(row, query):
+    if query.has_key('where'):
+        where = query['where']
+        return WhereRow(row, query['where'])
+    return 1
+
+def WhereRow(row, where):
+    if type(where) == type([]):
+        return And(row, where, WhereRow)
+    if type(where) == type(''):
+        return WhereString(row, where)
+    return And(row, where.keys(), 
+        lambda row, field: where[field] == row[field])
+
+def And(row, conds, condFunc):
+    for cond in conds:
+        if not condFunc(row, cond):
+            return 0
+    return 1
+
+def WhereString(row, where):
+    where = re.sub("\[(.*?)\]", r"row['\1']", where)
+    return eval(where)
+
+def Order(results, query):
+    if not query.has_key('order'):
+        return results
+    compare = lambda x,y: Compare(x,y,query['order'])
+    results.sort(compare)
+    for result in results:
+        del result['__row__']
+    return results
+
+def Compare(x, y, order):
+    for field in order:
+        val = cmp(
+            yaml.ypath(field,x['__row__']).next(),
+            yaml.ypath(field,y['__row__']).next()
+        )
+        if val != 0: return val
+
+def TestQuery(query, expected, data):
+    assertEquals(Query(query, data), expected, query)    
+
+doc = yaml.loadFile("query.yml").next()
+for test in doc['tests']:
+    if not test.has_key('ignore'):
+        TestQuery(test['query'], test['expected'], doc['data'])
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/LIMITATIONS
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/LIMITATIONS	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/LIMITATIONS	(revision 75)
@@ -0,0 +1,38 @@
+PYTHON VERSION: >
+   PyYaml is developed with Python version 2.2.  I can't live 
+   without Python 2.2--too many great features.  Please do 
+   yourself a favor and upgrade now.  I know the decision to
+   only support 2.2 and above may lock out some potential users,
+   but I believe it will pay dividends in the future, because
+   the version 2.2 features allow cleaner and more expressive 
+   code.  I do intend to support version 2.2 for a long time.
+
+DISCLAIMER: > 
+   PyYaml is not ready to be used as a robust serialization tool,
+   although it is moving in that direction, and you can certainly
+   experiment with it.
+
+   You can use it more safely for one-way applications.  You can
+   make YAML be an input-tool only, such as for configuration files
+   or data-driven programs.  You can also use YAML as an output-only
+   tool, for things like logging and debugging.
+
+   You can report bugs to showell@zipcon.net.  As of this writing
+   (August 2002), I am actively improving PyYaml.
+
+   The interface for YAML is stabilizing, but it is too early in 
+   the life cycle for me to guarantee backward compatibility in 
+   future releases.  I recommend wrapping your YAML calls in your 
+   own methods, if you are concerned about changing interfaces.
+   The basic paradigm of load, loadFile, save, and saveFile 
+   shouldn't change, but the way that you customize the loader 
+   and parser's behavior may.
+
+SOME KNOWN BUGS/LIMITATIONS:
+  - folded scalars can't lead with blank line
+  - emitter gives invalid YAML for multi-line scalars starting w/whitespace
+  - trailing white space after quotes not ignored
+  - support for inlined hashes and arrays very primitize--can't nest
+    structures and must use simple scalars
+  - specifiers like !str, !int, etc. are ignored
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/README
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/README	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/README	(revision 75)
@@ -0,0 +1,105 @@
+- Introductions: >
+   Hello.  Welcome to the Python YAML parser.  This is 
+   a work in progress.   The primary author is Steve Howell,
+   with a few contributions by Clark Evans.
+
+- installation: >
+   Simply type "make install" as root, this runs python setup.py install.
+   If you do not have distutils installed, you can simply copy the
+   yaml sub-directory into site-packages.
+
+- testing: >
+   You should be able to type "make test" both before and
+   after the installation.  This simply runs python on the
+   test programs.
+
+   This package uses python iterators, but there is a surrogate
+   which returns a list object instead of an iterator for python
+   versions below 2.2
+
+   This package should work with 1.5.2 and up, although many of
+   the tests fail with 1.5.2; if you are an expert with 1.5.2
+   please help us patch this up so that it works on older versions
+   of Python.
+
+- playing: >
+   The best way to play, is to start with demo.py and 
+   work from there.  Note that this implementation has quite
+   a way to go before it is compliant with the YAML specification.
+   
+   If something is failing in the tests for your platform
+   please let us know.  If something doesn't work, check the
+   tests to see if the test covering the feature you need is
+   active; if not, chances are it's not implemented.
+
+   Your feedback or any other contributions are certainly welcome.
+
+- ypath: >
+   The YPATH implementation is EXPERIMENTAL but included
+   in the yaml package beacuse it is fun and we'd like to get
+   feedback from the user community as to how they'd like it 
+   to work.  It requries Python 2.2 since it uses iterators.
+
+- query: >
+   There is a query.py and query.yml file in this directory,
+   it is currently broke as ypath was re-written.
+
+---
+contributors:
+  - who: Steve Howell
+    why?: |
+      Original author of the pure Python implementations of the 
+      YAML parser and emitter.  Many thanks to the other folks 
+      listed here, and some not listed here.  
+    email: showell@zipcon.net
+
+  - who: Brian Ingerson
+    why?: |
+      Brian got me hooked on YAML.  We have used his Perl 
+      implementation to do some really cool stuff, even on projects
+      that primarily used XML.  He also got me started on 
+      the Python project.
+
+  - who: Clark Evans
+    why?: |
+      Clark's YAML fame far precedes the Python implementation--he
+      founded the whole project.  But, he also contributed alias 
+      emitting to this project, and he's also generously allowed
+      me to bundle his very cool YPATH implementation.  Finally,
+      he's helped with module packaging issues and miscellaneous
+      features and bug fixes.
+
+  - who: Why The Lucky Stiff
+    why?: |
+      That's right, Why's the name, Ruby's the game.  Why devotes
+      most of his YAML effort to a Ruby implementation that grows
+      increasingly robust, but he's also a great team player on 
+      the YAML project.  For example, he consolidated the YAML
+      testing suites, so that multiple YAML implementations can 
+      share the same YAML test files.  If you look in this YAML
+      distribution, you will see Ruby all over the place.  Think
+      of it as a free introduction to another great scripting 
+      language.
+
+  - who: Ryan King
+    why?: |
+      Sharpener of saws and pair programmer extraordinaire.
+
+  - who: Neil Watkiss
+    why?: |
+      Donated hardware and major expertise to the project.       
+
+  - who: Oren Ben-Kiki
+    why?: |
+      YAML cofounder.  All library implementors owe a huge gratitude 
+      toward Oren for his work on the YAML spec.
+
+  - who: Lion Kimbro
+    why?: |
+      Early adopter, also known for his three-humped YAML.
+       
+  - who: Dave Kuhlman
+    why?: |
+      Dave's contributions include, but are not limited to, the 
+      XmlYaml code bundled with this distribution.  The README
+      with that code talks more about Dave.
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestInlineTokenizer.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestInlineTokenizer.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestInlineTokenizer.py	(revision 75)
@@ -0,0 +1,22 @@
+import YamlTest
+from test import assertEquals
+from yaml.load import *
+
+
+class Test(YamlTest.YamlTest):
+    def testSimple(self):
+        tokenizer = InlineTokenizer('[ foo, bar ]')
+        assertEquals(tokenizer.next(), '[')
+        assertEquals(tokenizer.next(), 'foo')
+        assertEquals(tokenizer.next(), 'bar')
+        assertEquals(tokenizer.next(), ']')
+
+    def testSimpleHash(self):
+        tokenizer = InlineTokenizer('{ foo: bar }')
+        assertEquals(tokenizer.next(), '{')
+        assertEquals(tokenizer.next(), 'foo: bar') # might change
+        assertEquals(tokenizer.next(), '}')
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/implicit.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/implicit.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/implicit.py	(revision 75)
@@ -0,0 +1,46 @@
+import re
+import string
+from timestamp import timestamp, matchTime
+
+DATETIME_REGEX   = re.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")
+FLOAT_REGEX      = re.compile("^[-+]?[0-9][0-9,]*\.[0-9]*$")
+SCIENTIFIC_REGEX = re.compile("^[-+]?[0-9]+(\.[0-9]*)?[eE][-+][0-9]+$")
+OCTAL_REGEX      = re.compile("^[-+]?([0][0-7,]*)$")
+HEX_REGEX        = re.compile("^[-+]?0x[0-9a-fA-F,]+$")
+INT_REGEX        = re.compile("^[-+]?(0|[1-9][0-9,]*)$")
+
+def convertImplicit(val):
+    if val == '~':
+        return None
+    if val == '+':
+        return 1
+    if val == '-':
+        return 0
+    if val[0] == "'" and val[-1] == "'":
+        val = val[1:-1]
+        return string.replace(val, "''", "\'")
+    if val[0] == '"' and val[-1] == '"':
+        if re.search(r"\u", val):
+            val = "u" + val
+        unescapedStr = eval (val)
+        return unescapedStr
+    if matchTime.match(val):
+        return timestamp(val)
+    if INT_REGEX.match(val):
+        return int(cleanseNumber(val))
+    if OCTAL_REGEX.match(val):
+        return int(val, 8)
+    if HEX_REGEX.match(val):
+        return int(val, 16)
+    if FLOAT_REGEX.match(val):
+        return float(cleanseNumber(val))
+    if SCIENTIFIC_REGEX.match(val):
+        return float(cleanseNumber(val))
+    return val
+
+def cleanseNumber(str):
+    if str[0] == '+':
+        str = str[1:]
+    str = string.replace(str,',','')
+    return str
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/stream.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/stream.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/stream.py	(revision 75)
@@ -0,0 +1,193 @@
+import re
+import string
+
+def indentLevel(line):
+    n = 0
+    while n < len(line) and line[n] == ' ':
+        n = n + 1
+    return n
+
+class LineNumberStream:
+    def __init__(self, filename=None):
+        self.curLine = 0
+        self.filename = filename
+
+    def get(self):
+        line = self.getLine()
+        self.curLine += 1 # used by subclass
+        if line:
+            line = noLineFeed(line)
+        return line
+
+    def lastLineRead(self):
+        return self.curLine
+
+class FileStream(LineNumberStream):
+    def __init__(self, filename):
+        self.fp = open(filename)
+        LineNumberStream.__init__(self, filename)
+
+    def getLine(self):
+        line = self.fp.readline()
+        if line == '': line = None
+        return line
+
+class StringStream(LineNumberStream):
+    def __init__(self, text):
+        self.lines = split(text)
+        self.numLines = len(self.lines)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        if self.curLine < self.numLines:
+            return self.lines[self.curLine]
+
+def split(text):
+    lines = string.split(text, '\n')
+    if lines[-1] == '':
+        lines.pop()
+    return lines
+
+def eatNewLines(stream):
+    while 1:
+       line = stream.get()
+       if line is None or len(string.strip(line)):
+           return line
+
+COMMENT_LINE_REGEX = re.compile(R"\s*#")
+def isComment(line):
+    return line is not None and COMMENT_LINE_REGEX.match(line)
+
+class CommentEater:
+    def __init__(self, stream):
+        self.stream = stream
+        self.peeked = 1
+        self.line = eatNewLines(stream)
+        self.eatComments()
+
+    def eatComments(self):
+        while isComment(self.line):
+            self.line = self.stream.get()
+
+    def peek(self):
+        if self.peeked:
+            return self.line
+        self.peeked = 1
+        self.line = self.stream.get()
+        self.eatComments()
+        return self.line
+
+    def lastLineRead(self):
+        return self.stream.lastLineRead()
+
+    def pop(self):
+        data = self.peek()
+        self.peeked = 0
+        return data
+
+class NestedText:
+    def __init__(self, stream):
+        self.commentEater = CommentEater(stream)
+        self.reset()
+
+    def lastLineRead(self):
+        return self.commentEater.lastLineRead()
+
+    def reset(self):
+        self.indentLevel = 0
+        self.oldIndents = [0]
+
+    def peek(self):
+        nextLine = self.commentEater.peek()
+        if nextLine is not None:
+            if indentLevel(nextLine) >= self.indentLevel:
+                return nextLine[self.indentLevel:]
+            elif nextLine == '':
+                return ''                
+
+    def pop(self):
+        line = self.peek()
+        if line is None:
+            self.indentLevel = self.oldIndents.pop()
+            return
+        self.commentEater.pop()
+        return line
+
+    def popNestedLines(self):
+        nextLine = self.peek()
+        if nextLine is None or nextLine == '' or nextLine[0] != ' ':
+            return []
+        self.nestToNextLine()
+        lines = []
+        while 1:
+            line = self.pop()
+            if line is None:
+                break
+            lines.append(line)
+        return lines
+
+    def nestToNextLine(self):
+        line = self.commentEater.peek()
+        indentation = indentLevel(line)
+        if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+            self.error("Inadequate indentation", line)
+        self.setNewIndent(indentation)
+
+    def nestBySpecificAmount(self, adjust):
+        self.setNewIndent(self.indentLevel + adjust)
+        
+    def setNewIndent(self, indentLevel):
+        self.oldIndents.append(self.indentLevel)
+        self.indentLevel = indentLevel    
+
+class YamlLoaderException(Exception):
+    def __init__(self, *args):
+        (self.msg, self.lineNum, self.line, self.filename) = args
+
+    def __str__(self):
+        msg = """\
+%(msg)s:
+near line %(lineNum)d:
+%(line)s
+""" % self.__dict__
+        if self.filename:
+            msg += "file: " + self.filename
+        return msg
+
+class NestedDocs(NestedText):
+    def __init__(self, stream):
+        self.filename = stream.filename
+        NestedText.__init__(self,stream)
+        line = NestedText.peek(self)
+        self.sep = '---'
+        if self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+        else:
+            self.eatenDocSep = self.sep
+
+    def startsWithSep(self,line):
+        if line and self.sep == line[:3]: return 1
+        return 0
+
+    def popDocSep(self):
+        line = self.eatenDocSep
+        self.eatenDocSep = None
+        self.reset()
+        return line
+
+    def pop(self):
+        if self.eatenDocSep is not None:
+            raise "error"
+        line = self.commentEater.peek()
+        if line and self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+            return None
+        return NestedText.pop(self)
+
+    def error(self, msg, line):
+        raise YamlLoaderException(msg, self.lastLineRead(), line, self.filename)
+
+def noLineFeed(s):
+    while s[-1:] in ('\n', '\r'):
+        s = s[:-1]
+    return s
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/redump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/redump.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/redump.py	(revision 75)
@@ -0,0 +1,14 @@
+from yaml.ordered_dict import OrderedDict
+from yaml import Parser, Dumper, StringStream
+
+def loadOrdered(stream):
+    parser = Parser(StringStream(stream))
+    parser.dictionary = OrderedDict
+    return iter(parser)
+
+def redump(stream):
+    docs = list(loadOrdered(stream))
+    dumper = Dumper()
+    dumper.alphaSort = 0
+    return dumper.dump(*docs)
+    
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/klass.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/klass.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/klass.py	(revision 71)
@@ -0,0 +1,48 @@
+import new
+import re
+
+class DefaultResolver:
+    def resolveType(self, data, typestring):
+        match = re.match('!!(.*?)\.(.*)', typestring)
+        if not match:
+            raise "Invalid private type specifier"
+        (modname, classname) = match.groups()
+        return makeClass(modname, classname, data)
+
+def makeClass(module, classname, dict):
+    exec('import %s' % (module))
+    klass = eval('%s.%s' % (module, classname))
+    obj = new.instance(klass) 
+    if hasMethod(obj, 'from_yaml'):
+        return obj.from_yaml(dict)
+    obj.__dict__ = dict
+    return obj
+
+def hasMethod(object, method_name):
+    try:    
+        klass = object.__class__
+    except:
+        return 0
+    if not hasattr(klass, method_name):
+        return 0
+    method = getattr(klass, method_name)
+    if not callable(method):
+        return 0
+    return 1
+
+def isDictionary(data):
+    return isinstance(data, dict)
+
+try:
+    isDictionary({})
+except:
+    def isDictionary(data): return type(data) == type({}) # XXX python 2.1
+    
+if __name__ == '__main__':
+    print isDictionary({'foo': 'bar'})
+    try:
+        print isDictionary(dict())
+        from ordered_dict import OrderedDict
+        print isDictionary(OrderedDict())
+    except:
+        pass
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/inline.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/inline.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/inline.py	(revision 71)
@@ -0,0 +1,38 @@
+import re
+import string
+
+class InlineTokenizer:
+    def __init__(self, data):
+        self.data = data
+
+    def punctuation(self):
+        puncts = [ '[', ']', '{', '}' ]
+        for punct in puncts:
+            if self.data[0] == punct:
+                self.data = self.data[1:]
+                return punct
+
+    def up_to_comma(self):
+        match = re.match('(.*?)\s*, (.*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def up_to_end_brace(self):
+        match = re.match('(.*?)(\s*[\]}].*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def next(self):
+        self.data = string.strip(self.data)
+        productions = [
+            self.punctuation,
+            self.up_to_comma,
+            self.up_to_end_brace
+        ]
+        for production in productions:
+            token = production()
+            if token:
+                return token
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/__init__.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/__init__.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/__init__.py	(revision 75)
@@ -0,0 +1,17 @@
+__version__ = "0.32"
+from load import loadFile, load, Parser, l
+from dump import dump, dumpToFile, Dumper, d
+from stream import YamlLoaderException, StringStream, FileStream
+from timestamp import timestamp
+import sys
+if sys.hexversion >= 0x02020000:
+    from redump import loadOrdered
+
+try:
+    from ypath import ypath
+except NameError:
+    def ypath(expr,target='',cntx=''):
+        raise NotImplementedError("ypath requires Python 2.2")
+
+if sys.hexversion < 0x02010000:
+    raise 'YAML is not tested for pre-2.1 versions of Python'
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/load.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/load.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/load.py	(revision 75)
@@ -0,0 +1,327 @@
+import re, string
+from implicit import convertImplicit
+from inline import InlineTokenizer
+from yaml.klass import DefaultResolver
+from yaml.stream import YamlLoaderException, FileStream, StringStream, NestedDocs
+
+try:
+    iter(list()) # is iter supported by this version of Python?
+except:
+    # XXX - Python 2.1 does not support iterators   
+    class StopIteration: pass
+    class iter:
+        def __init__(self,parser):
+            self._docs = []
+            try:
+                while 1:
+                   self._docs.append(parser.next())
+            except StopIteration: pass
+            self._idx = 0
+        def __len__(self): return len(self._docs)
+        def __getitem__(self,idx): return self._docs[idx]
+        def next(self):
+            if self._idx < len(self._docs):
+                ret = self._docs[self._idx] 
+                self._idx = self._idx + 1
+                return ret
+            raise StopIteration
+
+def loadFile(filename, typeResolver=None):
+    return loadStream(FileStream(filename),typeResolver)
+   
+def load(str, typeResolver=None):
+    return loadStream(StringStream(str), typeResolver)
+
+def l(str): return load(str).next()
+
+def loadStream(stream, typeResolver):
+    return iter(Parser(stream, typeResolver))
+
+def tryProductions(productions, value):
+    for production in productions:
+        results = production(value)
+        if results:
+            (ok, result) = results
+            if ok:
+                return (1, result)
+
+def dumpDictionary(): return {}
+
+class Parser:
+    def __init__(self, stream, typeResolver=None):
+        try:
+            self.dictionary = dict
+        except:
+            self.dictionary = dumpDictionary
+        self.nestedDocs = NestedDocs(stream)
+        self.aliases = {}
+        if typeResolver:
+            self.typeResolver = typeResolver
+        else:
+            self.typeResolver = DefaultResolver()
+
+    def error(self, msg):
+        self.nestedDocs.error(msg, self.line)
+
+    def nestPop(self):
+        line = self.nestedDocs.pop()
+        if line is not None:
+            self.line = line
+            return 1
+
+    def value(self, indicator):
+        return getToken(indicator+"\s*(.*)", self.line)
+
+    def getNextDocument(self): raise "getNextDocument() deprecated--use next()"
+
+    def next(self):
+        line = self.nestedDocs.popDocSep()
+        indicator = getIndicator(line)
+        if indicator:
+            return self.parse_value(indicator)
+        if line:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+        raise StopIteration
+
+    def __iter__(self): return self
+
+    def parseLines(self):
+        peekLine = self.nestedDocs.peek()
+        if peekLine:
+            if re.match("\s*-", peekLine):
+                return self.parse_collection([], self.parse_seq_line)
+            else:
+                return self.parse_collection(self.dictionary(), self.parse_map_line)
+        raise StopIteration
+
+    def parse_collection(self, items, lineParser):
+        while self.nestPop():
+            if self.line:
+                lineParser(items)
+        return items    
+
+    def parse_seq_line(self, items):
+        value = self.value("-")
+        if value is not None:
+            items.append(self.parse_seq_value(value))
+        else:
+            self.error("missing '-' for seq")
+
+    def parse_map_line(self, items):
+        if (self.line == '?'):
+            self.parse_map_line_nested(items)
+        else:
+            self.parse_map_line_simple(items, self.line)
+
+    def parse_map_line_nested(self, items):
+        self.nestedDocs.nestToNextLine()
+        key = self.parseLines()
+        if self.nestPop():
+            value = self.value(':')
+            if value is not None:
+                items[tuple(key)] = self.parse_value(value)
+                return
+        self.error("key has no value for nested map")
+
+    def parse_map_line_simple(self, items, line):
+        map_item = self.key_value(line)
+        if map_item:
+            (key, value) = map_item
+            key = convertImplicit(key)
+            if items.has_key(key):
+                self.error("Duplicate key "+key)
+            items[key] = self.parse_value(value)
+        else:
+            self.error("bad key for map")
+
+    def is_map(self, value):
+        # XXX - need real tokenizer
+        if len(value) == 0:
+            return 0
+        if value[0] == "'":
+            return 0
+        if re.search(':(\s|$)', value):       
+            return 1
+
+    def parse_seq_value(self, value):
+        if self.is_map(value):
+            return self.parse_compressed_map(value)
+        else:
+            return self.parse_value(value)
+
+    def parse_compressed_map(self, value):
+        items = self.dictionary()
+        line = self.line
+        token = getToken("(\s*-\s*)", line)
+        self.nestedDocs.nestBySpecificAmount(len(token))
+        self.parse_map_line_simple(items, value)
+        return self.parse_collection(items, self.parse_map_line)
+
+    def parse_value(self, value):
+        (alias, value) = self.testForRepeatOfAlias(value)
+        if alias:
+            return value
+        (alias, value) = self.testForAlias(value)            
+        value = self.parse_unaliased_value(value)
+        if alias:
+            self.aliases[alias] = value
+        return value          
+
+    def parse_unaliased_value(self, value):
+        match = re.match(r"(!\S*)(.*)", value)
+        if match:
+            (url, value) = match.groups()
+            value = self.parse_untyped_value(value)
+            if url[:2] == '!!':
+                return self.typeResolver.resolveType(value, url)
+            else:
+                # XXX - allows syntax, but ignores it
+                return value
+        return self.parse_untyped_value(value)
+
+    def parseInlineArray(self, value):        
+        if re.match("\s*\[", value):
+            return self.parseInline([], value, ']', 
+                self.parseInlineArrayItem)
+
+    def parseInlineHash(self, value):        
+        if re.match("\s*{", value):
+            return self.parseInline(self.dictionary(), value, '}', 
+                self.parseInlineHashItem)
+
+    def parseInlineArrayItem(self, result, token):
+        return result.append(convertImplicit(token))
+
+    def parseInlineHashItem(self, result, token):
+        (key, value) = self.key_value(token)
+        result[key] = value
+
+    def parseInline(self, result, value, end_marker, itemMethod):
+        tokenizer = InlineTokenizer(value)
+        tokenizer.next()
+        while 1:
+            token = tokenizer.next()
+            if token == end_marker:
+                break
+            itemMethod(result, token)
+        return (1, result)
+
+    def parseSpecial(self, value):
+        productions = [
+            self.parseMultiLineScalar,
+            self.parseInlineHash,
+            self.parseInlineArray,
+        ]
+        return tryProductions(productions, value)
+
+    def parse_untyped_value(self, value):
+        parse = self.parseSpecial(value)
+        if parse:
+            (ok, data) = parse
+            return data
+        token = getToken("(\S.*)", value)
+        if token:
+            lines = [token] + \
+                pruneTrailingEmpties(self.nestedDocs.popNestedLines())
+            return convertImplicit(joinLines(lines))
+        else:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+
+    def parseNative(self, value):
+        return (1, convertImplicit(value))
+
+    def parseMultiLineScalar(self, value):
+        if value == '>':
+            return (1, self.parseFolded())
+        elif value == '|':
+            return (1, joinLiteral(self.parseBlock()))
+        elif value == '|+':
+            return (1, joinLiteral(self.unprunedBlock()))
+
+    def parseFolded(self):
+        data = self.parseBlock()
+        i = 0
+        resultString = ''
+        while i < len(data)-1:
+            resultString = resultString + data[i]
+            resultString = resultString + foldChar(data[i], data[i+1])
+            i = i + 1
+        return resultString + data[-1] + "\n"        
+
+    def unprunedBlock(self):
+        self.nestedDocs.nestToNextLine()
+        data = []
+        while self.nestPop():
+            data.append(self.line)
+        return data
+
+    def parseBlock(self):
+        return pruneTrailingEmpties(self.unprunedBlock())
+
+    def testForAlias(self, value):
+        match = re.match("&(\S*)\s*(.*)", value)
+        if match:
+            return match.groups()
+        return (None, value)
+
+    def testForRepeatOfAlias(self, value):
+        match = re.match("\*(\S+)", value)
+        if match:
+            alias = match.groups()[0]
+            if self.aliases.has_key(alias):
+                return (alias, self.aliases[alias])
+            else:
+                self.error("Unknown alias")
+        return (None, value)
+
+    def key_value(self, str):
+        if str[-1] == ' ':
+            self.error("Trailing spaces not allowed without quotes.")
+        # XXX This allows mis-balanced " vs. ' stuff
+        match = re.match("[\"'](.+)[\"']\s*:\s*(.*)", str)
+        if match:
+            (key, value) = match.groups()
+            return (key, value)
+        match = re.match("(.+?)\s*:\s*(.*)", str)
+        if match:
+            (key, value) = match.groups()
+            if len(value) and value[0] == '#':
+                value = ''
+            return (key, value)
+
+def getToken(regex, value):
+    match = re.search(regex, value)
+    if match:
+        return match.groups()[0]
+
+def pruneTrailingEmpties(data):
+    while len(data) > 0 and data[-1] == '':
+        data = data[:-1]
+    return data
+
+def foldChar(line1, line2):
+    if re.match("^\S", line1) and re.match("^\S", line2):
+        return " "
+    return "\n"
+
+def getIndicator(line):
+    if line:
+        header = r"(#YAML:\d+\.\d+\s*){0,1}"
+        match = re.match("--- "+header+"(\S*.*)", line)
+        if match:
+            return match.groups()[-1]
+
+def joinLines(lines):
+    result = ''
+    for line in lines[:-1]:
+        if line[-1] == '\\':
+            result = result + line[:-1]
+        else:
+            result = result + line + " "
+    return result + lines[-1]
+
+def joinLiteral(data):
+    return string.join(data,"\n") + "\n"
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/timestamp.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/timestamp.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/timestamp.py	(revision 71)
@@ -0,0 +1,145 @@
+import time, re, string
+from types import ListType, TupleType
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+# 
+# Time specific operations
+#
+
+_splitTime = re.compile('\-|\s|T|t|:|\.|Z')
+matchTime = re.compile(\
+          '\d+-\d+-\d+([\s|T|t]\d+:\d+:\d+.\d+(Z|(\s?[\-|\+]\d+:\d+)))?')
+
+def _parseTime(val):
+    if not matchTime.match(val): raise ValueError(val)
+    tpl = _splitTime.split(val)
+    if not(tpl): raise ValueError(val)
+    siz = len(tpl)
+    sec = 0
+    if 3 == siz:
+       tpl += [0,0,0,0,0,-1]
+    elif 7 == siz:
+       tpl.append(0)
+       tpl.append(-1)
+    elif 8 == siz:
+       if len(tpl.pop()) > 0: raise ValueError(val)
+       tpl.append(0)
+       tpl.append(-1)
+    elif 9 == siz or 10 == siz:
+       mn = int(tpl.pop())
+       hr = int(tpl.pop())
+       sec = (hr*60+mn)*60
+       if val.find("+") > -1: sec = -sec
+       if 10 == siz: tpl.pop()
+       tpl.append(0)
+       tpl.append(-1)
+    else:
+       raise ValueError(val)
+    idx = 0
+    while idx < 9:
+       tpl[idx] = int(tpl[idx])
+       idx += 1
+    if tpl[1] < 1 or tpl[1] > 12: raise ValueError(val)
+    if tpl[2] < 1 or tpl[2] > 31: raise ValueError(val)
+    if tpl[3] > 24: raise ValueError(val)
+    if tpl[4] > 61: raise ValueError(val)
+    if tpl[5] > 61: raise ValueError(val)
+    if tpl[0] > 2038:
+        #TODO: Truncation warning
+        tpl = (2038,1,18,0,0,0,0,0,-1)
+    tpl = tuple(tpl)
+    ret = time.mktime(tpl)
+    ret = time.localtime(ret+sec)
+    ret = ret[:8] + (0,)
+    return ret
+
+
+class _timestamp:
+    def __init__(self,val=None):
+        if not val:
+           self.__tval = time.gmtime()
+        else:
+           typ = type(val)
+           if ListType == typ:
+               self.__tval = tuple(val)
+           elif TupleType == typ:
+               self.__tval = val
+           else:
+               self.__tval = _parseTime(val)
+           if 9 != len(self.__tval): raise ValueError
+    def __getitem__(self,idx): return self.__tval[idx]
+    def __len__(self): return 9
+    def strftime(self,format): return time.strftime(format,self.__tval)
+    def mktime(self):          return time.mktime(self.__tval)
+    def asctime(self):  return time.asctime(self.__tval)
+    def isotime(self):  
+        return "%04d-%02d-%02dT%02d:%02d:%02d.00Z" % self.__tval[:6]
+    def __repr__(self): return "yaml.timestamp('%s')" % self.isotime()    
+    def __str__(self):  return self.isotime()
+    def to_yaml_implicit(self): return self.isotime()
+    def __hash__(self): return hash(self.__tval[:6]) 
+    def __cmp__(self,other): 
+        try:
+            return cmp(self.__tval[:6],other.__tval[:6])
+        except AttributeError:
+            return -1
+
+try: # inherit from mx.DateTime functionality if available
+    from mx import DateTime
+    class timestamp(_timestamp):
+        def __init__(self,val=None):
+            _timestamp.__init__(self,val)
+            self.__mxdt = DateTime.mktime(self.__tval)
+        def __getattr__(self, name):
+              return getattr(self.__mxdt, name)
+except:
+    class timestamp(_timestamp): pass
+        
+
+
+def unquote(expr):
+    """
+        summary: >
+           Simply returns the unquoted string, and the
+           length of the quoted string token at the 
+           beginning of the expression.
+    """
+    tok = expr[0]
+    if "'" == tok: 
+        idx = 1
+        odd = 0
+        ret = ""
+        while idx < len(expr):
+            chr = expr[idx]
+            if "'" == chr:
+                if odd: ret += chr
+                odd = not odd
+            else:
+                if odd:
+                    tok = expr[:idx]
+                    break
+                ret += chr
+            idx += 1
+        if "'" == tok: tok = expr
+        return (ret,len(tok))
+    if '"' == tok:
+        idx = 1
+        esc = 0
+        while idx < len(expr):
+            chr = expr[idx]
+            if '"' == chr and not esc:
+                tok = expr[:idx] + '"'
+                break
+            if '\\' == chr and not esc: esc = 1
+            else: esc = 0
+            idx += 1
+        if '"' == tok:
+            raise SyntaxError("unmatched quote: " + expr)
+        ret = eval(tok)  #TODO: find better way to unquote
+        return (ret,len(tok))
+    return (expr,len(expr))
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/dump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/dump.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/dump.py	(revision 75)
@@ -0,0 +1,296 @@
+import types
+import string
+from types import StringType, UnicodeType, IntType, FloatType
+from types import DictType, ListType, TupleType, InstanceType
+from yaml.klass import hasMethod, isDictionary
+import re
+
+"""
+  The methods from this module that are exported to the top 
+  level yaml package should remain stable.  If you call
+  directly into other methods of this module, be aware that 
+  they may change or go away in future implementations.
+  Contact the authors if there are methods in this file 
+  that you wish to remain stable.
+"""
+
+def dump(*data):
+    return Dumper().dump(*data)
+
+def d(data): return dump(data)
+
+def dumpToFile(file, *data):
+    return Dumper().dumpToFile(file, *data)
+
+class Dumper:
+    def __init__(self):
+        self.currIndent   = "\n"
+        self.indent = "    "
+        self.keysrt   = None
+        self.alphaSort = 1 # legacy -- on by default
+
+    def setIndent(self, indent):
+        self.indent = indent
+        return self
+
+    def setSort(self, sort_hint):
+        self.keysrt = sortMethod(sort_hint)
+        return self
+
+    def dump(self, *data):
+        self.result = []  
+        self.output = self.outputToString
+        self.dumpDocuments(data)
+        return string.join(self.result,"")
+
+    def outputToString(self, data):
+        self.result.append(data)
+
+    def dumpToFile(self, file, *data):
+        self.file = file
+        self.output = self.outputToFile
+        self.dumpDocuments(data)
+
+    def outputToFile(self, data):
+        self.file.write(data)
+
+    def dumpDocuments(self, data):
+        for obj in data:
+            self.anchors  = YamlAnchors(obj)
+            self.output("---")
+            self.dumpData(obj)
+            self.output("\n")       
+
+    def indentDump(self, data):
+        oldIndent = self.currIndent
+        self.currIndent += self.indent
+        self.dumpData(data)
+        self.currIndent = oldIndent
+
+    def dumpData(self, data):
+        anchor = self.anchors.shouldAnchor(data)
+        if anchor: 
+            self.output(" &%d" % anchor )
+        else:
+            anchor = self.anchors.isAlias(data)
+            if anchor:
+                self.output(" *%d" % anchor )
+                return
+        if (data is None):
+            self.output(' ~')
+        elif hasMethod(data, 'to_yaml'):
+            self.dumpTransformedObject(data)            
+        elif hasMethod(data, 'to_yaml_implicit'):
+            self.output(" " + data.to_yaml_implicit())
+        elif type(data) is InstanceType:
+            self.dumpRawObject(data)
+        elif isDictionary(data):
+            self.dumpDict(data)
+        elif type(data) in [ListType, TupleType]:
+            self.dumpList(data)
+        else:
+            self.dumpScalar(data)
+
+    def dumpTransformedObject(self, data):
+        obj_yaml = data.to_yaml()
+        if type(obj_yaml) is not TupleType:
+            self.raiseToYamlSyntaxError()
+        (data, typestring) = obj_yaml
+        if typestring:
+            self.output(" " + typestring)
+        self.dumpData(data)
+
+    def dumpRawObject(self, data):
+        self.output(' !!%s.%s' % (data.__module__, data.__class__.__name__))
+        self.dumpData(data.__dict__)
+
+    def dumpDict(self, data):
+        keys = data.keys()
+        if len(keys) == 0:
+            self.output(" {}")
+            return
+        if self.keysrt:
+            keys = sort_keys(keys,self.keysrt)
+        else:
+            if self.alphaSort:
+                keys.sort()
+        for key in keys:
+            self.output(self.currIndent)
+            self.dumpKey(key)
+            self.output(":")
+            self.indentDump(data[key])
+
+    def dumpKey(self, key):
+        if type(key) is TupleType:
+            self.output("?")
+            self.indentDump(key) 
+            self.output("\n")
+        else:
+            self.output(quote(key))
+
+    def dumpList(self, data):
+        if len(data) == 0:
+            self.output(" []")
+            return
+        for item in data:
+            self.output(self.currIndent)
+            self.output("-")
+            self.indentDump(item)
+
+    def dumpScalar(self, data):
+        if isUnicode(data):
+            self.output(' "%s"' % repr(data)[2:-1])
+        elif isMulti(data):
+            self.dumpMultiLineScalar(data.splitlines())
+        else:
+            self.output(" ")
+            self.output(quote(data))
+    
+    def dumpMultiLineScalar(self, lines):
+        self.output(" |")
+        if lines[-1] == "":
+            self.output("+")
+        for line in lines:
+            self.output(self.currIndent)
+            self.output(line)
+
+    def raiseToYamlSyntaxError(self):
+            raise """
+to_yaml should return tuple w/object to dump 
+and optional YAML type.  Example:
+({'foo': 'bar'}, '!!foobar')
+"""
+
+#### ANCHOR-RELATED METHODS
+
+def accumulate(obj,occur):
+    typ = type(obj)
+    if obj is None or \
+       typ is IntType or \
+       typ is FloatType or \
+       ((typ is StringType or typ is UnicodeType) \
+       and len(obj) < 32): return
+    obid = id(obj)
+    if 0 == occur.get(obid,0):
+        occur[obid] = 1
+        if typ is ListType:
+            for x in obj: 
+                accumulate(x,occur)
+        if typ is DictType:
+            for (x,y) in obj.items():
+                accumulate(x,occur)
+                accumulate(y,occur)
+    else:
+        occur[obid] = occur[obid] + 1
+
+class YamlAnchors:
+     def __init__(self,data):
+         occur = {}
+         accumulate(data,occur)
+         anchorVisits = {}
+         for (obid, occur) in occur.items():
+             if occur > 1:
+                 anchorVisits[obid] = 0 
+         self._anchorVisits = anchorVisits
+         self._currentAliasIndex     = 0
+     def shouldAnchor(self,obj):
+         ret = self._anchorVisits.get(id(obj),None)
+         if 0 == ret:
+             self._currentAliasIndex = self._currentAliasIndex + 1
+             ret = self._currentAliasIndex
+             self._anchorVisits[id(obj)] = ret
+             return ret
+         return 0
+     def isAlias(self,obj):
+         return self._anchorVisits.get(id(obj),0)
+
+### SORTING METHODS
+
+def sort_keys(keys,fn):
+    tmp = []
+    for key in keys:
+        val = fn(key)
+        if val is None: val = '~'
+        tmp.append((val,key))
+    tmp.sort()
+    return [ y for (x,y) in tmp ]
+
+def sortMethod(sort_hint):
+    typ = type(sort_hint)
+    if DictType == typ:
+        return sort_hint.get
+    elif ListType == typ or TupleType == typ:
+        indexes = {}; idx = 0
+        for item in sort_hint:
+            indexes[item] = idx
+            idx += 1
+        return indexes.get
+    else:
+        return sort_hint
+
+### STRING QUOTING AND SCALAR HANDLING
+def isStr(data):
+    # XXX 2.1 madness
+    if type(data) == type(''):
+        return 1
+    if type(data) == type(u''):
+        return 1
+    return 0
+    
+def doubleUpQuotes(data):
+    return data.replace("'", "''")
+
+def quote(data):
+    if not isStr(data):
+        return str(data)
+    single = "'"
+    double = '"'
+    quote = ''
+    if len(data) == 0:
+        return "''"
+    if hasSpecialChar(data) or data[0] == single:
+        data = `data`[1:-1]
+        data = string.replace(data, r"\x08", r"\b")
+        quote = double 
+    elif needsSingleQuote(data):
+        quote = single
+        data = doubleUpQuotes(data)
+    return "%s%s%s" % (quote, data, quote)
+
+def needsSingleQuote(data):
+    if re.match(r"^-?\d", data):
+        return 1
+    if re.match(r"\*\S", data):
+        return 1
+    if data[0] in ['&', ' ']:
+        return 1
+    if data[0] == '"':
+        return 1
+    if data[-1] == ' ':
+        return 1
+    return (re.search(r'[:]', data) or re.search(r'(\d\.){2}', data))
+
+def hasSpecialChar(data):
+    # need test to drive out '#' from this
+    return re.search(r'[\t\b\r\f#]', data)
+
+def isMulti(data):
+    if not isStr(data):
+        return 0
+    if hasSpecialChar(data):
+        return 0
+    return re.search("\n", data)
+
+def isUnicode(data):
+    return type(data) == unicode
+    
+def sloppyIsUnicode(data):
+        # XXX - hack to make tests pass for 2.1
+        return repr(data)[:2] == "u'" and repr(data) != data
+
+import sys
+if sys.hexversion < 0x20200000:
+    isUnicode = sloppyIsUnicode
+    
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/ypath.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/ypath.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/ypath.py	(revision 71)
@@ -0,0 +1,462 @@
+from types import ListType, StringType, IntType, DictType, InstanceType
+import re
+from urllib import quote
+from timestamp import unquote
+
+noTarget = object()
+
+def escape(node):
+    """
+        summary: >
+            This function escapes a given key so that it
+            may appear within a ypath.  URI style escaping
+            is used so that ypath expressions can be a 
+            valid URI expression.
+    """
+    typ = type(node)
+    if typ is IntType: return str(node)
+    if typ is StringType: 
+        return quote(node,'')
+    raise ValueError("TODO: Support more than just string and integer keys.")
+
+class context:
+    """
+        summary: >
+            A ypath visit context through a YAML rooted graph.
+            This is implemented as a 3-tuple including the parent
+            node, the current key/index and the value.  This is
+            an immutable object so it can be cached.
+        properties: 
+            key:    mapping key or index within the parent collection
+            value:  current value within the parent's range
+            parent: the parent context
+            root:   the very top of the yaml graph
+            path:   a tuple of the domain keys
+        notes: >
+            The context class doesn't yet handle going down the
+            domain side of the tree... 
+    """         
+    def __init__(self,parent,key,value):
+        """
+            args:
+                parent: parent context (or None if this is the root)
+                key:    mapping key or index for this context
+                value:  value of current location...
+        """
+        self.parent = parent
+        self.key    = key
+        self.value  = value
+        if parent: 
+            assert parent.__class__ is self.__class__
+            self.path = parent.path + (escape(key),)
+            self.root = parent.root
+        else:      
+            assert not key
+            self.path = tuple()
+            self.root = self
+    def __setattr__(self,attname,attval):
+        if attname in ('parent','key','value'):
+            if self.__dict__.get(attname):
+                 raise ValueError("context is read-only")
+        self.__dict__[attname] = attval
+    def __hash__(self): return hash(self.path)
+    def __cmp__(self,other):   
+        try:
+            return cmp(self.path,other.path)
+        except AttributeError:
+            return -1
+    def __str__(self):
+        if self.path:
+            return "/".join(('',)+self.path)
+        else:
+            return '/'
+
+def to_context(target):
+    if type(target) is InstanceType:
+        if target.__class__ is context:
+            return target
+    return context(None,None,target)
+
+def context_test():
+    lst = ['value']
+    map = {'key':lst}
+    x = context(None,None,map)
+    y = context(x,'key',lst)
+    z = context(y,0,'value')
+    assert ('key',) == y.path
+    assert 'key'    == y.key
+    assert lst      == y.value
+    assert x        == y.parent
+    assert x        == y.root
+    assert 0        == z.key
+    assert 'value'  == z.value
+    assert y        == z.parent
+    assert x        == z.root 
+    assert hash(x)  
+    assert hash(y)
+    assert hash(z)
+    assert '/' == str(x)
+    assert '/key' == str(y)
+    assert '/key/0' == str(z)
+
+class null_seg:
+    """
+        summary: >
+            This is the simplest path segment, it
+            doesn't return any results and doesn't
+            depend upon its context.  It also happens to 
+            be the base class which all segments derive.
+    """
+    def __iter__(self): 
+        return self
+    def next_null(self):
+        raise StopIteration
+    def bind(self,cntx):  
+        """
+            summary: >
+                The bind function is called whenever
+                the parent context has changed.
+        """
+        assert(cntx.__class__ is context)
+        self.cntx = cntx
+    def apply(self,target):
+        self.bind(to_context(target))
+        return iter(self)
+    def exists(self,cntx):
+        try:
+            self.bind(cntx)
+            self.next()
+            return 1
+        except StopIteration:
+            return 0
+    next = next_null
+ 
+class self_seg(null_seg):
+    """
+        summary: >
+            This path segment returns the context
+            node exactly once.
+    """
+    def __str__(self): return '.'
+    def next_self(self):
+        self.next = self.next_null
+        return self.cntx
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.next = self.next_self
+
+class root_seg(self_seg):
+    def __str__(self): return '/'
+    def bind(self,cntx):  
+        self_seg.bind(self,cntx.root)
+
+class parent_seg(self_seg):
+    def __str__(self): return '..'
+    def bind(self,cntx):
+        if cntx.parent: cntx = cntx.parent
+        self_seg.bind(self,cntx)
+
+class wild_seg(null_seg):
+    """
+        summary: >
+            The wild segment simply loops through
+            all of the sub-contexts for a given object.
+            If there aren't any children, this isn't an
+            error it just doesn't return anything.
+    """
+    def __str__(self): return '*'
+    def next_wild(self):
+        key = self.keys.next()
+        return context(self.cntx,key,self.values[key])
+    def bind(self,cntx):  
+        null_seg.bind(self,cntx)
+        typ = type(cntx.value)
+        if typ is ListType:
+            self.keys   = iter(xrange(0,len(cntx.value)))
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return
+        if typ is DictType:
+            self.keys   = iter(cntx.value)
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return 
+        self.next = self.next_null
+
+class trav_seg(null_seg):
+    """
+        summary: >
+            This is a recursive traversal of the range, preorder.
+            It is a recursive combination of self and wild.
+    """
+    def __str__(self): return '/'
+    def next(self): 
+        while 1:
+            (cntx,seg) = self.stk[-1]
+            if not seg:
+                seg = wild_seg()
+                seg.bind(cntx)
+                self.stk[-1] = (cntx,seg)
+                return cntx
+            try:
+                cntx = seg.next()
+                self.stk.append((cntx,None))
+            except StopIteration:
+                self.stk.pop()
+                if not(self.stk):
+                    self.next = self.next_null
+                    raise StopIteration
+
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.stk = [(cntx,None)]
+
+class match_seg(self_seg):
+    """
+        summary: >
+            Matches a particular key within the
+            current context.  Kinda boring.
+    """
+    def __str__(self): return str(self.key)
+    def __init__(self,key):
+        #TODO: Do better implicit typing
+        try:
+           key = int(key)
+        except: pass
+        self.key = key
+    def bind(self,cntx):
+        try: 
+            mtch = cntx.value[self.key]
+            cntx = context(cntx,self.key,mtch)
+            self_seg.bind(self,cntx)
+        except:
+            null_seg.bind(self,cntx)
+        
+class conn_seg(null_seg):
+    """
+        summary: >
+            When two segments are connected via a slash,
+            this is a composite.  For each context of the
+            parent, it binds the child, and returns each
+            context of the child.
+    """
+    def __str__(self): 
+        if self.parent.__class__ == root_seg:  
+            return "/%s" % self.child
+        return "%s/%s" % (self.parent, self.child)
+    def __init__(self,parent,child):
+        self.parent = parent
+        self.child  = child
+    def next(self):
+        while 1:
+            try:
+                return self.child.next()
+            except StopIteration:
+                cntx = self.parent.next()
+                self.child.bind(cntx)
+ 
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+        try:
+            cntx = self.parent.next()
+        except StopIteration: 
+            return
+        self.child.bind(cntx)
+
+
+class pred_seg(null_seg):
+    def __str__(self): return "%s[%s]" % (self.parent, self.filter)
+    def __init__(self,parent,filter):
+        self.parent = parent
+        self.filter = filter
+    def next(self):
+        while 1:
+            ret = self.parent.next()
+            if self.filter.exists(ret):
+                return ret
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+
+class or_seg(null_seg):
+    def __str__(self): return "%s|%s" % (self.lhs,self.rhs)
+    def __init__(self,lhs,rhs):
+        self.rhs = rhs
+        self.lhs = lhs
+        self.unq = {}
+    def next(self):
+        seg = self.lhs
+        try:
+            nxt = seg.next()
+            self.unq[nxt] = nxt
+            return nxt
+        except StopIteration: pass
+        seg = self.rhs
+        while 1:
+            nxt = seg.next()
+            if self.unq.get(nxt,None): 
+                continue  
+            return nxt
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.lhs.bind(cntx)
+        self.rhs.bind(cntx)
+
+class scalar:
+    def __init__(self,val):  
+        self.val = val
+    def __str__(self): 
+        return str(self.val)
+    def value(self): 
+        return self.val
+
+class equal_pred: 
+    def exists_true(self,cntx): return 1
+    def exists_false(self,cntx): return 0
+    def exists_scalar(self,cntx):
+        self.rhs.bind(cntx)
+        try:
+            while 1:
+                cntx = self.rhs.next()
+                if str(cntx.value) == self.lhs:  #TODO: Remove type hack
+                     return 1
+        except StopIteration: pass
+        return 0
+    def exists_segment(self,cntx):
+        raise NotImplementedError()
+    def __init__(self,lhs,rhs):
+        if lhs.__class__ == scalar:
+            if rhs.__class__ == scalar:
+                if rhs.value() == lhs.value():
+                    self.exists = self.exists_true
+                else:
+                    self.exists = self.exists_false
+            else:
+                self.exists = self.exists_scalar
+        else:
+            if rhs.__class__ == scalar:
+                (lhs,rhs) = (rhs,lhs)
+                self.exists = self.exists_scalar
+            else:
+                self.exists = self.exists_segment
+        self.lhs = str(lhs.value())  #TODO: Remove type hack
+        self.rhs = rhs
+ 
+matchSegment = re.compile(r"""^(\w+|/|\.|\*|\"|\')""")
+
+def parse_segment(expr):
+    """
+        Segments occur between the slashes...
+    """
+    mtch = matchSegment.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if   '/' == tok: return (trav_seg(),expr)
+    elif '.' == tok: 
+        if len(expr) > 1 and '.' == expr[1]:
+            seg = parent_seg()
+            siz = 2
+        else: 
+            seg = self_seg()
+    elif '*' == tok: seg = wild_seg()
+    elif '"' == tok or "'" == tok:
+        (cur,siz) = unquote(expr)
+        seg = match_seg(cur)
+    else:
+        seg = match_seg(tok)
+    return (seg,expr[siz:])
+
+matchTerm = re.compile(r"""^(\w+|/|\.|\(|\"|\')""")
+
+def parse_term(expr):
+    mtch = matchTerm.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if '/' == tok or '.' == tok:
+        return parse(expr)
+    if '(' == tok:
+        (term,expr) = parse_predicate(expr)
+        assert ')' == expr[0]
+        return (term,expr[1:])
+    elif '"' == tok or "'" == tok:
+        (val,siz) = unquote(expr)
+    else:
+        val = tok; siz = len(tok)
+    return (scalar(val),expr[siz:])
+
+def parse_predicate(expr):
+    (term,expr) = parse_term(expr)
+    if not term: raise SyntaxError("term expected: '%s'" % expr)
+    tok = expr[0]
+    if '=' == tok:
+        (rhs,expr) = parse_term(expr[1:])
+        return (equal_pred(term,rhs),expr)
+    if '(' == tok:
+        raise "No functions allowed... yet!"
+    if ']' == tok or ')' == tok:
+        if term.__class__ is scalar:
+            term = match_seg(str(term))
+        return (term,expr)
+    raise SyntaxError("ypath: expecting operator '%s'" % expr)
+
+def parse_start(expr):
+    """
+        Initial checking on the expression, and 
+        determine if it is relative or absolute.
+    """
+    if type(expr) != StringType or len(expr) < 1: 
+        raise TypeError("string required: " + repr(expr))
+    if '/' == expr[0]:
+        ypth = root_seg()
+    else:
+        ypth = self_seg()
+        expr = '/' + expr
+    return (ypth,expr)
+
+def parse(expr):
+    """
+        This the parser entry point, the top level node
+        is always a root or self segment.  The self isn't
+        strictly necessary, but it keeps things simple.
+    """
+    (ypth,expr) = parse_start(expr)
+    while expr:
+        tok = expr[0]
+        if '/' == tok:
+            (child, expr) = parse_segment(expr[1:])    
+            if child: ypth = conn_seg(ypth,child)
+            continue
+        if '[' == tok:
+            (filter, expr) = parse_predicate(expr[1:])
+            assert ']' == expr[0]
+            expr = expr[1:]
+            ypth = pred_seg(ypth,filter)
+            continue
+        if '|' == tok:
+            (rhs, expr) = parse(expr[1:])
+            ypth = or_seg(ypth,rhs)
+            continue
+        if '(' == tok:
+            (child,expr) = parse(expr[1:])
+            assert ')' == expr[0]
+            expr = expr[1:]
+            ypth = conn_seg(ypth,child)
+            continue
+        break
+    return (ypth,expr)
+
+class convert_to_value(null_seg):
+    def __init__(self,itr):
+        self.itr = itr
+    def next(self):
+        return self.itr.next().value
+    def bind(self,cntx):
+        self.itr.bind(cntx)
+
+def ypath(expr,target=noTarget,cntx=0):
+    (ret,expr) = parse(expr)
+    if expr: raise SyntaxError("ypath parse error `%s`" % expr)
+    if not cntx: ret = convert_to_value(ret)
+    if target is noTarget: return ret
+    return ret.apply(target)
Index: /pyyaml-legacy/tags/PyYaml_0.32/yaml/ordered_dict.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/yaml/ordered_dict.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/yaml/ordered_dict.py	(revision 71)
@@ -0,0 +1,31 @@
+# This is extremely crude implementation of an OrderedDict.
+# If you know of a better implementation, please send it to
+# the author Steve Howell.  You can find my email via 
+# the YAML mailing list or wiki.
+
+class OrderedDict(dict): 
+    def __init__(self): 
+        self._keys = [] 
+ 
+    def __setitem__(self, key, val): 
+        self._keys.append(key) 
+        dict.__setitem__(self, key, val) 
+ 
+    def keys(self): 
+        return self._keys 
+ 
+    def items(self):
+        return [(key, self[key]) for key in self._keys]
+ 
+if __name__ == '__main__': 
+    data = OrderedDict()
+    data['z'] = 26
+    data['m'] = 13
+    data['a'] = 1
+    for key in data.keys(): 
+        print "The value for %s is %s" % (key, data[key]) 
+    print data
+
+
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/insert.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/insert.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/insert.yml	(revision 75)
@@ -0,0 +1,72 @@
+tests:
+    - data:
+        - foo
+        - bar
+      command:
+        value: baz
+      expected:
+        - foo
+        - bar
+        - baz
+    - data:
+        - apple
+        - banana
+      command:
+        value: carrot
+      expected:
+        - apple
+        - banana
+        - carrot
+    -
+      data: 
+        - foo
+      command:
+        value: 
+          name: steve
+          sport: hoops
+      expected:
+        - foo
+        - name: steve
+          sport: hoops
+    -
+      data: 
+        persons:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /persons
+        value: 
+          name: brian
+      expected:
+        persons:
+         - name: steve
+         - name: clark
+         - name: brian
+        tasks:
+          - task: eat
+          - task: sleep
+    -
+      data: 
+        folks:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /folks
+        value: 
+          name: ryan
+      expected:
+        folks: 
+         - name: steve
+         - name: clark
+         - name: ryan
+        tasks:
+          - task: eat
+          - task: sleep
+
+      
Index: /pyyaml-legacy/tags/PyYaml_0.32/profile.out
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/profile.out	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/profile.out	(revision 75)
@@ -0,0 +1,36 @@
+['Profile', 'Stats', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '_get_time_times', 'help', 'marshal', 'os', 'run', 'sys', 'time']
+Wed Sep 25 08:59:14 2002    profileResults
+
+         93074 function calls (91948 primitive calls) in 8.740 CPU seconds
+
+   Ordered by: internal time
+   List reduced from 134 to 25 due to restriction <25>
+
+   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
+    12179    0.727    0.000    1.967    0.000 yaml\stream.py:65(peek)
+     3747    0.672    0.000    3.529    0.001 yaml\stream.py:156(pop)
+     6176    0.664    0.000    1.082    0.000 C:\PYTHON22\lib\sre.py:129(match)
+     4551    0.578    0.000    1.196    0.000 yaml\stream.py:93(peek)
+     3772    0.457    0.000    1.554    0.000 yaml\stream.py:101(pop)
+     3324    0.408    0.000    0.764    0.000 yaml\stream.py:14(get)
+     3727    0.326    0.000    3.837    0.001 yaml\load.py:75(nestPop)
+     7018    0.319    0.000    0.509    0.000 C:\PYTHON22\lib\sre.py:215(_compile)
+     3266    0.292    0.000    0.519    0.000 yaml\stream.py:61(eatComments)
+     5137    0.282    0.000    0.282    0.000 yaml\stream.py:4(indentLevel)
+     3206    0.234    0.000    0.331    0.000 yaml\stream.py:76(pop)
+      380    0.233    0.001    3.412    0.009 yaml\load.py:257(parseBlock)
+  914/731    0.214    0.000    5.739    0.008 yaml\load.py:221(parse_untyped_value)
+     3324    0.214    0.000    0.214    0.000 yaml\stream.py:51(isComment)
+     2999    0.183    0.000    0.183    0.000 yaml\stream.py:29(getLine)
+  917/733    0.166    0.000    6.457    0.009 yaml\load.py:164(parse_value)
+     3216    0.163    0.000    0.163    0.000 yaml\stream.py:169(noLineFeed)
+     3528    0.152    0.000    0.152    0.000 yaml\stream.py:146(startsWithSep)
+     1235    0.148    0.000    0.167    0.000 yaml\implicit.py:12(convertImplicit)
+  793/697    0.148    0.000    6.731    0.010 yaml\load.py:132(parse_map_line_simple)
+      675    0.139    0.000    0.543    0.001 yaml\stream.py:122(nestToNextLine)
+      795    0.136    0.000    0.419    0.001 yaml\load.py:285(key_value)
+      914    0.131    0.000    4.038    0.004 yaml\load.py:55(tryProductions)
+  914/731    0.124    0.000    5.958    0.008 yaml\load.py:174(parse_unaliased_value)
+  318/190    0.113    0.000    7.956    0.042 yaml\load.py:103(parse_collection)
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc1.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc1.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc1.yml	(revision 71)
@@ -0,0 +1,1 @@
+foo: bar
Index: /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc2.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc2.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/doc2.yml	(revision 71)
@@ -0,0 +1,1 @@
+more: stuff
Index: /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/toplevel.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/toplevel.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/toplevel.yml	(revision 71)
@@ -0,0 +1,4 @@
+
+    - doc1: !!include doc1.yml
+    - doc2: !!include doc2.yml
+    
Index: /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/demo.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/demo.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/IncludeHack/demo.py	(revision 71)
@@ -0,0 +1,19 @@
+import yaml
+
+def writeFile(fn, data):
+    f = open(fn, 'w')
+    f.write(data)
+
+writeFile('toplevel.yml', """
+    - doc1: !!include doc1.yml
+    - doc2: !!include doc2.yml
+    """)
+
+writeFile('doc1.yml', "foo: bar")
+writeFile('doc2.yml', "more: stuff")
+
+class Includer:
+    def resolveType(self, value, url):
+        return yaml.loadFile(value).next()
+
+print yaml.loadFile('toplevel.yml', Includer()).next()
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestNestedText.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestNestedText.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestNestedText.py	(revision 75)
@@ -0,0 +1,311 @@
+import YamlTest
+from yaml.load import *
+from here import flushLeft
+from test import assertEquals
+from yaml.stream import NestedText, CommentEater, split
+
+here = flushLeft # pardon the Perlism
+
+def stringStream(str):
+    return StringStream(here(str))
+
+def commentEater(str):
+    return CommentEater(stringStream(str))
+
+def nestedText(str):
+    return NestedText(stringStream(str))
+
+def nestedDocs(str):
+    return NestedDocs(stringStream(str))
+
+class Test(YamlTest.YamlTest):
+    def tryPop(self, expected):
+        assertEquals(self.nt.pop(), expected)
+        
+    def tryPopNestedLines(self, expected):
+        assertEquals(self.nt.popNestedLines(), expected)
+        
+    def tryPeek(self, expected):
+        assertEquals(self.nt.peek(), expected)
+
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop('')
+        self.tryPop(None)
+        
+    def test2(self):
+        self.nt = nestedText("""
+            apple
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def test3(self):
+        self.nt = nestedDocs("""
+            seattle
+            --- foo
+            bluffton
+            """)
+        assertEquals(self.nt.popDocSep(), '---')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- foo')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+    def testEatComments(self):
+        self.nt = commentEater("""
+            # ignore
+              # these
+            silly
+            """)
+        self.tryPop('silly')
+
+    def testNestedDocsEatComments(self):
+        self.nt = nestedDocs("""
+            # foo
+              # bar
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+        assertEquals(self.nt.lastLineRead(), 4)
+
+    def testNestedTextEatNewline(self):
+        self.nt = nestedDocs("""
+            
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+
+    def testDocSep(self):
+        data = here("""
+            --- city
+            seattle
+            --- town
+            bluffton
+            """)
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- town')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+        data = here("""
+            # comments at top
+            # should be ignored
+            """) + data
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+
+    def testNestedComments(self):
+        self.nt = nestedText("""
+            apple
+              # ignore this comment
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def testStream(self):
+        stream = StringStream(here("""
+            python
+            perl
+            java
+            """))
+        assertEquals(stream.get(), "python")
+        assertEquals(stream.get(), "perl")
+        assertEquals(stream.get(), "java")
+        
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop(None)
+        
+    def XXXtestEmptyLines(self):
+        # not sure if this is valid test any more
+        self.nt = nestedDocs("""
+            ---
+             apple
+
+                banana
+            """)
+        self.nt.popDocSep()
+        self.nt.nestToNextLine()
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+
+    def testFoldedCase(self):
+        self.nt = nestedText(
+            """
+            ---
+             Aaa
+             Bbb
+
+               11
+               22
+
+             Ccc
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('Aaa')
+        self.tryPop('Bbb')
+        self.tryPop('')
+
+    def testRedHerringDocSep(self):
+        self.nt = nestedDocs(
+            """
+            ---
+            foo:
+                ---
+            """)
+        self.nt.popDocSep()
+        self.tryPop('foo:')
+        self.nt.nestToNextLine()
+        self.tryPop('---')
+
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            line1: this is
+               continued
+            line2
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('line1: this is')
+        self.tryPopNestedLines(['continued'])
+        self.tryPop('line2')
+            
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            key1: this is
+               continued
+               with multiple lines
+            key2:
+                 key2a:
+                   hello
+                   world
+            key3:
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('key1: this is')
+        self.tryPopNestedLines(['continued', 'with multiple lines'])
+        self.tryPop('key2:')
+        self.nt.nestToNextLine()
+        self.tryPop('key2a:')
+        self.tryPopNestedLines(['hello', 'world'])
+            
+    def testPopNestedLinesWithNoneNested(self):
+        self.nt = nestedText(
+            """
+            ---
+            - apple
+            - banana
+            - carrot
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('- apple')
+        self.tryPopNestedLines([])
+        self.tryPop('- banana')
+
+    def testLineNumbers(self):
+        data = \
+            """
+            one
+            two
+            #
+            three
+            """
+        stream = StringStream(here(data))
+        stream.get()
+        assertEquals(stream.lastLineRead(), 1)
+        stream.get()
+        assertEquals(stream.lastLineRead(), 2)
+        nt = nestedText(data)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 1)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 2)
+        nt.pop()  # eats a comment too
+        assertEquals(nt.lastLineRead(), 4)
+
+    def testSplit(self):
+        assertEquals(split("foo\nbar"), ['foo', 'bar'])
+        assertEquals(split("foo\nbar\n"), ['foo', 'bar'])        
+
+    def testLoaderException(self):
+        import yaml
+        from yaml.stream import YamlLoaderException
+        exception = None
+        try:
+            yaml.load('invalid YAML').next()
+        except YamlLoaderException, e:
+            exception = e
+        assertEquals(exception.lineNum, 1)
+            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestFileNamesInErrors.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestFileNamesInErrors.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestFileNamesInErrors.py	(revision 75)
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+import yaml, re
+try:
+    print yaml.loadFile('TestFileNamesInErrors.py').next()
+    raise "YAML actually parsed this file, uh oh!"
+except Exception, e:
+    if not re.search('TestFileNamesInErrors\.py', str(e)):
+        raise 'YAML not reporting filename properly ("%s")' % e
Index: /pyyaml-legacy/tags/PyYaml_0.32/LICENSE
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/LICENSE	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/LICENSE	(revision 75)
@@ -0,0 +1,71 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+The Python library for YAML was started by Steve Howell in 
+February 2002.  Steve is the primary author of the project,
+but others have contributed.  See the README for more on 
+the project.  The term "PyYaml" refers to the entire 
+distribution of this library, including examples, documentation,
+and test files, as well as the core implementation.
+
+This library is intended for general use, and the license 
+below protects the "open source" nature of the library.  The 
+license does, however, allow for use of the library in 
+commercial applications as well, subject to the terms 
+and conditions listed.  The license below is a minor 
+rewrite of the Python 2.2 license, with no substantive 
+differences.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PyYaml
+===============================================================
+
+LICENSE AGREEMENT FOR PyYaml
+----------------------------
+
+1. This LICENSE AGREEMENT is between Stephen S. Howell ("Author"), 
+and the Individual or Organization ("Licensee") accessing and
+otherwise using PyYaml software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, Author
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use PyYaml
+alone or in any derivative version, provided, however, that Author's
+License Agreement and Author's notice of copyright, i.e., "Copyright (c)
+2001 Steve Howell and Friends; All Rights Reserved" are never removed
+from PyYaml, and are included in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates PyYaml or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to PyYaml.
+
+4. Author is making PyYaml available to Licensee on an "AS IS"
+basis.  Author MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, Author MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PyYaml WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. Author SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.2 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.2,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between Author and
+Licensee.  This License Agreement does not grant permission to use Author
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using PyYaml, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestPushDumper.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestPushDumper.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestPushDumper.py	(revision 75)
@@ -0,0 +1,123 @@
+import YamlTest
+from here import *
+from test import assertEquals
+from types import DictType, ListType, TupleType, InstanceType
+
+"""
+This is experimental code.  It generates simulated events
+for a pull-based YAML parser.
+"""
+
+class MockEmitter:
+    """
+    A pushed-based emitter may be more awkward to write, 
+    because you have to keep track of more state.
+    """
+    def __init__(self):
+        self.events = []
+
+    def append(self, *event):
+        self.events.append(event)        
+
+    def pushScalar(self, data):
+        self.append('getType', 'scalar')
+        self.append('getScalar', data)
+
+    def appendType(self, typ):
+        self.append('getType', typ)
+
+    def startSeq(self):
+        self.appendType('seq')
+        
+    def endSeq(self):
+        self.appendType(None)
+
+    def startMap(self):
+        self.appendType('map')
+        
+    def endMap(self):
+        self.appendType(None)
+
+class Dumper:
+    def __init__(self, emitter):
+        self.emitter = emitter
+
+    def dump(self, data):
+        if type(data) in (ListType, TupleType):
+            return self.dumpList(data)
+        elif type(data) is DictType:
+            return self.dumpDict(data)
+        else:
+            self.emitter.pushScalar(data)
+
+    def dumpList(self, data):
+        self.emitter.startSeq()
+        for item in data:
+            self.dump(item)
+        self.emitter.endSeq()
+
+    def dumpDict(self, data):
+        self.emitter.startMap()
+        keys = data.keys()
+        keys.sort() # XXX - only for now
+        for key in keys:
+            value = data[key]
+            self.dump(key)
+            self.dump(value)
+        self.emitter.endMap()
+
+def mockEvents(data):
+    emitter = MockEmitter()
+    dumper = Dumper(emitter)
+    dumper.dump(data)
+    return emitter.events
+
+class Test(YamlTest.YamlTest):
+
+    def testScalar(self):
+        assertEquals(mockEvents('foobar'), self.scalar('foobar'))
+
+    def scalar(self, data):
+        return [ 
+            ('getType', 'scalar'),
+            ('getScalar', data)
+        ]
+
+    def list123(self):
+        (result) = (
+            [('getType', 'seq' )] +
+            self.scalar(1) +
+            self.scalar(2) +
+            self.scalar(3) +
+            [( 'getType', None )])
+        return result
+
+    def testList(self):
+        assertEquals(mockEvents([1,2,3]), self.list123())
+
+    def dictFoobar(self):
+        (result) = (
+            [('getType', 'map')] +
+            self.scalar('bar') +
+            self.scalar(2) + 
+            self.scalar('foo') +
+            self.scalar(1) +
+            [( 'getType', None)])
+        return result
+
+    def testDict(self):
+        events = mockEvents({'foo': 1, 'bar': 2})
+        assertEquals(events, self.dictFoobar())
+
+    def testListDict(self):
+        events = mockEvents([ [1,2,3], {'foo': 1, 'bar': 2} ])
+        self.assertEquals(
+            events,
+            [('getType', 'seq' )] +
+            self.list123() +
+            self.dictFoobar() + 
+            [('getType', None)])            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestDumper.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestDumper.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestDumper.py	(revision 75)
@@ -0,0 +1,469 @@
+import YamlTest
+from yaml.dump import *
+import yaml
+from here import flushLeft
+from test import assertEquals
+
+class SampleClass:
+    def expected(self, modname, classname):
+        """
+        Tough to test, because this class may be in __main__ 
+        namespace, may be in TestDumper, depending where you 
+        run it
+        """
+        return """
+        --- !!%s.%s
+        bar: 4
+        foo: 3
+        items:
+            - apple
+            - banana
+        """ % (modname, classname)
+
+    def __init__(self):
+        self.foo = 3
+        self.bar = 4
+        self.items = ['apple', 'banana']
+
+
+class SampleException(Exception):
+    def __init__(self, args):
+        self.args = args
+
+class Test(YamlTest.YamlTest):
+    def dumpTest(self, obj, expect):
+        assertEquals(yaml.dump(obj), flushLeft(expect))
+    def dumpTestSort(self,sort):
+        obj = {'a':'aaaa','d':'dddd','b':'bbbb','c':'cccc'}
+        exp = flushLeft(\
+            """
+            ---
+            b: bbbb
+            d: dddd
+            a: aaaa
+            c: cccc
+            """)
+        dumper = yaml.Dumper().setSort(sort)
+        self.assertEquals(dumper.dump(obj),exp)
+    def testsort_map(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3})
+    def testsort_tuple(self):
+        self.dumpTestSort(('b','d','a'))
+    def testsort_list(self):
+        self.dumpTestSort(['b','d','a'])
+    def testsort_func(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3}.get)
+    def test1(self):
+        self.dumpTest(
+            { 'foo': 'bar', 'yo': 'mama' },
+            """
+            ---
+            foo: bar
+            yo: mama
+            """,
+        )
+
+    def test2(self):
+        self.dumpTest(
+            { 'foo': {'bar': 3} },
+            """
+            ---
+            foo:
+                bar: 3
+            """,
+        )
+
+    def test3(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': {
+                    'apple': 'red',
+                    'banana': 'yellow',
+                }
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                apple: red
+                banana: yellow
+            """
+            )
+                
+    def test4(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ['apple', 'orange']
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testTuple(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ('apple', 'orange')
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testMultiLineBlock(self):
+        self.dumpTest(
+             { 
+                 'foo': "a\nb\nc\n",
+             },
+             """
+             ---
+             foo: |
+                 a
+                 b
+                 c
+             """
+             )
+
+    def testDoubleQuote(self):
+        assertEquals(doubleUpQuotes("foo'bar"), "foo''bar")
+        assertEquals(doubleUpQuotes("''x'"), "''''x''")
+
+    def testQuotingRules(self):
+        # Raw:
+        self.assertEquals(dump(None), "--- ~\n")
+        self.assertEquals(dump('simple'), "--- simple\n")
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('two words'), "--- two words\n")
+        self.assertEquals(dump('single\'quote'), "--- single'quote\n")
+        self.assertEquals(dump('5.2'), "--- '5.2'\n")
+        self.assertEquals(dump(5.2), "--- 5.2\n")
+        self.assertEquals(dump(1234), "--- 1234\n")
+        self.assertEquals(dump('harmless-dash'), "--- harmless-dash\n")
+        self.assertEquals(dump('* harmless bullet'), "--- * harmless bullet\n")
+        self.dumpTest(
+            [ "a - b", "another-harmless-dash" ],
+            """
+            ---
+            - a - b
+            - another-harmless-dash
+            """)
+        # Single Quoted:
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('4.3.1.5.2'), "--- '4.3.1.5.2'\n")
+        self.assertEquals(dump("'leading quote"), '--- "\'leading quote"\n')
+        self.assertEquals(dump('4.3.'), "--- '4.3.'\n")
+        self.assertEquals(dump('12345'), "--- '12345'\n")
+        self.assertEquals(dump('-12345'), "--- '-12345'\n")
+        self.assertEquals(dump('key: value'), "--- 'key: value'\n")
+        self.assertEquals(dump('ending colon:'), "--- 'ending colon:'\n")
+        self.assertEquals(dump('&foo'), "--- '&foo'\n")
+        self.assertEquals(dump(' xx'), "--- ' xx'\n")
+        self.assertEquals(dump('*bar'), "--- '*bar'\n")
+        assertEquals(dump('"middle \'quote'), '--- \'"middle \'\'quote\'\n')
+        # Double quoted:
+        self.assertEquals(dump("\thas a tab"), "--- \"\\thas a tab\"\n")
+        self.dumpTest(
+            { "key: quote": 'normal value' },
+            """
+            ---
+            'key: quote': normal value
+            """)
+
+    def testArrayWithSingleQuoted(self):
+        self.dumpTest(
+            [ 'foo:', {'bar': 'colon:'}],
+            """
+            ---
+            - 'foo:'
+            -
+                bar: 'colon:'
+            """
+            )
+
+    def testDumpObject(self):
+        sample = SampleClass()
+        self.dumpTest(sample, 
+            sample.expected(sample.__module__, 'SampleClass'))
+
+    def testWithSpuriousToYaml(self):
+        class ClassWithSpuriousToYaml(SampleClass):
+            to_yaml = 1 # Shouldn't get invoked
+        x = ClassWithSpuriousToYaml()
+        self.dumpTest(x, 
+            x.expected(x.__module__,'ClassWithSpuriousToYaml'))
+
+    def testNormalToYamlUse(self):
+        class NormalYamlUse(SampleClass):
+            def to_yaml(self):
+                dict = {}
+                dict['bar'] = self.foo * 2
+                return (dict, None)
+        self.dumpTest(NormalYamlUse(),
+            """
+            ---
+            bar: 6
+            """)
+
+    def testDumpingPrivateTypes(self):
+        class Foobar(SampleClass):
+            def to_yaml(self):
+                dict = {'foo': 'bar'}
+                return (dict, '!!foobar')
+        self.dumpTest(Foobar(),
+            """
+            --- !!foobar
+            foo: bar
+            """)
+        class OddList(SampleClass):
+            def to_yaml(self):
+                return ([1, 3, 5], '!!oddlist')
+        self.dumpTest(OddList(),
+            """
+            --- !!oddlist
+            - 1
+            - 3
+            - 5
+            """)
+
+
+    def testToYamlShouldBeAllowedToThrowIfItWants(self):
+        class ThrowsInsideToYaml:
+            def to_yaml(self):
+                raise SampleException('bla')
+        caught_exception = 'undef'
+        try:
+            dump(ThrowsInsideToYaml())
+        except Exception, e:
+            caught_exception = e
+        self.assertEquals('bla', caught_exception.args)
+
+    def testObjectWithListOfClasses(self):
+        class Foo:
+            def __init__(self, items):
+                self.items = items
+             
+        class Bar:
+            def __init__(self, data):
+                self.data = data
+
+        foo = Foo([Bar('apple'), Bar('banana')])
+        mod = foo.__module__ # depends where called
+        self.dumpTest(foo,
+            """
+            --- !!%s.Foo
+            items:
+                - !!%s.Bar
+                    data: apple
+                - !!%s.Bar
+                    data: banana
+            """ % (mod, mod, mod))
+
+    def testHasMethod(self):
+        class ClassWithMethodA:
+            b = 1
+            def a(): pass
+
+        sc = ClassWithMethodA()
+        self.assertEquals(1, hasMethod(sc, 'a'))
+        self.assertEquals(0, hasMethod(sc, 'b'))
+
+    def testComplexKey(self):
+        self.dumpTest( {(3,4): 4},
+            """
+            ---
+            ?
+                - 3
+                - 4
+            : 4
+            """)            
+    
+    def testApostrophe(self):
+        self.dumpTest( "Joe's hot dogs.\n",
+            """
+            --- |
+            Joe's hot dogs.
+            """)
+
+    def testCustomIndent(self):
+        self.assertEquals(
+            yaml.Dumper().setIndent('xx').dump(
+                { 
+                    'foo': 3,
+                    'fruits': ('apple', 'orange')
+                }, 
+            ),
+            flushLeft(
+                """
+                ---
+                foo: 3
+                fruits:
+                xx- apple
+                xx- orange
+                """
+            )
+            )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.dumpTest({'foo': u"Foo\u263A"},
+                r"""
+                ---
+                foo: "Foo\u263a"
+                """)
+
+    def testTab(self):
+        self.dumpTest({'tab': "foo\tbar"},
+            r"""
+            ---
+            tab: "foo\tbar"
+            """)
+
+    def testIsMulti(self):
+        self.failUnless(isMulti("foo\nbar"))
+        self.failIf(isMulti("foobar"))
+        self.failIf(isMulti("line\twith tab\nsecond line"))
+        self.failUnless(isMulti("foo\\slash\nbar"))
+
+    def testHasSpecialChar(self):
+        self.failUnless(hasSpecialChar("foo\tbar"))
+        self.failIf(hasSpecialChar("foobar"))
+
+    def testTabs(self):
+        self.dumpTest({'control': "\b1998\t1999\t2000\n"},
+            r"""
+            ---
+            control: "\b1998\t1999\t2000\n"
+            """)
+
+    def test12345(self):
+        self.dumpTest({'foo': 12345, 'bar': '12345'},
+            r"""
+            ---
+            bar: '12345'
+            foo: 12345
+            """)
+
+    def testDataThatsCoincidentallyTheSame(self):
+        self.dumpTest([ {'foo': 'bar'}, {'foo': 'bar'} ],
+            """
+            ---
+            -
+                foo: bar
+            -
+                foo: bar
+            """)
+
+    def testAliasClass(self):
+        dup = {'foo': 'bar'}
+        dupList = [dup, dup]
+        myAnchors = YamlAnchors(dupList)
+        self.assertEquals(id(dup), myAnchors._anchorVisits.keys()[0])
+        self.assertEquals(0,myAnchors.isAlias(dup))
+        self.assertEquals(1,myAnchors.shouldAnchor(dup) )
+        self.assertEquals(0,myAnchors.shouldAnchor('bar'))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup['foo']))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup))
+        self.assertEquals(1,myAnchors.isAlias(dup))
+
+    def testAliases(self):
+        dup = {'foo': 'bar'}
+        self.dumpTest([dup, dup],
+            """
+            ---
+            - &1
+                foo: bar
+            - *1
+            """)
+
+    def testHashAlias(self):
+        dup = {}
+        dup['foo'] = dup
+        self.dumpTest(dup, 
+            """
+            --- &1
+            foo: *1
+            """)
+
+    def testEmptyArray(self):
+        self.dumpTest([],
+            """
+            --- []
+            """)
+
+    def testEmptyHash(self):
+        self.dumpTest({},
+            """
+            --- {}
+            """)
+
+    def testEmptyHashAsHashKey(self):
+        self.dumpTest({'foo': {} },
+            """
+            ---
+            foo: {}
+            """)
+
+    def testEmptyArrrayAsHashKey(self):
+        self.dumpTest({'foo': [] },
+            """
+            ---
+            foo: []
+            """)
+
+    def testAliasNone(self):
+        foo = None
+        self.dumpTest([foo, foo, foo],
+            """
+            ---
+            - ~
+            - ~
+            - ~
+            """)
+
+    def testDumpMany(self):
+        assertEquals(
+            yaml.dump({'foo': 1}, ['a', 'b', 'c']),
+            flushLeft(
+                """
+                ---
+                foo: 1
+                ---
+                - a
+                - b
+                - c
+                """))
+
+    def testDumpExtraNewLines(self):
+        self.dumpTest( "Joe's hot dogs.\n\n",
+            """
+            --- |+
+            Joe's hot dogs.
+
+            """)
+
+
+    def testDumpExtraNewLinesInDict(self):
+        data = {'preserving': "extra new lines are kept\n\n\n"}
+        self.dumpTest(data,
+            """
+            ---
+            preserving: |+
+                extra new lines are kept
+                
+                
+            """)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_map.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_map.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_map.py	(revision 71)
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a
+dictionary (mapping) containing the following key/value pairs:
+    (1) "name" (required) -- a string.
+    (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+        pairs.
+    (3) "text" (optional) -- a string.
+    (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+For usage information, type:
+    python convertyaml_map.py
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if type(obj) == types.DictType and \
+            obj.has_key('name'):
+            name = obj['name']
+            attributes = None
+            if obj.has_key('attributes'):
+                attributes = obj['attributes']
+            text = None
+            if obj.has_key('text'):
+                text = obj['text']
+            children = None
+            if obj.has_key('children'):
+                children = obj['children']
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = {}
+    # Add the element name.
+    objDict['name'] = obj.nodeName
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict['attributes'] = attrDict
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict['text'] = textStr
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict['children'] = children
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/README_yaml2xml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/README_yaml2xml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/README_yaml2xml	(revision 71)
@@ -0,0 +1,76 @@
+                   Convert XML to and from YAML
+                   ============================
+
+
+===========
+Description
+===========
+
+This mini-package contains two implementations of conversion
+routines that convert XML to YAML and YAML to XML.  These two
+implementations use different canonical representations for XML in
+YAML as follows:
+
+convertyaml_map.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a
+    dictionary (mapping) containing the following key/value pairs:
+        (1) "name" (required) -- a string.
+        (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+            pairs.
+        (3) "text" (optional) -- a string.
+        (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+convertyaml_seq.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a 4-tuple
+    (a sequence) containing the following:
+        (1) element name
+        (2) attributes -- a mapping
+        (3) text -- a string
+        (4) children -- a sequence of elements
+
+Basically, convertyaml_map.py uses keywords (in a dictionary) to
+represent structures and convertyaml_seq.py uses position (within a
+list).
+
+=====
+Usage
+=====
+
+There is some usage information at the top of each implementation
+file.
+
+
+=======
+Testing
+=======
+
+Here are some simple tests:
+
+    python convertyaml_map.py -x2y people.xml
+    python convertyaml_map.py -x2y people.xml > people.yml
+    python convertyaml_map.py -y2x people.yml
+
+    python convertyaml_seq.py -x2y people.xml
+    python convertyaml_seq.py -x2y people.xml > people.yml
+    python convertyaml_seq.py -y2x people.yml
+
+
+======================
+Additional Information
+======================
+
+The YAML home site is at:
+
+    http://www.yaml.org/
+
+
+
+
+
+Dave Kuhlman
+dkuhlman@rexx.com
+http://www.rexx.com/~dkuhlman
+
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_seq.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_seq.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/convertyaml_seq.py	(revision 71)
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a 4-tuple
+(a sequence) containing the following:
+    (1) element name
+    (2) attributes -- a mapping
+    (3) text -- a string
+    (4) children -- a sequence of elements
+
+For usage information, type:
+    python convertyaml_seq.py
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if (type(obj) == types.ListType or type(obj) == types.TupleType) and \
+            len(obj) == 4:
+            name = obj[0]
+            attributes = obj[1]
+            text = obj[2]
+            children = obj[3]
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = []
+    # Add the element name.
+    objDict.append(obj.nodeName)
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict.append(attrDict)
+    else:
+        objDict.append(None)
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict.append(textStr)
+    else:
+        objDict.append(None)
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict.append(children)
+    else:
+        objDict.append(None)
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/people.xml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/people.xml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_0.32/XmlYaml/people.xml	(revision 71)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<people> 
+    <person id="1" value="abcd" ratio="3.2">
+        <name>Alberta</name>
+        <interest>gardening</interest>
+        <interest>reading</interest>
+        <category>5</category>
+    </person> 
+
+    <person id="2">
+        <name>Bernardo</name>
+        <interest>programming</interest>
+        <category></category>
+        <agent>
+            <firstname>Darren</firstname>
+            <lastname>Diddly</lastname>
+        </agent>
+
+    </person>
+
+    <person id="3">
+        <name>Charlie</name>
+        <interest>people</interest>
+        <interest>cats</interest>
+        <interest>dogs</interest>
+        <category>8</category>
+        <promoter>
+            <firstname>David</firstname>
+            <lastname>Donaldson</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+        <promoter>
+            <firstname>Edward</firstname>
+            <lastname>Eddleberry</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+    </person>
+
+</people>
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/TestValidatingParser.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/TestValidatingParser.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/TestValidatingParser.py	(revision 75)
@@ -0,0 +1,206 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals, assertError
+from TestPullParser import mockParser, Loader
+from yaml import load
+
+"""
+Part of the parse/pull experimental code.  This does a schema-driven
+validating parse of YAML documents, but it's built on top of a 
+crufty interim solution.
+
+The schema-driven parser requires a pull parser interface.  Ideally 
+a pull-parser would be pulling nodes from a YAML document on an
+as-needed basis, and this is the eventual goal.  But, I don't have
+a pull parser yet, so I simulate one by reading in the entire YAML
+document into a Python data structure, then I do a push-based dump 
+of the data structure to a mock emitter that stores up a list of
+parser events that a mock parser then serves up to the schema-driven
+parser on an as-needed basis.  Sounds complex, but there's really not
+much code involved.
+
+Nothing fancy is supported yet--just lists, dictionaries, and scalars; 
+no aliases, class transformations, multiple docs, etc.  Also, we lose
+the sort order on map keys, so you will notice that all the examples
+have alphabetically sorted keys.
+
+Also, once we go to a true pull parser, we could have more metadata,
+such as line numbers for nodes, attached comments, etc., that can 
+help with error reporting and round-tripping issues.
+"""
+
+testCases = """
+-
+    data: |
+        --- foo
+    schema:
+        type: scalar
+-
+    data: |
+        --- foo
+    schema:
+        type: seq
+    error: |
+        Wanted seq, got scalar
+ -
+    data: &list123 |
+        ---
+        - 1
+        - 2
+        - 3
+    schema:
+        type: seq
+        child:
+            type: scalar
+  -
+    data: *list123
+    schema:
+        type: seq
+        max: 2
+        child:
+            type: scalar
+    error: |
+        Seq has max 2 elements
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        street: Bourbon
+    schema: &StreetCityState
+        type: map
+        items:
+            - name: city
+              value:
+                  type: scalar
+            - name: state
+              value:
+                  type: scalar
+            - name: street
+              value:
+                  type: scalar
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        where ya got ya shoes: on ya feet, on Bourbon St.
+    schema: *StreetCityState
+    error: |
+        Expected key 'street', got 'where ya got ya shoes'
+-
+    data: |
+        ---
+        banana: yellow
+        carrot: orange
+        people:
+            - fname: al
+              salary: 44
+            - fname: bob
+              salary: 33
+    schema:
+        type: map
+        items:
+            - name: banana
+              value:
+                type: scalar
+            - name: carrot
+              value:
+                type: scalar
+            - name: people
+              value:
+                type: seq
+                child:
+                    type: map
+                    items:
+                        - name: fname
+                          value:
+                            type: scalar
+                        - name: salary
+                          value:
+                            type: scalar
+"""
+
+class ValidatingLoader:
+    def load(self, data, schema):
+        self.simulateParser(data)
+        return self.loadData(schema)
+
+    def loadData(self, schema):
+        typ = self.parser.getType()
+        return self._load(typ, schema)
+
+    def _load(self, typ, schema):
+        if typ != schema['type']:
+            raise Exception("Wanted %s, got %s\n" % (schema['type'], typ))
+        if typ == 'seq':
+            return self._loadSeq(schema)
+        if typ == 'map':
+            return self._loadMap(schema)
+        else:
+            return self.parser.getScalar()
+
+    def _loadSeq(self, schema):
+        results = []
+        cnt = 0
+        max = schema.get('max', None)
+        schema = schema['child']
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                cnt += 1
+                self.checkMax(cnt, max)
+                results.append(self._load(typ, schema))
+
+    def _loadMap(self, schema):
+        results = {}
+        for item in schema['items']:
+            self.parser.getType()
+            name = self.parser.getScalar()
+            self.checkName(name, item)
+            value = self.loadData(item['value'])
+            results[name] = value
+        self.parser.getType()
+        return results
+
+    def checkMax(self, cnt, max):
+            if max is not None and cnt > max:
+                raise Exception("Seq has max %d elements\n" % max)
+
+    def checkName(self, name, item):
+        if name != item['name']:
+            raise Exception("Expected key '%s', got '%s'\n" % \
+                (item['name'], name))
+
+    def simulateParser(self, data):
+        # This is the huge hack to work around
+        # not having a true pull parser
+        self.parser = mockParser(oldYamlLoad(data))
+
+def testRoundTrip(data, schema):
+    expected = oldYamlLoad(data)
+    obj = ValidatingLoader().load(data, schema)
+    assertEquals(expected, obj)
+
+def oldYamlLoad(data):
+    return load(data).next()
+
+def testOneCase(test):
+    data = test['data']
+    schema = test['schema']
+    if test.has_key('error'):
+        assertError(lambda: testRoundTrip(data, schema),
+            test['error'])
+    else:
+        testRoundTrip(data, schema)
+
+class Test(YamlTest.YamlTest):
+    def testFromYaml(self):
+        for test in load(testCases).next():
+            testOneCase(test)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_0.32/spec.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/spec.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/spec.yml	(revision 75)
@@ -0,0 +1,2 @@
+# OBSOLETE!
+# see TestingSuite/spec.yml or TESTING for details
Index: /pyyaml-legacy/tags/PyYaml_0.32/YAML.vim
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/YAML.vim	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/YAML.vim	(revision 75)
@@ -0,0 +1,41 @@
+" To make this file do stuff, add something like the following (without the
+" leading ") to your ~/.vimrc:
+" au BufNewFile,BufRead *.yaml,*.yml so ~/src/PyYaml/YAML.vim
+
+" Vim syntax/macro file
+" Language:	YAML
+" Author:	Igor Vergeichik <iverg@mail.ru>
+" Sponsor: Tom Sawyer <transami@transami.net>
+" Stayven: Ryan King <jking@panoptic.com>
+" Copyright (c) 2002 Tom Saywer
+
+" Add an item to a gangly list:
+map , o<bs><bs><bs><bs>-<esc>o
+" Convert to Canonical form:
+map \c :%!python -c 'from yaml.redump import redump; import sys; print redump(sys.stdin.read()).rstrip()'
+
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+syntax clear
+
+syn match yamlStream	"\s*---$"
+syn region yamlComment	start="\s*\#" end="$"
+syn match yamlDelimiter	"[:,]"
+syn match yamlBlock "[\[\]\{\}]"
+
+syn region yamlString	start="'" end="'" skip="\\'"
+syn region yamlString	start='"' end='"' skip='\\"' contains=yamlEscape
+
+syn match  yamlKey		"\w\+\ze\s*:"
+syn match  yamlType		"![^\s]\+\s\@="
+
+hi link yamlKey		Identifier
+hi link yamlComment	Comment
+hi link yamlStream	Statement
+hi link yamlBlock	Operator
+hi link yamlDelimiter	Delimiter
+hi link yamlString	String
+
Index: /pyyaml-legacy/tags/PyYaml_0.32/query.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/query.yml	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/query.yml	(revision 75)
@@ -0,0 +1,246 @@
+data:
+    title:
+        - &manager
+          caption: Manager
+          position: 0
+        - &programmer
+          caption: Programmer
+          position: 1
+          shadow:
+             position: 18
+        - &editor
+          caption: Editor
+          position: ~
+          shadow: 
+             position: 3
+    people:
+        - &mary
+          id: mary
+          name: Mary McFoo
+          number: 333
+          title: *programmer
+        - &al
+          id: al
+          name: Al Barson
+          number: 555
+          title: *manager
+    tasks:
+        - id: make a list
+          duration: 10
+          owner: al
+          person: *al
+        - id: go to store
+          duration: 15
+          owner: mary
+          person: *mary
+        - id: buy stuff
+          duration: 25
+          owner: mary
+          person: *mary
+          tasks:
+            - id: zoom
+              owner: *mary
+              duration: 22
+            - id: fly
+              owner: *al
+              duration: 33
+        - id: drive home
+          duration: 20
+          owner: mary
+          person: *mary
+        - id: watch tv
+          duration: 20
+          owner: al
+          person: *al
+        - id: cook food
+          duration: 60
+          owner: al
+          person: *al
+        - id: eat stuff
+          duration: 35
+          owner: al
+          person: *al
+tests:
+    - query:
+        select: 
+            - duration
+        from: tasks/*
+      expected:
+        - duration: 10
+        - duration: 15
+        - duration: 25
+        - duration: 20
+        - duration: 20
+        - duration: 60
+        - duration: 35
+    - query:
+        select: 
+            - owner
+        from: tasks/*
+        where:
+          id: cook food
+      expected:
+        - owner: al
+    - query:
+        select: 
+            - id
+        from: tasks/*
+        where:
+          duration: 20
+          owner: al
+      expected:
+        - id: watch tv
+    - query:
+        select: 
+            - caption
+        from: title/*
+        where:
+          position: ~
+      expected:
+         - caption: Editor
+    - query:
+        select: 
+            - position
+            - shadow/position
+        from: title/*
+        where:
+          caption: Editor
+      expected:
+         - position: ~
+           shadow/position: 3
+    - query:
+        select:
+          - id
+          - duration
+        from: tasks/*
+        where:
+            owner: mary
+        order:
+          - duration
+      expected:
+        - id: go to store
+          duration: 15
+        - id: drive home
+          duration: 20
+        - id: buy stuff
+          duration: 25
+    - query:
+        select:
+          - id
+          - owner
+        from: tasks/*
+        where: |
+          [duration] == 60
+      expected:
+        - id: cook food
+          owner: al
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: |
+          [duration] <= 20 and [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: 
+          - [duration] <= 20 
+          - [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: 
+          - [duration] <= 20 
+          - owner: 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+            - person/number
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - id: make a list
+          duration: 10
+          person/name: Al Barson
+          person/number: 555
+    - query:
+        select:
+            - person/name
+            - person/title/caption
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - person/name: Al Barson
+          person/title/caption: Manager
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+        from: tasks/*
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+          person/name: Al Barson
+        - id: cook food
+          duration: 60
+          person/name: Al Barson
+        - id: buy stuff
+          duration: 25
+          person/name: Mary McFoo
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+        from: tasks
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+        - id: cook food
+          duration: 60
+        - id: buy stuff
+          duration: 25
+      ignore: 1
+    - query:
+       select:
+         - id
+       from: //tasks
+      expected:
+        - id: make a list
+        - id: go to store
+        - id: buy stuff
+        - id: zoom
+        - id: fly
+        - id: drive home
+        - id: watch tv
+        - id: cook food
+        - id: eat stuff
+      ignore: 1
Index: /pyyaml-legacy/tags/PyYaml_0.32/test.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_0.32/test.py	(revision 75)
+++ /pyyaml-legacy/tags/PyYaml_0.32/test.py	(revision 75)
@@ -0,0 +1,18 @@
+def assertEquals(first, second, msg=''):
+    if first != second:
+        raise AssertionError, \
+              (msg + "\n%s !=\n%s" % (`first`, `second`))
+
+def assertError(func, expectedError):
+    raised = 1
+    try:
+        func()
+        raised = 0
+    except Exception, e:
+        assertEquals(str(e), expectedError)
+    except:
+        raise "Unexpected exception"
+    if raised == 0:
+        raise "Never threw exception"
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/timestamp.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/timestamp.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/timestamp.py	(revision 71)
@@ -0,0 +1,145 @@
+import time, re, string
+from types import ListType, TupleType
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+# 
+# Time specific operations
+#
+
+_splitTime = re.compile('\-|\s|T|t|:|\.|Z')
+matchTime = re.compile(\
+          '\d+-\d+-\d+([\s|T|t]\d+:\d+:\d+.\d+(Z|(\s?[\-|\+]\d+:\d+)))?')
+
+def _parseTime(val):
+    if not matchTime.match(val): raise ValueError(val)
+    tpl = _splitTime.split(val)
+    if not(tpl): raise ValueError(val)
+    siz = len(tpl)
+    sec = 0
+    if 3 == siz:
+       tpl += [0,0,0,0,0,-1]
+    elif 7 == siz:
+       tpl.append(0)
+       tpl.append(-1)
+    elif 8 == siz:
+       if len(tpl.pop()) > 0: raise ValueError(val)
+       tpl.append(0)
+       tpl.append(-1)
+    elif 9 == siz or 10 == siz:
+       mn = int(tpl.pop())
+       hr = int(tpl.pop())
+       sec = (hr*60+mn)*60
+       if val.find("+") > -1: sec = -sec
+       if 10 == siz: tpl.pop()
+       tpl.append(0)
+       tpl.append(-1)
+    else:
+       raise ValueError(val)
+    idx = 0
+    while idx < 9:
+       tpl[idx] = int(tpl[idx])
+       idx += 1
+    if tpl[1] < 1 or tpl[1] > 12: raise ValueError(val)
+    if tpl[2] < 1 or tpl[2] > 31: raise ValueError(val)
+    if tpl[3] > 24: raise ValueError(val)
+    if tpl[4] > 61: raise ValueError(val)
+    if tpl[5] > 61: raise ValueError(val)
+    if tpl[0] > 2038:
+        #TODO: Truncation warning
+        tpl = (2038,1,18,0,0,0,0,0,-1)
+    tpl = tuple(tpl)
+    ret = time.mktime(tpl)
+    ret = time.localtime(ret+sec)
+    ret = ret[:8] + (0,)
+    return ret
+
+
+class _timestamp:
+    def __init__(self,val=None):
+        if not val:
+           self.__tval = time.gmtime()
+        else:
+           typ = type(val)
+           if ListType == typ:
+               self.__tval = tuple(val)
+           elif TupleType == typ:
+               self.__tval = val
+           else:
+               self.__tval = _parseTime(val)
+           if 9 != len(self.__tval): raise ValueError
+    def __getitem__(self,idx): return self.__tval[idx]
+    def __len__(self): return 9
+    def strftime(self,format): return time.strftime(format,self.__tval)
+    def mktime(self):          return time.mktime(self.__tval)
+    def asctime(self):  return time.asctime(self.__tval)
+    def isotime(self):  
+        return "%04d-%02d-%02dT%02d:%02d:%02d.00Z" % self.__tval[:6]
+    def __repr__(self): return "yaml.timestamp('%s')" % self.isotime()    
+    def __str__(self):  return self.isotime()
+    def to_yaml_implicit(self): return self.isotime()
+    def __hash__(self): return hash(self.__tval[:6]) 
+    def __cmp__(self,other): 
+        try:
+            return cmp(self.__tval[:6],other.__tval[:6])
+        except AttributeError:
+            return -1
+
+try: # inherit from mx.DateTime functionality if available
+    from mx import DateTime
+    class timestamp(_timestamp):
+        def __init__(self,val=None):
+            _timestamp.__init__(self,val)
+            self.__mxdt = DateTime.mktime(self.__tval)
+        def __getattr__(self, name):
+              return getattr(self.__mxdt, name)
+except:
+    class timestamp(_timestamp): pass
+        
+
+
+def unquote(expr):
+    """
+        summary: >
+           Simply returns the unquoted string, and the
+           length of the quoted string token at the 
+           beginning of the expression.
+    """
+    tok = expr[0]
+    if "'" == tok: 
+        idx = 1
+        odd = 0
+        ret = ""
+        while idx < len(expr):
+            chr = expr[idx]
+            if "'" == chr:
+                if odd: ret += chr
+                odd = not odd
+            else:
+                if odd:
+                    tok = expr[:idx]
+                    break
+                ret += chr
+            idx += 1
+        if "'" == tok: tok = expr
+        return (ret,len(tok))
+    if '"' == tok:
+        idx = 1
+        esc = 0
+        while idx < len(expr):
+            chr = expr[idx]
+            if '"' == chr and not esc:
+                tok = expr[:idx] + '"'
+                break
+            if '\\' == chr and not esc: esc = 1
+            else: esc = 0
+            idx += 1
+        if '"' == tok:
+            raise SyntaxError("unmatched quote: " + expr)
+        ret = eval(tok)  #TODO: find better way to unquote
+        return (ret,len(tok))
+    return (expr,len(expr))
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/dump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/dump.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/dump.py	(revision 71)
@@ -0,0 +1,290 @@
+import types
+import string
+from types import StringType, UnicodeType, IntType, FloatType
+from types import DictType, ListType, TupleType, InstanceType
+from yaml.klass import hasMethod, isDictionary
+import re
+
+"""
+  The methods from this module that are exported to the top 
+  level yaml package should remain stable.  If you call
+  directly into other methods of this module, be aware that 
+  they may change or go away in future implementations.
+  Contact the authors if there are methods in this file 
+  that you wish to remain stable.
+"""
+
+def dump(*data):
+    return Dumper().dump(*data)
+
+def dumpToFile(file, *data):
+    return Dumper().dumpToFile(file, *data)
+
+class Dumper:
+    def __init__(self):
+        self.currIndent   = "\n"
+        self.indent = "    "
+        self.keysrt   = None
+        self.alphaSort = 1 # legacy -- on by default
+
+    def setIndent(self, indent):
+        self.indent = indent
+        return self
+
+    def setSort(self, sort_hint):
+        self.keysrt = sortMethod(sort_hint)
+        return self
+
+    def dump(self, *data):
+        self.result = []  
+        self.output = self.outputToString
+        self.dumpDocuments(data)
+        return string.join(self.result,"")
+
+    def outputToString(self, data):
+        self.result.append(data)
+
+    def dumpToFile(self, file, *data):
+        self.file = file
+        self.output = self.outputToFile
+        self.dumpDocuments(data)
+
+    def outputToFile(self, data):
+        self.file.write(data)
+
+    def dumpDocuments(self, data):
+        for obj in data:
+            self.anchors  = YamlAnchors(obj)
+            self.output("---")
+            self.dumpData(obj)
+            self.output("\n")       
+
+    def indentDump(self, data):
+        oldIndent = self.currIndent
+        self.currIndent += self.indent
+        self.dumpData(data)
+        self.currIndent = oldIndent
+
+    def dumpData(self, data):
+        anchor = self.anchors.shouldAnchor(data)
+        if anchor: 
+            self.output(" &%d" % anchor )
+        else:
+            anchor = self.anchors.isAlias(data)
+            if anchor:
+                self.output(" *%d" % anchor )
+                return
+        if (data is None):
+            self.output(' ~')
+        elif hasMethod(data, 'to_yaml'):
+            self.dumpTransformedObject(data)            
+        elif hasMethod(data, 'to_yaml_implicit'):
+            self.output(" " + data.to_yaml_implicit())
+        elif type(data) is InstanceType:
+            self.dumpRawObject(data)
+        elif isDictionary(data):
+            self.dumpDict(data)
+        elif type(data) in [ListType, TupleType]:
+            self.dumpList(data)
+        else:
+            self.dumpScalar(data)
+
+    def dumpTransformedObject(self, data):
+        obj_yaml = data.to_yaml()
+        if type(obj_yaml) is not TupleType:
+            self.raiseToYamlSyntaxError()
+        (data, typestring) = obj_yaml
+        if typestring:
+            self.output(" " + typestring)
+        self.dumpData(data)
+
+    def dumpRawObject(self, data):
+        self.output(' !!%s.%s' % (data.__module__, data.__class__.__name__))
+        self.dumpData(data.__dict__)
+
+    def dumpDict(self, data):
+        keys = data.keys()
+        if len(keys) == 0:
+            self.output(" {}")
+            return
+        if self.keysrt:
+            keys = sort_keys(keys,self.keysrt)
+        else:
+            if self.alphaSort:
+                keys.sort()
+        for key in keys:
+            self.output(self.currIndent)
+            self.dumpKey(key)
+            self.output(":")
+            self.indentDump(data[key])
+
+    def dumpKey(self, key):
+        if type(key) is TupleType:
+            self.output("?")
+            self.indentDump(key) 
+            self.output("\n")
+        else:
+            self.output(quote(key))
+
+    def dumpList(self, data):
+        if len(data) == 0:
+            self.output(" []")
+            return
+        for item in data:
+            self.output(self.currIndent)
+            self.output("-")
+            self.indentDump(item)
+
+    def dumpScalar(self, data):
+        if isUnicode(data):
+            self.output(' "%s"' % repr(data)[2:-1])
+        elif isMulti(data):
+            self.dumpMultiLineScalar(data.splitlines())
+        else:
+            self.output(" ")
+            self.output(quote(data))
+    
+    def dumpMultiLineScalar(self, lines):
+        self.output(" |")
+        if lines[-1] == "":
+            self.output("+")
+        for line in lines:
+            self.output(self.currIndent)
+            self.output(line)
+
+    def raiseToYamlSyntaxError(self):
+            raise """
+to_yaml should return tuple w/object to dump 
+and optional YAML type.  Example:
+({'foo': 'bar'}, '!!foobar')
+"""
+
+#### ANCHOR-RELATED METHODS
+
+def accumulate(obj,occur):
+    typ = type(obj)
+    if obj is None or \
+       typ is IntType or \
+       typ is FloatType or \
+       ((typ is StringType or typ is UnicodeType) \
+       and len(obj) < 32): return
+    obid = id(obj)
+    if 0 == occur.get(obid,0):
+        occur[obid] = 1
+        if typ is ListType:
+            for x in obj: 
+                accumulate(x,occur)
+        if typ is DictType:
+            for (x,y) in obj.items():
+                accumulate(x,occur)
+                accumulate(y,occur)
+    else:
+        occur[obid] = occur[obid] + 1
+
+class YamlAnchors:
+     def __init__(self,data):
+         occur = {}
+         accumulate(data,occur)
+         anchorVisits = {}
+         for (obid, occur) in occur.items():
+             if occur > 1:
+                 anchorVisits[obid] = 0 
+         self._anchorVisits = anchorVisits
+         self._currentAliasIndex     = 0
+     def shouldAnchor(self,obj):
+         ret = self._anchorVisits.get(id(obj),None)
+         if 0 == ret:
+             self._currentAliasIndex = self._currentAliasIndex + 1
+             ret = self._currentAliasIndex
+             self._anchorVisits[id(obj)] = ret
+             return ret
+         return 0
+     def isAlias(self,obj):
+         return self._anchorVisits.get(id(obj),0)
+
+### SORTING METHODS
+
+def sort_keys(keys,fn):
+    tmp = []
+    for key in keys:
+        val = fn(key)
+        if val is None: val = '~'
+        tmp.append((val,key))
+    tmp.sort()
+    return [ y for (x,y) in tmp ]
+
+def sortMethod(sort_hint):
+    typ = type(sort_hint)
+    if DictType == typ:
+        return sort_hint.get
+    elif ListType == typ or TupleType == typ:
+        indexes = {}; idx = 0
+        for item in sort_hint:
+            indexes[item] = idx
+            idx += 1
+        return indexes.get
+    else:
+        return sort_hint
+
+### STRING QUOTING AND SCALAR HANDLING
+def isStr(data):
+    # XXX 2.1 madness
+    if type(data) == type(''):
+        return 1
+    if type(data) == type(u''):
+        return 1
+    return 0
+    
+def doubleUpQuotes(data):
+    return data.replace("'", "''")
+
+def quote(data):
+    if not isStr(data):
+        return str(data)
+    single = "'"
+    double = '"'
+    quote = ''
+    if len(data) == 0:
+        return "''"
+    if hasSpecialChar(data) or data[0] == single:
+        data = `data`[1:-1]
+        data = string.replace(data, r"\x08", r"\b")
+        quote = double 
+    elif needsSingleQuote(data):
+        quote = single
+        data = doubleUpQuotes(data)
+    return "%s%s%s" % (quote, data, quote)
+
+def needsSingleQuote(data):
+    if re.match(r"^\d", data):
+        return 1
+    if data[0] == '&':
+        return 1
+    if data[0] == '"':
+        return 1
+    return (re.search(r'[-:]', data) or re.search(r'(\d\.){2}', data))
+
+def hasSpecialChar(data):
+    # need test to drive out '#' from this
+    return re.search(r'[\t\b\r\f#]', data)
+
+def isMulti(data):
+    if not isStr(data):
+        return 0
+    if hasSpecialChar(data):
+        return 0
+    return re.search("\n", data)
+
+def isUnicode(data):
+    return type(data) == unicode
+    
+def sloppyIsUnicode(data):
+        # XXX - hack to make tests pass for 2.1
+        return repr(data)[:2] == "u'" and repr(data) != data
+
+import sys
+if sys.hexversion < 0x20200000:
+    isUnicode = sloppyIsUnicode
+    
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ypath.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ypath.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ypath.py	(revision 71)
@@ -0,0 +1,462 @@
+from types import ListType, StringType, IntType, DictType, InstanceType
+import re
+from urllib import quote
+from timestamp import unquote
+
+noTarget = object()
+
+def escape(node):
+    """
+        summary: >
+            This function escapes a given key so that it
+            may appear within a ypath.  URI style escaping
+            is used so that ypath expressions can be a 
+            valid URI expression.
+    """
+    typ = type(node)
+    if typ is IntType: return str(node)
+    if typ is StringType: 
+        return quote(node,'')
+    raise ValueError("TODO: Support more than just string and integer keys.")
+
+class context:
+    """
+        summary: >
+            A ypath visit context through a YAML rooted graph.
+            This is implemented as a 3-tuple including the parent
+            node, the current key/index and the value.  This is
+            an immutable object so it can be cached.
+        properties: 
+            key:    mapping key or index within the parent collection
+            value:  current value within the parent's range
+            parent: the parent context
+            root:   the very top of the yaml graph
+            path:   a tuple of the domain keys
+        notes: >
+            The context class doesn't yet handle going down the
+            domain side of the tree... 
+    """         
+    def __init__(self,parent,key,value):
+        """
+            args:
+                parent: parent context (or None if this is the root)
+                key:    mapping key or index for this context
+                value:  value of current location...
+        """
+        self.parent = parent
+        self.key    = key
+        self.value  = value
+        if parent: 
+            assert parent.__class__ is self.__class__
+            self.path = parent.path + (escape(key),)
+            self.root = parent.root
+        else:      
+            assert not key
+            self.path = tuple()
+            self.root = self
+    def __setattr__(self,attname,attval):
+        if attname in ('parent','key','value'):
+            if self.__dict__.get(attname):
+                 raise ValueError("context is read-only")
+        self.__dict__[attname] = attval
+    def __hash__(self): return hash(self.path)
+    def __cmp__(self,other):   
+        try:
+            return cmp(self.path,other.path)
+        except AttributeError:
+            return -1
+    def __str__(self):
+        if self.path:
+            return "/".join(('',)+self.path)
+        else:
+            return '/'
+
+def to_context(target):
+    if type(target) is InstanceType:
+        if target.__class__ is context:
+            return target
+    return context(None,None,target)
+
+def context_test():
+    lst = ['value']
+    map = {'key':lst}
+    x = context(None,None,map)
+    y = context(x,'key',lst)
+    z = context(y,0,'value')
+    assert ('key',) == y.path
+    assert 'key'    == y.key
+    assert lst      == y.value
+    assert x        == y.parent
+    assert x        == y.root
+    assert 0        == z.key
+    assert 'value'  == z.value
+    assert y        == z.parent
+    assert x        == z.root 
+    assert hash(x)  
+    assert hash(y)
+    assert hash(z)
+    assert '/' == str(x)
+    assert '/key' == str(y)
+    assert '/key/0' == str(z)
+
+class null_seg:
+    """
+        summary: >
+            This is the simplest path segment, it
+            doesn't return any results and doesn't
+            depend upon its context.  It also happens to 
+            be the base class which all segments derive.
+    """
+    def __iter__(self): 
+        return self
+    def next_null(self):
+        raise StopIteration
+    def bind(self,cntx):  
+        """
+            summary: >
+                The bind function is called whenever
+                the parent context has changed.
+        """
+        assert(cntx.__class__ is context)
+        self.cntx = cntx
+    def apply(self,target):
+        self.bind(to_context(target))
+        return iter(self)
+    def exists(self,cntx):
+        try:
+            self.bind(cntx)
+            self.next()
+            return 1
+        except StopIteration:
+            return 0
+    next = next_null
+ 
+class self_seg(null_seg):
+    """
+        summary: >
+            This path segment returns the context
+            node exactly once.
+    """
+    def __str__(self): return '.'
+    def next_self(self):
+        self.next = self.next_null
+        return self.cntx
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.next = self.next_self
+
+class root_seg(self_seg):
+    def __str__(self): return '/'
+    def bind(self,cntx):  
+        self_seg.bind(self,cntx.root)
+
+class parent_seg(self_seg):
+    def __str__(self): return '..'
+    def bind(self,cntx):
+        if cntx.parent: cntx = cntx.parent
+        self_seg.bind(self,cntx)
+
+class wild_seg(null_seg):
+    """
+        summary: >
+            The wild segment simply loops through
+            all of the sub-contexts for a given object.
+            If there aren't any children, this isn't an
+            error it just doesn't return anything.
+    """
+    def __str__(self): return '*'
+    def next_wild(self):
+        key = self.keys.next()
+        return context(self.cntx,key,self.values[key])
+    def bind(self,cntx):  
+        null_seg.bind(self,cntx)
+        typ = type(cntx.value)
+        if typ is ListType:
+            self.keys   = iter(xrange(0,len(cntx.value)))
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return
+        if typ is DictType:
+            self.keys   = iter(cntx.value)
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return 
+        self.next = self.next_null
+
+class trav_seg(null_seg):
+    """
+        summary: >
+            This is a recursive traversal of the range, preorder.
+            It is a recursive combination of self and wild.
+    """
+    def __str__(self): return '/'
+    def next(self): 
+        while 1:
+            (cntx,seg) = self.stk[-1]
+            if not seg:
+                seg = wild_seg()
+                seg.bind(cntx)
+                self.stk[-1] = (cntx,seg)
+                return cntx
+            try:
+                cntx = seg.next()
+                self.stk.append((cntx,None))
+            except StopIteration:
+                self.stk.pop()
+                if not(self.stk):
+                    self.next = self.next_null
+                    raise StopIteration
+
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.stk = [(cntx,None)]
+
+class match_seg(self_seg):
+    """
+        summary: >
+            Matches a particular key within the
+            current context.  Kinda boring.
+    """
+    def __str__(self): return str(self.key)
+    def __init__(self,key):
+        #TODO: Do better implicit typing
+        try:
+           key = int(key)
+        except: pass
+        self.key = key
+    def bind(self,cntx):
+        try: 
+            mtch = cntx.value[self.key]
+            cntx = context(cntx,self.key,mtch)
+            self_seg.bind(self,cntx)
+        except:
+            null_seg.bind(self,cntx)
+        
+class conn_seg(null_seg):
+    """
+        summary: >
+            When two segments are connected via a slash,
+            this is a composite.  For each context of the
+            parent, it binds the child, and returns each
+            context of the child.
+    """
+    def __str__(self): 
+        if self.parent.__class__ == root_seg:  
+            return "/%s" % self.child
+        return "%s/%s" % (self.parent, self.child)
+    def __init__(self,parent,child):
+        self.parent = parent
+        self.child  = child
+    def next(self):
+        while 1:
+            try:
+                return self.child.next()
+            except StopIteration:
+                cntx = self.parent.next()
+                self.child.bind(cntx)
+ 
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+        try:
+            cntx = self.parent.next()
+        except StopIteration: 
+            return
+        self.child.bind(cntx)
+
+
+class pred_seg(null_seg):
+    def __str__(self): return "%s[%s]" % (self.parent, self.filter)
+    def __init__(self,parent,filter):
+        self.parent = parent
+        self.filter = filter
+    def next(self):
+        while 1:
+            ret = self.parent.next()
+            if self.filter.exists(ret):
+                return ret
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+
+class or_seg(null_seg):
+    def __str__(self): return "%s|%s" % (self.lhs,self.rhs)
+    def __init__(self,lhs,rhs):
+        self.rhs = rhs
+        self.lhs = lhs
+        self.unq = {}
+    def next(self):
+        seg = self.lhs
+        try:
+            nxt = seg.next()
+            self.unq[nxt] = nxt
+            return nxt
+        except StopIteration: pass
+        seg = self.rhs
+        while 1:
+            nxt = seg.next()
+            if self.unq.get(nxt,None): 
+                continue  
+            return nxt
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.lhs.bind(cntx)
+        self.rhs.bind(cntx)
+
+class scalar:
+    def __init__(self,val):  
+        self.val = val
+    def __str__(self): 
+        return str(self.val)
+    def value(self): 
+        return self.val
+
+class equal_pred: 
+    def exists_true(self,cntx): return 1
+    def exists_false(self,cntx): return 0
+    def exists_scalar(self,cntx):
+        self.rhs.bind(cntx)
+        try:
+            while 1:
+                cntx = self.rhs.next()
+                if str(cntx.value) == self.lhs:  #TODO: Remove type hack
+                     return 1
+        except StopIteration: pass
+        return 0
+    def exists_segment(self,cntx):
+        raise NotImplementedError()
+    def __init__(self,lhs,rhs):
+        if lhs.__class__ == scalar:
+            if rhs.__class__ == scalar:
+                if rhs.value() == lhs.value():
+                    self.exists = self.exists_true
+                else:
+                    self.exists = self.exists_false
+            else:
+                self.exists = self.exists_scalar
+        else:
+            if rhs.__class__ == scalar:
+                (lhs,rhs) = (rhs,lhs)
+                self.exists = self.exists_scalar
+            else:
+                self.exists = self.exists_segment
+        self.lhs = str(lhs.value())  #TODO: Remove type hack
+        self.rhs = rhs
+ 
+matchSegment = re.compile(r"""^(\w+|/|\.|\*|\"|\')""")
+
+def parse_segment(expr):
+    """
+        Segments occur between the slashes...
+    """
+    mtch = matchSegment.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if   '/' == tok: return (trav_seg(),expr)
+    elif '.' == tok: 
+        if len(expr) > 1 and '.' == expr[1]:
+            seg = parent_seg()
+            siz = 2
+        else: 
+            seg = self_seg()
+    elif '*' == tok: seg = wild_seg()
+    elif '"' == tok or "'" == tok:
+        (cur,siz) = unquote(expr)
+        seg = match_seg(cur)
+    else:
+        seg = match_seg(tok)
+    return (seg,expr[siz:])
+
+matchTerm = re.compile(r"""^(\w+|/|\.|\(|\"|\')""")
+
+def parse_term(expr):
+    mtch = matchTerm.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if '/' == tok or '.' == tok:
+        return parse(expr)
+    if '(' == tok:
+        (term,expr) = parse_predicate(expr)
+        assert ')' == expr[0]
+        return (term,expr[1:])
+    elif '"' == tok or "'" == tok:
+        (val,siz) = unquote(expr)
+    else:
+        val = tok; siz = len(tok)
+    return (scalar(val),expr[siz:])
+
+def parse_predicate(expr):
+    (term,expr) = parse_term(expr)
+    if not term: raise SyntaxError("term expected: '%s'" % expr)
+    tok = expr[0]
+    if '=' == tok:
+        (rhs,expr) = parse_term(expr[1:])
+        return (equal_pred(term,rhs),expr)
+    if '(' == tok:
+        raise "No functions allowed... yet!"
+    if ']' == tok or ')' == tok:
+        if term.__class__ is scalar:
+            term = match_seg(str(term))
+        return (term,expr)
+    raise SyntaxError("ypath: expecting operator '%s'" % expr)
+
+def parse_start(expr):
+    """
+        Initial checking on the expression, and 
+        determine if it is relative or absolute.
+    """
+    if type(expr) != StringType or len(expr) < 1: 
+        raise TypeError("string required: " + repr(expr))
+    if '/' == expr[0]:
+        ypth = root_seg()
+    else:
+        ypth = self_seg()
+        expr = '/' + expr
+    return (ypth,expr)
+
+def parse(expr):
+    """
+        This the parser entry point, the top level node
+        is always a root or self segment.  The self isn't
+        strictly necessary, but it keeps things simple.
+    """
+    (ypth,expr) = parse_start(expr)
+    while expr:
+        tok = expr[0]
+        if '/' == tok:
+            (child, expr) = parse_segment(expr[1:])    
+            if child: ypth = conn_seg(ypth,child)
+            continue
+        if '[' == tok:
+            (filter, expr) = parse_predicate(expr[1:])
+            assert ']' == expr[0]
+            expr = expr[1:]
+            ypth = pred_seg(ypth,filter)
+            continue
+        if '|' == tok:
+            (rhs, expr) = parse(expr[1:])
+            ypth = or_seg(ypth,rhs)
+            continue
+        if '(' == tok:
+            (child,expr) = parse(expr[1:])
+            assert ')' == expr[0]
+            expr = expr[1:]
+            ypth = conn_seg(ypth,child)
+            continue
+        break
+    return (ypth,expr)
+
+class convert_to_value(null_seg):
+    def __init__(self,itr):
+        self.itr = itr
+    def next(self):
+        return self.itr.next().value
+    def bind(self,cntx):
+        self.itr.bind(cntx)
+
+def ypath(expr,target=noTarget,cntx=0):
+    (ret,expr) = parse(expr)
+    if expr: raise SyntaxError("ypath parse error `%s`" % expr)
+    if not cntx: ret = convert_to_value(ret)
+    if target is noTarget: return ret
+    return ret.apply(target)
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ordered_dict.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ordered_dict.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/ordered_dict.py	(revision 71)
@@ -0,0 +1,31 @@
+# This is extremely crude implementation of an OrderedDict.
+# If you know of a better implementation, please send it to
+# the author Steve Howell.  You can find my email via 
+# the YAML mailing list or wiki.
+
+class OrderedDict(dict): 
+    def __init__(self): 
+        self._keys = [] 
+ 
+    def __setitem__(self, key, val): 
+        self._keys.append(key) 
+        dict.__setitem__(self, key, val) 
+ 
+    def keys(self): 
+        return self._keys 
+ 
+    def items(self):
+        return [(key, self[key]) for key in self._keys]
+ 
+if __name__ == '__main__': 
+    data = OrderedDict()
+    data['z'] = 26
+    data['m'] = 13
+    data['a'] = 1
+    for key in data.keys(): 
+        print "The value for %s is %s" % (key, data[key]) 
+    print data
+
+
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/implicit.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/implicit.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/implicit.py	(revision 71)
@@ -0,0 +1,46 @@
+import re
+import string
+from timestamp import timestamp, matchTime
+
+DATETIME_REGEX   = re.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")
+FLOAT_REGEX      = re.compile("^[-+]?[0-9][0-9,]*\.[0-9,]*$")
+SCIENTIFIC_REGEX = re.compile("^[-+]?[0-9][0-9,]*\.[0-9.]*[eE][-+][0-9]+$")
+OCTAL_REGEX      = re.compile("^[-+]?([0][0-7,]*)$")
+HEX_REGEX        = re.compile("^[-+]?0x[0-9a-fA-F,]+$")
+INT_REGEX        = re.compile("^[-+]?(0|[1-9][0-9,]*)$")
+
+def convertImplicit(val):
+    if val == '~':
+        return None
+    if val == '+':
+        return 1
+    if val == '-':
+        return 0
+    if val[0] == "'" and val[-1] == "'":
+        val = val[1:-1]
+        return string.replace(val, "''", "\'")
+    if val[0] == '"' and val[-1] == '"':
+        if re.search(r"\u", val):
+            val = "u" + val
+        unescapedStr = eval (val)
+        return unescapedStr
+    if matchTime.match(val):
+        return timestamp(val)
+    if INT_REGEX.match(val):
+        return int(cleanseNumber(val))
+    if OCTAL_REGEX.match(val):
+        return int(val, 8)
+    if HEX_REGEX.match(val):
+        return int(val, 16)
+    if FLOAT_REGEX.match(val):
+        return float(cleanseNumber(val))
+    if SCIENTIFIC_REGEX.match(val):
+        return float(cleanseNumber(val))
+    return val
+
+def cleanseNumber(str):
+    if str[0] == '+':
+        str = str[1:]
+    str = string.replace(str,',','')
+    return str
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/stream.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/stream.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/stream.py	(revision 71)
@@ -0,0 +1,186 @@
+import re
+import string
+
+def indentLevel(line):
+    n = 0
+    while n < len(line) and line[n] == ' ':
+        n = n + 1
+    return n
+
+class LineNumberStream:
+    def __init__(self):
+        self.curLine = 0
+
+    def get(self):
+        line = self.getLine()
+        self.curLine += 1 # used by subclass
+        if line:
+            line = noLineFeed(line)
+        return line
+
+    def lastLineRead(self):
+        return self.curLine
+
+class FileStream(LineNumberStream):
+    def __init__(self, filename):
+        self.fp = open(filename)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        line = self.fp.readline()
+        if line == '': line = None
+        return line
+
+class StringStream(LineNumberStream):
+    def __init__(self, text):
+        self.lines = split(text)
+        self.numLines = len(self.lines)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        if self.curLine < self.numLines:
+            return self.lines[self.curLine]
+
+def split(text):
+    lines = string.split(text, '\n')
+    if lines[-1] == '':
+        lines.pop()
+    return lines
+
+def eatNewLines(stream):
+    while 1:
+       line = stream.get()
+       if line is None or len(string.strip(line)):
+           return line
+
+COMMENT_LINE_REGEX = re.compile(R"\s*#")
+def isComment(line):
+    return line is not None and COMMENT_LINE_REGEX.match(line)
+
+class CommentEater:
+    def __init__(self, stream):
+        self.stream = stream
+        self.peeked = 1
+        self.line = eatNewLines(stream)
+        self.eatComments()
+
+    def eatComments(self):
+        while isComment(self.line):
+            self.line = self.stream.get()
+
+    def peek(self):
+        if self.peeked:
+            return self.line
+        self.peeked = 1
+        self.line = self.stream.get()
+        self.eatComments()
+        return self.line
+
+    def lastLineRead(self):
+        return self.stream.lastLineRead()
+
+    def pop(self):
+        data = self.peek()
+        self.peeked = 0
+        return data
+
+class NestedText:
+    def __init__(self, stream):
+        self.commentEater = CommentEater(stream)
+        self.reset()
+
+    def lastLineRead(self):
+        return self.commentEater.lastLineRead()
+
+    def reset(self):
+        self.indentLevel = 0
+        self.oldIndents = [0]
+
+    def peek(self):
+        nextLine = self.commentEater.peek()
+        if nextLine is not None:
+            if indentLevel(nextLine) >= self.indentLevel:
+                return nextLine[self.indentLevel:]
+            elif nextLine == '':
+                return ''                
+
+    def pop(self):
+        line = self.peek()
+        if line is None:
+            self.indentLevel = self.oldIndents.pop()
+            return
+        self.commentEater.pop()
+        return line
+
+    def popNestedLines(self):
+        nextLine = self.peek()
+        if nextLine is None or nextLine == '' or nextLine[0] != ' ':
+            return []
+        self.nestToNextLine()
+        lines = []
+        while 1:
+            line = self.pop()
+            if line is None:
+                break
+            lines.append(line)
+        return lines
+
+    def nestToNextLine(self):
+        line = self.commentEater.peek()
+        indentation = indentLevel(line)
+        if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+            self.error("Inadequate indentation", line)
+        self.setNewIndent(indentation)
+
+    def nestBySpecificAmount(self, adjust):
+        self.setNewIndent(self.indentLevel + adjust)
+        
+    def setNewIndent(self, indentLevel):
+        self.oldIndents.append(self.indentLevel)
+        self.indentLevel = indentLevel    
+
+class YamlLoaderException(Exception):
+    def __init__(self, *args):
+        (self.msg, self.lineNum, self.line) = args
+
+    def __str__(self):
+        return "%s:\n" "near line %d:\n" "%s\n" % \
+            (self.msg, self.lineNum, self.line)
+
+
+class NestedDocs(NestedText):
+    def __init__(self, stream):
+        NestedText.__init__(self,stream)
+        line = NestedText.peek(self)
+        self.sep = '---'
+        if self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+        else:
+            self.eatenDocSep = self.sep
+
+    def startsWithSep(self,line):
+        if line and self.sep == line[:3]: return 1
+        return 0
+
+    def popDocSep(self):
+        line = self.eatenDocSep
+        self.eatenDocSep = None
+        self.reset()
+        return line
+
+    def pop(self):
+        if self.eatenDocSep is not None:
+            raise "error"
+        line = self.commentEater.peek()
+        if line and self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+            return None
+        return NestedText.pop(self)
+
+    def error(self, msg, line):
+        raise YamlLoaderException(msg, self.lastLineRead(), line)
+
+def noLineFeed(s):
+    while s[-1:] in ('\n', '\r'):
+        s = s[:-1]
+    return s
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/redump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/redump.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/redump.py	(revision 71)
@@ -0,0 +1,11 @@
+from yaml.ordered_dict import OrderedDict
+from yaml import Parser, Dumper, StringStream
+
+def redump(stream):
+    parser = Parser(StringStream(stream))
+    parser.dictionary = OrderedDict
+    docs = list(iter(parser))
+    dumper = Dumper()
+    dumper.alphaSort = 0
+    return dumper.dump(*docs)
+    
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/klass.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/klass.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/klass.py	(revision 71)
@@ -0,0 +1,48 @@
+import new
+import re
+
+class DefaultResolver:
+    def resolveType(self, data, typestring):
+        match = re.match('!!(.*?)\.(.*)', typestring)
+        if not match:
+            raise "Invalid private type specifier"
+        (modname, classname) = match.groups()
+        return makeClass(modname, classname, data)
+
+def makeClass(module, classname, dict):
+    exec('import %s' % (module))
+    klass = eval('%s.%s' % (module, classname))
+    obj = new.instance(klass) 
+    if hasMethod(obj, 'from_yaml'):
+        return obj.from_yaml(dict)
+    obj.__dict__ = dict
+    return obj
+
+def hasMethod(object, method_name):
+    try:    
+        klass = object.__class__
+    except:
+        return 0
+    if not hasattr(klass, method_name):
+        return 0
+    method = getattr(klass, method_name)
+    if not callable(method):
+        return 0
+    return 1
+
+def isDictionary(data):
+    return isinstance(data, dict)
+
+try:
+    isDictionary({})
+except:
+    def isDictionary(data): return type(data) == type({}) # XXX python 2.1
+    
+if __name__ == '__main__':
+    print isDictionary({'foo': 'bar'})
+    try:
+        print isDictionary(dict())
+        from ordered_dict import OrderedDict
+        print isDictionary(OrderedDict())
+    except:
+        pass
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/inline.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/inline.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/inline.py	(revision 71)
@@ -0,0 +1,38 @@
+import re
+import string
+
+class InlineTokenizer:
+    def __init__(self, data):
+        self.data = data
+
+    def punctuation(self):
+        puncts = [ '[', ']', '{', '}' ]
+        for punct in puncts:
+            if self.data[0] == punct:
+                self.data = self.data[1:]
+                return punct
+
+    def up_to_comma(self):
+        match = re.match('(.*?)\s*, (.*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def up_to_end_brace(self):
+        match = re.match('(.*?)(\s*[\]}].*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def next(self):
+        self.data = string.strip(self.data)
+        productions = [
+            self.punctuation,
+            self.up_to_comma,
+            self.up_to_end_brace
+        ]
+        for production in productions:
+            token = production()
+            if token:
+                return token
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/__init__.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/__init__.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/__init__.py	(revision 71)
@@ -0,0 +1,20 @@
+__version__ = "0.25"
+from load import loadFile
+from load import load
+from load import Parser
+from dump import dump
+from dump import dumpToFile
+from dump import Dumper
+from stream import YamlLoaderException, StringStream, FileStream
+from timestamp import timestamp
+
+try:
+    from ypath import ypath
+except NameError:
+    def ypath(expr,target='',cntx=''):
+        raise NotImplementedError("ypath requires Python 2.2")
+
+
+import sys
+if sys.hexversion < 0x02010300:
+    raise 'YAML is not tested for pre-2.1.3 versions of Python'
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/load.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/load.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/yaml/load.py	(revision 71)
@@ -0,0 +1,328 @@
+import re, string
+from implicit import convertImplicit
+from inline import InlineTokenizer
+from yaml.klass import DefaultResolver
+from yaml.stream import FileStream, StringStream, NestedDocs
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+try:
+    iter(list()) # is iter supported by this version of Python?
+except:
+    # XXX - Python 2.1 does not support iterators   
+    class StopIteration: pass
+    class iter:
+        def __init__(self,parser):
+            self._docs = []
+            try:
+                while 1:
+                   self._docs.append(parser.next())
+            except StopIteration: pass
+            self._idx = 0
+        def __len__(self): return len(self._docs)
+        def __getitem__(self,idx): return self._docs[idx]
+        def next(self):
+            if self._idx < len(self._docs):
+                ret = self._docs[self._idx] 
+                self._idx = self._idx + 1
+                return ret
+            raise StopIteration
+
+def loadFile(filename, typeResolver=None):
+    return loadStream(FileStream(filename),typeResolver)
+   
+def load(str, typeResolver=None):
+    return loadStream(StringStream(str), typeResolver)
+
+def loadStream(stream, typeResolver):
+    return iter(Parser(stream, typeResolver))
+
+def tryProductions(productions, value):
+    for production in productions:
+        results = production(value)
+        if results:
+            (ok, result) = results
+            if ok:
+                return (1, result)
+
+def dumpDictionary(): return {}
+
+class Parser:
+    def __init__(self, stream, typeResolver=None):
+        try:
+            self.dictionary = dict
+        except:
+            self.dictionary = dumpDictionary
+        self.nestedDocs = NestedDocs(stream)
+        self.aliases = {}
+        if typeResolver:
+            self.typeResolver = typeResolver
+        else:
+            self.typeResolver = DefaultResolver()
+
+    def error(self, msg):
+        self.nestedDocs.error(msg, self.line)
+
+    def nestPop(self):
+        line = self.nestedDocs.pop()
+        if line is not None:
+            self.line = line
+            return 1
+
+    def value(self, indicator):
+        return getToken(indicator+"\s*(.*)", self.line)
+
+    def getNextDocument(self): raise "getNextDocument() deprecated--use next()"
+
+    def next(self):
+        line = self.nestedDocs.popDocSep()
+        indicator = getIndicator(line)
+        if indicator:
+            return self.parse_value(indicator)
+        if line:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+        raise StopIteration
+
+    def __iter__(self): return self
+
+    def parseLines(self):
+        peekLine = self.nestedDocs.peek()
+        if peekLine:
+            if re.match("\s*-", peekLine):
+                return self.parse_collection([], self.parse_seq_line)
+            else:
+                return self.parse_collection(self.dictionary(), self.parse_map_line)
+        raise StopIteration
+
+    def parse_collection(self, items, lineParser):
+        while self.nestPop():
+            if self.line:
+                lineParser(items)
+        return items    
+
+    def parse_seq_line(self, items):
+        value = self.value("-")
+        if value is not None:
+            items.append(self.parse_seq_value(value))
+        else:
+            self.error("missing '-' for seq")
+
+    def parse_map_line(self, items):
+        if (self.line == '?'):
+            self.parse_map_line_nested(items)
+        else:
+            self.parse_map_line_simple(items, self.line)
+
+    def parse_map_line_nested(self, items):
+        self.nestedDocs.nestToNextLine()
+        key = self.parseLines()
+        if self.nestPop():
+            value = self.value(':')
+            if value is not None:
+                items[tuple(key)] = self.parse_value(value)
+                return
+        self.error("key has no value for nested map")
+
+    def parse_map_line_simple(self, items, line):
+        map_item = key_value(line)
+        if map_item:
+            (key, value) = map_item
+            key = convertImplicit(key)
+            items[key] = self.parse_value(value)
+        else:
+            self.error("bad key for map")
+
+    def is_map(self, value):
+        # XXX - need real tokenizer
+        if len(value) == 0:
+            return 0
+        if value[0] == "'":
+            return 0
+        if re.search(':(\s|$)', value):       
+            return 1
+
+    def parse_seq_value(self, value):
+        if self.is_map(value):
+            return self.parse_compressed_map(value)
+        else:
+            return self.parse_value(value)
+
+    def parse_compressed_map(self, value):
+        items = self.dictionary()
+        line = self.line
+        token = getToken("(\s*-\s*)", line)
+        self.nestedDocs.nestBySpecificAmount(len(token))
+        self.parse_map_line_simple(items, value)
+        return self.parse_collection(items, self.parse_map_line)
+
+    def parse_value(self, value):
+        (alias, value) = self.testForRepeatOfAlias(value)
+        if alias:
+            return value
+        (alias, value) = self.testForAlias(value)            
+        value = self.parse_unaliased_value(value)
+        if alias:
+            self.aliases[alias] = value
+        return value          
+
+    def parse_unaliased_value(self, value):
+        match = re.match(r"(!\S*)(.*)", value)
+        if match:
+            (url, value) = match.groups()
+            value = self.parse_untyped_value(value)
+            if url[:2] == '!!':
+                return self.typeResolver.resolveType(value, url)
+            else:
+                # XXX - allows syntax, but ignores it
+                return value
+        return self.parse_untyped_value(value)
+
+    def parseInlineArray(self, value):        
+        if re.match("\s*\[", value):
+            return self.parseInline([], value, ']', 
+                self.parseInlineArrayItem)
+
+    def parseInlineHash(self, value):        
+        if re.match("\s*{", value):
+            return self.parseInline(self.dictionary(), value, '}', 
+                self.parseInlineHashItem)
+
+    def parseInlineArrayItem(self, result, token):
+        return result.append(convertImplicit(token))
+
+    def parseInlineHashItem(self, result, token):
+        (key, value) = key_value(token)
+        result[key] = value
+
+    def parseInline(self, result, value, end_marker, itemMethod):
+        tokenizer = InlineTokenizer(value)
+        tokenizer.next()
+        while 1:
+            token = tokenizer.next()
+            if token == end_marker:
+                break
+            itemMethod(result, token)
+        return (1, result)
+
+    def parseSpecial(self, value):
+        productions = [
+            self.parseMultiLineScalar,
+            self.parseInlineHash,
+            self.parseInlineArray,
+        ]
+        return tryProductions(productions, value)
+
+    def parse_untyped_value(self, value):
+        parse = self.parseSpecial(value)
+        if parse:
+            (ok, data) = parse
+            return data
+        token = getToken("(\S.*)", value)
+        if token:
+            lines = [token] + \
+                pruneTrailingEmpties(self.nestedDocs.popNestedLines())
+            return convertImplicit(joinLines(lines))
+        else:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+
+    def parseNative(self, value):
+        return (1, convertImplicit(value))
+
+    def parseMultiLineScalar(self, value):
+        if value == '>':
+            return (1, self.parseFolded())
+        elif value == '|':
+            return (1, joinLiteral(self.parseBlock()))
+        elif value == '|+':
+            return (1, joinLiteral(self.unprunedBlock()))
+
+    def parseFolded(self):
+        data = self.parseBlock()
+        i = 0
+        resultString = ''
+        while i < len(data)-1:
+            resultString = resultString + data[i]
+            resultString = resultString + foldChar(data[i], data[i+1])
+            i = i + 1
+        return resultString + data[-1] + "\n"        
+
+    def unprunedBlock(self):
+        self.nestedDocs.nestToNextLine()
+        data = []
+        while self.nestPop():
+            data.append(self.line)
+        return data
+
+    def parseBlock(self):
+        return pruneTrailingEmpties(self.unprunedBlock())
+
+    def testForAlias(self, value):
+        match = re.match("&(\S*)\s*(.*)", value)
+        if match:
+            return match.groups()
+        return (None, value)
+
+    def testForRepeatOfAlias(self, value):
+        match = re.match("\*(\S*)", value)
+        if match:
+            alias = match.groups()[0]
+            if self.aliases.has_key(alias):
+                return (alias, self.aliases[alias])
+            else:
+                self.error("Unknown alias")
+        return (None, value)
+
+def getToken(regex, value):
+    match = re.search(regex, value)
+    if match:
+        return match.groups()[0]
+
+def key_value(str):
+    # XXX This allows mis-balanced " vs. ' stuff
+    match = re.match("[\"'](.+)[\"']\s*:\s*(.*)", str)
+    if match:
+        (key, value) = match.groups()
+        return (key, value)
+
+    match = re.match("(.+?)\s*:\s*(.*)", str)
+    if match:
+        (key, value) = match.groups()
+        if len(value) and value[0] == '#':
+            value = ''
+        return (key, value)
+
+def pruneTrailingEmpties(data):
+    while len(data) > 0 and data[-1] == '':
+        data = data[:-1]
+    return data
+
+def foldChar(line1, line2):
+    if re.match("^\S", line1) and re.match("^\S", line2):
+        return " "
+    return "\n"
+
+def getIndicator(line):
+    if line:
+        header = r"(#YAML:\d+\.\d+\s*){0,1}"
+        match = re.match("--- "+header+"(\S*.*)", line)
+        if match:
+            return match.groups()[-1]
+
+def joinLines(lines):
+    result = ''
+    for line in lines[:-1]:
+        if line[-1] == '\\':
+            result = result + line[:-1]
+        else:
+            result = result + line + " "
+    return result + lines[-1]
+
+def joinLiteral(data):
+    return string.join(data,"\n") + "\n"
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.yml	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.yml	(revision 73)
@@ -0,0 +1,72 @@
+tests:
+    - data:
+        - foo
+        - bar
+      command:
+        value: baz
+      expected:
+        - foo
+        - bar
+        - baz
+    - data:
+        - apple
+        - banana
+      command:
+        value: carrot
+      expected:
+        - apple
+        - banana
+        - carrot
+    -
+      data: 
+        - foo
+      command:
+        value: 
+          name: steve
+          sport: hoops
+      expected:
+        - foo
+        - name: steve
+          sport: hoops
+    -
+      data: 
+        persons:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /persons
+        value: 
+          name: brian
+      expected:
+        persons:
+         - name: steve
+         - name: clark
+         - name: brian
+        tasks:
+          - task: eat
+          - task: sleep
+    -
+      data: 
+        folks:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /folks
+        value: 
+          name: ryan
+      expected:
+        folks: 
+         - name: steve
+         - name: clark
+         - name: ryan
+        tasks:
+          - task: eat
+          - task: sleep
+
+      
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/profile.out
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/profile.out	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/profile.out	(revision 73)
@@ -0,0 +1,36 @@
+['Profile', 'Stats', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '_get_time_times', 'help', 'marshal', 'os', 'run', 'sys', 'time']
+Wed Sep 25 08:59:14 2002    profileResults
+
+         93074 function calls (91948 primitive calls) in 8.740 CPU seconds
+
+   Ordered by: internal time
+   List reduced from 134 to 25 due to restriction <25>
+
+   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
+    12179    0.727    0.000    1.967    0.000 yaml\stream.py:65(peek)
+     3747    0.672    0.000    3.529    0.001 yaml\stream.py:156(pop)
+     6176    0.664    0.000    1.082    0.000 C:\PYTHON22\lib\sre.py:129(match)
+     4551    0.578    0.000    1.196    0.000 yaml\stream.py:93(peek)
+     3772    0.457    0.000    1.554    0.000 yaml\stream.py:101(pop)
+     3324    0.408    0.000    0.764    0.000 yaml\stream.py:14(get)
+     3727    0.326    0.000    3.837    0.001 yaml\load.py:75(nestPop)
+     7018    0.319    0.000    0.509    0.000 C:\PYTHON22\lib\sre.py:215(_compile)
+     3266    0.292    0.000    0.519    0.000 yaml\stream.py:61(eatComments)
+     5137    0.282    0.000    0.282    0.000 yaml\stream.py:4(indentLevel)
+     3206    0.234    0.000    0.331    0.000 yaml\stream.py:76(pop)
+      380    0.233    0.001    3.412    0.009 yaml\load.py:257(parseBlock)
+  914/731    0.214    0.000    5.739    0.008 yaml\load.py:221(parse_untyped_value)
+     3324    0.214    0.000    0.214    0.000 yaml\stream.py:51(isComment)
+     2999    0.183    0.000    0.183    0.000 yaml\stream.py:29(getLine)
+  917/733    0.166    0.000    6.457    0.009 yaml\load.py:164(parse_value)
+     3216    0.163    0.000    0.163    0.000 yaml\stream.py:169(noLineFeed)
+     3528    0.152    0.000    0.152    0.000 yaml\stream.py:146(startsWithSep)
+     1235    0.148    0.000    0.167    0.000 yaml\implicit.py:12(convertImplicit)
+  793/697    0.148    0.000    6.731    0.010 yaml\load.py:132(parse_map_line_simple)
+      675    0.139    0.000    0.543    0.001 yaml\stream.py:122(nestToNextLine)
+      795    0.136    0.000    0.419    0.001 yaml\load.py:285(key_value)
+      914    0.131    0.000    4.038    0.004 yaml\load.py:55(tryProductions)
+  914/731    0.124    0.000    5.958    0.008 yaml\load.py:174(parse_unaliased_value)
+  318/190    0.113    0.000    7.956    0.042 yaml\load.py:103(parse_collection)
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc1.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc1.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc1.yml	(revision 71)
@@ -0,0 +1,1 @@
+foo: bar
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc2.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc2.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/doc2.yml	(revision 71)
@@ -0,0 +1,1 @@
+more: stuff
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/toplevel.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/toplevel.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/toplevel.yml	(revision 71)
@@ -0,0 +1,4 @@
+
+    - doc1: !!include doc1.yml
+    - doc2: !!include doc2.yml
+    
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/demo.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/demo.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/IncludeHack/demo.py	(revision 71)
@@ -0,0 +1,19 @@
+import yaml
+
+def writeFile(fn, data):
+    f = open(fn, 'w')
+    f.write(data)
+
+writeFile('toplevel.yml', """
+    - doc1: !!include doc1.yml
+    - doc2: !!include doc2.yml
+    """)
+
+writeFile('doc1.yml', "foo: bar")
+writeFile('doc2.yml', "more: stuff")
+
+class Includer:
+    def resolveType(self, value, url):
+        return yaml.loadFile(value).next()
+
+print yaml.loadFile('toplevel.yml', Includer()).next()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestNestedText.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestNestedText.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestNestedText.py	(revision 73)
@@ -0,0 +1,311 @@
+import YamlTest
+from yaml.load import *
+from here import flushLeft
+from test import assertEquals
+from yaml.stream import NestedText, CommentEater, split
+
+here = flushLeft # pardon the Perlism
+
+def stringStream(str):
+    return StringStream(here(str))
+
+def commentEater(str):
+    return CommentEater(stringStream(str))
+
+def nestedText(str):
+    return NestedText(stringStream(str))
+
+def nestedDocs(str):
+    return NestedDocs(stringStream(str))
+
+class Test(YamlTest.YamlTest):
+    def tryPop(self, expected):
+        assertEquals(self.nt.pop(), expected)
+        
+    def tryPopNestedLines(self, expected):
+        assertEquals(self.nt.popNestedLines(), expected)
+        
+    def tryPeek(self, expected):
+        assertEquals(self.nt.peek(), expected)
+
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop('')
+        self.tryPop(None)
+        
+    def test2(self):
+        self.nt = nestedText("""
+            apple
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def test3(self):
+        self.nt = nestedDocs("""
+            seattle
+            --- foo
+            bluffton
+            """)
+        assertEquals(self.nt.popDocSep(), '---')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- foo')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+    def testEatComments(self):
+        self.nt = commentEater("""
+            # ignore
+              # these
+            silly
+            """)
+        self.tryPop('silly')
+
+    def testNestedDocsEatComments(self):
+        self.nt = nestedDocs("""
+            # foo
+              # bar
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+        assertEquals(self.nt.lastLineRead(), 4)
+
+    def testNestedTextEatNewline(self):
+        self.nt = nestedDocs("""
+            
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+
+    def testDocSep(self):
+        data = here("""
+            --- city
+            seattle
+            --- town
+            bluffton
+            """)
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- town')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+        data = here("""
+            # comments at top
+            # should be ignored
+            """) + data
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+
+    def testNestedComments(self):
+        self.nt = nestedText("""
+            apple
+              # ignore this comment
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def testStream(self):
+        stream = StringStream(here("""
+            python
+            perl
+            java
+            """))
+        assertEquals(stream.get(), "python")
+        assertEquals(stream.get(), "perl")
+        assertEquals(stream.get(), "java")
+        
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop(None)
+        
+    def XXXtestEmptyLines(self):
+        # not sure if this is valid test any more
+        self.nt = nestedDocs("""
+            ---
+             apple
+
+                banana
+            """)
+        self.nt.popDocSep()
+        self.nt.nestToNextLine()
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+
+    def testFoldedCase(self):
+        self.nt = nestedText(
+            """
+            ---
+             Aaa
+             Bbb
+
+               11
+               22
+
+             Ccc
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('Aaa')
+        self.tryPop('Bbb')
+        self.tryPop('')
+
+    def testRedHerringDocSep(self):
+        self.nt = nestedDocs(
+            """
+            ---
+            foo:
+                ---
+            """)
+        self.nt.popDocSep()
+        self.tryPop('foo:')
+        self.nt.nestToNextLine()
+        self.tryPop('---')
+
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            line1: this is
+               continued
+            line2
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('line1: this is')
+        self.tryPopNestedLines(['continued'])
+        self.tryPop('line2')
+            
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            key1: this is
+               continued
+               with multiple lines
+            key2:
+                 key2a:
+                   hello
+                   world
+            key3:
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('key1: this is')
+        self.tryPopNestedLines(['continued', 'with multiple lines'])
+        self.tryPop('key2:')
+        self.nt.nestToNextLine()
+        self.tryPop('key2a:')
+        self.tryPopNestedLines(['hello', 'world'])
+            
+    def testPopNestedLinesWithNoneNested(self):
+        self.nt = nestedText(
+            """
+            ---
+            - apple
+            - banana
+            - carrot
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('- apple')
+        self.tryPopNestedLines([])
+        self.tryPop('- banana')
+
+    def testLineNumbers(self):
+        data = \
+            """
+            one
+            two
+            #
+            three
+            """
+        stream = StringStream(here(data))
+        stream.get()
+        assertEquals(stream.lastLineRead(), 1)
+        stream.get()
+        assertEquals(stream.lastLineRead(), 2)
+        nt = nestedText(data)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 1)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 2)
+        nt.pop()  # eats a comment too
+        assertEquals(nt.lastLineRead(), 4)
+
+    def testSplit(self):
+        assertEquals(split("foo\nbar"), ['foo', 'bar'])
+        assertEquals(split("foo\nbar\n"), ['foo', 'bar'])        
+
+    def testLoaderException(self):
+        import yaml
+        from yaml.stream import YamlLoaderException
+        exception = None
+        try:
+            yaml.load('invalid YAML').next()
+        except YamlLoaderException, e:
+            exception = e
+        assertEquals(exception.lineNum, 1)
+            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/LICENSE
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/LICENSE	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/LICENSE	(revision 73)
@@ -0,0 +1,71 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+The Python library for YAML was started by Steve Howell in 
+February 2002.  Steve is the primary author of the project,
+but others have contributed.  See the README for more on 
+the project.  The term "PyYaml" refers to the entire 
+distribution of this library, including examples, documentation,
+and test files, as well as the core implementation.
+
+This library is intended for general use, and the license 
+below protects the "open source" nature of the library.  The 
+license does, however, allow for use of the library in 
+commercial applications as well, subject to the terms 
+and conditions listed.  The license below is a minor 
+rewrite of the Python 2.2 license, with no substantive 
+differences.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PyYaml
+===============================================================
+
+LICENSE AGREEMENT FOR PyYaml
+----------------------------
+
+1. This LICENSE AGREEMENT is between Stephen S. Howell ("Author"), 
+and the Individual or Organization ("Licensee") accessing and
+otherwise using PyYaml software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, Author
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use PyYaml
+alone or in any derivative version, provided, however, that Author's
+License Agreement and Author's notice of copyright, i.e., "Copyright (c)
+2001 Steve Howell and Friends; All Rights Reserved" are never removed
+from PyYaml, and are included in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates PyYaml or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to PyYaml.
+
+4. Author is making PyYaml available to Licensee on an "AS IS"
+basis.  Author MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, Author MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PyYaml WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. Author SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.2 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.2,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between Author and
+Licensee.  This License Agreement does not grant permission to use Author
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using PyYaml, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_map.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_map.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_map.py	(revision 71)
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a
+dictionary (mapping) containing the following key/value pairs:
+    (1) "name" (required) -- a string.
+    (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+        pairs.
+    (3) "text" (optional) -- a string.
+    (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+For usage information, type:
+    python convertyaml_map.py
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if type(obj) == types.DictType and \
+            obj.has_key('name'):
+            name = obj['name']
+            attributes = None
+            if obj.has_key('attributes'):
+                attributes = obj['attributes']
+            text = None
+            if obj.has_key('text'):
+                text = obj['text']
+            children = None
+            if obj.has_key('children'):
+                children = obj['children']
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = {}
+    # Add the element name.
+    objDict['name'] = obj.nodeName
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict['attributes'] = attrDict
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict['text'] = textStr
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict['children'] = children
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/README_yaml2xml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/README_yaml2xml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/README_yaml2xml	(revision 71)
@@ -0,0 +1,76 @@
+                   Convert XML to and from YAML
+                   ============================
+
+
+===========
+Description
+===========
+
+This mini-package contains two implementations of conversion
+routines that convert XML to YAML and YAML to XML.  These two
+implementations use different canonical representations for XML in
+YAML as follows:
+
+convertyaml_map.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a
+    dictionary (mapping) containing the following key/value pairs:
+        (1) "name" (required) -- a string.
+        (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+            pairs.
+        (3) "text" (optional) -- a string.
+        (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+convertyaml_seq.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a 4-tuple
+    (a sequence) containing the following:
+        (1) element name
+        (2) attributes -- a mapping
+        (3) text -- a string
+        (4) children -- a sequence of elements
+
+Basically, convertyaml_map.py uses keywords (in a dictionary) to
+represent structures and convertyaml_seq.py uses position (within a
+list).
+
+=====
+Usage
+=====
+
+There is some usage information at the top of each implementation
+file.
+
+
+=======
+Testing
+=======
+
+Here are some simple tests:
+
+    python convertyaml_map.py -x2y people.xml
+    python convertyaml_map.py -x2y people.xml > people.yml
+    python convertyaml_map.py -y2x people.yml
+
+    python convertyaml_seq.py -x2y people.xml
+    python convertyaml_seq.py -x2y people.xml > people.yml
+    python convertyaml_seq.py -y2x people.yml
+
+
+======================
+Additional Information
+======================
+
+The YAML home site is at:
+
+    http://www.yaml.org/
+
+
+
+
+
+Dave Kuhlman
+dkuhlman@rexx.com
+http://www.rexx.com/~dkuhlman
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_seq.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_seq.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/convertyaml_seq.py	(revision 71)
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a 4-tuple
+(a sequence) containing the following:
+    (1) element name
+    (2) attributes -- a mapping
+    (3) text -- a string
+    (4) children -- a sequence of elements
+
+For usage information, type:
+    python convertyaml_seq.py
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if (type(obj) == types.ListType or type(obj) == types.TupleType) and \
+            len(obj) == 4:
+            name = obj[0]
+            attributes = obj[1]
+            text = obj[2]
+            children = obj[3]
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = []
+    # Add the element name.
+    objDict.append(obj.nodeName)
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict.append(attrDict)
+    else:
+        objDict.append(None)
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict.append(textStr)
+    else:
+        objDict.append(None)
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict.append(children)
+    else:
+        objDict.append(None)
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/people.xml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/people.xml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/XmlYaml/people.xml	(revision 71)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<people> 
+    <person id="1" value="abcd" ratio="3.2">
+        <name>Alberta</name>
+        <interest>gardening</interest>
+        <interest>reading</interest>
+        <category>5</category>
+    </person> 
+
+    <person id="2">
+        <name>Bernardo</name>
+        <interest>programming</interest>
+        <category></category>
+        <agent>
+            <firstname>Darren</firstname>
+            <lastname>Diddly</lastname>
+        </agent>
+
+    </person>
+
+    <person id="3">
+        <name>Charlie</name>
+        <interest>people</interest>
+        <interest>cats</interest>
+        <interest>dogs</interest>
+        <category>8</category>
+        <promoter>
+            <firstname>David</firstname>
+            <lastname>Donaldson</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+        <promoter>
+            <firstname>Edward</firstname>
+            <lastname>Eddleberry</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+    </person>
+
+</people>
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestDumper.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestDumper.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestDumper.py	(revision 73)
@@ -0,0 +1,465 @@
+import YamlTest
+from yaml.dump import *
+import yaml
+from here import flushLeft
+from test import assertEquals
+
+class SampleClass:
+    def expected(self, modname, classname):
+        """
+        Tough to test, because this class may be in __main__ 
+        namespace, may be in TestDumper, depending where you 
+        run it
+        """
+        return """
+        --- !!%s.%s
+        bar: 4
+        foo: 3
+        items:
+            - apple
+            - banana
+        """ % (modname, classname)
+
+    def __init__(self):
+        self.foo = 3
+        self.bar = 4
+        self.items = ['apple', 'banana']
+
+
+class SampleException(Exception):
+    def __init__(self, args):
+        self.args = args
+
+class Test(YamlTest.YamlTest):
+    def dumpTest(self, obj, expect):
+        assertEquals(yaml.dump(obj), flushLeft(expect))
+    def dumpTestSort(self,sort):
+        obj = {'a':'aaaa','d':'dddd','b':'bbbb','c':'cccc'}
+        exp = flushLeft(\
+            """
+            ---
+            b: bbbb
+            d: dddd
+            a: aaaa
+            c: cccc
+            """)
+        dumper = yaml.Dumper().setSort(sort)
+        self.assertEquals(dumper.dump(obj),exp)
+    def testsort_map(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3})
+    def testsort_tuple(self):
+        self.dumpTestSort(('b','d','a'))
+    def testsort_list(self):
+        self.dumpTestSort(['b','d','a'])
+    def testsort_func(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3}.get)
+    def test1(self):
+        self.dumpTest(
+            { 'foo': 'bar', 'yo': 'mama' },
+            """
+            ---
+            foo: bar
+            yo: mama
+            """,
+        )
+
+    def test2(self):
+        self.dumpTest(
+            { 'foo': {'bar': 3} },
+            """
+            ---
+            foo:
+                bar: 3
+            """,
+        )
+
+    def test3(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': {
+                    'apple': 'red',
+                    'banana': 'yellow',
+                }
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                apple: red
+                banana: yellow
+            """
+            )
+                
+    def test4(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ['apple', 'orange']
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testTuple(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ('apple', 'orange')
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testMultiLineBlock(self):
+        self.dumpTest(
+             { 
+                 'foo': "a\nb\nc\n",
+             },
+             """
+             ---
+             foo: |
+                 a
+                 b
+                 c
+             """
+             )
+
+    def testDoubleQuote(self):
+        assertEquals(doubleUpQuotes("foo'bar"), "foo''bar")
+        assertEquals(doubleUpQuotes("''x'"), "''''x''")
+
+    def testQuotingRules(self):
+        # Raw:
+        self.assertEquals(dump(None), "--- ~\n")
+        self.assertEquals(dump('simple'), "--- simple\n")
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('two words'), "--- two words\n")
+        self.assertEquals(dump('single\'quote'), "--- single'quote\n")
+        self.assertEquals(dump('5.2'), "--- '5.2'\n")
+        self.assertEquals(dump(5.2), "--- 5.2\n")
+        self.assertEquals(dump(1234), "--- 1234\n")
+        # Single Quoted:
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('4.3.1.5.2'), "--- '4.3.1.5.2'\n")
+        self.assertEquals(dump("'leading quote"), '--- "\'leading quote"\n')
+        self.assertEquals(dump('4.3.'), "--- '4.3.'\n")
+        self.assertEquals(dump('12345'), "--- '12345'\n")
+        self.assertEquals(dump('key: value'), "--- 'key: value'\n")
+        self.assertEquals(dump('- pretend seq'), "--- '- pretend seq'\n")
+        self.assertEquals(dump('ending colon:'), "--- 'ending colon:'\n")
+        self.assertEquals(dump('&foo'), "--- '&foo'\n")
+        assertEquals(dump('"middle \'quote'), '--- \'"middle \'\'quote\'\n')
+        # Double quoted:
+        self.assertEquals(dump("\thas a tab"), "--- \"\\thas a tab\"\n")
+        self.dumpTest(
+            [ "a - b", "c" ],
+            """
+            ---
+            - 'a - b'
+            - c
+            """)
+        self.dumpTest(
+            { "key: quote": 'normal value' },
+            """
+            ---
+            'key: quote': normal value
+            """)
+
+    def testArrayWithSingleQuoted(self):
+        self.dumpTest(
+            [ 'foo:', {'bar': 'colon:'}],
+            """
+            ---
+            - 'foo:'
+            -
+                bar: 'colon:'
+            """
+            )
+
+    def testDumpObject(self):
+        sample = SampleClass()
+        self.dumpTest(sample, 
+            sample.expected(sample.__module__, 'SampleClass'))
+
+    def testWithSpuriousToYaml(self):
+        class ClassWithSpuriousToYaml(SampleClass):
+            to_yaml = 1 # Shouldn't get invoked
+        x = ClassWithSpuriousToYaml()
+        self.dumpTest(x, 
+            x.expected(x.__module__,'ClassWithSpuriousToYaml'))
+
+    def testNormalToYamlUse(self):
+        class NormalYamlUse(SampleClass):
+            def to_yaml(self):
+                dict = {}
+                dict['bar'] = self.foo * 2
+                return (dict, None)
+        self.dumpTest(NormalYamlUse(),
+            """
+            ---
+            bar: 6
+            """)
+
+    def testDumpingPrivateTypes(self):
+        class Foobar(SampleClass):
+            def to_yaml(self):
+                dict = {'foo': 'bar'}
+                return (dict, '!!foobar')
+        self.dumpTest(Foobar(),
+            """
+            --- !!foobar
+            foo: bar
+            """)
+        class OddList(SampleClass):
+            def to_yaml(self):
+                return ([1, 3, 5], '!!oddlist')
+        self.dumpTest(OddList(),
+            """
+            --- !!oddlist
+            - 1
+            - 3
+            - 5
+            """)
+
+
+    def testToYamlShouldBeAllowedToThrowIfItWants(self):
+        class ThrowsInsideToYaml:
+            def to_yaml(self):
+                raise SampleException('bla')
+        caught_exception = 'undef'
+        try:
+            dump(ThrowsInsideToYaml())
+        except Exception, e:
+            caught_exception = e
+        self.assertEquals('bla', caught_exception.args)
+
+    def testObjectWithListOfClasses(self):
+        class Foo:
+            def __init__(self, items):
+                self.items = items
+             
+        class Bar:
+            def __init__(self, data):
+                self.data = data
+
+        foo = Foo([Bar('apple'), Bar('banana')])
+        mod = foo.__module__ # depends where called
+        self.dumpTest(foo,
+            """
+            --- !!%s.Foo
+            items:
+                - !!%s.Bar
+                    data: apple
+                - !!%s.Bar
+                    data: banana
+            """ % (mod, mod, mod))
+
+    def testHasMethod(self):
+        class ClassWithMethodA:
+            b = 1
+            def a(): pass
+
+        sc = ClassWithMethodA()
+        self.assertEquals(1, hasMethod(sc, 'a'))
+        self.assertEquals(0, hasMethod(sc, 'b'))
+
+    def testComplexKey(self):
+        self.dumpTest( {(3,4): 4},
+            """
+            ---
+            ?
+                - 3
+                - 4
+            : 4
+            """)            
+    
+    def testApostrophe(self):
+        self.dumpTest( "Joe's hot dogs.\n",
+            """
+            --- |
+            Joe's hot dogs.
+            """)
+
+    def testCustomIndent(self):
+        self.assertEquals(
+            yaml.Dumper().setIndent('xx').dump(
+                { 
+                    'foo': 3,
+                    'fruits': ('apple', 'orange')
+                }, 
+            ),
+            flushLeft(
+                """
+                ---
+                foo: 3
+                fruits:
+                xx- apple
+                xx- orange
+                """
+            )
+            )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.dumpTest({'foo': u"Foo\u263A"},
+                r"""
+                ---
+                foo: "Foo\u263a"
+                """)
+
+    def testTab(self):
+        self.dumpTest({'tab': "foo\tbar"},
+            r"""
+            ---
+            tab: "foo\tbar"
+            """)
+
+    def testIsMulti(self):
+        self.failUnless(isMulti("foo\nbar"))
+        self.failIf(isMulti("foobar"))
+        self.failIf(isMulti("line\twith tab\nsecond line"))
+        self.failUnless(isMulti("foo\\slash\nbar"))
+
+    def testHasSpecialChar(self):
+        self.failUnless(hasSpecialChar("foo\tbar"))
+        self.failIf(hasSpecialChar("foobar"))
+
+    def testTabs(self):
+        self.dumpTest({'control': "\b1998\t1999\t2000\n"},
+            r"""
+            ---
+            control: "\b1998\t1999\t2000\n"
+            """)
+
+    def test12345(self):
+        self.dumpTest({'foo': 12345, 'bar': '12345'},
+            r"""
+            ---
+            bar: '12345'
+            foo: 12345
+            """)
+
+    def testDataThatsCoincidentallyTheSame(self):
+        self.dumpTest([ {'foo': 'bar'}, {'foo': 'bar'} ],
+            """
+            ---
+            -
+                foo: bar
+            -
+                foo: bar
+            """)
+
+    def testAliasClass(self):
+        dup = {'foo': 'bar'}
+        dupList = [dup, dup]
+        myAnchors = YamlAnchors(dupList)
+        self.assertEquals(id(dup), myAnchors._anchorVisits.keys()[0])
+        self.assertEquals(0,myAnchors.isAlias(dup))
+        self.assertEquals(1,myAnchors.shouldAnchor(dup) )
+        self.assertEquals(0,myAnchors.shouldAnchor('bar'))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup['foo']))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup))
+        self.assertEquals(1,myAnchors.isAlias(dup))
+
+    def testAliases(self):
+        dup = {'foo': 'bar'}
+        self.dumpTest([dup, dup],
+            """
+            ---
+            - &1
+                foo: bar
+            - *1
+            """)
+
+    def testHashAlias(self):
+        dup = {}
+        dup['foo'] = dup
+        self.dumpTest(dup, 
+            """
+            --- &1
+            foo: *1
+            """)
+
+    def testEmptyArray(self):
+        self.dumpTest([],
+            """
+            --- []
+            """)
+
+    def testEmptyHash(self):
+        self.dumpTest({},
+            """
+            --- {}
+            """)
+
+    def testEmptyHashAsHashKey(self):
+        self.dumpTest({'foo': {} },
+            """
+            ---
+            foo: {}
+            """)
+
+    def testEmptyArrrayAsHashKey(self):
+        self.dumpTest({'foo': [] },
+            """
+            ---
+            foo: []
+            """)
+
+    def testAliasNone(self):
+        foo = None
+        self.dumpTest([foo, foo, foo],
+            """
+            ---
+            - ~
+            - ~
+            - ~
+            """)
+
+    def testDumpMany(self):
+        assertEquals(
+            yaml.dump({'foo': 1}, ['a', 'b', 'c']),
+            flushLeft(
+                """
+                ---
+                foo: 1
+                ---
+                - a
+                - b
+                - c
+                """))
+
+    def testDumpExtraNewLines(self):
+        self.dumpTest( "Joe's hot dogs.\n\n",
+            """
+            --- |+
+            Joe's hot dogs.
+
+            """)
+
+
+    def testDumpExtraNewLinesInDict(self):
+        data = {'preserving': "extra new lines are kept\n\n\n"}
+        self.dumpTest(data,
+            """
+            ---
+            preserving: |+
+                extra new lines are kept
+                
+                
+            """)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPushDumper.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPushDumper.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPushDumper.py	(revision 73)
@@ -0,0 +1,123 @@
+import YamlTest
+from here import *
+from test import assertEquals
+from types import DictType, ListType, TupleType, InstanceType
+
+"""
+This is experimental code.  It generates simulated events
+for a pull-based YAML parser.
+"""
+
+class MockEmitter:
+    """
+    A pushed-based emitter may be more awkward to write, 
+    because you have to keep track of more state.
+    """
+    def __init__(self):
+        self.events = []
+
+    def append(self, *event):
+        self.events.append(event)        
+
+    def pushScalar(self, data):
+        self.append('getType', 'scalar')
+        self.append('getScalar', data)
+
+    def appendType(self, typ):
+        self.append('getType', typ)
+
+    def startSeq(self):
+        self.appendType('seq')
+        
+    def endSeq(self):
+        self.appendType(None)
+
+    def startMap(self):
+        self.appendType('map')
+        
+    def endMap(self):
+        self.appendType(None)
+
+class Dumper:
+    def __init__(self, emitter):
+        self.emitter = emitter
+
+    def dump(self, data):
+        if type(data) in (ListType, TupleType):
+            return self.dumpList(data)
+        elif type(data) is DictType:
+            return self.dumpDict(data)
+        else:
+            self.emitter.pushScalar(data)
+
+    def dumpList(self, data):
+        self.emitter.startSeq()
+        for item in data:
+            self.dump(item)
+        self.emitter.endSeq()
+
+    def dumpDict(self, data):
+        self.emitter.startMap()
+        keys = data.keys()
+        keys.sort() # XXX - only for now
+        for key in keys:
+            value = data[key]
+            self.dump(key)
+            self.dump(value)
+        self.emitter.endMap()
+
+def mockEvents(data):
+    emitter = MockEmitter()
+    dumper = Dumper(emitter)
+    dumper.dump(data)
+    return emitter.events
+
+class Test(YamlTest.YamlTest):
+
+    def testScalar(self):
+        assertEquals(mockEvents('foobar'), self.scalar('foobar'))
+
+    def scalar(self, data):
+        return [ 
+            ('getType', 'scalar'),
+            ('getScalar', data)
+        ]
+
+    def list123(self):
+        (result) = (
+            [('getType', 'seq' )] +
+            self.scalar(1) +
+            self.scalar(2) +
+            self.scalar(3) +
+            [( 'getType', None )])
+        return result
+
+    def testList(self):
+        assertEquals(mockEvents([1,2,3]), self.list123())
+
+    def dictFoobar(self):
+        (result) = (
+            [('getType', 'map')] +
+            self.scalar('bar') +
+            self.scalar(2) + 
+            self.scalar('foo') +
+            self.scalar(1) +
+            [( 'getType', None)])
+        return result
+
+    def testDict(self):
+        events = mockEvents({'foo': 1, 'bar': 2})
+        assertEquals(events, self.dictFoobar())
+
+    def testListDict(self):
+        events = mockEvents([ [1,2,3], {'foo': 1, 'bar': 2} ])
+        self.assertEquals(
+            events,
+            [('getType', 'seq' )] +
+            self.list123() +
+            self.dictFoobar() + 
+            [('getType', None)])            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestValidatingParser.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestValidatingParser.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestValidatingParser.py	(revision 73)
@@ -0,0 +1,206 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals, assertError
+from TestPullParser import mockParser, Loader
+from yaml import load
+
+"""
+Part of the parse/pull experimental code.  This does a schema-driven
+validating parse of YAML documents, but it's built on top of a 
+crufty interim solution.
+
+The schema-driven parser requires a pull parser interface.  Ideally 
+a pull-parser would be pulling nodes from a YAML document on an
+as-needed basis, and this is the eventual goal.  But, I don't have
+a pull parser yet, so I simulate one by reading in the entire YAML
+document into a Python data structure, then I do a push-based dump 
+of the data structure to a mock emitter that stores up a list of
+parser events that a mock parser then serves up to the schema-driven
+parser on an as-needed basis.  Sounds complex, but there's really not
+much code involved.
+
+Nothing fancy is supported yet--just lists, dictionaries, and scalars; 
+no aliases, class transformations, multiple docs, etc.  Also, we lose
+the sort order on map keys, so you will notice that all the examples
+have alphabetically sorted keys.
+
+Also, once we go to a true pull parser, we could have more metadata,
+such as line numbers for nodes, attached comments, etc., that can 
+help with error reporting and round-tripping issues.
+"""
+
+testCases = """
+-
+    data: |
+        --- foo
+    schema:
+        type: scalar
+-
+    data: |
+        --- foo
+    schema:
+        type: seq
+    error: |
+        Wanted seq, got scalar
+ -
+    data: &list123 |
+        ---
+        - 1
+        - 2
+        - 3
+    schema:
+        type: seq
+        child:
+            type: scalar
+  -
+    data: *list123
+    schema:
+        type: seq
+        max: 2
+        child:
+            type: scalar
+    error: |
+        Seq has max 2 elements
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        street: Bourbon
+    schema: &StreetCityState
+        type: map
+        items:
+            - name: city
+              value:
+                  type: scalar
+            - name: state
+              value:
+                  type: scalar
+            - name: street
+              value:
+                  type: scalar
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        where ya got ya shoes: on ya feet, on Bourbon St.
+    schema: *StreetCityState
+    error: |
+        Expected key 'street', got 'where ya got ya shoes'
+-
+    data: |
+        ---
+        banana: yellow
+        carrot: orange
+        people:
+            - fname: al
+              salary: 44
+            - fname: bob
+              salary: 33
+    schema:
+        type: map
+        items:
+            - name: banana
+              value:
+                type: scalar
+            - name: carrot
+              value:
+                type: scalar
+            - name: people
+              value:
+                type: seq
+                child:
+                    type: map
+                    items:
+                        - name: fname
+                          value:
+                            type: scalar
+                        - name: salary
+                          value:
+                            type: scalar
+"""
+
+class ValidatingLoader:
+    def load(self, data, schema):
+        self.simulateParser(data)
+        return self.loadData(schema)
+
+    def loadData(self, schema):
+        typ = self.parser.getType()
+        return self._load(typ, schema)
+
+    def _load(self, typ, schema):
+        if typ != schema['type']:
+            raise Exception("Wanted %s, got %s\n" % (schema['type'], typ))
+        if typ == 'seq':
+            return self._loadSeq(schema)
+        if typ == 'map':
+            return self._loadMap(schema)
+        else:
+            return self.parser.getScalar()
+
+    def _loadSeq(self, schema):
+        results = []
+        cnt = 0
+        max = schema.get('max', None)
+        schema = schema['child']
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                cnt += 1
+                self.checkMax(cnt, max)
+                results.append(self._load(typ, schema))
+
+    def _loadMap(self, schema):
+        results = {}
+        for item in schema['items']:
+            self.parser.getType()
+            name = self.parser.getScalar()
+            self.checkName(name, item)
+            value = self.loadData(item['value'])
+            results[name] = value
+        self.parser.getType()
+        return results
+
+    def checkMax(self, cnt, max):
+            if max is not None and cnt > max:
+                raise Exception("Seq has max %d elements\n" % max)
+
+    def checkName(self, name, item):
+        if name != item['name']:
+            raise Exception("Expected key '%s', got '%s'\n" % \
+                (item['name'], name))
+
+    def simulateParser(self, data):
+        # This is the huge hack to work around
+        # not having a true pull parser
+        self.parser = mockParser(oldYamlLoad(data))
+
+def testRoundTrip(data, schema):
+    expected = oldYamlLoad(data)
+    obj = ValidatingLoader().load(data, schema)
+    assertEquals(expected, obj)
+
+def oldYamlLoad(data):
+    return load(data).next()
+
+def testOneCase(test):
+    data = test['data']
+    schema = test['schema']
+    if test.has_key('error'):
+        assertError(lambda: testRoundTrip(data, schema),
+            test['error'])
+    else:
+        testRoundTrip(data, schema)
+
+class Test(YamlTest.YamlTest):
+    def testFromYaml(self):
+        for test in load(testCases).next():
+            testOneCase(test)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/spec.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/spec.yml	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/spec.yml	(revision 73)
@@ -0,0 +1,2 @@
+# OBSOLETE!
+# see TestingSuite/spec.yml or TESTING for details
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/inline.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/inline.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/inline.py	(revision 71)
@@ -0,0 +1,38 @@
+import re
+import string
+
+class InlineTokenizer:
+    def __init__(self, data):
+        self.data = data
+
+    def punctuation(self):
+        puncts = [ '[', ']', '{', '}' ]
+        for punct in puncts:
+            if self.data[0] == punct:
+                self.data = self.data[1:]
+                return punct
+
+    def up_to_comma(self):
+        match = re.match('(.*?)\s*, (.*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def up_to_end_brace(self):
+        match = re.match('(.*?)(\s*[\]}].*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def next(self):
+        self.data = string.strip(self.data)
+        productions = [
+            self.punctuation,
+            self.up_to_comma,
+            self.up_to_end_brace
+        ]
+        for production in productions:
+            token = production()
+            if token:
+                return token
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/__init__.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/__init__.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/__init__.py	(revision 71)
@@ -0,0 +1,20 @@
+__version__ = "0.25"
+from load import loadFile
+from load import load
+from load import Parser
+from dump import dump
+from dump import dumpToFile
+from dump import Dumper
+from stream import YamlLoaderException, StringStream, FileStream
+from timestamp import timestamp
+
+try:
+    from ypath import ypath
+except NameError:
+    def ypath(expr,target='',cntx=''):
+        raise NotImplementedError("ypath requires Python 2.2")
+
+
+import sys
+if sys.hexversion < 0x02010300:
+    raise 'YAML is not tested for pre-2.1.3 versions of Python'
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/load.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/load.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/load.py	(revision 71)
@@ -0,0 +1,328 @@
+import re, string
+from implicit import convertImplicit
+from inline import InlineTokenizer
+from yaml.klass import DefaultResolver
+from yaml.stream import FileStream, StringStream, NestedDocs
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+try:
+    iter(list()) # is iter supported by this version of Python?
+except:
+    # XXX - Python 2.1 does not support iterators   
+    class StopIteration: pass
+    class iter:
+        def __init__(self,parser):
+            self._docs = []
+            try:
+                while 1:
+                   self._docs.append(parser.next())
+            except StopIteration: pass
+            self._idx = 0
+        def __len__(self): return len(self._docs)
+        def __getitem__(self,idx): return self._docs[idx]
+        def next(self):
+            if self._idx < len(self._docs):
+                ret = self._docs[self._idx] 
+                self._idx = self._idx + 1
+                return ret
+            raise StopIteration
+
+def loadFile(filename, typeResolver=None):
+    return loadStream(FileStream(filename),typeResolver)
+   
+def load(str, typeResolver=None):
+    return loadStream(StringStream(str), typeResolver)
+
+def loadStream(stream, typeResolver):
+    return iter(Parser(stream, typeResolver))
+
+def tryProductions(productions, value):
+    for production in productions:
+        results = production(value)
+        if results:
+            (ok, result) = results
+            if ok:
+                return (1, result)
+
+def dumpDictionary(): return {}
+
+class Parser:
+    def __init__(self, stream, typeResolver=None):
+        try:
+            self.dictionary = dict
+        except:
+            self.dictionary = dumpDictionary
+        self.nestedDocs = NestedDocs(stream)
+        self.aliases = {}
+        if typeResolver:
+            self.typeResolver = typeResolver
+        else:
+            self.typeResolver = DefaultResolver()
+
+    def error(self, msg):
+        self.nestedDocs.error(msg, self.line)
+
+    def nestPop(self):
+        line = self.nestedDocs.pop()
+        if line is not None:
+            self.line = line
+            return 1
+
+    def value(self, indicator):
+        return getToken(indicator+"\s*(.*)", self.line)
+
+    def getNextDocument(self): raise "getNextDocument() deprecated--use next()"
+
+    def next(self):
+        line = self.nestedDocs.popDocSep()
+        indicator = getIndicator(line)
+        if indicator:
+            return self.parse_value(indicator)
+        if line:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+        raise StopIteration
+
+    def __iter__(self): return self
+
+    def parseLines(self):
+        peekLine = self.nestedDocs.peek()
+        if peekLine:
+            if re.match("\s*-", peekLine):
+                return self.parse_collection([], self.parse_seq_line)
+            else:
+                return self.parse_collection(self.dictionary(), self.parse_map_line)
+        raise StopIteration
+
+    def parse_collection(self, items, lineParser):
+        while self.nestPop():
+            if self.line:
+                lineParser(items)
+        return items    
+
+    def parse_seq_line(self, items):
+        value = self.value("-")
+        if value is not None:
+            items.append(self.parse_seq_value(value))
+        else:
+            self.error("missing '-' for seq")
+
+    def parse_map_line(self, items):
+        if (self.line == '?'):
+            self.parse_map_line_nested(items)
+        else:
+            self.parse_map_line_simple(items, self.line)
+
+    def parse_map_line_nested(self, items):
+        self.nestedDocs.nestToNextLine()
+        key = self.parseLines()
+        if self.nestPop():
+            value = self.value(':')
+            if value is not None:
+                items[tuple(key)] = self.parse_value(value)
+                return
+        self.error("key has no value for nested map")
+
+    def parse_map_line_simple(self, items, line):
+        map_item = key_value(line)
+        if map_item:
+            (key, value) = map_item
+            key = convertImplicit(key)
+            items[key] = self.parse_value(value)
+        else:
+            self.error("bad key for map")
+
+    def is_map(self, value):
+        # XXX - need real tokenizer
+        if len(value) == 0:
+            return 0
+        if value[0] == "'":
+            return 0
+        if re.search(':(\s|$)', value):       
+            return 1
+
+    def parse_seq_value(self, value):
+        if self.is_map(value):
+            return self.parse_compressed_map(value)
+        else:
+            return self.parse_value(value)
+
+    def parse_compressed_map(self, value):
+        items = self.dictionary()
+        line = self.line
+        token = getToken("(\s*-\s*)", line)
+        self.nestedDocs.nestBySpecificAmount(len(token))
+        self.parse_map_line_simple(items, value)
+        return self.parse_collection(items, self.parse_map_line)
+
+    def parse_value(self, value):
+        (alias, value) = self.testForRepeatOfAlias(value)
+        if alias:
+            return value
+        (alias, value) = self.testForAlias(value)            
+        value = self.parse_unaliased_value(value)
+        if alias:
+            self.aliases[alias] = value
+        return value          
+
+    def parse_unaliased_value(self, value):
+        match = re.match(r"(!\S*)(.*)", value)
+        if match:
+            (url, value) = match.groups()
+            value = self.parse_untyped_value(value)
+            if url[:2] == '!!':
+                return self.typeResolver.resolveType(value, url)
+            else:
+                # XXX - allows syntax, but ignores it
+                return value
+        return self.parse_untyped_value(value)
+
+    def parseInlineArray(self, value):        
+        if re.match("\s*\[", value):
+            return self.parseInline([], value, ']', 
+                self.parseInlineArrayItem)
+
+    def parseInlineHash(self, value):        
+        if re.match("\s*{", value):
+            return self.parseInline(self.dictionary(), value, '}', 
+                self.parseInlineHashItem)
+
+    def parseInlineArrayItem(self, result, token):
+        return result.append(convertImplicit(token))
+
+    def parseInlineHashItem(self, result, token):
+        (key, value) = key_value(token)
+        result[key] = value
+
+    def parseInline(self, result, value, end_marker, itemMethod):
+        tokenizer = InlineTokenizer(value)
+        tokenizer.next()
+        while 1:
+            token = tokenizer.next()
+            if token == end_marker:
+                break
+            itemMethod(result, token)
+        return (1, result)
+
+    def parseSpecial(self, value):
+        productions = [
+            self.parseMultiLineScalar,
+            self.parseInlineHash,
+            self.parseInlineArray,
+        ]
+        return tryProductions(productions, value)
+
+    def parse_untyped_value(self, value):
+        parse = self.parseSpecial(value)
+        if parse:
+            (ok, data) = parse
+            return data
+        token = getToken("(\S.*)", value)
+        if token:
+            lines = [token] + \
+                pruneTrailingEmpties(self.nestedDocs.popNestedLines())
+            return convertImplicit(joinLines(lines))
+        else:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+
+    def parseNative(self, value):
+        return (1, convertImplicit(value))
+
+    def parseMultiLineScalar(self, value):
+        if value == '>':
+            return (1, self.parseFolded())
+        elif value == '|':
+            return (1, joinLiteral(self.parseBlock()))
+        elif value == '|+':
+            return (1, joinLiteral(self.unprunedBlock()))
+
+    def parseFolded(self):
+        data = self.parseBlock()
+        i = 0
+        resultString = ''
+        while i < len(data)-1:
+            resultString = resultString + data[i]
+            resultString = resultString + foldChar(data[i], data[i+1])
+            i = i + 1
+        return resultString + data[-1] + "\n"        
+
+    def unprunedBlock(self):
+        self.nestedDocs.nestToNextLine()
+        data = []
+        while self.nestPop():
+            data.append(self.line)
+        return data
+
+    def parseBlock(self):
+        return pruneTrailingEmpties(self.unprunedBlock())
+
+    def testForAlias(self, value):
+        match = re.match("&(\S*)\s*(.*)", value)
+        if match:
+            return match.groups()
+        return (None, value)
+
+    def testForRepeatOfAlias(self, value):
+        match = re.match("\*(\S*)", value)
+        if match:
+            alias = match.groups()[0]
+            if self.aliases.has_key(alias):
+                return (alias, self.aliases[alias])
+            else:
+                self.error("Unknown alias")
+        return (None, value)
+
+def getToken(regex, value):
+    match = re.search(regex, value)
+    if match:
+        return match.groups()[0]
+
+def key_value(str):
+    # XXX This allows mis-balanced " vs. ' stuff
+    match = re.match("[\"'](.+)[\"']\s*:\s*(.*)", str)
+    if match:
+        (key, value) = match.groups()
+        return (key, value)
+
+    match = re.match("(.+?)\s*:\s*(.*)", str)
+    if match:
+        (key, value) = match.groups()
+        if len(value) and value[0] == '#':
+            value = ''
+        return (key, value)
+
+def pruneTrailingEmpties(data):
+    while len(data) > 0 and data[-1] == '':
+        data = data[:-1]
+    return data
+
+def foldChar(line1, line2):
+    if re.match("^\S", line1) and re.match("^\S", line2):
+        return " "
+    return "\n"
+
+def getIndicator(line):
+    if line:
+        header = r"(#YAML:\d+\.\d+\s*){0,1}"
+        match = re.match("--- "+header+"(\S*.*)", line)
+        if match:
+            return match.groups()[-1]
+
+def joinLines(lines):
+    result = ''
+    for line in lines[:-1]:
+        if line[-1] == '\\':
+            result = result + line[:-1]
+        else:
+            result = result + line + " "
+    return result + lines[-1]
+
+def joinLiteral(data):
+    return string.join(data,"\n") + "\n"
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/timestamp.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/timestamp.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/timestamp.py	(revision 71)
@@ -0,0 +1,145 @@
+import time, re, string
+from types import ListType, TupleType
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+# 
+# Time specific operations
+#
+
+_splitTime = re.compile('\-|\s|T|t|:|\.|Z')
+matchTime = re.compile(\
+          '\d+-\d+-\d+([\s|T|t]\d+:\d+:\d+.\d+(Z|(\s?[\-|\+]\d+:\d+)))?')
+
+def _parseTime(val):
+    if not matchTime.match(val): raise ValueError(val)
+    tpl = _splitTime.split(val)
+    if not(tpl): raise ValueError(val)
+    siz = len(tpl)
+    sec = 0
+    if 3 == siz:
+       tpl += [0,0,0,0,0,-1]
+    elif 7 == siz:
+       tpl.append(0)
+       tpl.append(-1)
+    elif 8 == siz:
+       if len(tpl.pop()) > 0: raise ValueError(val)
+       tpl.append(0)
+       tpl.append(-1)
+    elif 9 == siz or 10 == siz:
+       mn = int(tpl.pop())
+       hr = int(tpl.pop())
+       sec = (hr*60+mn)*60
+       if val.find("+") > -1: sec = -sec
+       if 10 == siz: tpl.pop()
+       tpl.append(0)
+       tpl.append(-1)
+    else:
+       raise ValueError(val)
+    idx = 0
+    while idx < 9:
+       tpl[idx] = int(tpl[idx])
+       idx += 1
+    if tpl[1] < 1 or tpl[1] > 12: raise ValueError(val)
+    if tpl[2] < 1 or tpl[2] > 31: raise ValueError(val)
+    if tpl[3] > 24: raise ValueError(val)
+    if tpl[4] > 61: raise ValueError(val)
+    if tpl[5] > 61: raise ValueError(val)
+    if tpl[0] > 2038:
+        #TODO: Truncation warning
+        tpl = (2038,1,18,0,0,0,0,0,-1)
+    tpl = tuple(tpl)
+    ret = time.mktime(tpl)
+    ret = time.localtime(ret+sec)
+    ret = ret[:8] + (0,)
+    return ret
+
+
+class _timestamp:
+    def __init__(self,val=None):
+        if not val:
+           self.__tval = time.gmtime()
+        else:
+           typ = type(val)
+           if ListType == typ:
+               self.__tval = tuple(val)
+           elif TupleType == typ:
+               self.__tval = val
+           else:
+               self.__tval = _parseTime(val)
+           if 9 != len(self.__tval): raise ValueError
+    def __getitem__(self,idx): return self.__tval[idx]
+    def __len__(self): return 9
+    def strftime(self,format): return time.strftime(format,self.__tval)
+    def mktime(self):          return time.mktime(self.__tval)
+    def asctime(self):  return time.asctime(self.__tval)
+    def isotime(self):  
+        return "%04d-%02d-%02dT%02d:%02d:%02d.00Z" % self.__tval[:6]
+    def __repr__(self): return "yaml.timestamp('%s')" % self.isotime()    
+    def __str__(self):  return self.isotime()
+    def to_yaml_implicit(self): return self.isotime()
+    def __hash__(self): return hash(self.__tval[:6]) 
+    def __cmp__(self,other): 
+        try:
+            return cmp(self.__tval[:6],other.__tval[:6])
+        except AttributeError:
+            return -1
+
+try: # inherit from mx.DateTime functionality if available
+    from mx import DateTime
+    class timestamp(_timestamp):
+        def __init__(self,val=None):
+            _timestamp.__init__(self,val)
+            self.__mxdt = DateTime.mktime(self.__tval)
+        def __getattr__(self, name):
+              return getattr(self.__mxdt, name)
+except:
+    class timestamp(_timestamp): pass
+        
+
+
+def unquote(expr):
+    """
+        summary: >
+           Simply returns the unquoted string, and the
+           length of the quoted string token at the 
+           beginning of the expression.
+    """
+    tok = expr[0]
+    if "'" == tok: 
+        idx = 1
+        odd = 0
+        ret = ""
+        while idx < len(expr):
+            chr = expr[idx]
+            if "'" == chr:
+                if odd: ret += chr
+                odd = not odd
+            else:
+                if odd:
+                    tok = expr[:idx]
+                    break
+                ret += chr
+            idx += 1
+        if "'" == tok: tok = expr
+        return (ret,len(tok))
+    if '"' == tok:
+        idx = 1
+        esc = 0
+        while idx < len(expr):
+            chr = expr[idx]
+            if '"' == chr and not esc:
+                tok = expr[:idx] + '"'
+                break
+            if '\\' == chr and not esc: esc = 1
+            else: esc = 0
+            idx += 1
+        if '"' == tok:
+            raise SyntaxError("unmatched quote: " + expr)
+        ret = eval(tok)  #TODO: find better way to unquote
+        return (ret,len(tok))
+    return (expr,len(expr))
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/dump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/dump.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/dump.py	(revision 71)
@@ -0,0 +1,290 @@
+import types
+import string
+from types import StringType, UnicodeType, IntType, FloatType
+from types import DictType, ListType, TupleType, InstanceType
+from yaml.klass import hasMethod, isDictionary
+import re
+
+"""
+  The methods from this module that are exported to the top 
+  level yaml package should remain stable.  If you call
+  directly into other methods of this module, be aware that 
+  they may change or go away in future implementations.
+  Contact the authors if there are methods in this file 
+  that you wish to remain stable.
+"""
+
+def dump(*data):
+    return Dumper().dump(*data)
+
+def dumpToFile(file, *data):
+    return Dumper().dumpToFile(file, *data)
+
+class Dumper:
+    def __init__(self):
+        self.currIndent   = "\n"
+        self.indent = "    "
+        self.keysrt   = None
+        self.alphaSort = 1 # legacy -- on by default
+
+    def setIndent(self, indent):
+        self.indent = indent
+        return self
+
+    def setSort(self, sort_hint):
+        self.keysrt = sortMethod(sort_hint)
+        return self
+
+    def dump(self, *data):
+        self.result = []  
+        self.output = self.outputToString
+        self.dumpDocuments(data)
+        return string.join(self.result,"")
+
+    def outputToString(self, data):
+        self.result.append(data)
+
+    def dumpToFile(self, file, *data):
+        self.file = file
+        self.output = self.outputToFile
+        self.dumpDocuments(data)
+
+    def outputToFile(self, data):
+        self.file.write(data)
+
+    def dumpDocuments(self, data):
+        for obj in data:
+            self.anchors  = YamlAnchors(obj)
+            self.output("---")
+            self.dumpData(obj)
+            self.output("\n")       
+
+    def indentDump(self, data):
+        oldIndent = self.currIndent
+        self.currIndent += self.indent
+        self.dumpData(data)
+        self.currIndent = oldIndent
+
+    def dumpData(self, data):
+        anchor = self.anchors.shouldAnchor(data)
+        if anchor: 
+            self.output(" &%d" % anchor )
+        else:
+            anchor = self.anchors.isAlias(data)
+            if anchor:
+                self.output(" *%d" % anchor )
+                return
+        if (data is None):
+            self.output(' ~')
+        elif hasMethod(data, 'to_yaml'):
+            self.dumpTransformedObject(data)            
+        elif hasMethod(data, 'to_yaml_implicit'):
+            self.output(" " + data.to_yaml_implicit())
+        elif type(data) is InstanceType:
+            self.dumpRawObject(data)
+        elif isDictionary(data):
+            self.dumpDict(data)
+        elif type(data) in [ListType, TupleType]:
+            self.dumpList(data)
+        else:
+            self.dumpScalar(data)
+
+    def dumpTransformedObject(self, data):
+        obj_yaml = data.to_yaml()
+        if type(obj_yaml) is not TupleType:
+            self.raiseToYamlSyntaxError()
+        (data, typestring) = obj_yaml
+        if typestring:
+            self.output(" " + typestring)
+        self.dumpData(data)
+
+    def dumpRawObject(self, data):
+        self.output(' !!%s.%s' % (data.__module__, data.__class__.__name__))
+        self.dumpData(data.__dict__)
+
+    def dumpDict(self, data):
+        keys = data.keys()
+        if len(keys) == 0:
+            self.output(" {}")
+            return
+        if self.keysrt:
+            keys = sort_keys(keys,self.keysrt)
+        else:
+            if self.alphaSort:
+                keys.sort()
+        for key in keys:
+            self.output(self.currIndent)
+            self.dumpKey(key)
+            self.output(":")
+            self.indentDump(data[key])
+
+    def dumpKey(self, key):
+        if type(key) is TupleType:
+            self.output("?")
+            self.indentDump(key) 
+            self.output("\n")
+        else:
+            self.output(quote(key))
+
+    def dumpList(self, data):
+        if len(data) == 0:
+            self.output(" []")
+            return
+        for item in data:
+            self.output(self.currIndent)
+            self.output("-")
+            self.indentDump(item)
+
+    def dumpScalar(self, data):
+        if isUnicode(data):
+            self.output(' "%s"' % repr(data)[2:-1])
+        elif isMulti(data):
+            self.dumpMultiLineScalar(data.splitlines())
+        else:
+            self.output(" ")
+            self.output(quote(data))
+    
+    def dumpMultiLineScalar(self, lines):
+        self.output(" |")
+        if lines[-1] == "":
+            self.output("+")
+        for line in lines:
+            self.output(self.currIndent)
+            self.output(line)
+
+    def raiseToYamlSyntaxError(self):
+            raise """
+to_yaml should return tuple w/object to dump 
+and optional YAML type.  Example:
+({'foo': 'bar'}, '!!foobar')
+"""
+
+#### ANCHOR-RELATED METHODS
+
+def accumulate(obj,occur):
+    typ = type(obj)
+    if obj is None or \
+       typ is IntType or \
+       typ is FloatType or \
+       ((typ is StringType or typ is UnicodeType) \
+       and len(obj) < 32): return
+    obid = id(obj)
+    if 0 == occur.get(obid,0):
+        occur[obid] = 1
+        if typ is ListType:
+            for x in obj: 
+                accumulate(x,occur)
+        if typ is DictType:
+            for (x,y) in obj.items():
+                accumulate(x,occur)
+                accumulate(y,occur)
+    else:
+        occur[obid] = occur[obid] + 1
+
+class YamlAnchors:
+     def __init__(self,data):
+         occur = {}
+         accumulate(data,occur)
+         anchorVisits = {}
+         for (obid, occur) in occur.items():
+             if occur > 1:
+                 anchorVisits[obid] = 0 
+         self._anchorVisits = anchorVisits
+         self._currentAliasIndex     = 0
+     def shouldAnchor(self,obj):
+         ret = self._anchorVisits.get(id(obj),None)
+         if 0 == ret:
+             self._currentAliasIndex = self._currentAliasIndex + 1
+             ret = self._currentAliasIndex
+             self._anchorVisits[id(obj)] = ret
+             return ret
+         return 0
+     def isAlias(self,obj):
+         return self._anchorVisits.get(id(obj),0)
+
+### SORTING METHODS
+
+def sort_keys(keys,fn):
+    tmp = []
+    for key in keys:
+        val = fn(key)
+        if val is None: val = '~'
+        tmp.append((val,key))
+    tmp.sort()
+    return [ y for (x,y) in tmp ]
+
+def sortMethod(sort_hint):
+    typ = type(sort_hint)
+    if DictType == typ:
+        return sort_hint.get
+    elif ListType == typ or TupleType == typ:
+        indexes = {}; idx = 0
+        for item in sort_hint:
+            indexes[item] = idx
+            idx += 1
+        return indexes.get
+    else:
+        return sort_hint
+
+### STRING QUOTING AND SCALAR HANDLING
+def isStr(data):
+    # XXX 2.1 madness
+    if type(data) == type(''):
+        return 1
+    if type(data) == type(u''):
+        return 1
+    return 0
+    
+def doubleUpQuotes(data):
+    return data.replace("'", "''")
+
+def quote(data):
+    if not isStr(data):
+        return str(data)
+    single = "'"
+    double = '"'
+    quote = ''
+    if len(data) == 0:
+        return "''"
+    if hasSpecialChar(data) or data[0] == single:
+        data = `data`[1:-1]
+        data = string.replace(data, r"\x08", r"\b")
+        quote = double 
+    elif needsSingleQuote(data):
+        quote = single
+        data = doubleUpQuotes(data)
+    return "%s%s%s" % (quote, data, quote)
+
+def needsSingleQuote(data):
+    if re.match(r"^\d", data):
+        return 1
+    if data[0] == '&':
+        return 1
+    if data[0] == '"':
+        return 1
+    return (re.search(r'[-:]', data) or re.search(r'(\d\.){2}', data))
+
+def hasSpecialChar(data):
+    # need test to drive out '#' from this
+    return re.search(r'[\t\b\r\f#]', data)
+
+def isMulti(data):
+    if not isStr(data):
+        return 0
+    if hasSpecialChar(data):
+        return 0
+    return re.search("\n", data)
+
+def isUnicode(data):
+    return type(data) == unicode
+    
+def sloppyIsUnicode(data):
+        # XXX - hack to make tests pass for 2.1
+        return repr(data)[:2] == "u'" and repr(data) != data
+
+import sys
+if sys.hexversion < 0x20200000:
+    isUnicode = sloppyIsUnicode
+    
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ypath.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ypath.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ypath.py	(revision 71)
@@ -0,0 +1,462 @@
+from types import ListType, StringType, IntType, DictType, InstanceType
+import re
+from urllib import quote
+from timestamp import unquote
+
+noTarget = object()
+
+def escape(node):
+    """
+        summary: >
+            This function escapes a given key so that it
+            may appear within a ypath.  URI style escaping
+            is used so that ypath expressions can be a 
+            valid URI expression.
+    """
+    typ = type(node)
+    if typ is IntType: return str(node)
+    if typ is StringType: 
+        return quote(node,'')
+    raise ValueError("TODO: Support more than just string and integer keys.")
+
+class context:
+    """
+        summary: >
+            A ypath visit context through a YAML rooted graph.
+            This is implemented as a 3-tuple including the parent
+            node, the current key/index and the value.  This is
+            an immutable object so it can be cached.
+        properties: 
+            key:    mapping key or index within the parent collection
+            value:  current value within the parent's range
+            parent: the parent context
+            root:   the very top of the yaml graph
+            path:   a tuple of the domain keys
+        notes: >
+            The context class doesn't yet handle going down the
+            domain side of the tree... 
+    """         
+    def __init__(self,parent,key,value):
+        """
+            args:
+                parent: parent context (or None if this is the root)
+                key:    mapping key or index for this context
+                value:  value of current location...
+        """
+        self.parent = parent
+        self.key    = key
+        self.value  = value
+        if parent: 
+            assert parent.__class__ is self.__class__
+            self.path = parent.path + (escape(key),)
+            self.root = parent.root
+        else:      
+            assert not key
+            self.path = tuple()
+            self.root = self
+    def __setattr__(self,attname,attval):
+        if attname in ('parent','key','value'):
+            if self.__dict__.get(attname):
+                 raise ValueError("context is read-only")
+        self.__dict__[attname] = attval
+    def __hash__(self): return hash(self.path)
+    def __cmp__(self,other):   
+        try:
+            return cmp(self.path,other.path)
+        except AttributeError:
+            return -1
+    def __str__(self):
+        if self.path:
+            return "/".join(('',)+self.path)
+        else:
+            return '/'
+
+def to_context(target):
+    if type(target) is InstanceType:
+        if target.__class__ is context:
+            return target
+    return context(None,None,target)
+
+def context_test():
+    lst = ['value']
+    map = {'key':lst}
+    x = context(None,None,map)
+    y = context(x,'key',lst)
+    z = context(y,0,'value')
+    assert ('key',) == y.path
+    assert 'key'    == y.key
+    assert lst      == y.value
+    assert x        == y.parent
+    assert x        == y.root
+    assert 0        == z.key
+    assert 'value'  == z.value
+    assert y        == z.parent
+    assert x        == z.root 
+    assert hash(x)  
+    assert hash(y)
+    assert hash(z)
+    assert '/' == str(x)
+    assert '/key' == str(y)
+    assert '/key/0' == str(z)
+
+class null_seg:
+    """
+        summary: >
+            This is the simplest path segment, it
+            doesn't return any results and doesn't
+            depend upon its context.  It also happens to 
+            be the base class which all segments derive.
+    """
+    def __iter__(self): 
+        return self
+    def next_null(self):
+        raise StopIteration
+    def bind(self,cntx):  
+        """
+            summary: >
+                The bind function is called whenever
+                the parent context has changed.
+        """
+        assert(cntx.__class__ is context)
+        self.cntx = cntx
+    def apply(self,target):
+        self.bind(to_context(target))
+        return iter(self)
+    def exists(self,cntx):
+        try:
+            self.bind(cntx)
+            self.next()
+            return 1
+        except StopIteration:
+            return 0
+    next = next_null
+ 
+class self_seg(null_seg):
+    """
+        summary: >
+            This path segment returns the context
+            node exactly once.
+    """
+    def __str__(self): return '.'
+    def next_self(self):
+        self.next = self.next_null
+        return self.cntx
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.next = self.next_self
+
+class root_seg(self_seg):
+    def __str__(self): return '/'
+    def bind(self,cntx):  
+        self_seg.bind(self,cntx.root)
+
+class parent_seg(self_seg):
+    def __str__(self): return '..'
+    def bind(self,cntx):
+        if cntx.parent: cntx = cntx.parent
+        self_seg.bind(self,cntx)
+
+class wild_seg(null_seg):
+    """
+        summary: >
+            The wild segment simply loops through
+            all of the sub-contexts for a given object.
+            If there aren't any children, this isn't an
+            error it just doesn't return anything.
+    """
+    def __str__(self): return '*'
+    def next_wild(self):
+        key = self.keys.next()
+        return context(self.cntx,key,self.values[key])
+    def bind(self,cntx):  
+        null_seg.bind(self,cntx)
+        typ = type(cntx.value)
+        if typ is ListType:
+            self.keys   = iter(xrange(0,len(cntx.value)))
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return
+        if typ is DictType:
+            self.keys   = iter(cntx.value)
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return 
+        self.next = self.next_null
+
+class trav_seg(null_seg):
+    """
+        summary: >
+            This is a recursive traversal of the range, preorder.
+            It is a recursive combination of self and wild.
+    """
+    def __str__(self): return '/'
+    def next(self): 
+        while 1:
+            (cntx,seg) = self.stk[-1]
+            if not seg:
+                seg = wild_seg()
+                seg.bind(cntx)
+                self.stk[-1] = (cntx,seg)
+                return cntx
+            try:
+                cntx = seg.next()
+                self.stk.append((cntx,None))
+            except StopIteration:
+                self.stk.pop()
+                if not(self.stk):
+                    self.next = self.next_null
+                    raise StopIteration
+
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.stk = [(cntx,None)]
+
+class match_seg(self_seg):
+    """
+        summary: >
+            Matches a particular key within the
+            current context.  Kinda boring.
+    """
+    def __str__(self): return str(self.key)
+    def __init__(self,key):
+        #TODO: Do better implicit typing
+        try:
+           key = int(key)
+        except: pass
+        self.key = key
+    def bind(self,cntx):
+        try: 
+            mtch = cntx.value[self.key]
+            cntx = context(cntx,self.key,mtch)
+            self_seg.bind(self,cntx)
+        except:
+            null_seg.bind(self,cntx)
+        
+class conn_seg(null_seg):
+    """
+        summary: >
+            When two segments are connected via a slash,
+            this is a composite.  For each context of the
+            parent, it binds the child, and returns each
+            context of the child.
+    """
+    def __str__(self): 
+        if self.parent.__class__ == root_seg:  
+            return "/%s" % self.child
+        return "%s/%s" % (self.parent, self.child)
+    def __init__(self,parent,child):
+        self.parent = parent
+        self.child  = child
+    def next(self):
+        while 1:
+            try:
+                return self.child.next()
+            except StopIteration:
+                cntx = self.parent.next()
+                self.child.bind(cntx)
+ 
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+        try:
+            cntx = self.parent.next()
+        except StopIteration: 
+            return
+        self.child.bind(cntx)
+
+
+class pred_seg(null_seg):
+    def __str__(self): return "%s[%s]" % (self.parent, self.filter)
+    def __init__(self,parent,filter):
+        self.parent = parent
+        self.filter = filter
+    def next(self):
+        while 1:
+            ret = self.parent.next()
+            if self.filter.exists(ret):
+                return ret
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+
+class or_seg(null_seg):
+    def __str__(self): return "%s|%s" % (self.lhs,self.rhs)
+    def __init__(self,lhs,rhs):
+        self.rhs = rhs
+        self.lhs = lhs
+        self.unq = {}
+    def next(self):
+        seg = self.lhs
+        try:
+            nxt = seg.next()
+            self.unq[nxt] = nxt
+            return nxt
+        except StopIteration: pass
+        seg = self.rhs
+        while 1:
+            nxt = seg.next()
+            if self.unq.get(nxt,None): 
+                continue  
+            return nxt
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.lhs.bind(cntx)
+        self.rhs.bind(cntx)
+
+class scalar:
+    def __init__(self,val):  
+        self.val = val
+    def __str__(self): 
+        return str(self.val)
+    def value(self): 
+        return self.val
+
+class equal_pred: 
+    def exists_true(self,cntx): return 1
+    def exists_false(self,cntx): return 0
+    def exists_scalar(self,cntx):
+        self.rhs.bind(cntx)
+        try:
+            while 1:
+                cntx = self.rhs.next()
+                if str(cntx.value) == self.lhs:  #TODO: Remove type hack
+                     return 1
+        except StopIteration: pass
+        return 0
+    def exists_segment(self,cntx):
+        raise NotImplementedError()
+    def __init__(self,lhs,rhs):
+        if lhs.__class__ == scalar:
+            if rhs.__class__ == scalar:
+                if rhs.value() == lhs.value():
+                    self.exists = self.exists_true
+                else:
+                    self.exists = self.exists_false
+            else:
+                self.exists = self.exists_scalar
+        else:
+            if rhs.__class__ == scalar:
+                (lhs,rhs) = (rhs,lhs)
+                self.exists = self.exists_scalar
+            else:
+                self.exists = self.exists_segment
+        self.lhs = str(lhs.value())  #TODO: Remove type hack
+        self.rhs = rhs
+ 
+matchSegment = re.compile(r"""^(\w+|/|\.|\*|\"|\')""")
+
+def parse_segment(expr):
+    """
+        Segments occur between the slashes...
+    """
+    mtch = matchSegment.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if   '/' == tok: return (trav_seg(),expr)
+    elif '.' == tok: 
+        if len(expr) > 1 and '.' == expr[1]:
+            seg = parent_seg()
+            siz = 2
+        else: 
+            seg = self_seg()
+    elif '*' == tok: seg = wild_seg()
+    elif '"' == tok or "'" == tok:
+        (cur,siz) = unquote(expr)
+        seg = match_seg(cur)
+    else:
+        seg = match_seg(tok)
+    return (seg,expr[siz:])
+
+matchTerm = re.compile(r"""^(\w+|/|\.|\(|\"|\')""")
+
+def parse_term(expr):
+    mtch = matchTerm.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if '/' == tok or '.' == tok:
+        return parse(expr)
+    if '(' == tok:
+        (term,expr) = parse_predicate(expr)
+        assert ')' == expr[0]
+        return (term,expr[1:])
+    elif '"' == tok or "'" == tok:
+        (val,siz) = unquote(expr)
+    else:
+        val = tok; siz = len(tok)
+    return (scalar(val),expr[siz:])
+
+def parse_predicate(expr):
+    (term,expr) = parse_term(expr)
+    if not term: raise SyntaxError("term expected: '%s'" % expr)
+    tok = expr[0]
+    if '=' == tok:
+        (rhs,expr) = parse_term(expr[1:])
+        return (equal_pred(term,rhs),expr)
+    if '(' == tok:
+        raise "No functions allowed... yet!"
+    if ']' == tok or ')' == tok:
+        if term.__class__ is scalar:
+            term = match_seg(str(term))
+        return (term,expr)
+    raise SyntaxError("ypath: expecting operator '%s'" % expr)
+
+def parse_start(expr):
+    """
+        Initial checking on the expression, and 
+        determine if it is relative or absolute.
+    """
+    if type(expr) != StringType or len(expr) < 1: 
+        raise TypeError("string required: " + repr(expr))
+    if '/' == expr[0]:
+        ypth = root_seg()
+    else:
+        ypth = self_seg()
+        expr = '/' + expr
+    return (ypth,expr)
+
+def parse(expr):
+    """
+        This the parser entry point, the top level node
+        is always a root or self segment.  The self isn't
+        strictly necessary, but it keeps things simple.
+    """
+    (ypth,expr) = parse_start(expr)
+    while expr:
+        tok = expr[0]
+        if '/' == tok:
+            (child, expr) = parse_segment(expr[1:])    
+            if child: ypth = conn_seg(ypth,child)
+            continue
+        if '[' == tok:
+            (filter, expr) = parse_predicate(expr[1:])
+            assert ']' == expr[0]
+            expr = expr[1:]
+            ypth = pred_seg(ypth,filter)
+            continue
+        if '|' == tok:
+            (rhs, expr) = parse(expr[1:])
+            ypth = or_seg(ypth,rhs)
+            continue
+        if '(' == tok:
+            (child,expr) = parse(expr[1:])
+            assert ')' == expr[0]
+            expr = expr[1:]
+            ypth = conn_seg(ypth,child)
+            continue
+        break
+    return (ypth,expr)
+
+class convert_to_value(null_seg):
+    def __init__(self,itr):
+        self.itr = itr
+    def next(self):
+        return self.itr.next().value
+    def bind(self,cntx):
+        self.itr.bind(cntx)
+
+def ypath(expr,target=noTarget,cntx=0):
+    (ret,expr) = parse(expr)
+    if expr: raise SyntaxError("ypath parse error `%s`" % expr)
+    if not cntx: ret = convert_to_value(ret)
+    if target is noTarget: return ret
+    return ret.apply(target)
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ordered_dict.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ordered_dict.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/ordered_dict.py	(revision 71)
@@ -0,0 +1,31 @@
+# This is extremely crude implementation of an OrderedDict.
+# If you know of a better implementation, please send it to
+# the author Steve Howell.  You can find my email via 
+# the YAML mailing list or wiki.
+
+class OrderedDict(dict): 
+    def __init__(self): 
+        self._keys = [] 
+ 
+    def __setitem__(self, key, val): 
+        self._keys.append(key) 
+        dict.__setitem__(self, key, val) 
+ 
+    def keys(self): 
+        return self._keys 
+ 
+    def items(self):
+        return [(key, self[key]) for key in self._keys]
+ 
+if __name__ == '__main__': 
+    data = OrderedDict()
+    data['z'] = 26
+    data['m'] = 13
+    data['a'] = 1
+    for key in data.keys(): 
+        print "The value for %s is %s" % (key, data[key]) 
+    print data
+
+
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/implicit.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/implicit.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/implicit.py	(revision 71)
@@ -0,0 +1,46 @@
+import re
+import string
+from timestamp import timestamp, matchTime
+
+DATETIME_REGEX   = re.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")
+FLOAT_REGEX      = re.compile("^[-+]?[0-9][0-9,]*\.[0-9,]*$")
+SCIENTIFIC_REGEX = re.compile("^[-+]?[0-9][0-9,]*\.[0-9.]*[eE][-+][0-9]+$")
+OCTAL_REGEX      = re.compile("^[-+]?([0][0-7,]*)$")
+HEX_REGEX        = re.compile("^[-+]?0x[0-9a-fA-F,]+$")
+INT_REGEX        = re.compile("^[-+]?(0|[1-9][0-9,]*)$")
+
+def convertImplicit(val):
+    if val == '~':
+        return None
+    if val == '+':
+        return 1
+    if val == '-':
+        return 0
+    if val[0] == "'" and val[-1] == "'":
+        val = val[1:-1]
+        return string.replace(val, "''", "\'")
+    if val[0] == '"' and val[-1] == '"':
+        if re.search(r"\u", val):
+            val = "u" + val
+        unescapedStr = eval (val)
+        return unescapedStr
+    if matchTime.match(val):
+        return timestamp(val)
+    if INT_REGEX.match(val):
+        return int(cleanseNumber(val))
+    if OCTAL_REGEX.match(val):
+        return int(val, 8)
+    if HEX_REGEX.match(val):
+        return int(val, 16)
+    if FLOAT_REGEX.match(val):
+        return float(cleanseNumber(val))
+    if SCIENTIFIC_REGEX.match(val):
+        return float(cleanseNumber(val))
+    return val
+
+def cleanseNumber(str):
+    if str[0] == '+':
+        str = str[1:]
+    str = string.replace(str,',','')
+    return str
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/stream.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/stream.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/stream.py	(revision 71)
@@ -0,0 +1,186 @@
+import re
+import string
+
+def indentLevel(line):
+    n = 0
+    while n < len(line) and line[n] == ' ':
+        n = n + 1
+    return n
+
+class LineNumberStream:
+    def __init__(self):
+        self.curLine = 0
+
+    def get(self):
+        line = self.getLine()
+        self.curLine += 1 # used by subclass
+        if line:
+            line = noLineFeed(line)
+        return line
+
+    def lastLineRead(self):
+        return self.curLine
+
+class FileStream(LineNumberStream):
+    def __init__(self, filename):
+        self.fp = open(filename)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        line = self.fp.readline()
+        if line == '': line = None
+        return line
+
+class StringStream(LineNumberStream):
+    def __init__(self, text):
+        self.lines = split(text)
+        self.numLines = len(self.lines)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        if self.curLine < self.numLines:
+            return self.lines[self.curLine]
+
+def split(text):
+    lines = string.split(text, '\n')
+    if lines[-1] == '':
+        lines.pop()
+    return lines
+
+def eatNewLines(stream):
+    while 1:
+       line = stream.get()
+       if line is None or len(string.strip(line)):
+           return line
+
+COMMENT_LINE_REGEX = re.compile(R"\s*#")
+def isComment(line):
+    return line is not None and COMMENT_LINE_REGEX.match(line)
+
+class CommentEater:
+    def __init__(self, stream):
+        self.stream = stream
+        self.peeked = 1
+        self.line = eatNewLines(stream)
+        self.eatComments()
+
+    def eatComments(self):
+        while isComment(self.line):
+            self.line = self.stream.get()
+
+    def peek(self):
+        if self.peeked:
+            return self.line
+        self.peeked = 1
+        self.line = self.stream.get()
+        self.eatComments()
+        return self.line
+
+    def lastLineRead(self):
+        return self.stream.lastLineRead()
+
+    def pop(self):
+        data = self.peek()
+        self.peeked = 0
+        return data
+
+class NestedText:
+    def __init__(self, stream):
+        self.commentEater = CommentEater(stream)
+        self.reset()
+
+    def lastLineRead(self):
+        return self.commentEater.lastLineRead()
+
+    def reset(self):
+        self.indentLevel = 0
+        self.oldIndents = [0]
+
+    def peek(self):
+        nextLine = self.commentEater.peek()
+        if nextLine is not None:
+            if indentLevel(nextLine) >= self.indentLevel:
+                return nextLine[self.indentLevel:]
+            elif nextLine == '':
+                return ''                
+
+    def pop(self):
+        line = self.peek()
+        if line is None:
+            self.indentLevel = self.oldIndents.pop()
+            return
+        self.commentEater.pop()
+        return line
+
+    def popNestedLines(self):
+        nextLine = self.peek()
+        if nextLine is None or nextLine == '' or nextLine[0] != ' ':
+            return []
+        self.nestToNextLine()
+        lines = []
+        while 1:
+            line = self.pop()
+            if line is None:
+                break
+            lines.append(line)
+        return lines
+
+    def nestToNextLine(self):
+        line = self.commentEater.peek()
+        indentation = indentLevel(line)
+        if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+            self.error("Inadequate indentation", line)
+        self.setNewIndent(indentation)
+
+    def nestBySpecificAmount(self, adjust):
+        self.setNewIndent(self.indentLevel + adjust)
+        
+    def setNewIndent(self, indentLevel):
+        self.oldIndents.append(self.indentLevel)
+        self.indentLevel = indentLevel    
+
+class YamlLoaderException(Exception):
+    def __init__(self, *args):
+        (self.msg, self.lineNum, self.line) = args
+
+    def __str__(self):
+        return "%s:\n" "near line %d:\n" "%s\n" % \
+            (self.msg, self.lineNum, self.line)
+
+
+class NestedDocs(NestedText):
+    def __init__(self, stream):
+        NestedText.__init__(self,stream)
+        line = NestedText.peek(self)
+        self.sep = '---'
+        if self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+        else:
+            self.eatenDocSep = self.sep
+
+    def startsWithSep(self,line):
+        if line and self.sep == line[:3]: return 1
+        return 0
+
+    def popDocSep(self):
+        line = self.eatenDocSep
+        self.eatenDocSep = None
+        self.reset()
+        return line
+
+    def pop(self):
+        if self.eatenDocSep is not None:
+            raise "error"
+        line = self.commentEater.peek()
+        if line and self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+            return None
+        return NestedText.pop(self)
+
+    def error(self, msg, line):
+        raise YamlLoaderException(msg, self.lastLineRead(), line)
+
+def noLineFeed(s):
+    while s[-1:] in ('\n', '\r'):
+        s = s[:-1]
+    return s
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/redump.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/redump.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/redump.py	(revision 71)
@@ -0,0 +1,11 @@
+from yaml.ordered_dict import OrderedDict
+from yaml import Parser, Dumper, StringStream
+
+def redump(stream):
+    parser = Parser(StringStream(stream))
+    parser.dictionary = OrderedDict
+    docs = list(iter(parser))
+    dumper = Dumper()
+    dumper.alphaSort = 0
+    return dumper.dump(*docs)
+    
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/klass.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/klass.py	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/build/lib/yaml/klass.py	(revision 71)
@@ -0,0 +1,48 @@
+import new
+import re
+
+class DefaultResolver:
+    def resolveType(self, data, typestring):
+        match = re.match('!!(.*?)\.(.*)', typestring)
+        if not match:
+            raise "Invalid private type specifier"
+        (modname, classname) = match.groups()
+        return makeClass(modname, classname, data)
+
+def makeClass(module, classname, dict):
+    exec('import %s' % (module))
+    klass = eval('%s.%s' % (module, classname))
+    obj = new.instance(klass) 
+    if hasMethod(obj, 'from_yaml'):
+        return obj.from_yaml(dict)
+    obj.__dict__ = dict
+    return obj
+
+def hasMethod(object, method_name):
+    try:    
+        klass = object.__class__
+    except:
+        return 0
+    if not hasattr(klass, method_name):
+        return 0
+    method = getattr(klass, method_name)
+    if not callable(method):
+        return 0
+    return 1
+
+def isDictionary(data):
+    return isinstance(data, dict)
+
+try:
+    isDictionary({})
+except:
+    def isDictionary(data): return type(data) == type({}) # XXX python 2.1
+    
+if __name__ == '__main__':
+    print isDictionary({'foo': 'bar'})
+    try:
+        print isDictionary(dict())
+        from ordered_dict import OrderedDict
+        print isDictionary(OrderedDict())
+    except:
+        pass
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.yml	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.yml	(revision 73)
@@ -0,0 +1,246 @@
+data:
+    title:
+        - &manager
+          caption: Manager
+          position: 0
+        - &programmer
+          caption: Programmer
+          position: 1
+          shadow:
+             position: 18
+        - &editor
+          caption: Editor
+          position: ~
+          shadow: 
+             position: 3
+    people:
+        - &mary
+          id: mary
+          name: Mary McFoo
+          number: 333
+          title: *programmer
+        - &al
+          id: al
+          name: Al Barson
+          number: 555
+          title: *manager
+    tasks:
+        - id: make a list
+          duration: 10
+          owner: al
+          person: *al
+        - id: go to store
+          duration: 15
+          owner: mary
+          person: *mary
+        - id: buy stuff
+          duration: 25
+          owner: mary
+          person: *mary
+          tasks:
+            - id: zoom
+              owner: *mary
+              duration: 22
+            - id: fly
+              owner: *al
+              duration: 33
+        - id: drive home
+          duration: 20
+          owner: mary
+          person: *mary
+        - id: watch tv
+          duration: 20
+          owner: al
+          person: *al
+        - id: cook food
+          duration: 60
+          owner: al
+          person: *al
+        - id: eat stuff
+          duration: 35
+          owner: al
+          person: *al
+tests:
+    - query:
+        select: 
+            - duration
+        from: tasks/*
+      expected:
+        - duration: 10
+        - duration: 15
+        - duration: 25
+        - duration: 20
+        - duration: 20
+        - duration: 60
+        - duration: 35
+    - query:
+        select: 
+            - owner
+        from: tasks/*
+        where:
+          id: cook food
+      expected:
+        - owner: al
+    - query:
+        select: 
+            - id
+        from: tasks/*
+        where:
+          duration: 20
+          owner: al
+      expected:
+        - id: watch tv
+    - query:
+        select: 
+            - caption
+        from: title/*
+        where:
+          position: ~
+      expected:
+         - caption: Editor
+    - query:
+        select: 
+            - position
+            - shadow/position
+        from: title/*
+        where:
+          caption: Editor
+      expected:
+         - position: ~
+           shadow/position: 3
+    - query:
+        select:
+          - id
+          - duration
+        from: tasks/*
+        where:
+            owner: mary
+        order:
+          - duration
+      expected:
+        - id: go to store
+          duration: 15
+        - id: drive home
+          duration: 20
+        - id: buy stuff
+          duration: 25
+    - query:
+        select:
+          - id
+          - owner
+        from: tasks/*
+        where: |
+          [duration] == 60
+      expected:
+        - id: cook food
+          owner: al
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: |
+          [duration] <= 20 and [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: 
+          - [duration] <= 20 
+          - [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: 
+          - [duration] <= 20 
+          - owner: 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+            - person/number
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - id: make a list
+          duration: 10
+          person/name: Al Barson
+          person/number: 555
+    - query:
+        select:
+            - person/name
+            - person/title/caption
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - person/name: Al Barson
+          person/title/caption: Manager
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+        from: tasks/*
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+          person/name: Al Barson
+        - id: cook food
+          duration: 60
+          person/name: Al Barson
+        - id: buy stuff
+          duration: 25
+          person/name: Mary McFoo
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+        from: tasks
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+        - id: cook food
+          duration: 60
+        - id: buy stuff
+          duration: 25
+      ignore: 1
+    - query:
+       select:
+         - id
+       from: //tasks
+      expected:
+        - id: make a list
+        - id: go to store
+        - id: buy stuff
+        - id: zoom
+        - id: fly
+        - id: drive home
+        - id: watch tv
+        - id: cook food
+        - id: eat stuff
+      ignore: 1
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/test.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/test.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/test.py	(revision 73)
@@ -0,0 +1,18 @@
+def assertEquals(first, second, msg=''):
+    if first != second:
+        raise AssertionError, \
+              (msg + "\n%s !=\n%s" % (`first`, `second`))
+
+def assertError(func, expectedError):
+    raised = 1
+    try:
+        func()
+        raised = 0
+    except Exception, e:
+        assertEquals(str(e), expectedError)
+    except:
+        raise "Unexpected exception"
+    if raised == 0:
+        raise "Never threw exception"
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/here.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/here.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/here.py	(revision 73)
@@ -0,0 +1,14 @@
+import re
+from string import split, join
+
+def flushLeft(s):
+    lines = split(s,'\n')
+    lastLine = lines.pop()
+    if re.match(r"\S", lastLine):
+        raise "bad last line"
+    indent = len(lastLine)
+    ret = []
+    for line in lines[1:]:
+        ret.append(line[indent:] + '\n')
+    return join(ret,'')
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/profileYaml.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/profileYaml.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/profileYaml.py	(revision 73)
@@ -0,0 +1,23 @@
+import profile
+import pstats
+import yaml
+import glob
+
+def loadAllFiles():
+    testFiles = glob.glob('TestingSuite/*.yml')
+    for file in testFiles:
+        docs = yaml.loadFile(file)
+        for doc in docs:
+            exercise(doc)
+
+def exercise(doc):                
+    if 'python' in doc:
+        if 'yaml' in doc:
+            for subDoc in yaml.load(doc['yaml']):
+                pass
+print dir(profile)
+profile.run('loadAllFiles()', 'profileResults')
+
+p = pstats.Stats('profileResults')
+file = open("profile.out", "w")
+p.sort_stats('time').print_stats(25)
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/demo.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/demo.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/demo.py	(revision 73)
@@ -0,0 +1,92 @@
+import yaml, string
+
+####### RUNNING YAML AGAINST THE README AND CHANGELOG
+
+readme = yaml.loadFile("README")
+print "README"
+for item in readme.next():
+    print item
+print "\n\nCONTRIBUTORS"
+for person in readme.next()['contributors']:
+    print "===%s===" % person['who']
+    print person['why?']
+    print
+print "\n\n"
+print "CHANGELOG:\n"
+print list(yaml.loadFile("CHANGELOG"))
+print "\n\n"
+
+######## USING YAML INSIDE YOUR PROGRAM
+
+testData = \
+"""
+program: PyYaml
+author: Steve Howell
+---
+shopping list:
+ - apple
+ - banana
+todo:
+ - eat more fruit:
+     - especially bananas!
+     - good for you
+ - write a better demo
+"""
+
+print "YAML INSIDE YOUR PROGRAM"
+for x in yaml.load(testData):
+   print repr(x)
+print "\n\n"
+
+
+######### YPATH STUFF
+
+try:
+    print "YPATH EXPERIMENTATION"
+    data = yaml.load(testData)
+    print yaml.ypath("/author",data.next()).next()
+    print yaml.dump(yaml.ypath("/todo/0",data.next()).next())
+except NotImplementedError:
+    print "Experimental YPATH requires Python 2.2"
+
+######### YAML DUMPER 
+
+class Person:
+    def __init__(self, fname, lname, salary, children):
+        self.fname = fname
+        self.lname = lname
+        self.salary = salary
+        self.children = children
+        # private variables
+        self._fullname = fname + ' ' + lname
+        if salary:
+            self._sal_per_month = salary / 12.0
+        self._num_children = len(children)
+    def to_yaml(self):
+        return ({
+            'first name': self.fname,
+            'last name':  self.lname,
+            'salary':     self.salary
+        }, '!!Person')
+
+mrBarson = Person('Foo', 'Barson', 20, ['ex', 'theomatic'])
+mrDoe = Person('John', 'Doe', None, [])
+print yaml.dump([mrBarson, mrDoe])
+
+print "\n\nANOTHER WAY TO STDOUT:\n"
+import sys
+yaml.dumpToFile(sys.stdout, [mrBarson, mrDoe])
+
+print "\n\nDUMP MULTIPLE DOCS TO A FILE:\n"
+file = open('DEMO_OUTPUT.TXT', 'w')
+yaml.dumpToFile(file, 
+    {'source': "Demo output from demo.py"},
+    [
+        'apple',
+        'banana',
+    ],
+    'Third document'      
+)
+file.close()
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYpath.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYpath.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYpath.py	(revision 73)
@@ -0,0 +1,20 @@
+import yaml
+from test import assertEquals
+
+try:    
+    for test in yaml.loadFile("./TestingSuite/ypath.yml"):
+        if not test.has_key('ignore'):
+            expr = test['ypath']
+            pth = yaml.ypath(expr,cntx=1)
+            lst = [] 
+            for x in pth.apply(test['data']):
+                lst.append(str(x))
+            exp = test['expected']
+            if test.has_key('unordered'):
+               lst.sort()
+               exp.sort()
+            assertEquals(lst,exp,expr + " => " + str(pth))
+
+    print "Experimental YPATH OK"
+except NotImplementedError: 
+    print "Experimental YPATH requires Python 2.2"
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TESTING
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TESTING	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TESTING	(revision 73)
@@ -0,0 +1,12 @@
+--- >
+As of July 2002, PyYaml shares its YAML-based testing suite with 
+other YAML implementations, starting with YamlForRuby.  Many
+thanks to Why The Lucky Stuff, the author of YamlForRuby, for
+setting this up.
+
+When you check code out of Perforce, please set up your client
+to check out TestingSuite as a subfolder of PyYaml.
+
+Thanks,
+
+Steve
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/Makefile
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/Makefile	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/Makefile	(revision 73)
@@ -0,0 +1,25 @@
+test:
+	python2.1 YamlTest.py
+	python2.1 TestYpath.py
+	python2.1 TestClasses.py
+	python YamlTest.py
+	python TestYpath.py
+	python TestClasses.py
+	python TestPluggableDictionary.py
+
+clean:
+	rm -f *.pyc
+	rm -f yaml/*.pyc
+	rm -rf build
+	rm -f DEMO*.TXT
+	rm -f profileResults
+
+profile:
+	python profileYaml.py > profile.out
+
+install:
+	python setup.py install
+
+build:
+	python setup.py build
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYamlBasics.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYamlBasics.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestYamlBasics.py	(revision 73)
@@ -0,0 +1,157 @@
+import YamlTest
+from here import *
+from test import assertEquals
+
+class Test(YamlTest.YamlTest):
+    def setUp(self):
+        # print '>>>>>>>>>>>>>>>'
+        pass
+
+    def testNoLineFeed(self):
+        from yaml.stream import noLineFeed
+        assertEquals("foo", noLineFeed("foo\n"))
+        assertEquals("bar", noLineFeed("bar\n"))
+        assertEquals("bar", noLineFeed("bar\r\n"))
+        assertEquals("", noLineFeed("\r\n"))
+
+    def XXXtest9(self):
+        # XXX - not sure how this gets handled now
+        self.verify(
+            """
+            - foo: 1
+                bar: 2
+            """,
+            [ {'foo': 1, '  bar': 2}])
+
+    def testOutlineSnippet(self):
+        self.verify(
+            """
+            - YAML ToDo:
+                - y2outline
+                - support generic transfers
+                - work on YAML.py:
+                    - work on Store
+            """,
+            [ {'YAML ToDo': [   
+                'y2outline',
+                'support generic transfers',
+                { 'work on YAML.py': ['work on Store'] }
+                ]
+              }
+            ])
+
+    def testQuotedString(self):
+        self.verify(
+            """
+            ---
+            foo: 'key: value'
+            """,
+            {'foo': "key: value"}
+            )
+
+    def testFloatRedHerring(self):
+        self.verify(
+            """
+            ---
+            - 'Version: 0.18.0'
+            """,
+            [ 'Version: 0.18.0' ]
+            )
+
+    def testDashInQuotes(self):
+        self.verify(
+            """
+            ---
+            title: 'Perspective Broker - twisted.spread'
+            """,
+            {'title': 'Perspective Broker - twisted.spread'}
+            )
+
+    def testQuestionMarks(self):
+        self.verify(
+            """
+            ---
+            hello: you there?
+            foo:
+                - ok?
+                - sure?
+            bar:
+                - for here or to go?
+                - more sugar?
+            """,
+            {   
+                'hello': 'you there?',
+                'foo': ['ok?', 'sure?'],
+                'bar': ['for here or to go?', 'more sugar?']
+            }
+            )
+
+    def testDoubleQuoteEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            "I'm escaped!": simple
+            """,
+            { "I'm escaped!": 'simple' }
+            )
+
+    def testColonsInsideEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            'aaa: bbbb': simple
+            """,
+            { 'aaa: bbbb': 'simple' }
+            )
+
+    def testControlChars(self):
+        self.verify(
+            r"""
+            control: "\b1998\t1999\t2000\n"
+            """,
+            { 'control': "\b1998\t1999\t2000\n" }
+        )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.verify(
+                r'''
+                unicode: "Sosa did fine.\u263A"
+                ''',
+                { 'unicode': u"Sosa did fine.\u263A"}
+            )
+
+    def testMultiLineScalar(self):
+        self.verify(
+            """
+            plain: This unquoted
+                   scalar spans
+                   many lines.
+            """,
+            { 'plain': 'This unquoted scalar spans many lines.' }
+        )
+
+    def testDomainType(self):
+        class MyYamlConfig:
+            def resolveType(self, data, url):
+                if url == '!!name':
+                    return 'Foo ' + data
+                elif url == '!!coords':
+                    return { 'x': data[0], 'y': data[1]}
+                else:
+                    raise 'url not passed in correctly'
+        data = YamlTest.loadFlushLeft("""
+            name: !!name Barson
+            coords: !!coords
+              - 10
+              - 20
+            """, 
+            MyYamlConfig())
+        self.assertEquals(data[0], 
+            {'name': 'Foo Barson',
+            'coords': { 'x': 10, 'y': 20 } }
+        )
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPluggableDictionary.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPluggableDictionary.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPluggableDictionary.py	(revision 73)
@@ -0,0 +1,27 @@
+import yaml
+from yaml.ordered_dict import OrderedDict
+from yaml.redump import redump
+from test import assertEquals
+
+stream = """\
+---
+zzz: 0
+yyy: 1
+xxx: 2
+alpha: 3
+---
+-
+    foo: 1
+    bar: 2
+-
+    z: 1
+    y: 2
+"""
+
+parser = yaml.Parser(yaml.StringStream(stream))
+parser.dictionary = OrderedDict
+my_dict = parser.next()
+assertEquals(my_dict.keys(), ['zzz', 'yyy', 'xxx', 'alpha'])
+
+assertEquals(redump(stream), stream)
+   
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPullParser.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPullParser.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestPullParser.py	(revision 73)
@@ -0,0 +1,116 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals
+from TestPushDumper import mockEvents
+from yaml import load
+
+"""
+This is experimental code.  I am moving toward a rewrite of the YAML 
+parser so that it uses a pull interface.  I am using a mock object
+to emulate the parser, so that I can experiment with the interface a bit,
+and also to sketch out some ideas for schema-driven parsing.
+"""
+
+class MockParser:
+    def __init__(self, events):
+        self.events = events
+        self.index = 0
+
+    def __getattr__(self, name):
+        (nextName, value) = self.events[self.index]
+        if name != nextName:
+            raise "Improper mocking for event %d (%s vs. %s)" % \
+                (self.index, name, nextName)
+        self.index += 1
+        return lambda: value
+
+class Loader:
+    def __init__(self, parser):
+        self.parser = parser
+
+    def load(self, data):
+        typ = self.parser.getType()
+        return self._load(typ)
+
+    def _load(self, typ):
+        if typ == 'seq':
+            return self._loadSeq()
+        elif typ == 'map':
+            return self._loadMap()
+        else:
+            return self._loadScalar()
+
+    def _loadSeq(self):
+        results = []
+        def itemFunc(self, results, typ):
+            results.append(self._load(typ))
+        return self.iterateItems(results, itemFunc)
+
+    def _loadMap(self):
+        results = {}
+        def itemFunc(self, results, typ):
+            key = self._load(typ)
+            valTyp = self.parser.getType()
+            value = self._load(typ)
+            results[key] = value
+        return self.iterateItems(results, itemFunc)
+
+    def iterateItems(self, results, func):
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                func(self, results, typ)
+
+    def _loadScalar(self):
+        return self.parser.getScalar()
+
+def mockParser(data):
+    events = mockEvents(data)
+    return MockParser(events)
+
+def mockLoad(data):
+    loader = Loader(mockParser(data))
+    return loader.load(None) # None for data cause events are all mocked 
+
+def testRoundTrip(data):
+    obj = mockLoad(data)
+    assertEquals(obj, data)
+
+class Test(YamlTest.YamlTest):
+
+    def testMock(self):
+        parser = MockParser( [
+            ('getScalar', 'foo'),
+            ('getArray', [1,2,3]),
+            ('getScalar', None),
+        ])
+        assertEquals(parser.getScalar(), 'foo')
+        assertEquals(parser.getArray(), [1,2,3])
+        assertEquals(parser.getScalar(), None)
+
+    def testList(self):
+        testRoundTrip([1,2,3])
+
+    def testDict(self):
+        testRoundTrip({'foo': 'bar'})
+
+    def testListDict(self):
+        testRoundTrip( [ [1,2,3], {'foo': 'bar'} ] )
+
+    def testComplexStructure(self):
+        data = load(flushLeft(
+            """
+            list:
+                - {foo: bar}
+                - [1, 2, 3]
+            dict:
+                name: steve
+                games: [hoops, pool]
+            """))
+        testRoundTrip(data)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestClasses.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestClasses.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestClasses.py	(revision 73)
@@ -0,0 +1,140 @@
+import yaml
+from test import assertEquals
+from here import flushLeft
+from math import sqrt
+
+"""
+DUMPING OBJECTS: > 
+    YAML has several ways of persisting objects.  One view of an 
+    object is that it's nothing more than it's dictionary.  By 
+    default, YAML emits self.__dict__ from objects.
+"""
+
+class SimpleObject:
+    def __init__(self):
+        self.x = 100
+        self.y = 20
+    
+    def xyz(self):
+        return self.x + self.y + self.z
+
+def testDumpingDictionary():
+    obj = SimpleObject()
+    obj.z = 3
+    output = yaml.dump(obj)
+    expected = simpleObjectYaml()
+    assertEquals(output, expected)
+
+def simpleObjectYaml():
+    return flushLeft("""
+        --- !!__main__.SimpleObject
+        x: 100
+        y: 20
+        z: 3
+        """)
+    
+
+testDumpingDictionary()
+
+"""
+LOADING OBJECTS: > 
+    Of course, we would expect to be able to load that
+    YAML right back into Python, and we can.  You get 
+    back an object of the intended class, with all of 
+    the normal methods.  Be aware, though, that if your 
+    class creates methods on the fly, or if it does 
+    other trickery, then you might get unexpected results.
+"""
+
+def testLoadingDictionary():
+    obj = yaml.load(simpleObjectYaml()).next()
+    assertEquals(obj.xyz(), 123)
+
+testLoadingDictionary()
+
+"""
+CUSTOM DUMPING: >
+    Some times you want more control over how you dump
+    objects in YAML.  You might not want to dump all 
+    members of the object, for example.  Also, you may 
+    not want to export the module name.
+"""
+
+class Triangle:
+    def __init__(self,x,y):
+        self.x = x
+        self.y = y
+        self._hypotneuse = sqrt(x*x + y*y)
+
+    def to_yaml(self):
+        # hide the hypotneuse attribute, it's private;
+        # also use inches instead of feet
+        view = {
+            'x_inches': self.x * 12,
+            'y_inches': self.y * 12
+        }
+        return (view, '!!triangle_in_inches')
+
+def testDumpTriangle():
+    triangle = Triangle(3,4)
+    assertEquals(yaml.dump(triangle), triangleYaml())
+
+def triangleYaml():
+    return flushLeft("""
+        --- !!triangle_in_inches
+        x_inches: 36
+        y_inches: 48
+        """)
+
+testDumpTriangle()
+
+"""
+CUSTOM LOADING: >
+    You have control over the YAML load process too.  Normally
+    YAML resolves private types for you automatically, but you
+    can override its behavior.
+"""
+
+class MyResolver:
+    def resolveType(self, data, typestring):
+        if typestring == '!!triangle_in_inches':
+            x = data['x_inches'] / 12
+            y = data['y_inches'] / 12
+            return Triangle(x,y)
+        else:
+            raise 'Private type %s not supported' % typestring
+
+def testCustomLoad():
+    obj = yaml.load(triangleYaml(),MyResolver()).next()
+    assertEquals(obj._hypotneuse, 5.0)
+
+testCustomLoad()
+
+"""
+USING FROM_YAML(): >
+    Another way to customize the YAML loading process is to 
+    supply a from_yaml() method.  For example, you might want
+    the loading of an object to have some kind of a side effect.
+    Or, you may need to calculate some value that is not part of 
+    the attribute.
+"""
+
+class TestConfig:
+    lastTester = None
+    def from_yaml(self, args):
+        self.tester = args['tester']
+        self.hitcount = args['hitcount'] + 1
+        TestConfig.lastTester = self.tester
+        return self
+
+def testFromYaml():
+    yamlData = flushLeft("""
+        --- !!__main__.TestConfig
+        tester: showell
+        hitcount: 42
+        """)
+    obj = yaml.load(yamlData).next()
+    assertEquals(obj.hitcount, 43)
+    assertEquals(TestConfig.lastTester, 'showell')
+
+testFromYaml()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/__init__.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/__init__.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/__init__.py	(revision 73)
@@ -0,0 +1,1 @@
+# 
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/CHANGELOG
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/CHANGELOG	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/CHANGELOG	(revision 73)
@@ -0,0 +1,51 @@
+---
+- version: 0.30
+  date: 2002-11-06
+  changes:
+    - bunch of changes for 2.1 support
+    - fully tested on 2.1.3 and 2.2
+    - added YamlLoaderException
+    - pluggable dictionaries (2.2 only)
+    - simplified iterator interface (deprecated getNextDocument)
+    - single quote &foo properly
+    - quote "foo'bar properly
+---
+- version: 0.29
+  date: 2002-11-03
+  changes:
+    - support |+ syntax
+---
+- version: 0.28
+  date: 2002-09-25
+  changes:
+    - use compiled regexes for speed
+    - streamlined stream.py for speed
+    - added profileYaml.py
+---
+- version: 0.27
+  date: 2002-09-24
+  changes:
+    - better error handling
+    - removed spurious spaces from specs.yml
+    - use a true FileStream class vs. reading in entire file up front
+---
+- version: 0.26
+  date: 2002-09-23
+  changes:
+    - support to_yaml() when you inherit from Python's dict class
+    - move implicit and inline logic into own modules
+    - require space after comma for inline collections (Brian Dorsey)
+    - only call user's resolver for !!private types
+    - don't choke on !str, etc. (but doesn't yet respect them)
+    - fixed bugs in loader/dumper related to integer dict keys (Joel Shprentz)
+---
+- version: 0.25
+  date: 2002-08-21
+  changes:
+    - extensive refactorings on dumper
+    - Dumper class made public
+    - new interface for setIndent and setSort
+    - added Dave Kuhlman's XmlYaml stuff
+    - limiting support to Python 2.2 and above
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/stream.py.patch
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/stream.py.patch	(revision 72)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/stream.py.patch	(revision 72)
@@ -0,0 +1,53 @@
+--- yaml/stream.py	2002-12-26 09:53:42.000000000 -0800
++++ yaml/stream.py	2003-12-04 13:14:41.000000000 -0800
+@@ -94,12 +94,15 @@
+         return self.commentEater.lastLineRead()
+ 
+     def reset(self):
+         self.indentLevel = 0
+         self.oldIndents = [0]
++        self.empty = 0
+ 
+     def peek(self):
++        if self.empty:
++            return
+         nextLine = self.commentEater.peek()
+         if nextLine is not None:
+             if indentLevel(nextLine) >= self.indentLevel:
+                 return nextLine[self.indentLevel:]
+             elif nextLine == '':
+@@ -107,10 +110,11 @@
+ 
+     def pop(self):
+         line = self.peek()
+         if line is None:
+             self.indentLevel = self.oldIndents.pop()
++            self.empty = 0
+             return
+         self.commentEater.pop()
+         return line
+ 
+     def popNestedLines(self):
+@@ -128,19 +132,20 @@
+ 
+     def nestToNextLine(self):
+         line = self.commentEater.peek()
+         indentation = indentLevel(line)
+         if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+-            self.error("Inadequate indentation", line)
++            self.empty = 1
++            #self.error("Inadequate indentation", line)
+         self.setNewIndent(indentation)
+ 
+     def nestBySpecificAmount(self, adjust):
+         self.setNewIndent(self.indentLevel + adjust)
+         
+     def setNewIndent(self, indentLevel):
+         self.oldIndents.append(self.indentLevel)
+-        self.indentLevel = indentLevel    
++        self.indentLevel = indentLevel
+ 
+ class YamlLoaderException(Exception):
+     def __init__(self, *args):
+         (self.msg, self.lineNum, self.line, self.filename) = args
+ 
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/load.py.patch
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/load.py.patch	(revision 72)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/patches/load.py.patch	(revision 72)
@@ -0,0 +1,103 @@
+--- yaml/load.py	2002-12-26 08:38:51.000000000 -0800
++++ yaml/load.py	2003-10-02 15:53:06.000000000 -0700
+@@ -45,10 +45,13 @@
+             if ok:
+                 return (1, result)
+ 
+ def dumpDictionary(): return {}
+ 
++_STRIP = 1
++_KEEP = 2
++
+ class Parser:
+     def __init__(self, stream, typeResolver=None):
+         try:
+             self.dictionary = dict
+         except:
+@@ -167,19 +170,16 @@
+         if alias:
+             self.aliases[alias] = value
+         return value          
+ 
+     def parse_unaliased_value(self, value):
+-        match = re.match(r"(!\S*)(.*)", value)
++        match = re.match(r"(!\S*) (.*)", value)
+         if match:
+             (url, value) = match.groups()
+-            value = self.parse_untyped_value(value)
+             if url[:2] == '!!':
+                 return self.typeResolver.resolveType(value, url)
+-            else:
+-                # XXX - allows syntax, but ignores it
+-                return value
++            return self.parse_untyped_value(value)
+         return self.parse_untyped_value(value)
+ 
+     def parseInlineArray(self, value):        
+         if re.match("\s*\[", value):
+             return self.parseInline([], value, ']', 
+@@ -231,36 +231,54 @@
+ 
+     def parseNative(self, value):
+         return (1, convertImplicit(value))
+ 
+     def parseMultiLineScalar(self, value):
++        # XXX does not handle indentation ex. >2, or |2
+         if value == '>':
+             return (1, self.parseFolded())
++        elif value == '>-':
++            return (1, self.parseFolded(_STRIP))
++        elif value == '>+':
++            return (1, self.parseFolded(_KEEP))
+         elif value == '|':
+-            return (1, joinLiteral(self.parseBlock()))
++            return (1, self.parseBlock())
++        elif value == '|-':
++            return (1, self.parseBlock(_STRIP))
+         elif value == '|+':
+-            return (1, joinLiteral(self.unprunedBlock()))
++            return (1, self.parseBlock(_KEEP))
+ 
+-    def parseFolded(self):
+-        data = self.parseBlock()
++    def parseFolded(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
+         i = 0
+         resultString = ''
+         while i < len(data)-1:
+-            resultString = resultString + data[i]
+-            resultString = resultString + foldChar(data[i], data[i+1])
+-            i = i + 1
+-        return resultString + data[-1] + "\n"        
++            resultString += data[i]
++            resultString += foldChar(data[i], data[i+1])
++            i += 1
++        resultString += data[-1]
++        if chomping ==_STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def unprunedBlock(self):
+         self.nestedDocs.nestToNextLine()
+         data = []
+         while self.nestPop():
+             data.append(self.line)
+         return data
+ 
+-    def parseBlock(self):
+-        return pruneTrailingEmpties(self.unprunedBlock())
++    def parseBlock(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
++        resultString = string.join(data, "\n")
++        if chomping == _STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def testForAlias(self, value):
+         match = re.match("&(\S*)\s*(.*)", value)
+         if match:
+             return match.groups()
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/alias.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/alias.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/alias.yml	(revision 71)
@@ -0,0 +1,52 @@
+--- #YAML:1.0
+test: Simple Alias Example
+brief: >
+    If you need to refer to the same item of data twice,
+    you can give that item an alias.  The alias is a plain
+    string, starting with an ampersand.  The item may then
+    be referred to by the alias throughout your document
+    by using an asterisk before the name of the alias.
+    This is called an anchor.
+yaml: |
+    - &showell Steve
+    - Clark
+    - Brian
+    - Oren
+    - *showell
+python: |
+    [
+        [ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve']
+    ]
+ruby-setup: |
+    showell = 'Steve'
+ruby: |
+    [ showell, 'Clark', 'Brian', 'Oren', showell ]
+
+---
+test: Alias of a Mapping
+brief: >
+    An alias can be used on any item of data, including
+    sequences, mappings, and other complex data types.
+yaml: |
+    - &hello
+        Meat: pork
+        Starch: potato
+    - banana
+    - *hello
+python: |
+    [
+        [ 
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+            'banana',
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+        ]
+    ]
+ruby-setup: |
+    hello = { 'Meat' => 'pork', 'Starch' => 'potato' }
+ruby: |
+    [ 
+      hello, 
+      'banana',
+      hello
+    ]
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/error.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/error.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/error.yml	(revision 71)
@@ -0,0 +1,30 @@
+--- #YAML:1.0
+test: Missing value for hash item
+brief: >
+    Third item in this hash doesn't have a value
+yaml: |
+    okay: value
+    also okay: ~
+    causes error because no value specified
+    last key: value okay here too
+error:
+    python: |
+        bad key for map:
+        near line 3:
+        causes error because no value specified
+---
+test: Not indenting enough
+brief: >
+    There was a bug in PyYaml where it was off by one
+    in the indentation check.  It was allowing the YAML 
+    below.
+yaml: |
+    foo:
+    firstline: 1
+    secondline: 2
+error:
+    python: |
+        Inadequate indentation:
+        near line 2:
+        firstline: 1
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/inlineCollection.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/inlineCollection.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/inlineCollection.yml	(revision 71)
@@ -0,0 +1,74 @@
+---
+test: Simple Inline Array
+brief: >
+    Sequences can be contained on a
+    single line, using the inline syntax.
+    Separate each entry with commas and
+    enclose in square brackets.
+yaml: |
+    --- 
+    seq: [ a, b, c ]
+python: |
+    [
+        { 'seq': [ 'a', 'b', 'c' ] }
+    ]
+ruby: |
+    { 'seq' => [ 'a', 'b', 'c' ] }
+
+---
+test: Simple Inline Hash
+brief: >
+    Mapping can also be contained on
+    a single line, using the inline
+    syntax.  Each key-value pair is
+    separated by a colon, with a comma
+    between each entry in the mapping.
+    Enclose with curly braces.
+yaml: |
+    ---
+    hash: { name: Steve, foo: bar }
+python: |
+    [
+        { 'hash': {'name': 'Steve', 'foo': 'bar'} }
+    ]
+ruby: |
+    { 'hash' => { 'name' => 'Steve', 'foo' => 'bar' } }
+
+---
+test: Multi-line Inline Collections
+brief: >
+    Both inline sequences and inline mappings
+    can span multiple lines, provided that you
+    indent the additional lines.
+yaml: |
+    languages: [ Ruby,
+                 Perl,
+                 Python ]
+    websites: { YAML: yaml.org,
+                Ruby: ruby-lang.org,
+                Python: python.org,
+                Perl: use.perl.org }
+ruby: |
+    { 'languages' => [ 'Ruby', 'Perl', 'Python' ],
+      'websites' => {
+        'YAML' => 'yaml.org',
+        'Ruby' => 'ruby-lang.org',
+        'Python' => 'python.org',
+        'Perl' => 'use.perl.org' 
+      }
+    }
+---
+test: Commas in Values
+brief: >
+    List items in collections are delimited by commas, but 
+    there must be a space after each comma.  This allows you
+    to add numbers without quoting.
+yaml: |
+    attendances: [ 45,123, 70,000, 17,222 ]
+python: |
+    [
+        {'attendances': [ 45123, 70000, 17222 ]}
+    ]
+ruby: |
+    { 'attendances' => [ 45123, 70000, 17222 ] }
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/spec.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/spec.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/spec.yml	(revision 71)
@@ -0,0 +1,1576 @@
+--- #YAML:1.0
+test: Sequence of scalars
+spec: A1
+yaml: |
+  - Mark McGwire
+  - Sammy Sosa
+  - Ken Griffey
+perl: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+python: |
+  [ ['Mark McGwire', 'Sammy Sosa', 'Ken Griffey'] ]
+ruby: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Mapping of scalars to scalars
+spec: A2
+yaml: |
+  hr:  65
+  avg: 0.278
+  rbi: 147
+perl: |
+  { hr => 65, avg => 0.278, rbi => 147 }
+python: |
+  [ {'hr': 65, 'avg': .278, 'rbi': 147} ]
+ruby: |
+  { 'hr' => 65, 'avg' => 0.278, 'rbi' => 147 }
+
+---
+test: Mapping of scalars to sequences
+spec: A3
+yaml: |
+    american:
+       - Boston Red Sox
+       - Detroit Tigers
+       - New York Yankees
+       - Texas Rangers
+    national:
+       - New York Mets
+       - Chicago Cubs
+       - Atlanta Braves
+       - Montreal Expos
+perl: |
+    { american => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      national =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+python: |
+    [
+    {
+    'american': 
+        ['Boston Red Sox', 'Detroit Tigers', 
+        'New York Yankees', 'Texas Rangers'],
+    'national':
+        ['New York Mets', 'Chicago Cubs',
+        'Atlanta Braves', 'Montreal Expos']
+    }
+    ]
+ruby: |
+    { 'american' => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      'national' =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+
+---
+test: Sequence of mappings
+spec: A4
+yaml: |
+    - 
+      name: Mark McGwire
+      hr:   65
+      avg:  0.278
+      rbi:  147
+    - 
+      name: Sammy Sosa
+      hr:   63
+      avg:  0.288
+      rbi:  141
+perl: |
+    [
+      {name => 'Mark McGwire', hr => 65, avg => 0.278, rbi => 147},
+      {name => 'Sammy Sosa',   hr => 63, avg => 0.288, rbi => 141}
+    ]
+python: |
+    [[ 
+        {
+        'name': 'Mark McGwire',
+        'hr': 65,
+        'avg': 0.278,
+        'rbi': 147
+        },
+        {
+        'name': 'Sammy Sosa',
+        'hr': 63,
+        'avg': 0.288,
+        'rbi': 141
+        }
+    ]]
+ruby: |
+    [
+      {'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278, 'rbi' => 147},
+      {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288, 'rbi' => 141}
+    ]
+
+---
+test: Legacy A5
+spec: legacy_A5
+yaml: |
+    ?
+        - New York Yankees
+        - Atlanta Braves
+    :
+      - 2001-07-02
+      - 2001-08-12
+      - 2001-08-14
+    ?
+        - Detroit Tigers
+        - Chicago Cubs
+    :
+      - 2001-07-23
+perl-busted: >
+    YAML.pm will be able to emulate this behavior soon. In this regard
+    it may be somewhat more correct than Python's native behaviour which
+    can only use tuples as mapping keys. PyYAML will also need to figure
+    out some clever way to roundtrip structured keys. Not sure how full
+    featured Ruby is in this regard.
+python: |
+    [
+    {
+        ('New York Yankees', 'Atlanta Braves'):
+            [yaml.timestamp('2001-07-02'), 
+             yaml.timestamp('2001-08-12'),
+             yaml.timestamp('2001-08-14')],
+        ('Detroit Tigers', 'Chicago Cubs'):
+        [yaml.timestamp('2001-07-23')]
+    }
+    ]
+ruby: |
+    {
+      [ 'New York Yankees', 'Atlanta Braves' ] =>
+        [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ],
+      [ 'Detroit Tigers', 'Chicago Cubs' ] =>
+        [ Date.new( 2001, 7, 23 ) ]
+    }
+
+
+---
+test: Sequence of sequences
+spec: A5
+yaml: |
+  - [ name         , hr , avg   ]
+  - [ Mark McGwire , 65 , 0.278 ]
+  - [ Sammy Sosa   , 63 , 0.288 ]
+perl: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ],
+  ]
+python: |
+  [[
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]]
+ruby: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]
+
+---
+test: Mapping of mappings
+spec: A6
+yaml: |
+  Mark McGwire: {hr: 65, avg: 0.278} 
+  Sammy Sosa:   {hr: 63,
+                 avg: 0.288}
+perl: |
+  { 
+    'Mark McGwire' => { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' => { 'hr' => 63, 'avg' => 0.288 },
+  }
+not_yet_in_python: |
+  [{ 
+    'Mark McGwire': 
+      { 'hr': 65, 'avg': 0.278 },
+    'Sammy Sosa':
+      { 'hr': 63, 'avg': 0.288 }
+  }]
+ruby: |
+  { 
+    'Mark McGwire' =>
+      { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' =>
+      { 'hr' => 63, 'avg' => 0.288 }
+  }
+
+---
+test: Two documents, one stream
+spec: B1
+yaml: |
+  ---
+  name: Mark McGwire
+  hr:   65
+  avg:  0.278
+  ---
+  name: Sammy Sosa
+  hr:   63
+  avg:  0.288
+python: |
+  [
+    { 'name': 'Mark McGwire', 'hr': 65, 'avg': 0.278 },
+    { 'name': 'Sammy Sosa', 'hr': 63, 'avg': 0.288 }
+  ]
+ruby: |
+  y = Stream.new
+  y.add( { 'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278 } )
+  y.add( { 'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288 } )
+documents: 2
+
+---
+test: Document with leading comment
+spec: B2
+yaml: |
+   # Ranking of players by
+   # 1998 season home runs.
+   ---
+      - Mark McGwire
+      - Sammy Sosa
+      - Ken Griffey
+python: |
+   [[ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]]
+ruby: |
+   [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Single document with two comments
+spec: B3
+yaml: |
+  hr: # 1998 hr ranking
+    - Mark McGwire
+    - Sammy Sosa
+  rbi:
+    # 1998 rbi ranking
+    - Sammy Sosa
+    - Ken Griffey
+python: |
+  [{ 
+    'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi': [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }]
+ruby: |
+  { 
+    'hr' => [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }
+
+---
+test: Node for Sammy Sosa appears twice in this document
+spec: B4
+yaml: |
+   hr:
+      - Mark McGwire
+      # Following node labeled SS
+      - &SS Sammy Sosa
+   rbi:
+      - *SS # Subsequent occurance
+      - Ken Griffey
+python: |
+   [{ 
+      'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi': [ 'Sammy Sosa', 'Ken Griffey' ]
+   }]
+ruby: |
+   { 
+      'hr' =>
+         [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi' =>
+         [ 'Sammy Sosa', 'Ken Griffey' ]
+   }
+
+---
+test: Mapping between sequences
+spec: B5
+yaml: |
+   ? # PLAY SCHEDULE
+     - Detroit Tigers
+     - Chicago Cubs
+   :  
+     - 2001-07-23
+   
+   ? [ New York Yankees,
+       Atlanta Braves ]
+   : [ 2001-07-02, 2001-08-12, 
+       2001-08-14 ]
+ruby: |
+   { 
+      [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
+      [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ]
+   }
+
+---
+test: Sequence key shortcut
+spec: B6
+yaml: |
+   invoice: 34843
+   date   : 2001-01-23
+   bill-to: Chris Dumars
+   product:
+      - item    : Super Hoop
+        quantity: 1
+      - item    : Basketball
+        quantity: 4
+      - item    : Big Shoes
+        quantity: 1
+ruby: |
+   { 
+      'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+      'bill-to' => 'Chris Dumars', 'product' =>
+      [ 
+         { 'item' => 'Super Hoop', 'quantity' => 1 },
+         { 'item' => 'Basketball', 'quantity' => 4 },
+         { 'item' => 'Big Shoes', 'quantity' => 1 } 
+      ] 
+   }
+python: |
+    [{
+        'invoice': 34843,
+        'date': yaml.timestamp('2001-01-23'),
+        'bill-to': 'Chris Dumars',
+        'product': [
+             { 'item': 'Super Hoop', 'quantity': 1 },
+             { 'item': 'Basketball', 'quantity': 4 },
+             { 'item': 'Big Shoes',  'quantity': 1 } 
+        ]
+    }]
+
+---
+test: Literal perserves newlines
+spec: C1
+yaml: |
+  --- |
+      \/|\/|
+      / |  |_
+ruby: |
+  "\\/|\\/|\n/ |  |_\n"
+python: |
+    [
+        flushLeft(
+        """
+        \/|\/|
+        / |  |_
+        """
+        )
+    ]
+
+---
+test: Folded treats newlines as a space
+spec: C2
+yaml: |
+  --- >
+      Mark McGwire's
+      year was crippled
+      by a knee injury.
+ruby: |
+  "Mark McGwire's year was crippled by a knee injury.\n"
+python: |
+    [ "Mark McGwire's year was crippled by a knee injury.\n" ]
+
+---
+test: Newlines preserved for indented and blank lines
+spec: C3
+yaml: |
+  --- >
+   Sammy Sosa completed another
+   fine season with great stats.
+  
+     63 Home Runs
+     0.288 Batting Average
+  
+   What a year!
+ruby: | 
+  "Sammy Sosa completed another fine season with great stats.\n\n  63 Home Runs\n  0.288 Batting Average\n\nWhat a year!\n"
+python: |
+    [
+        flushLeft(
+        """
+        Sammy Sosa completed another fine season with great stats.
+
+          63 Home Runs
+          0.288 Batting Average
+
+        What a year!
+        """
+        )
+    ]
+
+
+---
+test: Indentation determines scope
+spec: C4
+yaml: |
+  name: Mark McGwire
+  accomplishment: >
+     Mark set a major league
+     home run record in 1998.
+  stats: |
+     65 Home Runs
+     0.278 Batting Average
+ruby: |
+  { 
+    'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n",
+    'stats' => "65 Home Runs\n0.278 Batting Average\n"
+  }
+python: |
+    [
+        {
+        'name': 'Mark McGwire',
+        'accomplishment': 
+            'Mark set a major league home run record in 1998.\n',
+        'stats': "65 Home Runs\n0.278 Batting Average\n"
+        }
+    ]
+
+---
+test: Quoted scalars
+spec: C5
+yaml: |
+  unicode: "Sosa did fine.\u263A"
+  control: "\b1998\t1999\t2000\n"
+  hexesc:  "\x0D\x0A is \r\n"
+  
+  single: '"Howdy!" he cried.'
+  quoted: ' # not a ''comment''.'
+  tie-fighter: '|\-*-/|'
+ruby: |
+  {
+    "tie-fighter" => "|\\-*-/|",
+    "control"=>"\0101998\t1999\t2000\n",
+    "unicode"=>"Sosa did fine." + ["263A".hex ].pack('U*'),
+    "quoted"=>" # not a 'comment'.",
+    "single"=>"\"Howdy!\" he cried.",
+    "hexesc"=>"\r\n is \r\n"
+  }
+python: |
+    [ {
+        'unicode': u"Sosa did fine.\u263A",
+        'control': "\b1998\t1999\t2000\n", 
+        'hexesc':  "\x0D\x0A is \r\n",
+        'single': '"Howdy!" he cried.',
+        'quoted': ' # not a \'comment\'.',
+        'tie-fighter': '|\-*-/|',
+    } ]
+
+
+---
+test: Multiline flow scalars
+spec: C6
+yaml: |
+  plain: This unquoted
+         scalar spans
+         many lines.
+  quoted: "\
+    So does this quoted
+    scalar.\n"
+ruby: |
+  { 
+    'plain' => 'This unquoted scalar spans many lines.',
+    'quoted' => "So does this quoted scalar.\n"
+  }
+python: |
+    [ {
+        'plain': 'This unquoted scalar spans many lines.',
+        'quoted': 'So does this quoted scalar.\n'
+      }
+    ]
+
+---
+test: Integers
+spec: D1
+yaml: |
+  canonical: 12345
+  decimal: +12,345
+  octal: 014
+  hexadecimal: 0xC
+ruby: |
+  { 
+    'canonical' => 12345, 
+    'decimal' => 12345, 
+    'octal' => '014'.oct, 
+    'hexadecimal' => '0xC'.hex 
+  }
+python: |
+    [ {
+        'canonical': 12345,
+        'decimal': 12345,
+        'octal': 014,
+        'hexadecimal': 0xC
+    } ]
+
+---
+test: Floating point
+spec: D2
+yaml: |
+  canonical: 1.23015e+3
+  exponential: 12.3015e+02
+  fixed: 1,230.15
+  negative infinity: (-inf)
+  not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+python: |
+    [ {
+        'canonical': 1.23015e+3,
+        'exponential': 1.23015e+3,
+        'fixed': 1230.15,
+        'negative infinity': '(-inf)',
+        'not a number': '(NaN)',
+    } ]
+
+---
+test: Miscellaneous
+spec: D3
+yaml: |
+  null: ~
+  true: +
+  false: -
+  string: '12345'
+ruby: | 
+  { 
+    'null' => nil, 
+    'true' => true, 
+    'false' => false, 
+    'string' => '12345' 
+  }
+python: |
+    [ {
+        'null': None,
+        'true': 1,
+        'false': 0,
+        'string': '12345',
+    } ]
+
+---
+test: Timestamps
+spec: D4
+yaml: |
+  canonical: 2001-12-15T02:59:43.1Z
+  iso8601:  2001-12-14t21:59:43.10-05:00
+  spaced:  2001-12-14 21:59:43.10 -05:00
+  date:   2002-12-14 # Time is noon UTC 
+ruby: |
+  {
+    'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+    'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'date' => Date.new( 2002, 12, 14 )
+  }
+---
+test: legacy Timestamps test
+spec: legacy D4
+yaml: |
+    canonical: 2001-12-15T02:59:43.00Z
+    iso8601:  2001-02-28t21:59:43.00-05:00
+    spaced:  2001-12-14 21:59:43.00 -05:00
+    date:   2002-12-14
+python: |
+    [ {
+        'canonical': yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'iso8601':   yaml.timestamp('2001-03-01T02:59:43.00Z'),
+        'spaced':    yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'date':      yaml.timestamp('2002-12-14T00:00:00.00Z')
+    } ]
+ruby: |
+   {
+     'canonical' => Time::utc( 2001, 12, 15, 2, 59, 43, 0 ),
+     'iso8601' => YAML::mktime( 2001, 2, 28, 21, 59, 43, 0, "-05:00" ),
+     'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0, "-05:00" ),
+     'date' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Various explicit families
+spec: D5
+yaml: |
+  not-date: !str 2002-04-28
+  picture: !binary|base64 |
+   R0lGODlhDAAMAIQAAP//9/X
+   17unp5WZmZgAAAOfn515eXv
+   Pz7Y6OjuDg4J+fn5OTk6enp
+   56enmleECcgggoBADs=
+  
+  hmm: !somewhere.com,2002/type |
+   family above is short for
+   tag:somewhere.com,2002:type
+
+ruby-setup: |
+  YAML.add_domain_type( "somewhere.com,2002", /^type$/ ) { |type, val|
+    return "SOMEWHERE: #{val}"
+  }
+ruby: |
+  { 
+    'not-date' => '2002-04-28',
+    'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 
+    'hmm' => "SOMEWHERE: family above is short for\ntag:somewhere.com,2002:type\n" 
+  }
+
+---
+test: Application specific family
+spec: D6
+yaml: |
+  --- !clarkevans.com,2002/graph/^shape
+  - !^circle
+    center: &ORIGIN {x: 73, y: 129}
+    radius: 7
+  - !^line # !clarkevans.com,2002/graph/line
+    start: *ORIGIN
+    finish: { x: 89, y: 102 }
+  - !^text
+    start: *ORIGIN
+    color: 0xFFEEBB
+    value: Pretty vector drawing.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/shape/ ) { |type, val|
+    if val.type == Array
+      val << "Shape Container"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  one_shape_proc = Proc.new { |type, val|
+    if val.is_a? Kernel::Hash
+      val['TYPE'] = "Shape: #{type}"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/circle/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/line/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/text/, &one_shape_proc )
+ruby: |
+  [
+    { 
+      "radius" => 7, 
+      "center"=>
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "TYPE" => "Shape: graph/circle"
+    }, {
+      "finish" => 
+      {
+        "x" => 89, 
+        "y" => 102
+      }, 
+      "TYPE" => "Shape: graph/line", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }
+    }, {
+      "TYPE" => "Shape: graph/text", 
+      "value" => "Pretty vector drawing.", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "color" => 16772795
+    }, 
+    "Shape Container"
+  ]
+
+---
+test: Invoice
+spec: E1
+yaml: |
+  --- !clarkevans.com,2002/^invoice
+  invoice: 34843
+  date   : 2001-01-23
+  bill-to: &id001
+    given  : Chris
+    family : Dumars
+    address:
+      lines: |
+        458 Walkman Dr.
+        Suite #292
+      city    : Royal Oak
+      state   : MI
+      postal  : 48046
+  ship-to: *id001
+  product:
+    - sku         : BL394D
+      quantity    : 4
+      description : Basketball
+      price       : 450.00
+    - sku         : BL4438H
+      quantity    : 1
+      description : Super Hoop
+      price       : 2392.00
+  tax  : 251.42
+  total: 4443.52
+  comments: >
+    Late afternoon is best.
+    Backup contact is Nancy
+    Billsmer @ 338-4338.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", "invoice" ) { |type, val| val }
+  id001 = { 'given' => 'Chris', 'family' => 'Dumars', 'address' =>
+  { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak',
+    'state' => 'MI', 'postal' => 48046 } }
+ruby: |
+  { 
+     'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+     'bill-to' => id001, 'ship-to' => id001, 'product' =>
+       [ { 'sku' => 'BL394D', 'quantity' => 4,
+           'description' => 'Basketball', 'price' => 450.00 },
+         { 'sku' => 'BL4438H', 'quantity' => 1,
+           'description' => 'Super Hoop', 'price' => 2392.00 } ],
+     'tax' => 251.42, 'total' => 4443.52,
+     'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }
+
+---
+test: Log file
+spec: E2
+yaml: |
+  ---
+  Time: 2001-11-23 15:01:42 -05:00
+  User: ed
+  Warning: >
+    This is an error message
+    for the log file
+  ---
+  Time: 2001-11-23 15:02:31 -05:00
+  User: ed
+  Warning: >
+    A slightly different error
+    message.
+  ---
+  Date: 2001-11-23 15:03:17 -05:00
+  User: ed
+  Fatal: >
+    Unknown variable "bar"
+  Stack:
+    - file: TopClass.py
+      line: 23
+      code: |
+        x = MoreObject("345\n")
+    - file: MoreClass.py
+      line: 58
+      code: |-
+        foo = bar
+ruby: |
+  y = Stream.new
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
+  y.add( { 'Date' => YAML::mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
+           'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
+           'Stack' => [
+           { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
+           { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
+documents: 3
+
+---
+test: Throwaway comments
+yaml: |
+   ### These are four throwaway comment  ###
+   
+   ### lines (the second line is empty). ###
+   this: |   # Comments may trail lines.
+      contains three lines of text.
+      The third one starts with a
+      # character. This isn't a comment.
+   
+   # These are three throwaway comment
+   # lines (the first line is empty).
+ruby: |
+   {
+     'this' => "contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"
+   }
+
+---
+test: Document with a single value
+yaml: |
+   --- >
+   This YAML stream contains a single text value.
+   The next stream is a log file - a sequence of
+   log entries. Adding an entry to the log is a
+   simple matter of appending it at the end.
+ruby: |
+   "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n"
+
+---
+test: Document stream
+yaml: |
+   ---
+   at: 2001-08-12 09:25:00.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/index.html'
+   ---
+   at: 2001-08-12 09:25:10.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/toc.html'
+ruby: |
+   y = Stream.new
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 00 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/index.html'
+   } )
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 10 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/toc.html'
+   } )
+documents: 2
+
+---
+test: Top level mapping
+yaml: |
+   # This stream is an example of a top-level mapping.
+   invoice : 34843
+   date    : 2001-01-23
+   total   : 4443.52
+ruby: |
+   {
+      'invoice' => 34843,
+      'date' => Date.new( 2001, 1, 23 ),
+      'total' => 4443.52
+   }
+
+---
+test: Single-line documents
+yaml: |
+  # The following is a sequence of three documents.
+  # The first contains an empty mapping, the second
+  # an empty sequence, and the last an empty string.
+  --- {}
+  --- [ ]
+  --- ''
+ruby: |
+  y = Stream.new
+  y.add( {} )
+  y.add( [] )
+  y.add( '' )
+documents: 3
+
+---
+test: Document with pause
+yaml: |
+  # A communication channel based on a YAML stream.
+  ---
+  sent at: 2002-06-06 11:46:25.10 Z
+  payload: Whatever
+  # Receiver can process this as soon as the following is sent:
+  ...
+  # Even if the next message is sent long after:
+  ---
+  sent at: 2002-06-06 12:05:53.47 Z
+  payload: Whatever
+  ...
+ruby: |
+  y = Stream.new
+  y.add(
+    { 'sent at' => YAML::mktime( 2002, 6, 6, 11, 46, 25, .10 ),
+      'payload' => 'Whatever' }
+  )
+  y.add( 
+    { "payload" => "Whatever", "sent at" => YAML::mktime( 2002, 6, 6, 12, 5, 53, .47 ) }
+  )
+  y.add( nil )
+documents: 3
+
+---
+test: Explicit typing
+yaml: |
+   integer: 12
+   also int: ! "12"
+   string: !str 12
+ruby: |
+   { 'integer' => 12, 'also int' => 12, 'string' => '12' }
+
+---
+test: Private types
+yaml: |
+  # Both examples below make use of the 'x-private:ball'
+  # type family URI, but with different semantics.
+  ---
+  pool: !!ball
+    number: 8
+    color: black
+  ---
+  bearing: !!ball
+    material: steel
+ruby: |
+  y = Stream.new
+  y.add( { 'pool' =>
+    PrivateType.new( 'ball',
+      { 'number' => 8, 'color' => 'black' } ) }
+  )
+  y.add( { 'bearing' => 
+    PrivateType.new( 'ball',
+      { 'material' => 'steel' } ) }
+  )
+documents: 2
+
+---
+test: Type family under yaml.org
+yaml: |
+  # The URI is 'tag:yaml.org,2002:str'
+  - !str a Unicode string
+python: |
+  [ [ 'a Unicode string' ] ]
+ruby: |
+  [ 'a Unicode string' ]
+
+---
+test: Type family under perl.yaml.org
+yaml: |
+  # The URI is 'tag:perl.yaml.org,2002:Text::Tabs'
+  - !perl/Text::Tabs {}
+ruby: |
+  DomainType.new( 'perl.yaml.org,2002', 'Text::Tabs', {} )
+
+---
+test: Type family under clarkevans.com
+yaml: |
+  # The URI is 'tag:clarkevans.com,2003-02:timesheet'
+  - !clarkevans.com,2003-02/timesheet
+ruby: |
+  DomainType.new( 'clarkevans.com,2003-02', 'timesheet', {} )
+
+---
+test: URI Escaping
+yaml: |
+  same:
+    - !domain.tld,2002/type%30%10 value
+    - !domain.tld,2002/type\0x30\n value
+  different: # As far as the YAML parser is concerned
+    - !domain.tld,2002/type0%10 value
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", "type%30%10" ) { |type, val|
+    "ONE: #{val}"
+  }
+  YAML.add_domain_type( "domain.tld,2002", "type0%10" ) { |type, val|
+    "TWO: #{val}"
+  }
+ruby: |
+  { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }
+
+---
+test: URI Prefixing
+yaml: |
+  # 'tag:domain.tld,2002:invoice' is some type family.
+  invoice: !domain.tld,2002/^invoice
+    # 'seq' is shorthand for 'tag:yaml.org,2002:seq'.
+    # This does not effect '^customer' below
+    # because it is does not specify a prefix.
+    customers: !seq
+      # '^customer' is shorthand for the full
+      # notation 'tag:domain.tld,2002:customer'.
+      - !^customer
+        given : Chris
+        family : Dumars
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", /(invoice|customer)/ ) { |type, val|
+    if val.is_a? Kernel::Hash
+      val['type'] = "domain #{type}"
+      return val
+    else
+      raise YAML::Error, "Not a Hash in domain.tld/invoice: " + val.inspect
+    end
+  }
+ruby: |
+  { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }
+
+---
+test: Overriding anchors
+yaml: |
+  anchor : &A001 This scalar has an anchor.
+  override : &A001 >
+   The alias node below is a
+   repeated use of this value.
+  alias : *A001
+ruby: |
+  { 'anchor' => 'This scalar has an anchor.', 
+    'override' => "The alias node below is a repeated use of this value.\n", 
+    'alias' => "The alias node below is a repeated use of this value.\n" }
+
+---
+test: Flow and block formatting
+yaml: |
+  empty: []
+  flow: [ one, two, three # May span lines,
+           , four,           # indentation is
+             five ]          # mostly ignored.
+  block:
+   - First item in top sequence
+   -
+    - Subordinate sequence entry
+   - >
+    A folded sequence entry
+   - Sixth item in top sequence
+ruby: |
+  { 'empty' => [], 'flow' => [ 'one', 'two', 'three', 'four', 'five' ],
+    'block' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
+    "A folded sequence entry\n", 'Sixth item in top sequence' ] }
+
+---
+test: Complete mapping test
+yaml: |
+ empty: {}
+ flow: { one: 1, two: 2 }
+ spanning: { one: 1,
+    two: 2 }
+ block:
+  first : First entry
+  second:
+   key: Subordinate mapping
+  third:
+   - Subordinate sequence
+   - { }
+   - Previous mapping is empty.
+   - A key: value pair in a sequence.
+     A second: key:value pair.
+   - The previous entry is equal to the following one.
+   -
+    A key: value pair in a sequence.
+    A second: key:value pair.
+  !float 12 : This key is a float.
+  ? >
+   ?
+  : This key had to be protected.
+  "\a" : This key had to be escaped.
+  ? >
+   This is a
+   multi-line
+   folded key
+  : Whose value is
+    also multi-line.
+  ? this also works as a key
+  : with a value at the next line.
+  ?
+   - This key
+   - is a sequence
+  :
+   - With a sequence value.
+  ?
+   This: key
+   is a: mapping
+  :
+   with a: mapping value.
+ruby: |
+  { 'empty' => {}, 'flow' => { 'one' => 1, 'two' => 2 },
+    'spanning' => { 'one' => 1, 'two' => 2 },
+    'block' => { 'first' => 'First entry', 'second' =>
+    { 'key' => 'Subordinate mapping' }, 'third' =>
+      [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
+        'The previous entry is equal to the following one.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
+    12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
+    "\a" => 'This key had to be escaped.',
+    "This is a multi-line folded key\n" => "Whose value is also multi-line.",
+    'this also works as a key' => 'with a value at the next line.',
+    [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }
+  # Couldn't recreate map exactly, so we'll do a detailed check to be sure it's entact
+  obj_y['block'].keys.each { |k|
+    if k.type == Hash
+      v = obj_y['block'][k]
+      if k['This'] == 'key' and k['is a'] == 'mapping' and v['with a'] == 'mapping value.'
+         obj_r['block'][k] = v
+      end
+    end
+  }
+no-round-trip:
+  - ruby
+
+---
+test: Literal explicit indentation
+yaml: |
+   # Explicit indentation must
+   # be given in all the three
+   # following cases.
+   leading spaces: |2
+         This value starts with four spaces.
+   
+   leading line break: |2
+   
+     This value starts with a line break.
+   
+   leading comment indicator: |2
+     # first line starts with a
+     # character.
+   
+   # Explicit indentation may
+   # also be given when it is
+   # not required.
+   redundant: |2
+     This value is indented 2 spaces.
+ruby: |
+   {
+      'leading spaces' => "    This value starts with four spaces.\n",
+      'leading line break' => "\nThis value starts with a line break.\n",
+      'leading comment indicator' => "# first line starts with a\n# character.\n",
+      'redundant' => "This value is indented 2 spaces.\n"
+   }
+
+---
+test: Chomping and keep modifiers
+yaml: |
+    clipped: |
+        This has one newline.
+    
+    same as "clipped" above: "This has one newline.\n"
+    
+    stripped: |-
+        This has no newline.
+    
+    same as "stripped" above: "This has no newline."
+    
+    kept: |+
+        This has two newlines.
+    
+    same as "kept" above: "This has two newlines.\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has two newlines.\n\n",
+      'same as "kept" above' => "This has two newlines.\n\n"
+    }
+
+---
+test: Literal combinations
+yaml: |
+   empty: |
+   
+   literal: |
+    The \ ' " characters may be
+    freely used. Leading white
+       space is significant.
+    
+    Line breaks are significant.
+    Thus this value contains one
+    empty line and ends with a
+    single line break, but does
+    not start with one.
+    
+   is equal to: "The \\ ' \" characters may \
+    be\nfreely used. Leading white\n   space \
+    is significant.\n\nLine breaks are \
+    significant.\nThus this value contains \
+    one\nempty line and ends with a\nsingle \
+    line break, but does\nnot start with one.\n"
+   
+   # Comments may follow a block
+   # scalar value. They must be
+   # less indented.
+   
+   # Modifiers may be combined in any order.
+   indented and chomped: |2-
+       This has no newline.
+   
+   also written as: |-2
+       This has no newline.
+   
+   both are equal to: "  This has no newline."
+ruby: |
+   {
+     'empty' => '',
+     'literal' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'is equal to' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'indented and chomped' => '  This has no newline.',
+     'also written as' => '  This has no newline.',
+     'both are equal to' => '  This has no newline.'
+   }
+
+---
+test: Folded combinations
+yaml: |
+   empty: >
+   
+   one paragraph: >
+    Line feeds are converted
+    to spaces, so this value
+    contains no line breaks
+    except for the final one.
+   
+   multiple paragraphs: >2
+   
+     An empty line, either
+     at the start or in
+     the value:
+   
+     Is interpreted as a
+     line break. Thus this
+     value contains three
+     line breaks.
+   
+   indented text: >
+       This is a folded
+       paragraph followed
+       by a list:
+        * first entry
+        * second entry
+       Followed by another
+       folded paragraph,
+       another list:
+   
+        * first entry
+   
+        * second entry
+    
+       And a final folded
+       paragraph.
+   
+   above is equal to: |
+       This is a folded paragraph followed by a list:
+        * first entry
+        * second entry
+       Followed by another folded paragraph, another list:
+   
+        * first entry
+
+        * second entry
+    
+       And a final folded paragraph.
+   
+   # Explicit comments may follow
+   # but must be less indented.
+ruby: |
+   {
+     'empty' => '',
+     'one paragraph' => 'Line feeds are converted to spaces, so this value' +
+       " contains no line breaks except for the final one.\n",
+     'multiple paragraphs' => "\nAn empty line, either at the start or in the value:\n" +
+       "Is interpreted as a line break. Thus this value contains three line breaks.\n",
+     'indented text' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n",
+     'above is equal to' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n"
+   }
+
+---
+test: Single quotes
+yaml: |
+   empty: ''
+   second: '! : \ etc. can be used freely.'
+   third: 'a single quote '' must be escaped.'
+   span: 'this contains
+         six spaces
+   
+         and one
+         line break'
+   is same as: "this contains six spaces\nand one line break"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : \\ etc. can be used freely.',
+     'third' => "a single quote ' must be escaped.",
+     'span' => "this contains six spaces\nand one line break",
+     'is same as' => "this contains six spaces\nand one line break"
+   }
+
+---
+test: Double quotes
+yaml: |
+   empty: ""
+   second: "! : etc. can be used freely."
+   third: "a \" or a \\ must be escaped."
+   fourth: "this value ends with an LF.\n"
+   span: "this contains
+     four  \
+         spaces"
+   is equal to: "this contains four  spaces"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : etc. can be used freely.',
+     'third' => 'a " or a \\ must be escaped.',
+     'fourth' => "this value ends with an LF.\n",
+     'span' => "this contains four  spaces",
+     'is equal to' => "this contains four  spaces"
+   }
+
+---
+test: Unquoted strings
+yaml: |
+   first: There is no unquoted empty string.
+   
+   second: 12          ## This is an integer.
+   
+   boolean: -          ## This is (false).
+   
+   third: !str 12      ## This is a string.
+   
+   span: this contains
+         six spaces
+   
+         and one
+         line break
+   
+   indicators: this has no comments.
+               #:foo and bar# are
+               both text.
+   
+   flow: [ can span
+              lines, # comment
+              like
+              this ]
+   
+   note: { one-line keys: but
+           multi-line values }
+   
+ruby: |
+   {
+     'first' => 'There is no unquoted empty string.',
+     'second' => 12,
+     'boolean' => false,
+     'third' => '12',
+     'span' => "this contains six spaces\nand one line break",
+     'indicators' => "this has no comments. #:foo and bar# are both text.",
+     'flow' => [ 'can span lines', 'like this' ],
+     'note' => { 'one-line keys' => 'but multi-line values' }
+   }
+
+---
+test: Spanning sequences
+yaml: |
+   # The following are equal seqs
+   # with different identities.
+   flow: [ one, two ]
+   spanning: [ one,
+        two ]
+   block:
+     - one
+     - two
+ruby: |
+   {
+     'flow' => [ 'one', 'two' ],
+     'spanning' => [ 'one', 'two' ],
+     'block' => [ 'one', 'two' ]
+   }
+
+---
+test: Flow mappings
+yaml: |
+   # The following are equal maps
+   # with different identities.
+   flow: { one: 1, two: 2 }
+   block:
+       one: 1
+       two: 2
+ruby: |
+   {
+     'flow' => { 'one' => 1, 'two' => 2 },
+     'block' => { 'one' => 1, 'two' => 2 }
+   }
+
+---
+test: Representations of 12
+yaml: |
+   - 12 # An integer
+   # The following scalars
+   # are loaded to the
+   # string value '1' '2'.
+   - !str 12
+   - '12'
+   - "12"
+   - "\
+    1\
+    2\
+    "
+   # Strings containing paths and regexps can be unquoted:
+   - /foo/bar
+   - d:/foo/bar
+   - foo/bar
+   - /a.*b/
+ruby: |
+   [ 12, '12', '12', '12', '12', '/foo/bar', 'd:/foo/bar', 'foo/bar', '/a.*b/' ]
+
+---
+test: Null
+yaml: |
+   canonical: ~
+   
+   english: (null)
+   
+   # This sequence has four
+   # entries, two with values.
+   sparse:
+     - ~
+     - 2nd entry
+     - (nil)
+     - 4th entry
+   
+   four: This mapping has four keys,
+         only two with values.
+ruby: |
+   {
+     'canonical' => nil,
+     'english' => nil,
+     'sparse' => [ nil, '2nd entry', nil, '4th entry' ],
+     'four' => 'This mapping has four keys, only two with values.'
+   }
+
+---
+test: Boolean
+yaml: |
+   - : used as key  # Does not indicate a sequence.
+   canonical: +
+   logical:  (true)
+   informal: (no)
+ruby: |
+   {
+     false => 'used as key',
+     'canonical' => true,
+     'logical' => true,
+     'informal' => false
+   }
+
+---
+test: Integer
+yaml: |
+   canonical: 12345
+   decimal: +12,345
+   octal: 014
+   hexadecimal: 0xC
+ruby: |
+   {
+     'canonical' => 12345,
+     'decimal' => 12345,
+     'octal' => 12,
+     'hexadecimal' => 12 
+   }
+
+---
+test: Float
+yaml: |
+   canonical: 1.23015e+3
+   exponential: 12.3015e+02
+   fixed: 1,230.15
+   negative infinity: (-inf)
+   not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+no-round-trip:
+  - ruby
+
+---
+test: Timestamp
+yaml: |
+   canonical:       2001-12-15T02:59:43.1Z
+   valid iso8601:   2001-12-14t21:59:43.10-05:00
+   space separated: 2001-12-14 21:59:43.10 -05:00
+   date (noon UTC): 2002-12-14
+ruby: |
+   {
+     'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+     'valid iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'space separated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'date (noon UTC)' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Binary
+yaml: |
+   canonical: !binary "\
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf\
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW\
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++\
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg\
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN\
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww\
+    EeECcgggoBADs="
+   base64: !binary |
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww
+    EeECcgggoBADs=
+   description: >
+    The binary value above is a tiny arrow
+    encoded as a gif image.
+ruby-setup: |
+   arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005,  \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
+ruby: |
+   {
+     'canonical' => arrow_gif,
+     'base64' => arrow_gif,
+     'description' => "The binary value above is a tiny arrow encoded as a gif image.\n"
+   }
+
+---
+test: Default key
+yaml: |
+   ---     # Old schema
+   link with: 
+     - library1.dll
+     - library2.dll
+   ---     # New schema
+   link with:
+     - = : library1.dll
+       version: 1.2
+     - = : library2.dll
+       version: 2.3
+ruby: |
+   y = Stream.new
+   y.add( { 'link with' => [ 'library1.dll', 'library2.dll' ] } )
+   obj_h = YAML::SpecialHash[ 'version' => 1.2 ]
+   obj_h.default = 'library1.dll'
+   obj_h2 = YAML::SpecialHash[ 'version' => 2.3 ]
+   obj_h2.default = 'library2.dll'
+   y.add( { 'link with' => [ obj_h, obj_h2 ] } )
+documents: 2
+
+---
+test: Special keys
+yaml: |
+   "!": These three keys
+   "&": had to be quoted
+   "=": and are normal strings.
+   # NOTE: the following node should NOT be serialized this way.
+   encoded node :
+    !special '!' : '!type'
+    !special|canonical '&' : 12
+    = : value
+   # The proper way to serialize the above node is as follows:
+   node : !!type &12 value
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/docSep.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/docSep.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/docSep.yml	(revision 71)
@@ -0,0 +1,103 @@
+--- #YAML:1.0
+test: Trailing Document Separator
+brief: >
+    You can separate YAML documents
+    with a string of three dashes.
+yaml: |
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: Leading Document Separator
+brief: >
+    You can explicity give an opening
+    document separator to your YAML stream.
+yaml: |
+    ---
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: YAML Header
+brief: >
+    The opening separator can contain directives
+    to the YAML parser, such as the version
+    number.
+yaml: |
+    --- #YAML:1.0
+    foo: 1
+    bar: 2
+python: |
+    [
+        { 'foo': 1, 'bar': 2 }
+    ]
+ruby: |
+    y = Stream.new
+    y.add( { 'foo' => 1, 'bar' => 2 } )
+documents: 1
+
+---
+test: Red Herring Document Separator
+brief: >
+    Separators included in blocks or strings
+    are treated as blocks or strings, as the
+    document separator should have no indentation
+    preceding it.
+yaml: |
+    foo: |
+        ---
+python: |
+    [
+        { 'foo': "---\n" }
+    ]
+ruby: |
+    { 'foo' => "---\n" }
+
+---
+test: Multiple Document Separators in Block
+brief: >
+    This technique allows you to embed other YAML
+    documents within literal blocks.
+yaml: |
+    foo: |
+        ---
+        foo: bar
+        ---
+        yo: baz
+    bar: |
+        fooness
+python: |
+    [
+        {  'foo': flushLeft("""
+            ---
+            foo: bar
+            ---
+            yo: baz
+            """),
+           'bar': "fooness\n"
+        }
+    ]
+ruby: |
+    {  
+       'foo' => "---\nfoo: bar\n---\nyo: baz\n",
+       'bar' => "fooness\n"
+    }
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/basic.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/basic.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/basic.yml	(revision 71)
@@ -0,0 +1,242 @@
+--- #YAML:1.0
+test: Simple Sequence
+brief: >
+    You can specify a list in YAML by placing each
+    member of the list on a new line with an opening
+    dash. These lists are called sequences.
+yaml: |
+    - apple
+    - banana
+    - carrot
+perl: |
+    ['apple', 'banana', 'carrot'] 
+python: |
+    [ 
+        ['apple', 'banana', 'carrot'] 
+    ]
+ruby: |
+    ['apple', 'banana', 'carrot'] 
+
+---
+test: Nested Sequences
+brief: >
+    You can include a sequence within another
+    sequence by giving the sequence an empty
+    dash, followed by an indented list.
+yaml: |
+    -
+     - foo
+     - bar
+     - baz
+perl: |
+    [['foo', 'bar', 'baz']]
+python: |
+    [
+        [['foo', 'bar', 'baz']]
+    ]
+ruby: |
+    [['foo', 'bar', 'baz']]
+
+---
+test: Mixed Sequences
+brief: >
+    Sequences can contain any YAML data,
+    including strings and other sequences.
+yaml: |
+    - apple
+    -
+     - foo
+     - bar
+     - x123
+    - banana
+    - carrot
+perl: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+python: |
+    [
+        ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+    ]
+ruby: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+
+---
+test: Deeply Nested Sequences
+brief: >
+    Sequences can be nested even deeper, with each
+    level of indentation representing a level of
+    depth.
+yaml: |
+    -
+     -
+      - uno
+      - dos
+perl: |
+    [[['uno', 'dos']]]
+python: |
+    [
+        [[['uno', 'dos']]]
+    ]
+ruby: |
+    [[['uno', 'dos']]]
+
+---
+test: Simple Mapping
+brief: >
+    You can add a keyed list (also known as a dictionary or
+    hash) to your document by placing each member of the
+    list on a new line, with a colon seperating the key
+    from its value.  In YAML, this type of list is called
+    a mapping.
+yaml: |
+    foo: whatever
+    bar: stuff
+perl: |
+    { foo => 'whatever', bar => 'stuff' }
+python: |
+    [
+        {'foo': 'whatever', 'bar': 'stuff'}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => 'stuff' }
+
+---
+test: Sequence in a Mapping
+brief: >
+    A value in a mapping can be a sequence.
+yaml: |
+    foo: whatever
+    bar:
+     - uno
+     - dos
+perl: |
+    { foo => 'whatever', bar => [ 'uno', 'dos' ] }
+python: |
+    [
+        {'foo': 'whatever', 'bar': ['uno', 'dos']}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => [ 'uno', 'dos' ] }
+
+---
+test: Nested Mappings
+yaml: |
+    foo: whatever
+    bar:
+     fruit: apple
+     name: steve
+     sport: baseball
+brief: >
+    A value in a mapping can be another mapping.
+perl: |
+    { foo => 'whatever', 
+      bar => {
+         fruit => 'apple', 
+         name => 'steve',
+         sport => 'baseball'
+       }
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': {
+            'fruit': 'apple', 
+            'name': 'steve',
+            'sport': 'baseball'
+            }
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => {
+         'fruit' => 'apple', 
+         'name' => 'steve',
+         'sport' => 'baseball'
+       }
+    }
+
+---
+test: Mixed Mapping
+brief: >
+    A mapping can contain any assortment
+    of mappings and sequences as values.
+yaml: |
+    foo: whatever
+    bar:
+     -
+      fruit: apple
+      name: steve
+      sport: baseball
+     - more
+     -
+      python: rocks
+      perl: papers
+      ruby: scissorses
+perl: |
+    { foo => 'whatever', 
+      bar => [
+        {
+            fruit => 'apple', 
+            name => 'steve',
+            sport => 'baseball'
+        },
+        'more',
+        {
+            python => 'rocks',
+            perl => 'papers',
+            ruby => 'scissorses'
+        }
+      ]
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': [
+            {
+                'fruit': 'apple', 
+                'name': 'steve',
+                'sport': 'baseball'
+            },
+            'more',
+            {
+                'python': 'rocks',
+                'perl':  'papers',
+                'ruby': 'scissorses'
+            }
+         ]
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => [
+        {
+            'fruit' => 'apple', 
+            'name' => 'steve',
+            'sport' => 'baseball'
+        },
+        'more',
+        {
+            'python' => 'rocks',
+            'perl' => 'papers',
+            'ruby' => 'scissorses'
+        }
+      ]
+    }
+
+---
+test: Sequence-Mapping Shortcut
+brief: >
+     If you are adding a mapping to a sequence, you
+     can place the mapping on the same line as the
+     dash as a shortcut.
+yaml: |
+     - work on YAML.py:
+        - work on Store
+perl: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+python: |
+    [
+        [ {'work on YAML.py': ['work on Store']} ]
+    ]
+ruby: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ruby.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ruby.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ruby.yml	(revision 71)
@@ -0,0 +1,222 @@
+--- #YAML:1.0
+test: Symbols
+brief: >
+    Ruby Symbols can be simply serialized using
+    the !ruby/symbol transfer method, or the
+    abbreviated !ruby/sym.
+yaml: |
+    simple symbol: !ruby/symbol Simple
+    shortcut syntax: !ruby/sym Simple
+    symbols in seqs:
+      - !ruby/symbol ValOne
+      - !ruby/symbol ValTwo
+      - !ruby/symbol ValThree
+    symbols in maps:
+      !ruby/symbol MapKey: !ruby/symbol MapValue
+ruby: |
+    { 'simple symbol' => :Simple,
+      'shortcut syntax' => :Simple,
+      'symbols in seqs' => [ :ValOne, :ValTwo, :ValThree ],
+      'symbols in maps' => { :MapKey => :MapValue }
+    }
+
+---
+test: Ranges
+brief: >
+    Ranges are serialized with the !ruby/range
+    type family.
+yaml: |
+    normal range: !ruby/range 10..20
+    exclusive range: !ruby/range 11...20
+    negative range: !ruby/range -1..-5
+    ? !ruby/range 0..40
+    : range as a map key
+ruby: |
+    { 'normal range' => (10..20),
+      'exclusive range' => (11...20),
+      'negative range' => (-1..-5),
+      (0..40) => 'range as a map key'
+    }
+
+---
+test: Regexps
+brief: >
+    Regexps may be serialized to YAML, both its
+    syntax and any modifiers.
+yaml: |
+    case-insensitive: !ruby/regexp "/George McFly/i"
+    complex: !ruby/regexp "/\\A\"((?:[^\"]|\\\")+)\"/"
+    simple: !ruby/regexp '/a.b/'
+ruby: |
+    { 'simple' => /a.b/, 'complex' => /\A"((?:[^"]|\")+)"/,
+      'case-insensitive' => /George McFly/i }
+
+---
+test: Perl Regexps
+brief: >
+    Regexps may also be imported from serialized
+    Perl.
+yaml: |
+    --- !perl/regexp:
+      REGEXP: "R[Uu][Bb][Yy]$"
+      MODIFIERS: i
+ruby: |
+    /R[Uu][Bb][Yy]$/i
+
+---
+test: Struct class
+brief: >
+    The Ruby Struct class is registered as a YAML
+    builtin type through Ruby, so it can safely 
+    be serialized.  To use it, first make sure you
+    define your Struct with Struct::new.  Then,
+    you are able to serialize with Struct#to_yaml
+    and unserialize from a YAML stream.
+yaml: |
+    --- !ruby/struct:BookStruct
+      author: Yukihiro Matsumoto
+      title: Ruby in a Nutshell
+      year: 2002
+      isbn: 0-596-00214-9
+ruby-setup: |
+    book_struct = Struct::new( "BookStruct", :author, :title, :year, :isbn )
+ruby: |
+    book_struct.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" )
+
+---
+test: Nested Structs
+brief: >
+    As with other YAML builtins, you may nest the
+    Struct inside of other Structs or other data
+    types.
+yaml: |
+    - !ruby/struct:FoodStruct
+      name: Nachos
+      ingredients:
+        - Mission Chips
+        - !ruby/struct:FoodStruct
+          name: Tostitos Nacho Cheese
+          ingredients:
+            - Milk and Enzymes
+            - Jack Cheese
+            - Some Volatile Chemicals
+          taste: Angelic
+        - Sour Cream
+      taste: Zesty
+    - !ruby/struct:FoodStruct
+      name: Banana Cream Pie
+      ingredients:
+        - Bananas
+        - Creamy Stuff
+        - And Such
+      taste: Puffy
+ruby-setup: |
+    food_struct = Struct::new( "FoodStruct", :name, :ingredients, :taste )
+ruby: |
+    [
+      food_struct.new( 'Nachos', [ 'Mission Chips',
+        food_struct.new( 'Tostitos Nacho Cheese', [ 'Milk and Enzymes', 'Jack Cheese', 'Some Volatile Chemicals' ], 'Angelic' ),
+        'Sour Cream' ], 'Zesty' ),
+      food_struct.new( 'Banana Cream Pie', [ 'Bananas', 'Creamy Stuff', 'And Such' ], 'Puffy' )
+    ]
+
+---
+test: Objects
+brief: >
+    YAML has generic support for serializing objects
+    from any class available in Ruby.  If using the
+    generic object serialization, no extra code is
+    needed.
+yaml: |
+    --- !ruby/object:YAML::Zoolander
+      name: Derek
+      look: Blue Steel
+ruby-setup: |
+    class Zoolander
+      attr_accessor :name, :look
+      def initialize( look )
+        @name = "Derek"
+        @look = look
+      end
+      def ==( z )
+        self.name == z.name and self.look == z.look
+      end
+    end
+ruby: |
+    Zoolander.new( "Blue Steel" )
+
+---
+test: Extending Kernel::Array
+brief: > 
+    When extending the Array class, your instances
+    of such a class will dump as YAML sequences,
+    tagged with a class name.
+yaml: |
+    --- !ruby/array:YAML::MyArray
+    - jacket
+    - sweater
+    - windbreaker
+ruby-setup: |
+    class MyArray < Kernel::Array; end
+ruby: |
+    outerwear = MyArray.new
+    outerwear << 'jacket'
+    outerwear << 'sweater'
+    outerwear << 'windbreaker'
+    outerwear
+
+---
+test: Extending Kernel::Hash
+brief: >
+    When extending the Hash class, your instances
+    of such a class will dump as YAML maps, tagged
+    with a class name.
+yaml: |
+    --- !ruby/hash:YAML::MyHash
+    Black Francis: Frank Black
+    Kim Deal: Breeders
+    Joey Santiago: Martinis
+ruby-setup: |
+    # Note that the @me attribute isn't dumped
+    # because the default to_yaml is trained
+    # to dump as a regular Hash.
+    class MyHash < Kernel::Hash
+      attr_accessor :me
+      def initialize
+        @me = "Why"
+      end
+    end
+ruby: |
+    pixies = MyHash.new
+    pixies['Black Francis'] = 'Frank Black'
+    pixies['Kim Deal'] = 'Breeders'
+    pixies['Joey Santiago'] = 'Martinis'
+    pixies
+
+---
+test: YAML::Pairs
+brief: >
+    The sequence-mapping shortcut in YAML allows you to 
+    place the first line of the mapping on the same line 
+    as the dash for the entry containing the mapping. 
+    The !ruby/pairs type takes advantage of this shortcut 
+    to create (instead of a sequence including maps) a 
+    single object of pairs which can be accessed like an 
+    ordered hash. Entries in which the last value in the 
+    pair is null can simply show the first value in the pair.
+yaml: |
+    --- !ruby/pairs
+    - Minh Thai: 22.95
+    - Guus Razous-Schultz: 24.32
+    - Zoltan Labas Hungary: 24.49
+    - Lars Petrus
+    - Ken`ichi Ueno Japan
+ruby: |
+    winners = YAML::Pairs.new
+    winners[ 'Minh Thai' ] = 22.95
+    winners[ 'Guus Razous-Schultz' ] = 24.32
+    winners[ 'Zoltan Labas Hungary' ] = 24.49
+    winners[ 'Lars Petrus' ] = nil
+    winners[ 'Ken`ichi Ueno Japan' ] = nil
+    winners
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/foldedScalar.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/foldedScalar.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/foldedScalar.yml	(revision 71)
@@ -0,0 +1,216 @@
+--- #YAML:1.0
+test: Single ending newline
+brief: >
+    A pipe character, followed by an indented
+    block of text is treated as a literal
+    block, in which newlines are preserved
+    throughout the block, including the final
+    newline.
+yaml: |
+    ---
+    this: |
+        Foo
+        Bar
+
+ruby: |
+    { 'this' => "Foo\nBar\n" }
+python: |
+    [ 
+        { 'this': "Foo\nBar\n" }
+    ]
+---
+test: The '+' indicator
+brief: >
+    The '+' indicator says to keep newlines at the end of text
+    blocks.
+yaml: |
+    normal: |
+      extra new lines not kept
+
+    preserving: |+
+      extra new lines are kept
+
+
+    dummy: value
+ruby: |
+    {
+        'normal' => "extra new lines not kept\n",
+        'preserving' => "extra new lines are kept\n\n\n",
+        'dummy' => 'value'
+    }
+python: |
+    [ {
+        'normal': "extra new lines not kept\n",
+        'preserving': "extra new lines are kept\n\n\n",
+        'dummy': 'value'
+    } ]
+---
+test: Three trailing newlines in literals
+brief: >
+    To give you more control over how space
+    is preserved in text blocks, YAML has
+    the keep '+' and chomp '-' indicators.
+    The keep indicator will preserve all
+    ending newlines, while the chomp indicator
+    will strip all ending newlines.
+yaml: |
+    clipped: |
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: |-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: |+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+not_yet_in_python: |
+    [
+    { 
+      'clipped': "This has one newline.\n",
+      'same as "clipped" above': "This has one newline.\n",
+      'stripped': 'This has no newline.',
+      'same as "stripped" above': 'This has no newline.',
+      'kept': "This has four newlines.\n\n\n\n",
+      'same as "kept" above': "This has four newlines.\n\n\n\n"
+    }
+    ]
+
+---
+test: Extra trailing newlines with spaces
+brief: >
+    Normally, only a single newline is kept
+    from the end of a literal block, unless the
+    keep '+' character is used in combination
+    with the pipe.  The following example
+    will preserve all ending whitespace
+    since the last line of both literal blocks
+    contains spaces which extend past the indentation
+    level.
+yaml: |
+    ---
+    this: |
+        Foo
+
+          
+    kept: |+
+        Foo
+
+          
+ruby: |
+    { 'this' => "Foo\n\n  \n", 
+      'kept' => "Foo\n\n  \n" }
+
+---
+test: Folded Block in a Sequence
+brief: >
+    A greater-then character, followed by an indented
+    block of text is treated as a folded block, in
+    which lines of text separated by a single newline
+    are concatenated as a single line.
+yaml: |
+    ---
+    - apple
+    - banana
+    - >
+        can't you see
+        the beauty of yaml?
+        hmm
+    - dog
+python: |
+    [
+        [
+            'apple', 
+            'banana', 
+            "can't you see the beauty of yaml? hmm\n",
+            'dog'
+        ]
+    ]
+ruby: |
+    [
+        'apple', 
+        'banana', 
+        "can't you see the beauty of yaml? hmm\n",
+        'dog'
+    ]
+---
+test: Folded Block as a Mapping Value
+brief: >
+    Both literal and folded blocks can be
+    used in collections, as values in a 
+    sequence or a mapping.
+yaml: |
+    --- 
+    quote: >
+        Mark McGwire's
+        year was crippled
+        by a knee injury.
+    source: espn
+python: |
+    [
+        { 
+            'quote': "Mark McGwire's year was crippled by a knee injury.\n",
+            'source': 'espn'
+        }
+    ]
+ruby: |
+    { 
+        'quote' => "Mark McGwire's year was crippled by a knee injury.\n",
+        'source' => 'espn'
+    }
+
+---
+test: Three trailing newlines in folded blocks
+brief: >
+    The keep and chomp indicators can also
+    be applied to folded blocks.
+yaml: |
+    clipped: >
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: >-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: >+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/types.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/types.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/types.yml	(revision 71)
@@ -0,0 +1,239 @@
+--- #YAML:1.0
+test: Strings
+brief: >
+    Any group of characters beginning with an
+    alphabetic or numeric character is a string,
+    unless it belongs to one of the groups below
+    (such as an Integer or Time).  
+yaml: |
+    String
+ruby: |
+    'String'
+
+---
+test: String characters
+brief: >
+    A string can contain any alphabetic or
+    numeric character, along with many
+    punctuation characters, including the
+    period, dash, space, quotes, exclamation, and
+    question mark.
+yaml: |
+    - What's Yaml?
+    - It's for writing data structures in plain text.
+    - And?
+    - And what? That's not good enough for you?
+    - No, I mean, "And what about Yaml?"
+    - Oh, oh yeah. Uh.. Yaml for Ruby.
+ruby: |
+    [
+      "What's Yaml?",
+      "It's for writing data structures in plain text.",
+      "And?",
+      "And what? That's not good enough for you?",
+      "No, I mean, \"And what about Yaml?\"",
+      "Oh, oh yeah. Uh.. Yaml for Ruby."
+    ]
+
+---
+test: Indicators in Strings
+brief: >
+    Be careful using indicators in strings.  In particular,
+    the comma, colon, and pound sign must be used carefully.
+yaml: |
+    the colon followed by space is an indicator: but is a string:right here
+    same for the pound sign: here we have it#in a string
+    the comma can, honestly, be used in most cases: [ but not in, inline collections ]
+ruby: |
+    {
+      'the colon followed by space is an indicator' => 'but is a string:right here',
+      'same for the pound sign' => 'here we have it#in a string',
+      'the comma can, honestly, be used in most cases' => [ 'but not in', 'inline collections' ]
+    }
+
+---
+test: Forcing Strings
+brief: >
+    Any YAML type can be forced into a string using the
+    explicit !str method.
+yaml: |
+    date string: !str 2001-08-01
+    number string: !str 192
+ruby: |
+    {
+      'date string' => '2001-08-01',
+      'number string' => '192'
+    }
+
+---
+test: Single-quoted Strings
+brief: >
+    You can also enclose your strings within single quotes,
+    which allows use of slashes, colons, and other indicators
+    freely.  Inside single quotes, you can represent a single
+    quote in your string by using two single quotes next to
+    each other.
+yaml: |
+    all my favorite symbols: '#:!/%.)'
+    a few i hate: '&(*'
+    why do i hate them?: 'it''s very hard to explain'
+ruby: |
+    {
+      'all my favorite symbols' => '#:!/%.)',
+      'a few i hate' => '&(*',
+      'why do i hate them?' => 'it\'s very hard to explain'
+    }
+
+---
+test: Double-quoted Strings
+brief: >
+    Enclosing strings in double quotes allows you
+    to use escapings to represent ASCII and
+    Unicode characters.
+yaml: |
+    i know where i want my line breaks: "one here\nand another here\n"
+ruby: |
+    {
+      'i know where i want my line breaks' => "one here\nand another here\n"
+    }
+
+---
+test: Multi-line Quoted Strings
+brief: >
+    Both single- and double-quoted strings may be
+    carried on to new lines in your YAML document.
+    They must be indented a step and indentation
+    is interpreted as a single space.
+yaml: |
+    i want a long string: "so i'm going to
+      let it go on and on to other lines
+      until i end it with a quote."
+ruby: |
+    { 'i want a long string' => "so i'm going to " +
+         "let it go on and on to other lines " +
+         "until i end it with a quote."
+    }
+
+---
+test: Null
+brief: >
+    You can use the tilde '~' character for a null value.
+yaml: |
+    name: Mr. Show
+    hosted by: Bob and David
+    date of next season: ~
+ruby: |
+    {
+      'name' => 'Mr. Show',
+      'hosted by' => 'Bob and David',
+      'date of next season' => nil
+    }
+
+---
+test: Boolean
+brief: >
+    You can use the plus sign '+' and the negative
+    sign '-' for True and False.
+yaml: |
+    Is Gus a Liar?: +
+    Do I rely on Gus for Sustenance?: -
+ruby: |
+    {
+      'Is Gus a Liar?' => true,
+      'Do I rely on Gus for Sustenance?' => false
+    }
+
+---
+test: Integers
+brief: >
+    An integer is a series of numbers, optionally
+    starting with a positive or negative sign.  Integers
+    may also contain commas for readability.
+yaml: |
+    zero: 0
+    simple: 12
+    one-thousand: 1,000
+    negative one-thousand: -1,000
+ruby: |
+    {
+      'zero' => 0,
+      'simple' => 12,
+      'one-thousand' => 1000,
+      'negative one-thousand' => -1000
+    }
+python: |
+    [ 
+        {
+            'zero': 0,
+            'simple': 12,
+            'one-thousand': 1000,
+            'negative one-thousand': -1000,
+        }
+    ]
+---
+test: Integers as Map Keys
+brief: >
+    An integer can be used a dictionary key.
+yaml: |
+    1: one
+    2: two
+    3: three
+python: |
+    [
+        {
+            1: 'one',
+            2: 'two',
+            3: 'three',
+        }
+    ]       
+ruby: |
+    {
+        1 => 'one',
+        2 => 'two',
+        3 => 'three'
+    }
+
+---
+test: Floats
+brief: >
+     Floats are represented by numbers with decimals,
+     allowing for scientific notation, as well as
+     positive and negative infinity and "not a number."
+yaml: |
+     a simple float: 2.00
+     larger float: 1,000.09
+     scientific notation: 1.00009e+3
+ruby: |
+     {
+       'a simple float' => 2.0,
+       'larger float' => 1000.09,
+       'scientific notation' => 1000.09
+     }
+
+---
+test: Time
+brief: >
+    You can represent timestamps by using
+    ISO8601 format, or a variation which
+    allows spaces between the date, time and
+    time zone.
+yaml: |
+    iso8601: 2001-12-14t21:59:43.10-05:00
+    space seperated: 2001-12-14 21:59:43.10 -05:00
+ruby: |
+    {
+      'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+      'space seperated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" )
+    }
+
+---
+test: Date
+brief: >
+    A date can be represented by its year,
+    month and day in ISO8601 order.
+yaml: |
+    1976-07-31
+ruby: |
+    Date.new( 1976, 7, 31 )
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ypath.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ypath.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/ypath.yml	(revision 71)
@@ -0,0 +1,221 @@
+data:
+  apple: red
+ypath: /
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: .
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: /*
+expected:
+ - /apple
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /*
+expected:
+ - /apple
+ - /lemon
+unordered: 1
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: //.
+expected:  
+  - /
+  - /fruit
+  - /fruit/banana
+  - /vegetable
+  - /vegetable/carrot
+unordered: 1
+---
+data:
+  one:
+    two: xxx
+ypath: //two/..
+expected:
+ - /one
+---
+data:
+  apple: red
+ypath: /apple
+expected: 
+ - /apple
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /"lemon"
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /'lemon'
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /lemon
+expected:
+ - /lemon
+----
+data:
+  - apple
+  - lemon
+ypath: /0
+expected:
+ - /0
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /orange
+expected: []
+----
+data:
+  apple: red
+ypath: ./.
+expected:
+ - /
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: /fruit/banana
+expected: 
+ - /fruit/banana
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: fruit/banana
+expected:
+ - /fruit/banana
+---
+data:
+  names:
+    - Steve Howell
+    - Clark Evans
+ypath: /names/0
+expected:
+ - /names/0
+---
+data: 
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/1/first
+expected:
+  - /names/1/first
+----
+data: 
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/*/first
+expected:
+  - /names/0/first
+  - /names/1/first
+---
+data: 
+  names:
+    python-heads:
+      - first: Clark
+        last:  Evans
+      - first: Steve
+        last:  Howell
+    perl-heads:
+      - first: Brian
+        last:  Ingerson
+ypath: names//first
+expected:
+  - /names/python-heads/0/first
+  - /names/python-heads/1/first
+  - /names/perl-heads/0/first
+---
+data:
+    task:
+       - name: wake
+         foo: bar
+       - name: eat
+         task:
+            - name: veggies
+            - name: meats
+       - name: sleep
+ypath: //task
+expected:
+  - /task
+  - /task/1/task
+---
+data:
+  - one: 
+      name: xxx
+  - two: 
+      name: yyy
+  - three: 
+      name: zzz
+ypath: /*/one/name|//three/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  apple: red
+ypath: .|/apple|apple|/|.
+expected:
+ - /
+ - /apple
+---
+data:
+  - one: 
+      name: xxx
+  - two: 
+      name: yyy
+  - three: 
+      name: zzz
+ypath: /*/(one|three)/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  - one: xxx
+  - two: yyy
+  - one: zzz
+ypath: /*[one]
+expected:
+  - /0
+  - /2
+---
+data: 
+ - food: Hamburger
+   calories: 900
+ - food: Fries
+   calories: 650
+ - food: Soft Drink
+   calories: 350
+ypath: //food[.=Fries]
+expected:
+  - /1/food
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/nullsAndEmpties.yml
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/nullsAndEmpties.yml	(revision 71)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestingSuite/nullsAndEmpties.yml	(revision 71)
@@ -0,0 +1,66 @@
+--- #YAML:1.0
+test: Empty Sequence
+brief: >
+    You can represent the empty sequence
+    with an empty inline sequence.
+yaml: |
+    empty: []
+python: |
+    [
+        { 'empty': [] }
+    ]
+ruby: |
+    { 'empty' => [] }
+
+---
+test: Empty Mapping
+brief: >
+    You can represent the empty mapping
+    with an empty inline mapping.
+yaml: |
+    empty: {}
+python: |
+    [
+        { 'empty': {} }
+    ]
+ruby: |
+    { 'empty' => {} }
+
+---
+test: Empty Sequence as Entire Document
+yaml: |
+    --- []
+python: |
+    [ [] ]
+ruby: |
+    []
+
+---
+test: Empty Mapping as Entire Document
+yaml: |
+    --- {}
+python: |
+    [ {} ]
+ruby: |
+    {}
+
+--- 
+test: Null as Document
+yaml: |
+    --- ~
+python: |
+    [ None ]
+ruby: |
+    nil
+
+---
+test: Empty String
+brief: >
+    You can represent an empty string
+    with a pair of quotes.
+yaml: |
+    --- ''
+python: |
+    [ '' ]
+ruby: |
+    ''
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/setup.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/setup.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/setup.py	(revision 73)
@@ -0,0 +1,4 @@
+from distutils.core import setup
+setup (name = "yaml",
+       version = "0.25",
+       packages = ["yaml"])
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/YamlTest.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/YamlTest.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/YamlTest.py	(revision 73)
@@ -0,0 +1,114 @@
+import unittest, sys, string
+import yaml
+from here import flushLeft
+import re
+import glob
+from test import assertEquals, assertError
+from yaml.klass import makeClass
+
+try:
+   unicode('')
+   hasUnicode = 1
+except:
+   hasUnicode = 0
+
+
+def loadFlushLeft(stream, typeResolver=None):
+    return list(yaml.load(flushLeft(stream), typeResolver))
+
+class YamlTest(unittest.TestCase):
+
+    def runTest(self):
+        # reinvent the wheel, instead of trying to 
+        # understand unittest's braindead interface
+        for name in dir(self.__class__):
+            if re.match('test', name):
+                exec('self.%s()' % name)
+
+    def verify(self, stream, results):
+        self.verifyMany(stream, [results])
+
+    def verifyMany(self, stream, expected):
+        results = loadFlushLeft(stream)
+        assertEquals(results, expected)
+
+class ClassForRuntime:
+    def __init__(self):
+        self.foo = 1
+        self.bar = 2
+
+class YamlLoader:
+    # XXX python 2.1 has weak lambda support
+    def __init__(self, doc):
+        self.doc = doc
+    def __call__(self):
+        return list(yaml.load(self.doc['yaml']))
+
+class TestFromSpec(YamlTest):
+    def testFromYaml(self):
+        testFiles = glob.glob('TestingSuite/*.yml')
+        for file in testFiles:
+            # print "\n\n\n\n", file
+            try:
+                docs = yaml.loadFile(file)
+            except IOError:
+                raise "See TESTING for how to set up TestingSuite"
+            for doc in docs:
+                if doc.has_key('python'):
+                    self.verifyOneDoc(doc)
+                if doc.has_key('error') and doc['error'].has_key('python'):
+                    assertError(YamlLoader(doc), doc['error']['python'])
+
+    def verifyOneDoc(self, doc):
+        if doc.has_key('python_setup'):
+            exec(doc['python_setup'])
+        data = eval(doc['python'])
+        # print data
+        assertEquals(list(yaml.load(doc['yaml'])), data)
+        if not doc.has_key('NO_ROUND_TRIP'):
+            self.assertRoundTrip(data)
+
+    def assertRoundTrip(self, data):
+        # XXX - A5 won't round trip when enclosed by 
+        # an array...need to investigate
+        for item in data:
+            # print dump(item)
+            assertEquals(item, 
+                yaml.load(yaml.dump(item)).next(), 'roundtrip')
+
+
+class TestUtils(YamlTest):    
+    class Dummy:
+        pass
+
+    def testMakeClass(self):
+        self.assertEquals(42,
+            makeClass('YamlTest', 'TestUtils.Dummy', 
+                {'a': 27, 'b': 42}).b)
+
+    class FromYaml:
+        def from_yaml(self, dict):
+            self.sum = dict['a'] + dict['b']
+            return self
+
+    def testMakeClassFromYaml(self):
+        self.assertEquals(6,
+            makeClass('YamlTest', 'TestUtils.FromYaml',
+                {'a': 2, 'b': 4}).sum)
+
+
+
+if __name__ == '__main__':
+    import TestYamlBasics
+    import TestNestedText
+    import TestInlineTokenizer
+    import TestDumper
+    ts = unittest.TestSuite()
+    ts.addTest(TestYamlBasics.Test())
+    ts.addTest(TestNestedText.Test())
+    ts.addTest(TestInlineTokenizer.Test())
+    ts.addTest(TestDumper.Test())
+    ts.addTest(TestFromSpec())
+    ts.addTest(TestUtils())
+    unittest.TextTestRunner().run(ts)
+    yaml.dumpToFile(sys.stdout, {'TESTING dumpToFile': 'ok'})
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/insert.py	(revision 73)
@@ -0,0 +1,20 @@
+from PyYaml import yaml
+from test import assertEquals
+from ypath import Ypath
+import re
+
+def Insert(data, command):
+    if command.has_key('ypath'):
+        Ypath(data, command['ypath']).append(command['value'])
+        return data
+    return data + [command['value']]
+
+def TestInsert(data, command, expected):
+    assertEquals(Insert(data, command), expected)    
+
+doc = yaml.loadFile("insert.yml")[0]
+for test in doc['tests']:
+    if not test.has_key('ignore'):
+        TestInsert(test['data'], test['command'], test['expected'])
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/query.py	(revision 73)
@@ -0,0 +1,66 @@
+import yaml
+from test import assertEquals
+import re
+
+def Query(query, doc):
+    results = []
+    for row in yaml.ypath(query['from'],doc):
+        data = {}
+        if Where(row, query):
+            for field in query['select']:
+                data[field] = yaml.ypath(field,row).next()
+            if query.has_key('order'):
+                data['__row__'] = row
+            results.append(data)
+    return Order(results, query)
+
+def Where(row, query):
+    if query.has_key('where'):
+        where = query['where']
+        return WhereRow(row, query['where'])
+    return 1
+
+def WhereRow(row, where):
+    if type(where) == type([]):
+        return And(row, where, WhereRow)
+    if type(where) == type(''):
+        return WhereString(row, where)
+    return And(row, where.keys(), 
+        lambda row, field: where[field] == row[field])
+
+def And(row, conds, condFunc):
+    for cond in conds:
+        if not condFunc(row, cond):
+            return 0
+    return 1
+
+def WhereString(row, where):
+    where = re.sub("\[(.*?)\]", r"row['\1']", where)
+    return eval(where)
+
+def Order(results, query):
+    if not query.has_key('order'):
+        return results
+    compare = lambda x,y: Compare(x,y,query['order'])
+    results.sort(compare)
+    for result in results:
+        del result['__row__']
+    return results
+
+def Compare(x, y, order):
+    for field in order:
+        val = cmp(
+            yaml.ypath(field,x['__row__']).next(),
+            yaml.ypath(field,y['__row__']).next()
+        )
+        if val != 0: return val
+
+def TestQuery(query, expected, data):
+    assertEquals(Query(query, data), expected, query)    
+
+doc = yaml.loadFile("query.yml").next()
+for test in doc['tests']:
+    if not test.has_key('ignore'):
+        TestQuery(test['query'], test['expected'], doc['data'])
+
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/LIMITATIONS
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/LIMITATIONS	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/LIMITATIONS	(revision 73)
@@ -0,0 +1,38 @@
+PYTHON VERSION: >
+   PyYaml is developed with Python version 2.2.  I can't live 
+   without Python 2.2--too many great features.  Please do 
+   yourself a favor and upgrade now.  I know the decision to
+   only support 2.2 and above may lock out some potential users,
+   but I believe it will pay dividends in the future, because
+   the version 2.2 features allow cleaner and more expressive 
+   code.  I do intend to support version 2.2 for a long time.
+
+DISCLAIMER: > 
+   PyYaml is not ready to be used as a robust serialization tool,
+   although it is moving in that direction, and you can certainly
+   experiment with it.
+
+   You can use it more safely for one-way applications.  You can
+   make YAML be an input-tool only, such as for configuration files
+   or data-driven programs.  You can also use YAML as an output-only
+   tool, for things like logging and debugging.
+
+   You can report bugs to showell@zipcon.net.  As of this writing
+   (August 2002), I am actively improving PyYaml.
+
+   The interface for YAML is stabilizing, but it is too early in 
+   the life cycle for me to guarantee backward compatibility in 
+   future releases.  I recommend wrapping your YAML calls in your 
+   own methods, if you are concerned about changing interfaces.
+   The basic paradigm of load, loadFile, save, and saveFile 
+   shouldn't change, but the way that you customize the loader 
+   and parser's behavior may.
+
+SOME KNOWN BUGS/LIMITATIONS:
+  - folded scalars can't lead with blank line
+  - emitter gives invalid YAML for multi-line scalars starting w/whitespace
+  - trailing white space after quotes not ignored
+  - support for inlined hashes and arrays very primitize--can't nest
+    structures and must use simple scalars
+  - specifiers like !str, !int, etc. are ignored
+
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/README
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/README	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/README	(revision 73)
@@ -0,0 +1,105 @@
+- Introductions: >
+   Hello.  Welcome to the Python YAML parser.  This is 
+   a work in progress.   The primary author is Steve Howell,
+   with a few contributions by Clark Evans.
+
+- installation: >
+   Simply type "make install" as root, this runs python setup.py install.
+   If you do not have distutils installed, you can simply copy the
+   yaml sub-directory into site-packages.
+
+- testing: >
+   You should be able to type "make test" both before and
+   after the installation.  This simply runs python on the
+   test programs.
+
+   This package uses python iterators, but there is a surrogate
+   which returns a list object instead of an iterator for python
+   versions below 2.2
+
+   This package should work with 1.5.2 and up, although many of
+   the tests fail with 1.5.2; if you are an expert with 1.5.2
+   please help us patch this up so that it works on older versions
+   of Python.
+
+- playing: >
+   The best way to play, is to start with demo.py and 
+   work from there.  Note that this implementation has quite
+   a way to go before it is compliant with the YAML specification.
+   
+   If something is failing in the tests for your platform
+   please let us know.  If something doesn't work, check the
+   tests to see if the test covering the feature you need is
+   active; if not, chances are it's not implemented.
+
+   Your feedback or any other contributions are certainly welcome.
+
+- ypath: >
+   The YPATH implementation is EXPERIMENTAL but included
+   in the yaml package beacuse it is fun and we'd like to get
+   feedback from the user community as to how they'd like it 
+   to work.  It requries Python 2.2 since it uses iterators.
+
+- query: >
+   There is a query.py and query.yml file in this directory,
+   it is currently broke as ypath was re-written.
+
+---
+contributors:
+  - who: Steve Howell
+    why?: |
+      Original author of the pure Python implementations of the 
+      YAML parser and emitter.  Many thanks to the other folks 
+      listed here, and some not listed here.  
+    email: showell@zipcon.net
+
+  - who: Brian Ingerson
+    why?: |
+      Brian got me hooked on YAML.  We have used his Perl 
+      implementation to do some really cool stuff, even on projects
+      that primarily used XML.  He also got me started on 
+      the Python project.
+
+  - who: Clark Evans
+    why?: |
+      Clark's YAML fame far precedes the Python implementation--he
+      founded the whole project.  But, he also contributed alias 
+      emitting to this project, and he's also generously allowed
+      me to bundle his very cool YPATH implementation.  Finally,
+      he's helped with module packaging issues and miscellaneous
+      features and bug fixes.
+
+  - who: Why The Lucky Stiff
+    why?: |
+      That's right, Why's the name, Ruby's the game.  Why devotes
+      most of his YAML effort to a Ruby implementation that grows
+      increasingly robust, but he's also a great team player on 
+      the YAML project.  For example, he consolidated the YAML
+      testing suites, so that multiple YAML implementations can 
+      share the same YAML test files.  If you look in this YAML
+      distribution, you will see Ruby all over the place.  Think
+      of it as a free introduction to another great scripting 
+      language.
+
+  - who: Ryan King
+    why?: |
+      Sharpener of saws and pair programmer extraordinaire.
+
+  - who: Neil Watkiss
+    why?: |
+      Donated hardware and major expertise to the project.       
+
+  - who: Oren Ben-Kiki
+    why?: |
+      YAML cofounder.  All library implementors owe a huge gratitude 
+      toward Oren for his work on the YAML spec.
+
+  - who: Lion Kimbro
+    why?: |
+      Early adopter, also known for his three-humped YAML.
+       
+  - who: Dave Kuhlman
+    why?: |
+      Dave's contributions include, but are not limited to, the 
+      XmlYaml code bundled with this distribution.  The README
+      with that code talks more about Dave.
Index: /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestInlineTokenizer.py
===================================================================
--- /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestInlineTokenizer.py	(revision 73)
+++ /pyyaml-legacy/tags/PyYaml_fromyamlorg/TestInlineTokenizer.py	(revision 73)
@@ -0,0 +1,22 @@
+import YamlTest
+from test import assertEquals
+from yaml.load import *
+
+
+class Test(YamlTest.YamlTest):
+    def testSimple(self):
+        tokenizer = InlineTokenizer('[ foo, bar ]')
+        assertEquals(tokenizer.next(), '[')
+        assertEquals(tokenizer.next(), 'foo')
+        assertEquals(tokenizer.next(), 'bar')
+        assertEquals(tokenizer.next(), ']')
+
+    def testSimpleHash(self):
+        tokenizer = InlineTokenizer('{ foo: bar }')
+        assertEquals(tokenizer.next(), '{')
+        assertEquals(tokenizer.next(), 'foo: bar') # might change
+        assertEquals(tokenizer.next(), '}')
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/__init__.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/__init__.py	(revision 76)
+++ /pyyaml-legacy/trunk/yaml/__init__.py	(revision 76)
@@ -0,0 +1,17 @@
+__version__ = "0.32"
+from load import loadFile, load, Parser, l, file
+from dump import dump, dumpToFile, Dumper, d
+from stream import YamlLoaderException, StringStream, FileStream
+from timestamp import timestamp
+import sys
+if sys.hexversion >= 0x02020000:
+    from redump import loadOrdered
+
+try:
+    from ypath import ypath
+except NameError:
+    def ypath(expr,target='',cntx=''):
+        raise NotImplementedError("ypath requires Python 2.2")
+
+if sys.hexversion < 0x02010000:
+    raise 'YAML is not tested for pre-2.1 versions of Python'
Index: /pyyaml-legacy/trunk/yaml/load.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/load.py	(revision 100)
+++ /pyyaml-legacy/trunk/yaml/load.py	(revision 100)
@@ -0,0 +1,329 @@
+import re, string
+from implicit import convertImplicit
+from inline import InlineTokenizer
+from yaml.klass import DefaultResolver
+from yaml.stream import YamlLoaderException, FileStream, StringStream, NestedDocs
+
+try:
+    iter(list()) # is iter supported by this version of Python?
+except:
+    # XXX - Python 2.1 does not support iterators   
+    class StopIteration: pass
+    class iter:
+        def __init__(self,parser):
+            self._docs = []
+            try:
+                while 1:
+                   self._docs.append(parser.next())
+            except StopIteration: pass
+            self._idx = 0
+        def __len__(self): return len(self._docs)
+        def __getitem__(self,idx): return self._docs[idx]
+        def next(self):
+            if self._idx < len(self._docs):
+                ret = self._docs[self._idx] 
+                self._idx = self._idx + 1
+                return ret
+            raise StopIteration
+
+def loadFile(filename, typeResolver=None):
+    return loadStream(FileStream(filename),typeResolver)
+   
+def load(str, typeResolver=None):
+    return loadStream(StringStream(str), typeResolver)
+
+def l(str): return load(str).next()
+
+def file(filename): return loadFile(filename).next()
+
+def loadStream(stream, typeResolver):
+    return iter(Parser(stream, typeResolver))
+
+def tryProductions(productions, value):
+    for production in productions:
+        results = production(value)
+        if results:
+            (ok, result) = results
+            if ok:
+                return (1, result)
+
+def dumpDictionary(): return {}
+
+class Parser:
+    def __init__(self, stream, typeResolver=None):
+        try:
+            self.dictionary = dict
+        except:
+            self.dictionary = dumpDictionary
+        self.nestedDocs = NestedDocs(stream)
+        self.aliases = {}
+        if typeResolver:
+            self.typeResolver = typeResolver
+        else:
+            self.typeResolver = DefaultResolver()
+
+    def error(self, msg):
+        self.nestedDocs.error(msg, self.line)
+
+    def nestPop(self):
+        line = self.nestedDocs.pop()
+        if line is not None:
+            self.line = line
+            return 1
+
+    def value(self, indicator):
+        return getToken(indicator+"\s*(.*)", self.line)
+
+    def getNextDocument(self): raise "getNextDocument() deprecated--use next()"
+
+    def next(self):
+        line = self.nestedDocs.popDocSep()
+        indicator = getIndicator(line)
+        if indicator:
+            return self.parse_value(indicator)
+        if line:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+        raise StopIteration
+
+    def __iter__(self): return self
+
+    def parseLines(self):
+        peekLine = self.nestedDocs.peek()
+        if peekLine:
+            if re.match("\s*-", peekLine):
+                return self.parse_collection([], self.parse_seq_line)
+            else:
+                return self.parse_collection(self.dictionary(), self.parse_map_line)
+        raise StopIteration
+
+    def parse_collection(self, items, lineParser):
+        while self.nestPop():
+            if self.line:
+                lineParser(items)
+        return items    
+
+    def parse_seq_line(self, items):
+        value = self.value("-")
+        if value is not None:
+            items.append(self.parse_seq_value(value))
+        else:
+            self.error("missing '-' for seq")
+
+    def parse_map_line(self, items):
+        if (self.line == '?'):
+            self.parse_map_line_nested(items)
+        else:
+            self.parse_map_line_simple(items, self.line)
+
+    def parse_map_line_nested(self, items):
+        self.nestedDocs.nestToNextLine()
+        key = self.parseLines()
+        if self.nestPop():
+            value = self.value(':')
+            if value is not None:
+                items[tuple(key)] = self.parse_value(value)
+                return
+        self.error("key has no value for nested map")
+
+    def parse_map_line_simple(self, items, line):
+        map_item = self.key_value(line)
+        if map_item:
+            (key, value) = map_item
+            key = convertImplicit(key)
+            if items.has_key(key):
+                self.error("Duplicate key "+key)
+            items[key] = self.parse_value(value)
+        else:
+            self.error("bad key for map")
+
+    def is_map(self, value):
+        # XXX - need real tokenizer
+        if len(value) == 0:
+            return 0
+        if value[0] == "'":
+            return 0
+        if re.search(':(\s|$)', value):       
+            return 1
+
+    def parse_seq_value(self, value):
+        if self.is_map(value):
+            return self.parse_compressed_map(value)
+        else:
+            return self.parse_value(value)
+
+    def parse_compressed_map(self, value):
+        items = self.dictionary()
+        line = self.line
+        token = getToken("(\s*-\s*)", line)
+        self.nestedDocs.nestBySpecificAmount(len(token))
+        self.parse_map_line_simple(items, value)
+        return self.parse_collection(items, self.parse_map_line)
+
+    def parse_value(self, value):
+        (alias, value) = self.testForRepeatOfAlias(value)
+        if alias:
+            return value
+        (alias, value) = self.testForAlias(value)            
+        value = self.parse_unaliased_value(value)
+        if alias:
+            self.aliases[alias] = value
+        return value          
+
+    def parse_unaliased_value(self, value):
+        match = re.match(r"(!\S*)(.*)", value)
+        if match:
+            (url, value) = match.groups()
+            value = self.parse_untyped_value(value)
+            if url[:2] == '!!':
+                return self.typeResolver.resolveType(value, url)
+            else:
+                # XXX - allows syntax, but ignores it
+                return value
+        return self.parse_untyped_value(value)
+
+    def parseInlineArray(self, value):        
+        if re.match("\s*\[", value):
+            return self.parseInline([], value, ']', 
+                self.parseInlineArrayItem)
+
+    def parseInlineHash(self, value):        
+        if re.match("\s*{", value):
+            return self.parseInline(self.dictionary(), value, '}', 
+                self.parseInlineHashItem)
+
+    def parseInlineArrayItem(self, result, token):
+        return result.append(convertImplicit(token))
+
+    def parseInlineHashItem(self, result, token):
+        (key, value) = self.key_value(token)
+        result[key] = value
+
+    def parseInline(self, result, value, end_marker, itemMethod):
+        tokenizer = InlineTokenizer(value)
+        tokenizer.next()
+        while 1:
+            token = tokenizer.next()
+            if token == end_marker:
+                break
+            itemMethod(result, token)
+        return (1, result)
+
+    def parseSpecial(self, value):
+        productions = [
+            self.parseMultiLineScalar,
+            self.parseInlineHash,
+            self.parseInlineArray,
+        ]
+        return tryProductions(productions, value)
+
+    def parse_untyped_value(self, value):
+        parse = self.parseSpecial(value)
+        if parse:
+            (ok, data) = parse
+            return data
+        token = getToken("(\S.*)", value)
+        if token:
+            lines = [token] + \
+                pruneTrailingEmpties(self.nestedDocs.popNestedLines())
+            return convertImplicit(joinLines(lines))
+        else:
+            self.nestedDocs.nestToNextLine()
+            return self.parseLines()
+
+    def parseNative(self, value):
+        return (1, convertImplicit(value))
+
+    def parseMultiLineScalar(self, value):
+        if value == '>':
+            return (1, self.parseFolded())
+        elif value == '|':
+            return (1, joinLiteral(self.parseBlock()))
+        elif value == '|+':
+            return (1, joinLiteral(self.unprunedBlock()))
+
+    def parseFolded(self):
+        data = self.parseBlock()
+        i = 0
+        resultString = ''
+        while i < len(data)-1:
+            resultString = resultString + data[i]
+            resultString = resultString + foldChar(data[i], data[i+1])
+            i = i + 1
+        return resultString + data[-1] + "\n"        
+
+    def unprunedBlock(self):
+        self.nestedDocs.nestToNextLine()
+        data = []
+        while self.nestPop():
+            data.append(self.line)
+        return data
+
+    def parseBlock(self):
+        return pruneTrailingEmpties(self.unprunedBlock())
+
+    def testForAlias(self, value):
+        match = re.match("&(\S*)\s*(.*)", value)
+        if match:
+            return match.groups()
+        return (None, value)
+
+    def testForRepeatOfAlias(self, value):
+        match = re.match("\*(\S+)", value)
+        if match:
+            alias = match.groups()[0]
+            if self.aliases.has_key(alias):
+                return (alias, self.aliases[alias])
+            else:
+                self.error("Unknown alias")
+        return (None, value)
+
+    def key_value(self, str):
+        #if str[-1] == ' ':
+        #    self.error("Trailing spaces not allowed without quotes.")
+        # XXX This allows mis-balanced " vs. ' stuff
+        match = re.match("[\"'](.+)[\"']\s*:\s*(.*)", str)
+        if match:
+            (key, value) = match.groups()
+            return (key, value)
+        match = re.match("(.+?)\s*:\s*(.*)", str)
+        if match:
+            (key, value) = match.groups()
+            if len(value) and value[0] == '#':
+                value = ''
+            return (key, value)
+
+def getToken(regex, value):
+    match = re.search(regex, value)
+    if match:
+        return match.groups()[0]
+
+def pruneTrailingEmpties(data):
+    while len(data) > 0 and data[-1] == '':
+        data = data[:-1]
+    return data
+
+def foldChar(line1, line2):
+    if re.match("^\S", line1) and re.match("^\S", line2):
+        return " "
+    return "\n"
+
+def getIndicator(line):
+    if line:
+        header = r"(#YAML:\d+\.\d+\s*){0,1}"
+        match = re.match("--- "+header+"(\S*.*)", line)
+        if match:
+            return match.groups()[-1]
+
+def joinLines(lines):
+    result = ''
+    for line in lines[:-1]:
+        if line[-1] == '\\':
+            result = result + line[:-1]
+        else:
+            result = result + line + " "
+    return result + lines[-1]
+
+def joinLiteral(data):
+    return string.join(data,"\n") + "\n"
+
Index: /pyyaml-legacy/trunk/yaml/timestamp.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/timestamp.py	(revision 102)
+++ /pyyaml-legacy/trunk/yaml/timestamp.py	(revision 102)
@@ -0,0 +1,146 @@
+import time, re, string
+from types import ListType, TupleType
+from yaml_escapes import escape
+
+PRIVATE_NOTICE = """
+  This module is considered to be private implementation
+  details and is subject to change.  Please only use the
+  objects and methods exported to the top level yaml package.
+"""
+
+# 
+# Time specific operations
+#
+
+_splitTime = re.compile('\-|\s|T|t|:|\.|Z')
+matchTime = re.compile(\
+          '\d+-\d+-\d+([\s|T|t]\d+:\d+:\d+.\d+(Z|(\s?[\-|\+]\d+:\d+)))?')
+
+def _parseTime(val):
+    if not matchTime.match(val): raise ValueError(val)
+    tpl = _splitTime.split(val)
+    if not(tpl): raise ValueError(val)
+    siz = len(tpl)
+    sec = 0
+    if 3 == siz:
+       tpl += [0,0,0,0,0,-1]
+    elif 7 == siz:
+       tpl.append(0)
+       tpl.append(-1)
+    elif 8 == siz:
+       if len(tpl.pop()) > 0: raise ValueError(val)
+       tpl.append(0)
+       tpl.append(-1)
+    elif 9 == siz or 10 == siz:
+       mn = int(tpl.pop())
+       hr = int(tpl.pop())
+       sec = (hr*60+mn)*60
+       if val.find("+") > -1: sec = -sec
+       if 10 == siz: tpl.pop()
+       tpl.append(0)
+       tpl.append(-1)
+    else:
+       raise ValueError(val)
+    idx = 0
+    while idx < 9:
+       tpl[idx] = int(tpl[idx])
+       idx += 1
+    if tpl[1] < 1 or tpl[1] > 12: raise ValueError(val)
+    if tpl[2] < 1 or tpl[2] > 31: raise ValueError(val)
+    if tpl[3] > 24: raise ValueError(val)
+    if tpl[4] > 61: raise ValueError(val)
+    if tpl[5] > 61: raise ValueError(val)
+    if tpl[0] > 2038:
+        #TODO: Truncation warning
+        tpl = (2038,1,18,0,0,0,0,0,-1)
+    tpl = tuple(tpl)
+    ret = time.mktime(tpl)
+    ret = time.localtime(ret+sec)
+    ret = ret[:8] + (0,)
+    return ret
+
+
+class _timestamp:
+    def __init__(self,val=None):
+        if not val:
+           self.__tval = time.gmtime()
+        else:
+           typ = type(val)
+           if ListType == typ:
+               self.__tval = tuple(val)
+           elif TupleType == typ:
+               self.__tval = val
+           else:
+               self.__tval = _parseTime(val)
+           if 9 != len(self.__tval): raise ValueError
+    def __getitem__(self,idx): return self.__tval[idx]
+    def __len__(self): return 9
+    def strftime(self,format): return time.strftime(format,self.__tval)
+    def mktime(self):          return time.mktime(self.__tval)
+    def asctime(self):  return time.asctime(self.__tval)
+    def isotime(self):  
+        return "%04d-%02d-%02dT%02d:%02d:%02d.00Z" % self.__tval[:6]
+    def __repr__(self): return "yaml.timestamp('%s')" % self.isotime()    
+    def __str__(self):  return self.isotime()
+    def to_yaml_implicit(self): return self.isotime()
+    def __hash__(self): return hash(self.__tval[:6]) 
+    def __cmp__(self,other): 
+        try:
+            return cmp(self.__tval[:6],other.__tval[:6])
+        except AttributeError:
+            return -1
+
+try: # inherit from mx.DateTime functionality if available
+    from mx import DateTime
+    class timestamp(_timestamp):
+        def __init__(self,val=None):
+            _timestamp.__init__(self,val)
+            self.__mxdt = DateTime.mktime(self.__tval)
+        def __getattr__(self, name):
+              return getattr(self.__mxdt, name)
+except:
+    class timestamp(_timestamp): pass
+        
+
+
+def unquote(expr):
+    """
+        summary: >
+           Simply returns the unquoted string, and the
+           length of the quoted string token at the 
+           beginning of the expression.
+    """
+    tok = expr[0]
+    if "'" == tok: 
+        idx = 1
+        odd = 0
+        ret = ""
+        while idx < len(expr):
+            chr = expr[idx]
+            if "'" == chr:
+                if odd: ret += chr
+                odd = not odd
+            else:
+                if odd:
+                    tok = expr[:idx]
+                    break
+                ret += chr
+            idx += 1
+        if "'" == tok: tok = expr
+        return (ret,len(tok))
+    if '"' == tok:
+        idx = 1
+        esc = 0
+        while idx < len(expr):
+            chr = expr[idx]
+            if '"' == chr and not esc:
+                tok = expr[:idx] + '"'
+                break
+            if '\\' == chr and not esc: esc = 1
+            else: esc = 0
+            idx += 1
+        if '"' == tok:
+            raise SyntaxError("unmatched quote: " + expr)
+        ret = escape(tok)[1:-1]
+        return (ret,len(tok))
+    return (expr,len(expr))
Index: /pyyaml-legacy/trunk/yaml/dump.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/dump.py	(revision 107)
+++ /pyyaml-legacy/trunk/yaml/dump.py	(revision 107)
@@ -0,0 +1,302 @@
+import types
+import string
+from types import StringType, UnicodeType, IntType, FloatType
+from types import DictType, ListType, TupleType, InstanceType
+from yaml.klass import hasMethod, isDictionary
+import re
+
+"""
+  The methods from this module that are exported to the top 
+  level yaml package should remain stable.  If you call
+  directly into other methods of this module, be aware that 
+  they may change or go away in future implementations.
+  Contact the authors if there are methods in this file 
+  that you wish to remain stable.
+"""
+
+def dump(*data):
+    return Dumper().dump(*data)
+
+def d(data): return dump(data)
+
+def dumpToFile(file, *data):
+    return Dumper().dumpToFile(file, *data)
+
+class Dumper:
+    def __init__(self):
+        self.currIndent   = "\n"
+        self.indent = "    "
+        self.keysrt   = None
+        self.alphaSort = 1 # legacy -- on by default
+
+    def setIndent(self, indent):
+        self.indent = indent
+        return self
+
+    def setSort(self, sort_hint):
+        self.keysrt = sortMethod(sort_hint)
+        return self
+
+    def dump(self, *data):
+        self.result = []  
+        self.output = self.outputToString
+        self.dumpDocuments(data)
+        return string.join(self.result,"")
+
+    def outputToString(self, data):
+        self.result.append(data)
+
+    def dumpToFile(self, file, *data):
+        self.file = file
+        self.output = self.outputToFile
+        self.dumpDocuments(data)
+
+    def outputToFile(self, data):
+        self.file.write(data)
+
+    def dumpDocuments(self, data):
+        for obj in data:
+            self.anchors  = YamlAnchors(obj)
+            self.output("---")
+            self.dumpData(obj)
+            self.output("\n")       
+
+    def indentDump(self, data):
+        oldIndent = self.currIndent
+        self.currIndent += self.indent
+        self.dumpData(data)
+        self.currIndent = oldIndent
+
+    def dumpData(self, data):
+        anchor = self.anchors.shouldAnchor(data)
+        if anchor: 
+            self.output(" &%d" % anchor )
+        else:
+            anchor = self.anchors.isAlias(data)
+            if anchor:
+                self.output(" *%d" % anchor )
+                return
+        if (data is None):
+            self.output(' ~')
+        elif data is True:
+            self.output(' +')
+        elif data is False:
+            self.output(' -')
+        elif hasMethod(data, 'to_yaml'):
+            self.dumpTransformedObject(data)            
+        elif hasMethod(data, 'to_yaml_implicit'):
+            self.output(" " + data.to_yaml_implicit())
+        elif type(data) is InstanceType:
+            self.dumpRawObject(data)
+        elif isDictionary(data):
+            self.dumpDict(data)
+        elif type(data) in [ListType, TupleType]:
+            self.dumpList(data)
+        else:
+            self.dumpScalar(data)
+
+    def dumpTransformedObject(self, data):
+        obj_yaml = data.to_yaml()
+        if type(obj_yaml) is not TupleType:
+            self.raiseToYamlSyntaxError()
+        (data, typestring) = obj_yaml
+        if typestring:
+            self.output(" " + typestring)
+        self.dumpData(data)
+
+    def dumpRawObject(self, data):
+        self.output(' !!%s.%s' % (data.__module__, data.__class__.__name__))
+        self.dumpData(data.__dict__)
+
+    def dumpDict(self, data):
+        keys = data.keys()
+        if len(keys) == 0:
+            self.output(" {}")
+            return
+        if self.keysrt:
+            keys = sort_keys(keys,self.keysrt)
+        else:
+            if self.alphaSort:
+                keys.sort()
+        for key in keys:
+            self.output(self.currIndent)
+            self.dumpKey(key)
+            self.output(":")
+            self.indentDump(data[key])
+
+    def dumpKey(self, key):
+        if type(key) is TupleType:
+            self.output("?")
+            self.indentDump(key) 
+            self.output("\n")
+        else:
+            self.output(quote(key))
+
+    def dumpList(self, data):
+        if len(data) == 0:
+            self.output(" []")
+            return
+        for item in data:
+            self.output(self.currIndent)
+            self.output("-")
+            self.indentDump(item)
+
+    def dumpScalar(self, data):
+        if isUnicode(data):
+            self.output(' "%s"' % repr(data)[2:-1])
+        elif isMulti(data):
+            self.dumpMultiLineScalar(data.splitlines())
+        else:
+            self.output(" ")
+            self.output(quote(data))
+    
+    def dumpMultiLineScalar(self, lines):
+        self.output(" |")
+        if lines[-1] == "":
+            self.output("+")
+        for line in lines:
+            self.output(self.currIndent)
+            self.output(line)
+
+    def raiseToYamlSyntaxError(self):
+            raise """
+to_yaml should return tuple w/object to dump 
+and optional YAML type.  Example:
+({'foo': 'bar'}, '!!foobar')
+"""
+
+#### ANCHOR-RELATED METHODS
+
+def accumulate(obj,occur):
+    typ = type(obj)
+    if obj is None or \
+       typ is IntType or \
+       typ is FloatType or \
+       ((typ is StringType or typ is UnicodeType) \
+       and len(obj) < 32): return
+    obid = id(obj)
+    if 0 == occur.get(obid,0):
+        occur[obid] = 1
+        if typ is ListType:
+            for x in obj: 
+                accumulate(x,occur)
+        if typ is DictType:
+            for (x,y) in obj.items():
+                accumulate(x,occur)
+                accumulate(y,occur)
+    else:
+        occur[obid] = occur[obid] + 1
+
+class YamlAnchors:
+     def __init__(self,data):
+         occur = {}
+         accumulate(data,occur)
+         anchorVisits = {}
+         for (obid, occur) in occur.items():
+             if occur > 1:
+                 anchorVisits[obid] = 0 
+         self._anchorVisits = anchorVisits
+         self._currentAliasIndex     = 0
+     def shouldAnchor(self,obj):
+         ret = self._anchorVisits.get(id(obj),None)
+         if 0 == ret:
+             self._currentAliasIndex = self._currentAliasIndex + 1
+             ret = self._currentAliasIndex
+             self._anchorVisits[id(obj)] = ret
+             return ret
+         return 0
+     def isAlias(self,obj):
+         return self._anchorVisits.get(id(obj),0)
+
+### SORTING METHODS
+
+def sort_keys(keys,fn):
+    tmp = []
+    for key in keys:
+        val = fn(key)
+        if val is None: val = '~'
+        tmp.append((val,key))
+    tmp.sort()
+    return [ y for (x,y) in tmp ]
+
+def sortMethod(sort_hint):
+    typ = type(sort_hint)
+    if DictType == typ:
+        return sort_hint.get
+    elif ListType == typ or TupleType == typ:
+        indexes = {}; idx = 0
+        for item in sort_hint:
+            indexes[item] = idx
+            idx += 1
+        return indexes.get
+    else:
+        return sort_hint
+
+### STRING QUOTING AND SCALAR HANDLING
+def isStr(data):
+    # XXX 2.1 madness
+    if type(data) == type(''):
+        return 1
+    if type(data) == type(u''):
+        return 1
+    return 0
+    
+def doubleUpQuotes(data):
+    return data.replace("'", "''")
+
+def quote(data):
+    if not isStr(data):
+        return str(data)
+    single = "'"
+    double = '"'
+    quote = ''
+    if len(data) == 0:
+        return "''"
+    if hasSpecialChar(data) or data[0] == single:
+        data = `data`[1:-1]
+        data = string.replace(data, r"\x08", r"\b")
+        quote = double 
+    elif needsSingleQuote(data):
+        quote = single
+        data = doubleUpQuotes(data)
+    elif len(data) == 1 and data in ['~', '+', '-']:
+        quote = single
+    return "%s%s%s" % (quote, data, quote)
+
+def needsSingleQuote(data):
+    if re.match(r"^-?\d", data):
+        return 1
+    if re.match(r"\*\S", data):
+        return 1
+    if data[0] in ['&', ' ']:
+        return 1
+    if data[0] == '"':
+        return 1
+    if data[-1] == ' ':
+        return 1
+    return (re.search(r'[:]', data) or re.search(r'(\d\.){2}', data))
+
+def hasSpecialChar(data):
+    # need test to drive out '#' from this
+    return re.search(r'[\t\b\r\f#]', data)
+
+def isMulti(data):
+    if not isStr(data):
+        return 0
+    if hasSpecialChar(data):
+        return 0
+    return re.search("\n", data)
+
+def isUnicode(data):
+    return type(data) == unicode
+    
+def sloppyIsUnicode(data):
+        # XXX - hack to make tests pass for 2.1
+        return repr(data)[:2] == "u'" and repr(data) != data
+
+import sys
+if sys.hexversion < 0x20200000:
+    isUnicode = sloppyIsUnicode
+    
+
+
Index: /pyyaml-legacy/trunk/yaml/yaml_escapes.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/yaml_escapes.py	(revision 102)
+++ /pyyaml-legacy/trunk/yaml/yaml_escapes.py	(revision 102)
@@ -0,0 +1,67 @@
+import re
+
+class YamlInvalidEscapeChar(Exception): pass
+
+escapeCodes = {
+    '0'  : '\x00',
+    'a'  : '\x07',
+    'b'  : '\x08',
+    't'  : '\x09',
+    'n'  : '\x0a',
+    'v'  : '\x0b',
+    'f'  : '\x0c',
+    'r'  : '\x0d',
+    ' '  : '\x20',
+    'e'  : '\x1b',
+    'N'  : u'\u0085',
+    'L'  : u'\u2028',
+    'P'  : u'\u2029',
+    '_'  : u'\u00a0'
+}
+
+escapeCodeChars = reduce(lambda x, y: x + y, escapeCodes.keys())
+
+def escape_slash(match):
+    escaped = match.groupdict()['esc']
+
+
+    if escaped in ['\\', '"']:
+        return escaped
+
+    elif escaped in escapeCodes.keys():
+        return escapeCodes[escaped] 
+
+    elif escaped[0] == 'x':
+        return chr(int(escaped[1:3], 16))
+
+    elif escaped[0] == 'u':
+        return unichr(int(escaped[1:5], 16))
+
+    elif escaped[0] == 'U':
+        return ( chr(int(escaped[1:3], base=16)) +
+                         chr(int(escaped[3:5], base=16)) + 
+                 chr(int(escaped[5:7], base=16)) + 
+                         chr(int(escaped[7:9], base=16)) )
+    else:
+        raise YamlInvalidEscapeChar
+
+
+escapeCodePat = "[%s]" % escapeCodeChars
+whackPat = r"\\"
+asciiPat = "x[\da-fA-F]{2}"
+u16Pat = "u[\da-fA-F]{4}"
+u32Pat = "U[\da-fA-F]{8}"
+
+pat = re.compile(r"\\(?P<esc>%s|%s|%s|%s|%s|.)"%(escapeCodePat,
+                    whackPat, asciiPat,
+                    u16Pat, u32Pat))
+
+upat = re.compile(r"\\(?P<esc>%s|%s)"%(u16Pat, u32Pat))
+
+def escape(val):
+    val = pat.sub(escape_slash, val)
+    return val
+
+def escape_unicode(val):
+    val = upat.sub(escape_slash, val)
+    return val
Index: /pyyaml-legacy/trunk/yaml/ypath.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/ypath.py	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/ypath.py	(revision 71)
@@ -0,0 +1,462 @@
+from types import ListType, StringType, IntType, DictType, InstanceType
+import re
+from urllib import quote
+from timestamp import unquote
+
+noTarget = object()
+
+def escape(node):
+    """
+        summary: >
+            This function escapes a given key so that it
+            may appear within a ypath.  URI style escaping
+            is used so that ypath expressions can be a 
+            valid URI expression.
+    """
+    typ = type(node)
+    if typ is IntType: return str(node)
+    if typ is StringType: 
+        return quote(node,'')
+    raise ValueError("TODO: Support more than just string and integer keys.")
+
+class context:
+    """
+        summary: >
+            A ypath visit context through a YAML rooted graph.
+            This is implemented as a 3-tuple including the parent
+            node, the current key/index and the value.  This is
+            an immutable object so it can be cached.
+        properties: 
+            key:    mapping key or index within the parent collection
+            value:  current value within the parent's range
+            parent: the parent context
+            root:   the very top of the yaml graph
+            path:   a tuple of the domain keys
+        notes: >
+            The context class doesn't yet handle going down the
+            domain side of the tree... 
+    """         
+    def __init__(self,parent,key,value):
+        """
+            args:
+                parent: parent context (or None if this is the root)
+                key:    mapping key or index for this context
+                value:  value of current location...
+        """
+        self.parent = parent
+        self.key    = key
+        self.value  = value
+        if parent: 
+            assert parent.__class__ is self.__class__
+            self.path = parent.path + (escape(key),)
+            self.root = parent.root
+        else:      
+            assert not key
+            self.path = tuple()
+            self.root = self
+    def __setattr__(self,attname,attval):
+        if attname in ('parent','key','value'):
+            if self.__dict__.get(attname):
+                 raise ValueError("context is read-only")
+        self.__dict__[attname] = attval
+    def __hash__(self): return hash(self.path)
+    def __cmp__(self,other):   
+        try:
+            return cmp(self.path,other.path)
+        except AttributeError:
+            return -1
+    def __str__(self):
+        if self.path:
+            return "/".join(('',)+self.path)
+        else:
+            return '/'
+
+def to_context(target):
+    if type(target) is InstanceType:
+        if target.__class__ is context:
+            return target
+    return context(None,None,target)
+
+def context_test():
+    lst = ['value']
+    map = {'key':lst}
+    x = context(None,None,map)
+    y = context(x,'key',lst)
+    z = context(y,0,'value')
+    assert ('key',) == y.path
+    assert 'key'    == y.key
+    assert lst      == y.value
+    assert x        == y.parent
+    assert x        == y.root
+    assert 0        == z.key
+    assert 'value'  == z.value
+    assert y        == z.parent
+    assert x        == z.root 
+    assert hash(x)  
+    assert hash(y)
+    assert hash(z)
+    assert '/' == str(x)
+    assert '/key' == str(y)
+    assert '/key/0' == str(z)
+
+class null_seg:
+    """
+        summary: >
+            This is the simplest path segment, it
+            doesn't return any results and doesn't
+            depend upon its context.  It also happens to 
+            be the base class which all segments derive.
+    """
+    def __iter__(self): 
+        return self
+    def next_null(self):
+        raise StopIteration
+    def bind(self,cntx):  
+        """
+            summary: >
+                The bind function is called whenever
+                the parent context has changed.
+        """
+        assert(cntx.__class__ is context)
+        self.cntx = cntx
+    def apply(self,target):
+        self.bind(to_context(target))
+        return iter(self)
+    def exists(self,cntx):
+        try:
+            self.bind(cntx)
+            self.next()
+            return 1
+        except StopIteration:
+            return 0
+    next = next_null
+ 
+class self_seg(null_seg):
+    """
+        summary: >
+            This path segment returns the context
+            node exactly once.
+    """
+    def __str__(self): return '.'
+    def next_self(self):
+        self.next = self.next_null
+        return self.cntx
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.next = self.next_self
+
+class root_seg(self_seg):
+    def __str__(self): return '/'
+    def bind(self,cntx):  
+        self_seg.bind(self,cntx.root)
+
+class parent_seg(self_seg):
+    def __str__(self): return '..'
+    def bind(self,cntx):
+        if cntx.parent: cntx = cntx.parent
+        self_seg.bind(self,cntx)
+
+class wild_seg(null_seg):
+    """
+        summary: >
+            The wild segment simply loops through
+            all of the sub-contexts for a given object.
+            If there aren't any children, this isn't an
+            error it just doesn't return anything.
+    """
+    def __str__(self): return '*'
+    def next_wild(self):
+        key = self.keys.next()
+        return context(self.cntx,key,self.values[key])
+    def bind(self,cntx):  
+        null_seg.bind(self,cntx)
+        typ = type(cntx.value)
+        if typ is ListType:
+            self.keys   = iter(xrange(0,len(cntx.value)))
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return
+        if typ is DictType:
+            self.keys   = iter(cntx.value)
+            self.values = cntx.value
+            self.next   = self.next_wild
+            return 
+        self.next = self.next_null
+
+class trav_seg(null_seg):
+    """
+        summary: >
+            This is a recursive traversal of the range, preorder.
+            It is a recursive combination of self and wild.
+    """
+    def __str__(self): return '/'
+    def next(self): 
+        while 1:
+            (cntx,seg) = self.stk[-1]
+            if not seg:
+                seg = wild_seg()
+                seg.bind(cntx)
+                self.stk[-1] = (cntx,seg)
+                return cntx
+            try:
+                cntx = seg.next()
+                self.stk.append((cntx,None))
+            except StopIteration:
+                self.stk.pop()
+                if not(self.stk):
+                    self.next = self.next_null
+                    raise StopIteration
+
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.stk = [(cntx,None)]
+
+class match_seg(self_seg):
+    """
+        summary: >
+            Matches a particular key within the
+            current context.  Kinda boring.
+    """
+    def __str__(self): return str(self.key)
+    def __init__(self,key):
+        #TODO: Do better implicit typing
+        try:
+           key = int(key)
+        except: pass
+        self.key = key
+    def bind(self,cntx):
+        try: 
+            mtch = cntx.value[self.key]
+            cntx = context(cntx,self.key,mtch)
+            self_seg.bind(self,cntx)
+        except:
+            null_seg.bind(self,cntx)
+        
+class conn_seg(null_seg):
+    """
+        summary: >
+            When two segments are connected via a slash,
+            this is a composite.  For each context of the
+            parent, it binds the child, and returns each
+            context of the child.
+    """
+    def __str__(self): 
+        if self.parent.__class__ == root_seg:  
+            return "/%s" % self.child
+        return "%s/%s" % (self.parent, self.child)
+    def __init__(self,parent,child):
+        self.parent = parent
+        self.child  = child
+    def next(self):
+        while 1:
+            try:
+                return self.child.next()
+            except StopIteration:
+                cntx = self.parent.next()
+                self.child.bind(cntx)
+ 
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+        try:
+            cntx = self.parent.next()
+        except StopIteration: 
+            return
+        self.child.bind(cntx)
+
+
+class pred_seg(null_seg):
+    def __str__(self): return "%s[%s]" % (self.parent, self.filter)
+    def __init__(self,parent,filter):
+        self.parent = parent
+        self.filter = filter
+    def next(self):
+        while 1:
+            ret = self.parent.next()
+            if self.filter.exists(ret):
+                return ret
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.parent.bind(cntx)
+
+class or_seg(null_seg):
+    def __str__(self): return "%s|%s" % (self.lhs,self.rhs)
+    def __init__(self,lhs,rhs):
+        self.rhs = rhs
+        self.lhs = lhs
+        self.unq = {}
+    def next(self):
+        seg = self.lhs
+        try:
+            nxt = seg.next()
+            self.unq[nxt] = nxt
+            return nxt
+        except StopIteration: pass
+        seg = self.rhs
+        while 1:
+            nxt = seg.next()
+            if self.unq.get(nxt,None): 
+                continue  
+            return nxt
+    def bind(self,cntx):
+        null_seg.bind(self,cntx)
+        self.lhs.bind(cntx)
+        self.rhs.bind(cntx)
+
+class scalar:
+    def __init__(self,val):  
+        self.val = val
+    def __str__(self): 
+        return str(self.val)
+    def value(self): 
+        return self.val
+
+class equal_pred: 
+    def exists_true(self,cntx): return 1
+    def exists_false(self,cntx): return 0
+    def exists_scalar(self,cntx):
+        self.rhs.bind(cntx)
+        try:
+            while 1:
+                cntx = self.rhs.next()
+                if str(cntx.value) == self.lhs:  #TODO: Remove type hack
+                     return 1
+        except StopIteration: pass
+        return 0
+    def exists_segment(self,cntx):
+        raise NotImplementedError()
+    def __init__(self,lhs,rhs):
+        if lhs.__class__ == scalar:
+            if rhs.__class__ == scalar:
+                if rhs.value() == lhs.value():
+                    self.exists = self.exists_true
+                else:
+                    self.exists = self.exists_false
+            else:
+                self.exists = self.exists_scalar
+        else:
+            if rhs.__class__ == scalar:
+                (lhs,rhs) = (rhs,lhs)
+                self.exists = self.exists_scalar
+            else:
+                self.exists = self.exists_segment
+        self.lhs = str(lhs.value())  #TODO: Remove type hack
+        self.rhs = rhs
+ 
+matchSegment = re.compile(r"""^(\w+|/|\.|\*|\"|\')""")
+
+def parse_segment(expr):
+    """
+        Segments occur between the slashes...
+    """
+    mtch = matchSegment.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if   '/' == tok: return (trav_seg(),expr)
+    elif '.' == tok: 
+        if len(expr) > 1 and '.' == expr[1]:
+            seg = parent_seg()
+            siz = 2
+        else: 
+            seg = self_seg()
+    elif '*' == tok: seg = wild_seg()
+    elif '"' == tok or "'" == tok:
+        (cur,siz) = unquote(expr)
+        seg = match_seg(cur)
+    else:
+        seg = match_seg(tok)
+    return (seg,expr[siz:])
+
+matchTerm = re.compile(r"""^(\w+|/|\.|\(|\"|\')""")
+
+def parse_term(expr):
+    mtch = matchTerm.search(expr)
+    if not(mtch): return (None,expr)
+    tok = mtch.group(); siz = len(tok)
+    if '/' == tok or '.' == tok:
+        return parse(expr)
+    if '(' == tok:
+        (term,expr) = parse_predicate(expr)
+        assert ')' == expr[0]
+        return (term,expr[1:])
+    elif '"' == tok or "'" == tok:
+        (val,siz) = unquote(expr)
+    else:
+        val = tok; siz = len(tok)
+    return (scalar(val),expr[siz:])
+
+def parse_predicate(expr):
+    (term,expr) = parse_term(expr)
+    if not term: raise SyntaxError("term expected: '%s'" % expr)
+    tok = expr[0]
+    if '=' == tok:
+        (rhs,expr) = parse_term(expr[1:])
+        return (equal_pred(term,rhs),expr)
+    if '(' == tok:
+        raise "No functions allowed... yet!"
+    if ']' == tok or ')' == tok:
+        if term.__class__ is scalar:
+            term = match_seg(str(term))
+        return (term,expr)
+    raise SyntaxError("ypath: expecting operator '%s'" % expr)
+
+def parse_start(expr):
+    """
+        Initial checking on the expression, and 
+        determine if it is relative or absolute.
+    """
+    if type(expr) != StringType or len(expr) < 1: 
+        raise TypeError("string required: " + repr(expr))
+    if '/' == expr[0]:
+        ypth = root_seg()
+    else:
+        ypth = self_seg()
+        expr = '/' + expr
+    return (ypth,expr)
+
+def parse(expr):
+    """
+        This the parser entry point, the top level node
+        is always a root or self segment.  The self isn't
+        strictly necessary, but it keeps things simple.
+    """
+    (ypth,expr) = parse_start(expr)
+    while expr:
+        tok = expr[0]
+        if '/' == tok:
+            (child, expr) = parse_segment(expr[1:])    
+            if child: ypth = conn_seg(ypth,child)
+            continue
+        if '[' == tok:
+            (filter, expr) = parse_predicate(expr[1:])
+            assert ']' == expr[0]
+            expr = expr[1:]
+            ypth = pred_seg(ypth,filter)
+            continue
+        if '|' == tok:
+            (rhs, expr) = parse(expr[1:])
+            ypth = or_seg(ypth,rhs)
+            continue
+        if '(' == tok:
+            (child,expr) = parse(expr[1:])
+            assert ')' == expr[0]
+            expr = expr[1:]
+            ypth = conn_seg(ypth,child)
+            continue
+        break
+    return (ypth,expr)
+
+class convert_to_value(null_seg):
+    def __init__(self,itr):
+        self.itr = itr
+    def next(self):
+        return self.itr.next().value
+    def bind(self,cntx):
+        self.itr.bind(cntx)
+
+def ypath(expr,target=noTarget,cntx=0):
+    (ret,expr) = parse(expr)
+    if expr: raise SyntaxError("ypath parse error `%s`" % expr)
+    if not cntx: ret = convert_to_value(ret)
+    if target is noTarget: return ret
+    return ret.apply(target)
Index: /pyyaml-legacy/trunk/yaml/ordered_dict.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/ordered_dict.py	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/ordered_dict.py	(revision 71)
@@ -0,0 +1,31 @@
+# This is extremely crude implementation of an OrderedDict.
+# If you know of a better implementation, please send it to
+# the author Steve Howell.  You can find my email via 
+# the YAML mailing list or wiki.
+
+class OrderedDict(dict): 
+    def __init__(self): 
+        self._keys = [] 
+ 
+    def __setitem__(self, key, val): 
+        self._keys.append(key) 
+        dict.__setitem__(self, key, val) 
+ 
+    def keys(self): 
+        return self._keys 
+ 
+    def items(self):
+        return [(key, self[key]) for key in self._keys]
+ 
+if __name__ == '__main__': 
+    data = OrderedDict()
+    data['z'] = 26
+    data['m'] = 13
+    data['a'] = 1
+    for key in data.keys(): 
+        print "The value for %s is %s" % (key, data[key]) 
+    print data
+
+
+
+
Index: /pyyaml-legacy/trunk/yaml/implicit.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/implicit.py	(revision 102)
+++ /pyyaml-legacy/trunk/yaml/implicit.py	(revision 102)
@@ -0,0 +1,47 @@
+import re
+import string
+from timestamp import timestamp, matchTime
+from yaml_escapes import escape
+
+DATETIME_REGEX   = re.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")
+FLOAT_REGEX      = re.compile("^[-+]?[0-9][0-9,]*\.[0-9]*$")
+SCIENTIFIC_REGEX = re.compile("^[-+]?[0-9]+(\.[0-9]*)?[eE][-+][0-9]+$")
+OCTAL_REGEX      = re.compile("^[-+]?([0][0-7,]*)$")
+HEX_REGEX        = re.compile("^[-+]?0x[0-9a-fA-F,]+$")
+INT_REGEX        = re.compile("^[-+]?(0|[1-9][0-9,]*)$")
+
+def convertImplicit(val):
+    if val == '~':
+        return None
+    if val == '+':
+        return 1
+    if val == '-':
+        return 0
+    if val[0] == "'" and val[-1] == "'":
+        val = val[1:-1]
+        return string.replace(val, "''", "\'")
+    if val[0] == '"' and val[-1] == '"':
+        val = val[1:-1]
+        unescapedStr = escape(val)
+
+        return unescapedStr
+    if matchTime.match(val):
+        return timestamp(val)
+    if INT_REGEX.match(val):
+        return int(cleanseNumber(val))
+    if OCTAL_REGEX.match(val):
+        return int(val, 8)
+    if HEX_REGEX.match(val):
+        return int(val, 16)
+    if FLOAT_REGEX.match(val):
+        return float(cleanseNumber(val))
+    if SCIENTIFIC_REGEX.match(val):
+        return float(cleanseNumber(val))
+    return val
+
+def cleanseNumber(str):
+    if str[0] == '+':
+        str = str[1:]
+    str = string.replace(str,',','')
+    return str
+
Index: /pyyaml-legacy/trunk/yaml/stream.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/stream.py	(revision 74)
+++ /pyyaml-legacy/trunk/yaml/stream.py	(revision 74)
@@ -0,0 +1,193 @@
+import re
+import string
+
+def indentLevel(line):
+    n = 0
+    while n < len(line) and line[n] == ' ':
+        n = n + 1
+    return n
+
+class LineNumberStream:
+    def __init__(self, filename=None):
+        self.curLine = 0
+        self.filename = filename
+
+    def get(self):
+        line = self.getLine()
+        self.curLine += 1 # used by subclass
+        if line:
+            line = noLineFeed(line)
+        return line
+
+    def lastLineRead(self):
+        return self.curLine
+
+class FileStream(LineNumberStream):
+    def __init__(self, filename):
+        self.fp = open(filename)
+        LineNumberStream.__init__(self, filename)
+
+    def getLine(self):
+        line = self.fp.readline()
+        if line == '': line = None
+        return line
+
+class StringStream(LineNumberStream):
+    def __init__(self, text):
+        self.lines = split(text)
+        self.numLines = len(self.lines)
+        LineNumberStream.__init__(self)
+
+    def getLine(self):
+        if self.curLine < self.numLines:
+            return self.lines[self.curLine]
+
+def split(text):
+    lines = string.split(text, '\n')
+    if lines[-1] == '':
+        lines.pop()
+    return lines
+
+def eatNewLines(stream):
+    while 1:
+       line = stream.get()
+       if line is None or len(string.strip(line)):
+           return line
+
+COMMENT_LINE_REGEX = re.compile(R"\s*#")
+def isComment(line):
+    return line is not None and COMMENT_LINE_REGEX.match(line)
+
+class CommentEater:
+    def __init__(self, stream):
+        self.stream = stream
+        self.peeked = 1
+        self.line = eatNewLines(stream)
+        self.eatComments()
+
+    def eatComments(self):
+        while isComment(self.line):
+            self.line = self.stream.get()
+
+    def peek(self):
+        if self.peeked:
+            return self.line
+        self.peeked = 1
+        self.line = self.stream.get()
+        self.eatComments()
+        return self.line
+
+    def lastLineRead(self):
+        return self.stream.lastLineRead()
+
+    def pop(self):
+        data = self.peek()
+        self.peeked = 0
+        return data
+
+class NestedText:
+    def __init__(self, stream):
+        self.commentEater = CommentEater(stream)
+        self.reset()
+
+    def lastLineRead(self):
+        return self.commentEater.lastLineRead()
+
+    def reset(self):
+        self.indentLevel = 0
+        self.oldIndents = [0]
+
+    def peek(self):
+        nextLine = self.commentEater.peek()
+        if nextLine is not None:
+            if indentLevel(nextLine) >= self.indentLevel:
+                return nextLine[self.indentLevel:]
+            elif nextLine == '':
+                return ''                
+
+    def pop(self):
+        line = self.peek()
+        if line is None:
+            self.indentLevel = self.oldIndents.pop()
+            return
+        self.commentEater.pop()
+        return line
+
+    def popNestedLines(self):
+        nextLine = self.peek()
+        if nextLine is None or nextLine == '' or nextLine[0] != ' ':
+            return []
+        self.nestToNextLine()
+        lines = []
+        while 1:
+            line = self.pop()
+            if line is None:
+                break
+            lines.append(line)
+        return lines
+
+    def nestToNextLine(self):
+        line = self.commentEater.peek()
+        indentation = indentLevel(line)
+        if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+            self.error("Inadequate indentation", line)
+        self.setNewIndent(indentation)
+
+    def nestBySpecificAmount(self, adjust):
+        self.setNewIndent(self.indentLevel + adjust)
+        
+    def setNewIndent(self, indentLevel):
+        self.oldIndents.append(self.indentLevel)
+        self.indentLevel = indentLevel    
+
+class YamlLoaderException(Exception):
+    def __init__(self, *args):
+        (self.msg, self.lineNum, self.line, self.filename) = args
+
+    def __str__(self):
+        msg = """\
+%(msg)s:
+near line %(lineNum)d:
+%(line)s
+""" % self.__dict__
+        if self.filename:
+            msg += "file: " + self.filename
+        return msg
+
+class NestedDocs(NestedText):
+    def __init__(self, stream):
+        self.filename = stream.filename
+        NestedText.__init__(self,stream)
+        line = NestedText.peek(self)
+        self.sep = '---'
+        if self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+        else:
+            self.eatenDocSep = self.sep
+
+    def startsWithSep(self,line):
+        if line and self.sep == line[:3]: return 1
+        return 0
+
+    def popDocSep(self):
+        line = self.eatenDocSep
+        self.eatenDocSep = None
+        self.reset()
+        return line
+
+    def pop(self):
+        if self.eatenDocSep is not None:
+            raise "error"
+        line = self.commentEater.peek()
+        if line and self.startsWithSep(line):
+            self.eatenDocSep = NestedText.pop(self)
+            return None
+        return NestedText.pop(self)
+
+    def error(self, msg, line):
+        raise YamlLoaderException(msg, self.lastLineRead(), line, self.filename)
+
+def noLineFeed(s):
+    while s[-1:] in ('\n', '\r'):
+        s = s[:-1]
+    return s
Index: /pyyaml-legacy/trunk/yaml/tests/testInlineTokenizer.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testInlineTokenizer.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testInlineTokenizer.py	(revision 90)
@@ -0,0 +1,22 @@
+import YamlTest
+from test import assertEquals
+from yaml.load import *
+
+
+class Test(YamlTest.YamlTest):
+    def testSimple(self):
+        tokenizer = InlineTokenizer('[ foo, bar ]')
+        assertEquals(tokenizer.next(), '[')
+        assertEquals(tokenizer.next(), 'foo')
+        assertEquals(tokenizer.next(), 'bar')
+        assertEquals(tokenizer.next(), ']')
+
+    def testSimpleHash(self):
+        tokenizer = InlineTokenizer('{ foo: bar }')
+        assertEquals(tokenizer.next(), '{')
+        assertEquals(tokenizer.next(), 'foo: bar') # might change
+        assertEquals(tokenizer.next(), '}')
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/test.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/test.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/test.py	(revision 91)
@@ -0,0 +1,18 @@
+def assertEquals(first, second, msg=''):
+    if first != second:
+        raise AssertionError, \
+              (msg + "\n%s !=\n%s" % (`first`, `second`))
+
+def assertError(func, expectedError):
+    raised = 1
+    try:
+        func()
+        raised = 0
+    except Exception, e:
+        assertEquals(str(e), expectedError)
+    except:
+        raise "Unexpected exception"
+    if raised == 0:
+        raise "Never threw exception"
+
+
Index: /pyyaml-legacy/trunk/yaml/tests/here.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/here.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/here.py	(revision 91)
@@ -0,0 +1,14 @@
+import re
+from string import split, join
+
+def flushLeft(s):
+    lines = split(s,'\n')
+    lastLine = lines.pop()
+    if re.match(r"\S", lastLine):
+        raise "bad last line"
+    indent = len(lastLine)
+    ret = []
+    for line in lines[1:]:
+        ret.append(line[indent:] + '\n')
+    return join(ret,'')
+
Index: /pyyaml-legacy/trunk/yaml/tests/testYpath.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testYpath.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/testYpath.py	(revision 91)
@@ -0,0 +1,24 @@
+import YamlTest
+import yaml
+from test import assertEquals
+
+class Test(YamlTest.YamlTest):
+    def testYpath(self):
+        try:    
+            for test in yaml.loadFile("./yaml/tests/TestingSuite/ypath.yml"):
+                if not test.has_key('ignore'):
+                    expr = test['ypath']
+                    pth = yaml.ypath(expr,cntx=1)
+                    lst = [] 
+                    for x in pth.apply(test['data']):
+                        lst.append(str(x))
+                    exp = test['expected']
+                    if test.has_key('unordered'):
+                       lst.sort()
+                       exp.sort()
+                    assertEquals(lst,exp,expr + " => " + str(pth))
+        except NotImplementedError: 
+            assert()
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testYamlBasics.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testYamlBasics.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testYamlBasics.py	(revision 90)
@@ -0,0 +1,163 @@
+import YamlTest
+from here import *
+from test import assertEquals
+from yaml.load import l
+from yaml.dump import d
+
+class Test(YamlTest.YamlTest):
+    def setUp(self):
+        # print '>>>>>>>>>>>>>>>'
+        pass
+
+    def testNoLineFeed(self):
+        from yaml.stream import noLineFeed
+        assertEquals("foo", noLineFeed("foo\n"))
+        assertEquals("bar", noLineFeed("bar\n"))
+        assertEquals("bar", noLineFeed("bar\r\n"))
+        assertEquals("", noLineFeed("\r\n"))
+
+    def XXXtest9(self):
+        # XXX - not sure how this gets handled now
+        self.verify(
+            """
+            - foo: 1
+                bar: 2
+            """,
+            [ {'foo': 1, '  bar': 2}])
+
+    def testOutlineSnippet(self):
+        self.verify(
+            """
+            - YAML ToDo:
+                - y2outline
+                - support generic transfers
+                - work on YAML.py:
+                    - work on Store
+            """,
+            [ {'YAML ToDo': [   
+                'y2outline',
+                'support generic transfers',
+                { 'work on YAML.py': ['work on Store'] }
+                ]
+              }
+            ])
+
+    def testQuotedString(self):
+        self.verify(
+            """
+            ---
+            foo: 'key: value'
+            """,
+            {'foo': "key: value"}
+            )
+
+    def testFloatRedHerring(self):
+        self.verify(
+            """
+            ---
+            - 'Version: 0.18.0'
+            """,
+            [ 'Version: 0.18.0' ]
+            )
+
+    def testDashInQuotes(self):
+        self.verify(
+            """
+            ---
+            title: 'Perspective Broker - twisted.spread'
+            """,
+            {'title': 'Perspective Broker - twisted.spread'}
+            )
+
+    def testQuestionMarks(self):
+        self.verify(
+            """
+            ---
+            hello: you there?
+            foo:
+                - ok?
+                - sure?
+            bar:
+                - for here or to go?
+                - more sugar?
+            """,
+            {   
+                'hello': 'you there?',
+                'foo': ['ok?', 'sure?'],
+                'bar': ['for here or to go?', 'more sugar?']
+            }
+            )
+
+    def testDoubleQuoteEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            "I'm escaped!": simple
+            """,
+            { "I'm escaped!": 'simple' }
+            )
+
+    def testColonsInsideEscapedKeys(self):
+        self.verify(
+            """
+            ---
+            'aaa: bbbb': simple
+            """,
+            { 'aaa: bbbb': 'simple' }
+            )
+
+    def testControlChars(self):
+        self.verify(
+            r"""
+            control: "\b1998\t1999\t2000\n"
+            """,
+            { 'control': "\b1998\t1999\t2000\n" }
+        )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.verify(
+                r'''
+                unicode: "Sosa did fine.\u263A"
+                ''',
+                { 'unicode': u"Sosa did fine.\u263A"}
+            )
+
+    def testMultiLineScalar(self):
+        self.verify(
+            """
+            plain: This unquoted
+                   scalar spans
+                   many lines.
+            """,
+            { 'plain': 'This unquoted scalar spans many lines.' }
+        )
+
+    def testDomainType(self):
+        class MyYamlConfig:
+            def resolveType(self, data, url):
+                if url == '!!name':
+                    return 'Foo ' + data
+                elif url == '!!coords':
+                    return { 'x': data[0], 'y': data[1]}
+                else:
+                    raise 'url not passed in correctly'
+        data = YamlTest.loadFlushLeft("""
+            name: !!name Barson
+            coords: !!coords
+              - 10
+              - 20
+            """, 
+            MyYamlConfig())
+        self.assertEquals(data[0], 
+            {'name': 'Foo Barson',
+            'coords': { 'x': 10, 'y': 20 } }
+        )
+
+    def testQuickInterfaces(self):
+        assertEquals(l("--- foo"), "foo")
+        assertEquals(d({'foo': 'bar'}), "---\nfoo: bar\n")
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testFileNamesInErrors.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testFileNamesInErrors.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testFileNamesInErrors.py	(revision 90)
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import YamlTest
+import yaml, re
+from test import assertError
+
+class Test(YamlTest.YamlTest):
+    def testParseErrors(self):
+        try:
+            out = yaml.loadFile('TestFileNamesInErrors.py').next()
+            assertError('Parsed an invalid file')
+        except Exception, e:
+            self.failUnless(re.search('TestFileNamesInErrors\.py', str(e)))
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testNestedText.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testNestedText.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testNestedText.py	(revision 90)
@@ -0,0 +1,311 @@
+import YamlTest
+from yaml.load import *
+from here import flushLeft
+from test import assertEquals
+from yaml.stream import NestedText, CommentEater, split
+
+here = flushLeft # pardon the Perlism
+
+def stringStream(str):
+    return StringStream(here(str))
+
+def commentEater(str):
+    return CommentEater(stringStream(str))
+
+def nestedText(str):
+    return NestedText(stringStream(str))
+
+def nestedDocs(str):
+    return NestedDocs(stringStream(str))
+
+class Test(YamlTest.YamlTest):
+    def tryPop(self, expected):
+        assertEquals(self.nt.pop(), expected)
+        
+    def tryPopNestedLines(self, expected):
+        assertEquals(self.nt.popNestedLines(), expected)
+        
+    def tryPeek(self, expected):
+        assertEquals(self.nt.peek(), expected)
+
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop('')
+        self.tryPop(None)
+        
+    def test2(self):
+        self.nt = nestedText("""
+            apple
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def test3(self):
+        self.nt = nestedDocs("""
+            seattle
+            --- foo
+            bluffton
+            """)
+        assertEquals(self.nt.popDocSep(), '---')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- foo')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+    def testEatComments(self):
+        self.nt = commentEater("""
+            # ignore
+              # these
+            silly
+            """)
+        self.tryPop('silly')
+
+    def testNestedDocsEatComments(self):
+        self.nt = nestedDocs("""
+            # foo
+              # bar
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+        assertEquals(self.nt.lastLineRead(), 4)
+
+    def testNestedTextEatNewline(self):
+        self.nt = nestedDocs("""
+            
+            ---
+            shabazz
+            """)
+        self.nt.popDocSep()
+        self.tryPop('shabazz')
+
+    def testDocSep(self):
+        data = here("""
+            --- city
+            seattle
+            --- town
+            bluffton
+            """)
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+        self.tryPop(None)
+        assertEquals(self.nt.popDocSep(), '--- town')
+        self.tryPop('bluffton')
+        self.tryPop(None)
+
+        data = here("""
+            # comments at top
+            # should be ignored
+            """) + data
+        self.nt = NestedDocs(StringStream(data))
+        assertEquals(self.nt.popDocSep(), '--- city')
+        self.tryPop('seattle')
+
+    def testNestedComments(self):
+        self.nt = nestedText("""
+            apple
+              # ignore this comment
+                banana
+                   foo
+            """)
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+        self.nt.nestBySpecificAmount(2)
+        self.tryPop(' foo')
+
+    def testStream(self):
+        stream = StringStream(here("""
+            python
+            perl
+            java
+            """))
+        assertEquals(stream.get(), "python")
+        assertEquals(stream.get(), "perl")
+        assertEquals(stream.get(), "java")
+        
+    def test1(self):
+        self.nt = nestedText(
+            """
+            1a
+             2a
+             2b
+                 3a
+             2c
+            1b
+            """)
+        self.tryPop('1a')
+        self.nt.nestToNextLine()
+        self.tryPop('2a')
+        self.tryPop('2b')
+        self.nt.nestToNextLine()
+        self.tryPop('3a')
+        self.tryPop(None)
+        self.tryPop('2c')
+        self.tryPop(None)
+        self.tryPeek('1b')
+        self.tryPop('1b')
+        self.tryPop(None)
+        
+    def XXXtestEmptyLines(self):
+        # not sure if this is valid test any more
+        self.nt = nestedDocs("""
+            ---
+             apple
+
+                banana
+            """)
+        self.nt.popDocSep()
+        self.nt.nestToNextLine()
+        self.tryPop('apple')
+        self.nt.nestToNextLine()
+        self.tryPop('')
+        self.nt.nestToNextLine()
+        self.tryPop('banana')
+
+    def testFoldedCase(self):
+        self.nt = nestedText(
+            """
+            ---
+             Aaa
+             Bbb
+
+               11
+               22
+
+             Ccc
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('Aaa')
+        self.tryPop('Bbb')
+        self.tryPop('')
+
+    def testRedHerringDocSep(self):
+        self.nt = nestedDocs(
+            """
+            ---
+            foo:
+                ---
+            """)
+        self.nt.popDocSep()
+        self.tryPop('foo:')
+        self.nt.nestToNextLine()
+        self.tryPop('---')
+
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            line1: this is
+               continued
+            line2
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('line1: this is')
+        self.tryPopNestedLines(['continued'])
+        self.tryPop('line2')
+            
+    def testGetToNextIndent(self):
+        self.nt = nestedText(
+            """
+            ---
+            key1: this is
+               continued
+               with multiple lines
+            key2:
+                 key2a:
+                   hello
+                   world
+            key3:
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('key1: this is')
+        self.tryPopNestedLines(['continued', 'with multiple lines'])
+        self.tryPop('key2:')
+        self.nt.nestToNextLine()
+        self.tryPop('key2a:')
+        self.tryPopNestedLines(['hello', 'world'])
+            
+    def testPopNestedLinesWithNoneNested(self):
+        self.nt = nestedText(
+            """
+            ---
+            - apple
+            - banana
+            - carrot
+            """)
+        self.nt.pop()
+        self.nt.nestToNextLine()
+        self.tryPop('- apple')
+        self.tryPopNestedLines([])
+        self.tryPop('- banana')
+
+    def testLineNumbers(self):
+        data = \
+            """
+            one
+            two
+            #
+            three
+            """
+        stream = StringStream(here(data))
+        stream.get()
+        assertEquals(stream.lastLineRead(), 1)
+        stream.get()
+        assertEquals(stream.lastLineRead(), 2)
+        nt = nestedText(data)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 1)
+        nt.pop()
+        assertEquals(nt.lastLineRead(), 2)
+        nt.pop()  # eats a comment too
+        assertEquals(nt.lastLineRead(), 4)
+
+    def testSplit(self):
+        assertEquals(split("foo\nbar"), ['foo', 'bar'])
+        assertEquals(split("foo\nbar\n"), ['foo', 'bar'])        
+
+    def testLoaderException(self):
+        import yaml
+        from yaml.stream import YamlLoaderException
+        exception = None
+        try:
+            yaml.load('invalid YAML').next()
+        except YamlLoaderException, e:
+            exception = e
+        assertEquals(exception.lineNum, 1)
+            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testPluggableDictionary.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testPluggableDictionary.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testPluggableDictionary.py	(revision 90)
@@ -0,0 +1,30 @@
+import YamlTest
+import yaml
+from yaml.ordered_dict import OrderedDict
+from yaml.redump import redump
+from test import assertEquals
+
+stream = """\
+---
+zzz: 0
+yyy: 1
+xxx: 2
+alpha: 3
+---
+-
+    foo: 1
+    bar: 2
+-
+    z: 1
+    y: 2
+"""
+class Test(YamlTest.YamlTest):
+    
+    def testPluggable(self):
+        my_dict = yaml.loadOrdered(stream).next()
+        assertEquals(my_dict.keys(), ['zzz', 'yyy', 'xxx', 'alpha'])
+        assertEquals(redump(stream), stream)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testPullParser.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testPullParser.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/testPullParser.py	(revision 91)
@@ -0,0 +1,116 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals
+from testPushDumper import mockEvents
+from yaml import load
+
+"""
+This is experimental code.  I am moving toward a rewrite of the YAML 
+parser so that it uses a pull interface.  I am using a mock object
+to emulate the parser, so that I can experiment with the interface a bit,
+and also to sketch out some ideas for schema-driven parsing.
+"""
+
+class MockParser:
+    def __init__(self, events):
+        self.events = events
+        self.index = 0
+
+    def __getattr__(self, name):
+        (nextName, value) = self.events[self.index]
+        if name != nextName:
+            raise "Improper mocking for event %d (%s vs. %s)" % \
+                (self.index, name, nextName)
+        self.index += 1
+        return lambda: value
+
+class Loader:
+    def __init__(self, parser):
+        self.parser = parser
+
+    def load(self, data):
+        typ = self.parser.getType()
+        return self._load(typ)
+
+    def _load(self, typ):
+        if typ == 'seq':
+            return self._loadSeq()
+        elif typ == 'map':
+            return self._loadMap()
+        else:
+            return self._loadScalar()
+
+    def _loadSeq(self):
+        results = []
+        def itemFunc(self, results, typ):
+            results.append(self._load(typ))
+        return self.iterateItems(results, itemFunc)
+
+    def _loadMap(self):
+        results = {}
+        def itemFunc(self, results, typ):
+            key = self._load(typ)
+            valTyp = self.parser.getType()
+            value = self._load(typ)
+            results[key] = value
+        return self.iterateItems(results, itemFunc)
+
+    def iterateItems(self, results, func):
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                func(self, results, typ)
+
+    def _loadScalar(self):
+        return self.parser.getScalar()
+
+def mockParser(data):
+    events = mockEvents(data)
+    return MockParser(events)
+
+def mockLoad(data):
+    loader = Loader(mockParser(data))
+    return loader.load(None) # None for data cause events are all mocked 
+
+def testRoundTrip(data):
+    obj = mockLoad(data)
+    assertEquals(obj, data)
+
+class Test(YamlTest.YamlTest):
+
+    def testMock(self):
+        parser = MockParser( [
+            ('getScalar', 'foo'),
+            ('getArray', [1,2,3]),
+            ('getScalar', None),
+        ])
+        assertEquals(parser.getScalar(), 'foo')
+        assertEquals(parser.getArray(), [1,2,3])
+        assertEquals(parser.getScalar(), None)
+
+    def testList(self):
+        testRoundTrip([1,2,3])
+
+    def testDict(self):
+        testRoundTrip({'foo': 'bar'})
+
+    def testListDict(self):
+        testRoundTrip( [ [1,2,3], {'foo': 'bar'} ] )
+
+    def testComplexStructure(self):
+        data = load(flushLeft(
+            """
+            list:
+                - {foo: bar}
+                - [1, 2, 3]
+            dict:
+                name: steve
+                games: [hoops, pool]
+            """))
+        testRoundTrip(data)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testSpec.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testSpec.py	(revision 95)
+++ /pyyaml-legacy/trunk/yaml/tests/testSpec.py	(revision 95)
@@ -0,0 +1,55 @@
+import YamlTest
+import yaml
+import re
+import glob
+from test import assertEquals, assertError
+from here import flushLeft
+
+
+def loadFlushLeft(stream, typeResolver=None):
+    return list(yaml.load(flushLeft(stream), typeResolver))
+
+class YamlLoader:
+    # XXX python 2.1 has weak lambda support
+    def __init__(self, doc):
+        self.doc = doc
+    def __call__(self):
+        return list(yaml.load(self.doc['yaml']))
+
+class Test(YamlTest.YamlTest):
+    def testFromYaml(self):
+        testFiles = glob.glob('./yaml/tests/TestingSuite/*.yml')
+        for file in testFiles:
+            try:
+                docs = yaml.loadFile(file)
+            except IOError:
+                raise "See TESTING for how to set up TestingSuite"
+            for doc in docs:
+                if doc.has_key('python'):
+                    self.verifyOneDoc(doc)
+                if doc.has_key('error') and doc['error'].has_key('python'):
+                    #if doc.has_key('test'):
+                    #    print 'asserting error on ',doc['test']
+                    assertError(YamlLoader(doc), doc['error']['python'])
+
+    def verifyOneDoc(self, doc):
+        if doc.has_key('python_setup'):
+            exec(doc['python_setup'])
+        data = eval(doc['python'])
+        #if doc.has_key('test'):
+        #    print 'asserting equals on ',doc['test']
+        assertEquals(list(yaml.load(doc['yaml'])), data)
+        if not doc.has_key('NO_ROUND_TRIP'):
+            self.assertRoundTrip(data)
+
+    def assertRoundTrip(self, data):
+        # XXX - A5 won't round trip when enclosed by 
+        # an array...need to investigate
+        for item in data:
+            assertEquals(item, 
+                yaml.load(yaml.dump(item)).next(), 'roundtrip')
+
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testDumper.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testDumper.py	(revision 107)
+++ /pyyaml-legacy/trunk/yaml/tests/testDumper.py	(revision 107)
@@ -0,0 +1,478 @@
+import YamlTest
+from yaml.dump import *
+import yaml
+from here import flushLeft
+from test import assertEquals
+
+class SampleClass:
+    def expected(self, modname, classname):
+        """
+        Tough to test, because this class may be in __main__ 
+        namespace, may be in TestDumper, depending where you 
+        run it
+        """
+        return """
+        --- !!%s.%s
+        bar: 4
+        foo: 3
+        items:
+            - apple
+            - banana
+        """ % (modname, classname)
+
+    def __init__(self):
+        self.foo = 3
+        self.bar = 4
+        self.items = ['apple', 'banana']
+
+
+class SampleException(Exception):
+    def __init__(self, args):
+        self.args = args
+
+class Test(YamlTest.YamlTest):
+    def dumpTest(self, obj, expect):
+        assertEquals(yaml.dump(obj), flushLeft(expect))
+    def dumpTestSort(self,sort):
+        obj = {'a':'aaaa','d':'dddd','b':'bbbb','c':'cccc'}
+        exp = flushLeft(\
+            """
+            ---
+            b: bbbb
+            d: dddd
+            a: aaaa
+            c: cccc
+            """)
+        dumper = yaml.Dumper().setSort(sort)
+        self.assertEquals(dumper.dump(obj),exp)
+    def testsort_map(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3})
+    def testsort_tuple(self):
+        self.dumpTestSort(('b','d','a'))
+    def testsort_list(self):
+        self.dumpTestSort(['b','d','a'])
+    def testsort_func(self):
+        self.dumpTestSort({'a':4,'b':2,'d':3}.get)
+    def test1(self):
+        self.dumpTest(
+            { 'foo': 'bar', 'yo': 'mama' },
+            """
+            ---
+            foo: bar
+            yo: mama
+            """,
+        )
+
+    def test2(self):
+        self.dumpTest(
+            { 'foo': {'bar': 3} },
+            """
+            ---
+            foo:
+                bar: 3
+            """,
+        )
+
+    def test3(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': {
+                    'apple': 'red',
+                    'banana': 'yellow',
+                }
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                apple: red
+                banana: yellow
+            """
+            )
+                
+    def test4(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ['apple', 'orange']
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testTuple(self):
+        self.dumpTest(
+            { 
+                'foo': 3,
+                'fruits': ('apple', 'orange')
+            },
+            """
+            ---
+            foo: 3
+            fruits:
+                - apple
+                - orange
+            """
+            )
+                
+    def testMultiLineBlock(self):
+        self.dumpTest(
+             { 
+                 'foo': "a\nb\nc\n",
+             },
+             """
+             ---
+             foo: |
+                 a
+                 b
+                 c
+             """
+             )
+
+    def testDoubleQuote(self):
+        assertEquals(doubleUpQuotes("foo'bar"), "foo''bar")
+        assertEquals(doubleUpQuotes("''x'"), "''''x''")
+
+    def testQuotingRules(self):
+        # Raw:
+        self.assertEquals(dump(None), "--- ~\n")
+        self.assertEquals(dump('simple'), "--- simple\n")
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('two words'), "--- two words\n")
+        self.assertEquals(dump('single\'quote'), "--- single'quote\n")
+        self.assertEquals(dump('5.2'), "--- '5.2'\n")
+        self.assertEquals(dump(5.2), "--- 5.2\n")
+        self.assertEquals(dump(1234), "--- 1234\n")
+        self.assertEquals(dump('harmless-dash'), "--- harmless-dash\n")
+        self.assertEquals(dump('* harmless bullet'), "--- * harmless bullet\n")
+        self.dumpTest(
+            [ "a - b", "another-harmless-dash" ],
+            """
+            ---
+            - a - b
+            - another-harmless-dash
+            """)
+        # Single Quoted:
+        self.assertEquals(dump(''), "--- ''\n")
+        self.assertEquals(dump('4.3.1.5.2'), "--- '4.3.1.5.2'\n")
+        self.assertEquals(dump("'leading quote"), '--- "\'leading quote"\n')
+        self.assertEquals(dump('4.3.'), "--- '4.3.'\n")
+        self.assertEquals(dump('12345'), "--- '12345'\n")
+        self.assertEquals(dump('-12345'), "--- '-12345'\n")
+        self.assertEquals(dump('key: value'), "--- 'key: value'\n")
+        self.assertEquals(dump('ending colon:'), "--- 'ending colon:'\n")
+        self.assertEquals(dump('&foo'), "--- '&foo'\n")
+        self.assertEquals(dump(' xx'), "--- ' xx'\n")
+        self.assertEquals(dump('*bar'), "--- '*bar'\n")
+        assertEquals(dump('"middle \'quote'), '--- \'"middle \'\'quote\'\n')
+        # Double quoted:
+        self.assertEquals(dump("\thas a tab"), "--- \"\\thas a tab\"\n")
+        self.dumpTest(
+            { "key: quote": 'normal value' },
+            """
+            ---
+            'key: quote': normal value
+            """)
+
+    def testArrayWithSingleQuoted(self):
+        self.dumpTest(
+            [ 'foo:', {'bar': 'colon:'}],
+            """
+            ---
+            - 'foo:'
+            -
+                bar: 'colon:'
+            """
+            )
+
+    def testDumpObject(self):
+        sample = SampleClass()
+        self.dumpTest(sample, 
+            sample.expected(sample.__module__, 'SampleClass'))
+
+    def testWithSpuriousToYaml(self):
+        class ClassWithSpuriousToYaml(SampleClass):
+            to_yaml = 1 # Shouldn't get invoked
+        x = ClassWithSpuriousToYaml()
+        self.dumpTest(x, 
+            x.expected(x.__module__,'ClassWithSpuriousToYaml'))
+
+    def testNormalToYamlUse(self):
+        class NormalYamlUse(SampleClass):
+            def to_yaml(self):
+                dict = {}
+                dict['bar'] = self.foo * 2
+                return (dict, None)
+        self.dumpTest(NormalYamlUse(),
+            """
+            ---
+            bar: 6
+            """)
+
+    def testDumpingPrivateTypes(self):
+        class Foobar(SampleClass):
+            def to_yaml(self):
+                dict = {'foo': 'bar'}
+                return (dict, '!!foobar')
+        self.dumpTest(Foobar(),
+            """
+            --- !!foobar
+            foo: bar
+            """)
+        class OddList(SampleClass):
+            def to_yaml(self):
+                return ([1, 3, 5], '!!oddlist')
+        self.dumpTest(OddList(),
+            """
+            --- !!oddlist
+            - 1
+            - 3
+            - 5
+            """)
+
+
+    def testToYamlShouldBeAllowedToThrowIfItWants(self):
+        class ThrowsInsideToYaml:
+            def to_yaml(self):
+                raise SampleException('bla')
+        caught_exception = 'undef'
+        try:
+            dump(ThrowsInsideToYaml())
+        except Exception, e:
+            caught_exception = e
+        self.assertEquals('bla', caught_exception.args)
+
+    def testObjectWithListOfClasses(self):
+        class Foo:
+            def __init__(self, items):
+                self.items = items
+             
+        class Bar:
+            def __init__(self, data):
+                self.data = data
+
+        foo = Foo([Bar('apple'), Bar('banana')])
+        mod = foo.__module__ # depends where called
+        self.dumpTest(foo,
+            """
+            --- !!%s.Foo
+            items:
+                - !!%s.Bar
+                    data: apple
+                - !!%s.Bar
+                    data: banana
+            """ % (mod, mod, mod))
+
+    def testHasMethod(self):
+        class ClassWithMethodA:
+            b = 1
+            def a(): pass
+
+        sc = ClassWithMethodA()
+        self.assertEquals(1, hasMethod(sc, 'a'))
+        self.assertEquals(0, hasMethod(sc, 'b'))
+
+    def testComplexKey(self):
+        self.dumpTest( {(3,4): 4},
+            """
+            ---
+            ?
+                - 3
+                - 4
+            : 4
+            """)            
+    
+    def testApostrophe(self):
+        self.dumpTest( "Joe's hot dogs.\n",
+            """
+            --- |
+            Joe's hot dogs.
+            """)
+
+    def testCustomIndent(self):
+        self.assertEquals(
+            yaml.Dumper().setIndent('xx').dump(
+                { 
+                    'foo': 3,
+                    'fruits': ('apple', 'orange')
+                }, 
+            ),
+            flushLeft(
+                """
+                ---
+                foo: 3
+                fruits:
+                xx- apple
+                xx- orange
+                """
+            )
+            )
+
+    def testUnicode(self):
+        if YamlTest.hasUnicode:
+            self.dumpTest({'foo': u"Foo\u263A"},
+                r"""
+                ---
+                foo: "Foo\u263a"
+                """)
+
+    def testTab(self):
+        self.dumpTest({'tab': "foo\tbar"},
+            r"""
+            ---
+            tab: "foo\tbar"
+            """)
+
+    def testIsMulti(self):
+        self.failUnless(isMulti("foo\nbar"))
+        self.failIf(isMulti("foobar"))
+        self.failIf(isMulti("line\twith tab\nsecond line"))
+        self.failUnless(isMulti("foo\\slash\nbar"))
+
+    def testHasSpecialChar(self):
+        self.failUnless(hasSpecialChar("foo\tbar"))
+        self.failIf(hasSpecialChar("foobar"))
+
+    def testTabs(self):
+        self.dumpTest({'control': "\b1998\t1999\t2000\n"},
+            r"""
+            ---
+            control: "\b1998\t1999\t2000\n"
+            """)
+
+    def test12345(self):
+        self.dumpTest({'foo': 12345, 'bar': '12345'},
+            r"""
+            ---
+            bar: '12345'
+            foo: 12345
+            """)
+
+    def testDataThatsCoincidentallyTheSame(self):
+        self.dumpTest([ {'foo': 'bar'}, {'foo': 'bar'} ],
+            """
+            ---
+            -
+                foo: bar
+            -
+                foo: bar
+            """)
+
+    def testAliasClass(self):
+        dup = {'foo': 'bar'}
+        dupList = [dup, dup]
+        myAnchors = YamlAnchors(dupList)
+        self.assertEquals(id(dup), myAnchors._anchorVisits.keys()[0])
+        self.assertEquals(0,myAnchors.isAlias(dup))
+        self.assertEquals(1,myAnchors.shouldAnchor(dup) )
+        self.assertEquals(0,myAnchors.shouldAnchor('bar'))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup['foo']))
+        self.assertEquals(0,myAnchors.shouldAnchor(dup))
+        self.assertEquals(1,myAnchors.isAlias(dup))
+
+    def testAliases(self):
+        dup = {'foo': 'bar'}
+        self.dumpTest([dup, dup],
+            """
+            ---
+            - &1
+                foo: bar
+            - *1
+            """)
+
+    def testHashAlias(self):
+        dup = {}
+        dup['foo'] = dup
+        self.dumpTest(dup, 
+            """
+            --- &1
+            foo: *1
+            """)
+
+    def testEmptyArray(self):
+        self.dumpTest([],
+            """
+            --- []
+            """)
+
+    def testEmptyHash(self):
+        self.dumpTest({},
+            """
+            --- {}
+            """)
+
+    def testEmptyHashAsHashKey(self):
+        self.dumpTest({'foo': {} },
+            """
+            ---
+            foo: {}
+            """)
+
+    def testEmptyArrrayAsHashKey(self):
+        self.dumpTest({'foo': [] },
+            """
+            ---
+            foo: []
+            """)
+
+    def testAliasNone(self):
+        foo = None
+        self.dumpTest([foo, foo, foo],
+            """
+            ---
+            - ~
+            - ~
+            - ~
+            """)
+
+    def testDumpMany(self):
+        assertEquals(
+            yaml.dump({'foo': 1}, ['a', 'b', 'c']),
+            flushLeft(
+                """
+                ---
+                foo: 1
+                ---
+                - a
+                - b
+                - c
+                """))
+
+    def testDumpExtraNewLines(self):
+        self.dumpTest( "Joe's hot dogs.\n\n",
+            """
+            --- |+
+            Joe's hot dogs.
+
+            """)
+
+
+    def testDumpExtraNewLinesInDict(self):
+        data = {'preserving': "extra new lines are kept\n\n\n"}
+        self.dumpTest(data,
+            """
+            ---
+            preserving: |+
+                extra new lines are kept
+                
+                
+            """)
+
+    def testDumpBoolean(self):
+        data = {'boolean true': True, 'boolean false': False}
+        self.dumpTest(data,
+            """
+            ---
+            boolean false: -
+            boolean true: +
+            """)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testPushDumper.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testPushDumper.py	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testPushDumper.py	(revision 90)
@@ -0,0 +1,123 @@
+import YamlTest
+from here import *
+from test import assertEquals
+from types import DictType, ListType, TupleType, InstanceType
+
+"""
+This is experimental code.  It generates simulated events
+for a pull-based YAML parser.
+"""
+
+class MockEmitter:
+    """
+    A pushed-based emitter may be more awkward to write, 
+    because you have to keep track of more state.
+    """
+    def __init__(self):
+        self.events = []
+
+    def append(self, *event):
+        self.events.append(event)        
+
+    def pushScalar(self, data):
+        self.append('getType', 'scalar')
+        self.append('getScalar', data)
+
+    def appendType(self, typ):
+        self.append('getType', typ)
+
+    def startSeq(self):
+        self.appendType('seq')
+        
+    def endSeq(self):
+        self.appendType(None)
+
+    def startMap(self):
+        self.appendType('map')
+        
+    def endMap(self):
+        self.appendType(None)
+
+class Dumper:
+    def __init__(self, emitter):
+        self.emitter = emitter
+
+    def dump(self, data):
+        if type(data) in (ListType, TupleType):
+            return self.dumpList(data)
+        elif type(data) is DictType:
+            return self.dumpDict(data)
+        else:
+            self.emitter.pushScalar(data)
+
+    def dumpList(self, data):
+        self.emitter.startSeq()
+        for item in data:
+            self.dump(item)
+        self.emitter.endSeq()
+
+    def dumpDict(self, data):
+        self.emitter.startMap()
+        keys = data.keys()
+        keys.sort() # XXX - only for now
+        for key in keys:
+            value = data[key]
+            self.dump(key)
+            self.dump(value)
+        self.emitter.endMap()
+
+def mockEvents(data):
+    emitter = MockEmitter()
+    dumper = Dumper(emitter)
+    dumper.dump(data)
+    return emitter.events
+
+class Test(YamlTest.YamlTest):
+
+    def testScalar(self):
+        assertEquals(mockEvents('foobar'), self.scalar('foobar'))
+
+    def scalar(self, data):
+        return [ 
+            ('getType', 'scalar'),
+            ('getScalar', data)
+        ]
+
+    def list123(self):
+        (result) = (
+            [('getType', 'seq' )] +
+            self.scalar(1) +
+            self.scalar(2) +
+            self.scalar(3) +
+            [( 'getType', None )])
+        return result
+
+    def testList(self):
+        assertEquals(mockEvents([1,2,3]), self.list123())
+
+    def dictFoobar(self):
+        (result) = (
+            [('getType', 'map')] +
+            self.scalar('bar') +
+            self.scalar(2) + 
+            self.scalar('foo') +
+            self.scalar(1) +
+            [( 'getType', None)])
+        return result
+
+    def testDict(self):
+        events = mockEvents({'foo': 1, 'bar': 2})
+        assertEquals(events, self.dictFoobar())
+
+    def testListDict(self):
+        events = mockEvents([ [1,2,3], {'foo': 1, 'bar': 2} ])
+        self.assertEquals(
+            events,
+            [('getType', 'seq' )] +
+            self.list123() +
+            self.dictFoobar() + 
+            [('getType', None)])            
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testClasses.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testClasses.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/testClasses.py	(revision 91)
@@ -0,0 +1,135 @@
+import YamlTest
+import yaml
+from test import assertEquals
+from here import flushLeft
+from math import sqrt
+
+def triangleYaml():
+    """
+    Triangle YAML data
+    """
+    return flushLeft("""
+        --- !!triangle_in_inches
+        x_inches: 36
+        y_inches: 48
+        """)
+
+def simpleObjectYaml():
+    return flushLeft("""
+        --- !!yaml.tests.testClasses.SimpleObject
+        x: 100
+        y: 20
+        z: 3
+        """)
+
+class SimpleObject:
+    def __init__(self):
+        self.x = 100
+        self.y = 20
+    
+    def xyz(self):
+        return self.x + self.y + self.z
+
+class Triangle:
+    def __init__(self,x,y):
+        self.x = x
+        self.y = y
+        self._hypotneuse = sqrt(x*x + y*y)
+
+    def to_yaml(self):
+        # hide the hypotneuse attribute, it's private;
+        # also use inches instead of feet
+        view = {
+            'x_inches': self.x * 12,
+            'y_inches': self.y * 12
+        }
+        return (view, '!!triangle_in_inches')
+
+class MyResolver:
+    def resolveType(self, data, typestring):
+        if typestring == '!!triangle_in_inches':
+            x = data['x_inches'] / 12
+            y = data['y_inches'] / 12
+            return Triangle(x,y)
+        else:
+            raise 'Private type %s not supported' % typestring
+
+class TestConfig:
+    lastTester = None
+    def from_yaml(self, args):
+        self.tester = args['tester']
+        self.hitcount = args['hitcount'] + 1
+        TestConfig.lastTester = self.tester
+        return self
+
+class Test(YamlTest.YamlTest):
+
+    def testDumpingDictionary(self):
+        """
+        DUMPING OBJECTS: > 
+            YAML has several ways of persisting objects.  One view of an 
+            object is that it's nothing more than it's dictionary.  By 
+            default, YAML emits self.__dict__ from objects.
+        """
+        obj = SimpleObject()
+        obj.z = 3
+        output = yaml.dump(obj)
+        expected = simpleObjectYaml()
+        assertEquals(output, expected)
+    
+    def testLoadingDictionary(self):
+        """
+        LOADING OBJECTS: > 
+            Of course, we would expect to be able to load that
+            YAML right back into Python, and we can.  You get 
+            back an object of the intended class, with all of 
+            the normal methods.  Be aware, though, that if your 
+            class creates methods on the fly, or if it does 
+            other trickery, then you might get unexpected results.
+        """
+        obj = yaml.load(simpleObjectYaml()).next()
+        assertEquals(obj.xyz(), 123)
+
+        
+    def testDumpTriangle(self):
+        """
+        CUSTOM DUMPING: >
+            Some times you want more control over how you dump
+            objects in YAML.  You might not want to dump all 
+            members of the object, for example.  Also, you may 
+            not want to export the module name.
+        """
+        triangle = Triangle(3,4)
+        assertEquals(yaml.dump(triangle), triangleYaml())
+
+    def testCustomLoad(self):
+        """
+        CUSTOM LOADING: >
+            You have control over the YAML load process too.  Normally
+            YAML resolves private types for you automatically, but you
+            can override its behavior.
+        """    
+        obj = yaml.load(triangleYaml(),MyResolver()).next()
+        assertEquals(obj._hypotneuse, 5.0)
+
+    def testFromYaml(self):
+        """
+        USING FROM_YAML(): >
+            Another way to customize the YAML loading process is to 
+            supply a from_yaml() method.  For example, you might want
+            the loading of an object to have some kind of a side effect.
+            Or, you may need to calculate some value that is not part of 
+            the attribute.
+        """
+        yamlData = flushLeft("""
+            --- !!yaml.tests.testClasses.TestConfig
+            tester: showell
+            hitcount: 42
+            """)
+        obj = yaml.load(yamlData).next()
+        assertEquals(obj.hitcount, 43)
+        assertEquals(TestConfig.lastTester, 'showell')
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/testValidatingParser.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testValidatingParser.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/testValidatingParser.py	(revision 91)
@@ -0,0 +1,206 @@
+import YamlTest
+from here import flushLeft
+from test import assertEquals, assertError
+from testPullParser import mockParser, Loader
+from yaml import load
+
+"""
+Part of the parse/pull experimental code.  This does a schema-driven
+validating parse of YAML documents, but it's built on top of a 
+crufty interim solution.
+
+The schema-driven parser requires a pull parser interface.  Ideally 
+a pull-parser would be pulling nodes from a YAML document on an
+as-needed basis, and this is the eventual goal.  But, I don't have
+a pull parser yet, so I simulate one by reading in the entire YAML
+document into a Python data structure, then I do a push-based dump 
+of the data structure to a mock emitter that stores up a list of
+parser events that a mock parser then serves up to the schema-driven
+parser on an as-needed basis.  Sounds complex, but there's really not
+much code involved.
+
+Nothing fancy is supported yet--just lists, dictionaries, and scalars; 
+no aliases, class transformations, multiple docs, etc.  Also, we lose
+the sort order on map keys, so you will notice that all the examples
+have alphabetically sorted keys.
+
+Also, once we go to a true pull parser, we could have more metadata,
+such as line numbers for nodes, attached comments, etc., that can 
+help with error reporting and round-tripping issues.
+"""
+
+testCases = """
+-
+    data: |
+        --- foo
+    schema:
+        type: scalar
+-
+    data: |
+        --- foo
+    schema:
+        type: seq
+    error: |
+        Wanted seq, got scalar
+ -
+    data: &list123 |
+        ---
+        - 1
+        - 2
+        - 3
+    schema:
+        type: seq
+        child:
+            type: scalar
+  -
+    data: *list123
+    schema:
+        type: seq
+        max: 2
+        child:
+            type: scalar
+    error: |
+        Seq has max 2 elements
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        street: Bourbon
+    schema: &StreetCityState
+        type: map
+        items:
+            - name: city
+              value:
+                  type: scalar
+            - name: state
+              value:
+                  type: scalar
+            - name: street
+              value:
+                  type: scalar
+-
+    data: |
+        ---
+        city: New Orleans
+        state: LA
+        where ya got ya shoes: on ya feet, on Bourbon St.
+    schema: *StreetCityState
+    error: |
+        Expected key 'street', got 'where ya got ya shoes'
+-
+    data: |
+        ---
+        banana: yellow
+        carrot: orange
+        people:
+            - fname: al
+              salary: 44
+            - fname: bob
+              salary: 33
+    schema:
+        type: map
+        items:
+            - name: banana
+              value:
+                type: scalar
+            - name: carrot
+              value:
+                type: scalar
+            - name: people
+              value:
+                type: seq
+                child:
+                    type: map
+                    items:
+                        - name: fname
+                          value:
+                            type: scalar
+                        - name: salary
+                          value:
+                            type: scalar
+"""
+
+class ValidatingLoader:
+    def load(self, data, schema):
+        self.simulateParser(data)
+        return self.loadData(schema)
+
+    def loadData(self, schema):
+        typ = self.parser.getType()
+        return self._load(typ, schema)
+
+    def _load(self, typ, schema):
+        if typ != schema['type']:
+            raise Exception("Wanted %s, got %s\n" % (schema['type'], typ))
+        if typ == 'seq':
+            return self._loadSeq(schema)
+        if typ == 'map':
+            return self._loadMap(schema)
+        else:
+            return self.parser.getScalar()
+
+    def _loadSeq(self, schema):
+        results = []
+        cnt = 0
+        max = schema.get('max', None)
+        schema = schema['child']
+        while 1:
+            typ = self.parser.getType()
+            if typ is None:
+                return results
+            else:
+                cnt += 1
+                self.checkMax(cnt, max)
+                results.append(self._load(typ, schema))
+
+    def _loadMap(self, schema):
+        results = {}
+        for item in schema['items']:
+            self.parser.getType()
+            name = self.parser.getScalar()
+            self.checkName(name, item)
+            value = self.loadData(item['value'])
+            results[name] = value
+        self.parser.getType()
+        return results
+
+    def checkMax(self, cnt, max):
+            if max is not None and cnt > max:
+                raise Exception("Seq has max %d elements\n" % max)
+
+    def checkName(self, name, item):
+        if name != item['name']:
+            raise Exception("Expected key '%s', got '%s'\n" % \
+                (item['name'], name))
+
+    def simulateParser(self, data):
+        # This is the huge hack to work around
+        # not having a true pull parser
+        self.parser = mockParser(oldYamlLoad(data))
+
+def testRoundTrip(data, schema):
+    expected = oldYamlLoad(data)
+    obj = ValidatingLoader().load(data, schema)
+    assertEquals(expected, obj)
+
+def oldYamlLoad(data):
+    return load(data).next()
+
+def testOneCase(test):
+    data = test['data']
+    schema = test['schema']
+    if test.has_key('error'):
+        assertError(lambda: testRoundTrip(data, schema),
+            test['error'])
+    else:
+        testRoundTrip(data, schema)
+
+class Test(YamlTest.YamlTest):
+    def testFromYaml(self):
+        for test in load(testCases).next():
+            testOneCase(test)
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ypath.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ypath.yml	(revision 78)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ypath.yml	(revision 78)
@@ -0,0 +1,221 @@
+data:
+  apple: red
+ypath: /
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: .
+expected:
+ - /
+---
+data:
+  apple: red
+ypath: /*
+expected:
+ - /apple
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /*
+expected:
+ - /apple
+ - /lemon
+unordered: 1
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: //.
+expected:
+  - /
+  - /fruit
+  - /fruit/banana
+  - /vegetable
+  - /vegetable/carrot
+unordered: 1
+---
+data:
+  one:
+    two: xxx
+ypath: //two/..
+expected:
+ - /one
+---
+data:
+  apple: red
+ypath: /apple
+expected:
+ - /apple
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /"lemon"
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /'lemon'
+expected:
+ - /lemon
+-----
+data:
+  apple: red
+  lemon: yellow
+ypath: /lemon
+expected:
+ - /lemon
+----
+data:
+  - apple
+  - lemon
+ypath: /0
+expected:
+ - /0
+---
+data:
+  apple: red
+  lemon: yellow
+ypath: /orange
+expected: []
+----
+data:
+  apple: red
+ypath: ./.
+expected:
+ - /
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: /fruit/banana
+expected:
+ - /fruit/banana
+---
+data:
+  fruit:
+    banana: yellow
+  vegetable:
+    carrot: orange
+ypath: fruit/banana
+expected:
+ - /fruit/banana
+---
+data:
+  names:
+    - Steve Howell
+    - Clark Evans
+ypath: /names/0
+expected:
+ - /names/0
+---
+data:
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/1/first
+expected:
+  - /names/1/first
+----
+data:
+  names:
+    - first: Clark
+      last:  Evans
+    - first: Steve
+      last:  Howell
+ypath: /names/*/first
+expected:
+  - /names/0/first
+  - /names/1/first
+---
+data:
+  names:
+    python-heads:
+      - first: Clark
+        last:  Evans
+      - first: Steve
+        last:  Howell
+    perl-heads:
+      - first: Brian
+        last:  Ingerson
+ypath: names//first
+expected:
+  - /names/python-heads/0/first
+  - /names/python-heads/1/first
+  - /names/perl-heads/0/first
+---
+data:
+    task:
+       - name: wake
+         foo: bar
+       - name: eat
+         task:
+            - name: veggies
+            - name: meats
+       - name: sleep
+ypath: //task
+expected:
+  - /task
+  - /task/1/task
+---
+data:
+  - one:
+      name: xxx
+  - two:
+      name: yyy
+  - three:
+      name: zzz
+ypath: /*/one/name|//three/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  apple: red
+ypath: .|/apple|apple|/|.
+expected:
+ - /
+ - /apple
+---
+data:
+  - one:
+      name: xxx
+  - two:
+      name: yyy
+  - three:
+      name: zzz
+ypath: /*/(one|three)/name
+expected:
+ - /0/one/name
+ - /2/three/name
+---
+data:
+  - one: xxx
+  - two: yyy
+  - one: zzz
+ypath: /*[one]
+expected:
+  - /0
+  - /2
+---
+data:
+ - food: Hamburger
+   calories: 900
+ - food: Fries
+   calories: 650
+ - food: Soft Drink
+   calories: 350
+ypath: //food[.=Fries]
+expected:
+  - /1/food
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/nullsAndEmpties.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/nullsAndEmpties.yml	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/nullsAndEmpties.yml	(revision 71)
@@ -0,0 +1,66 @@
+--- #YAML:1.0
+test: Empty Sequence
+brief: >
+    You can represent the empty sequence
+    with an empty inline sequence.
+yaml: |
+    empty: []
+python: |
+    [
+        { 'empty': [] }
+    ]
+ruby: |
+    { 'empty' => [] }
+
+---
+test: Empty Mapping
+brief: >
+    You can represent the empty mapping
+    with an empty inline mapping.
+yaml: |
+    empty: {}
+python: |
+    [
+        { 'empty': {} }
+    ]
+ruby: |
+    { 'empty' => {} }
+
+---
+test: Empty Sequence as Entire Document
+yaml: |
+    --- []
+python: |
+    [ [] ]
+ruby: |
+    []
+
+---
+test: Empty Mapping as Entire Document
+yaml: |
+    --- {}
+python: |
+    [ {} ]
+ruby: |
+    {}
+
+--- 
+test: Null as Document
+yaml: |
+    --- ~
+python: |
+    [ None ]
+ruby: |
+    nil
+
+---
+test: Empty String
+brief: >
+    You can represent an empty string
+    with a pair of quotes.
+yaml: |
+    --- ''
+python: |
+    [ '' ]
+ruby: |
+    ''
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/alias.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/alias.yml	(revision 78)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/alias.yml	(revision 78)
@@ -0,0 +1,61 @@
+--- #YAML:1.0
+test: Simple Alias Example
+brief: >
+    If you need to refer to the same item of data twice,
+    you can give that item an alias.  The alias is a plain
+    string, starting with an ampersand.  The item may then
+    be referred to by the alias throughout your document
+    by using an asterisk before the name of the alias.
+    This is called an anchor.
+yaml: |
+    - &showell Steve
+    - Clark
+    - Brian
+    - Oren
+    - *showell
+python: |
+    [
+        [ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve']
+    ]
+ruby-setup: |
+    showell = 'Steve'
+ruby: |
+    [ showell, 'Clark', 'Brian', 'Oren', showell ]
+
+---
+test: Alias of a Mapping
+brief: >
+    An alias can be used on any item of data, including
+    sequences, mappings, and other complex data types.
+yaml: |
+    - &hello
+        Meat: pork
+        Starch: potato
+    - banana
+    - *hello
+python: |
+    [
+        [ 
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+            'banana',
+            {'Meat': 'pork', 'Starch': 'potato'}, 
+        ]
+    ]
+ruby-setup: |
+    hello = { 'Meat' => 'pork', 'Starch' => 'potato' }
+ruby: |
+    [ 
+      hello, 
+      'banana',
+      hello
+    ]
+---
+test: Liberal Asterisk Handling
+brief: >
+    We need to allow strings to begin with asterisks.
+yaml: |
+    - * Bulleted item
+python: |
+    [
+        [ '* Bulleted item' ]
+    ]
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/error.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/error.yml	(revision 103)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/error.yml	(revision 103)
@@ -0,0 +1,56 @@
+--- #YAML:1.0
+test: Missing value for hash item
+brief: >
+    Third item in this hash doesn't have a value
+yaml: |
+    okay: value
+    also okay: ~
+    causes error because no value specified
+    last key: value okay here too
+error:
+    python: |
+        bad key for map:
+        near line 3:
+        causes error because no value specified
+---
+test: Not indenting enough
+brief: >
+    There was a bug in PyYaml where it was off by one
+    in the indentation check.  It was allowing the YAML 
+    below.
+yaml: |
+    foo:
+    firstline: 1
+    secondline: 2
+error:
+    python: |
+        Inadequate indentation:
+        near line 2:
+        firstline: 1
+---
+test: Duplicate keys
+brief: >
+    YAML should complain when you have duplicate
+    dictionary keys, rather than silently overwriting them.
+yaml: |
+    foo: 1
+    foo: 2
+error:
+    python: |
+        Duplicate key foo:
+        near line 2:
+        foo: 2
+---
+test: Duplicate keys w/complex children
+brief: >
+    same thing for complex keys
+yaml: |
+    foo:
+        yo: 1
+    foo:
+        bar: 1
+error:
+    python: |
+        Duplicate key foo:
+        near line 3:
+        foo:
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/inlineCollection.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/inlineCollection.yml	(revision 78)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/inlineCollection.yml	(revision 78)
@@ -0,0 +1,80 @@
+---
+test: Simple Inline Array
+brief: >
+    Sequences can be contained on a
+    single line, using the inline syntax.
+    Separate each entry with commas and
+    enclose in square brackets.
+yaml: |
+    --- 
+    seq: [ a, b, c ]
+python: |
+    [
+        { 'seq': [ 'a', 'b', 'c' ] }
+    ]
+ruby: |
+    { 'seq' => [ 'a', 'b', 'c' ] }
+
+---
+test: Simple Inline Hash
+brief: >
+    Mapping can also be contained on
+    a single line, using the inline
+    syntax.  Each key-value pair is
+    separated by a colon, with a comma
+    between each entry in the mapping.
+    Enclose with curly braces.
+yaml: |
+    ---
+    hash: { name: Steve, foo: bar }
+python: |
+    [
+        { 'hash': {'name': 'Steve', 'foo': 'bar'} }
+    ]
+ruby: |
+    { 'hash' => { 'name' => 'Steve', 'foo' => 'bar' } }
+
+---
+test: Multi-line Inline Collections
+brief: >
+    Both inline sequences and inline mappings
+    can span multiple lines, provided that you
+    indent the additional lines.
+yaml: |
+    languages: [ Ruby,
+                 Perl,
+                 Python ]
+    websites: { YAML: yaml.org,
+                Ruby: ruby-lang.org,
+                Python: python.org,
+                Perl: use.perl.org }
+ruby: |
+    { 'languages' => [ 'Ruby', 'Perl', 'Python' ],
+      'websites' => {
+        'YAML' => 'yaml.org',
+        'Ruby' => 'ruby-lang.org',
+        'Python' => 'python.org',
+        'Perl' => 'use.perl.org' 
+      }
+    }
+---
+test: Commas in Values
+brief: >
+    List items in collections are delimited by commas, but 
+    there must be a space after each comma.  This allows you
+    to add numbers without quoting.
+yaml: |
+    attendances: [ 45,123, 70,000, 17,222 ]
+python: |
+    [
+        {'attendances': [ 45123, 70000, 17222 ]}
+    ]
+
+python_quoted: |
+    [
+        {'attendances': [ '45,123', '70,000', '17,222' ]}
+    ]
+
+ruby: |
+    { 'attendances' => [ 45123, 70000, 17222 ] }
+
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/spec.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/spec.yml	(revision 107)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/spec.yml	(revision 107)
@@ -0,0 +1,1636 @@
+--- #YAML:1.0
+test: Sequence of scalars
+spec: A1
+yaml: |
+  - Mark McGwire
+  - Sammy Sosa
+  - Ken Griffey
+perl: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+python: |
+  [ ['Mark McGwire', 'Sammy Sosa', 'Ken Griffey'] ]
+ruby: |
+  [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Mapping of scalars to scalars
+spec: A2
+yaml: |
+  hr:  65
+  avg: 0.278
+  rbi: 147
+perl: |
+  { hr => 65, avg => 0.278, rbi => 147 }
+python: |
+  [ {'hr': 65, 'avg': .278, 'rbi': 147} ]
+ruby: |
+  { 'hr' => 65, 'avg' => 0.278, 'rbi' => 147 }
+
+---
+test: Mapping of scalars to sequences
+spec: A3
+yaml: |
+    american:
+       - Boston Red Sox
+       - Detroit Tigers
+       - New York Yankees
+       - Texas Rangers
+    national:
+       - New York Mets
+       - Chicago Cubs
+       - Atlanta Braves
+       - Montreal Expos
+perl: |
+    { american => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      national =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+python: |
+    [
+    {
+    'american': 
+        ['Boston Red Sox', 'Detroit Tigers', 
+        'New York Yankees', 'Texas Rangers'],
+    'national':
+        ['New York Mets', 'Chicago Cubs',
+        'Atlanta Braves', 'Montreal Expos']
+    }
+    ]
+ruby: |
+    { 'american' => 
+        [ 'Boston Red Sox', 'Detroit Tigers', 
+          'New York Yankees', 'Texas Rangers' ],
+      'national' =>
+        [ 'New York Mets', 'Chicago Cubs', 
+          'Atlanta Braves', 'Montreal Expos' ] 
+    }
+
+---
+test: Sequence of mappings
+spec: A4
+yaml: |
+    - 
+      name: Mark McGwire
+      hr:   65
+      avg:  0.278
+      rbi:  147
+    - 
+      name: Sammy Sosa
+      hr:   63
+      avg:  0.288
+      rbi:  141
+perl: |
+    [
+      {name => 'Mark McGwire', hr => 65, avg => 0.278, rbi => 147},
+      {name => 'Sammy Sosa',   hr => 63, avg => 0.288, rbi => 141}
+    ]
+python: |
+    [[ 
+        {
+        'name': 'Mark McGwire',
+        'hr': 65,
+        'avg': 0.278,
+        'rbi': 147
+        },
+        {
+        'name': 'Sammy Sosa',
+        'hr': 63,
+        'avg': 0.288,
+        'rbi': 141
+        }
+    ]]
+ruby: |
+    [
+      {'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278, 'rbi' => 147},
+      {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288, 'rbi' => 141}
+    ]
+
+---
+test: Legacy A5
+spec: legacy_A5
+yaml: |
+    ?
+        - New York Yankees
+        - Atlanta Braves
+    :
+      - 2001-07-02
+      - 2001-08-12
+      - 2001-08-14
+    ?
+        - Detroit Tigers
+        - Chicago Cubs
+    :
+      - 2001-07-23
+perl-busted: >
+    YAML.pm will be able to emulate this behavior soon. In this regard
+    it may be somewhat more correct than Python's native behaviour which
+    can only use tuples as mapping keys. PyYAML will also need to figure
+    out some clever way to roundtrip structured keys. Not sure how full
+    featured Ruby is in this regard.
+python: |
+    [
+    {
+        ('New York Yankees', 'Atlanta Braves'):
+            [yaml.timestamp('2001-07-02'), 
+             yaml.timestamp('2001-08-12'),
+             yaml.timestamp('2001-08-14')],
+        ('Detroit Tigers', 'Chicago Cubs'):
+        [yaml.timestamp('2001-07-23')]
+    }
+    ]
+ruby: |
+    {
+      [ 'New York Yankees', 'Atlanta Braves' ] =>
+        [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ],
+      [ 'Detroit Tigers', 'Chicago Cubs' ] =>
+        [ Date.new( 2001, 7, 23 ) ]
+    }
+
+
+---
+test: Sequence of sequences
+spec: A5
+yaml: |
+  - [ name         , hr , avg   ]
+  - [ Mark McGwire , 65 , 0.278 ]
+  - [ Sammy Sosa   , 63 , 0.288 ]
+perl: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ],
+  ]
+python: |
+  [[
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]]
+ruby: |
+  [
+    [ 'name', 'hr', 'avg' ],
+    [ 'Mark McGwire', 65, 0.278 ],
+    [ 'Sammy Sosa', 63, 0.288 ]
+  ]
+
+---
+test: Mapping of mappings
+spec: A6
+yaml: |
+  Mark McGwire: {hr: 65, avg: 0.278} 
+  Sammy Sosa:   {hr: 63,
+                 avg: 0.288}
+perl: |
+  { 
+    'Mark McGwire' => { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' => { 'hr' => 63, 'avg' => 0.288 },
+  }
+not_yet_in_python: |
+  [{ 
+    'Mark McGwire': 
+      { 'hr': 65, 'avg': 0.278 },
+    'Sammy Sosa':
+      { 'hr': 63, 'avg': 0.288 }
+  }]
+ruby: |
+  { 
+    'Mark McGwire' =>
+      { 'hr' => 65, 'avg' => 0.278 },
+    'Sammy Sosa' =>
+      { 'hr' => 63, 'avg' => 0.288 }
+  }
+
+---
+test: Two documents, one stream
+spec: B1
+yaml: |
+  ---
+  name: Mark McGwire
+  hr:   65
+  avg:  0.278
+  ---
+  name: Sammy Sosa
+  hr:   63
+  avg:  0.288
+python: |
+  [
+    { 'name': 'Mark McGwire', 'hr': 65, 'avg': 0.278 },
+    { 'name': 'Sammy Sosa', 'hr': 63, 'avg': 0.288 }
+  ]
+ruby: |
+  y = Stream.new
+  y.add( { 'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278 } )
+  y.add( { 'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288 } )
+documents: 2
+
+---
+test: Document with leading comment
+spec: B2
+yaml: |
+   # Ranking of players by
+   # 1998 season home runs.
+   ---
+      - Mark McGwire
+      - Sammy Sosa
+      - Ken Griffey
+python: |
+   [[ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]]
+ruby: |
+   [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
+
+---
+test: Single document with two comments
+spec: B3
+yaml: |
+  hr: # 1998 hr ranking
+    - Mark McGwire
+    - Sammy Sosa
+  rbi:
+    # 1998 rbi ranking
+    - Sammy Sosa
+    - Ken Griffey
+python: |
+  [{ 
+    'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi': [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }]
+ruby: |
+  { 
+    'hr' => [ 'Mark McGwire', 'Sammy Sosa' ],
+    'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] 
+  }
+
+---
+test: Node for Sammy Sosa appears twice in this document
+spec: B4
+yaml: |
+   hr:
+      - Mark McGwire
+      # Following node labeled SS
+      - &SS Sammy Sosa
+   rbi:
+      - *SS # Subsequent occurance
+      - Ken Griffey
+python: |
+   [{ 
+      'hr': [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi': [ 'Sammy Sosa', 'Ken Griffey' ]
+   }]
+ruby: |
+   { 
+      'hr' =>
+         [ 'Mark McGwire', 'Sammy Sosa' ],
+      'rbi' =>
+         [ 'Sammy Sosa', 'Ken Griffey' ]
+   }
+
+---
+test: Mapping between sequences
+spec: B5
+yaml: |
+   ? # PLAY SCHEDULE
+     - Detroit Tigers
+     - Chicago Cubs
+   :  
+     - 2001-07-23
+   
+   ? [ New York Yankees,
+       Atlanta Braves ]
+   : [ 2001-07-02, 2001-08-12, 
+       2001-08-14 ]
+ruby: |
+   { 
+      [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
+      [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ]
+   }
+
+---
+test: Sequence key shortcut
+spec: B6
+yaml: |
+   invoice: 34843
+   date   : 2001-01-23
+   bill-to: Chris Dumars
+   product:
+      - item    : Super Hoop
+        quantity: 1
+      - item    : Basketball
+        quantity: 4
+      - item    : Big Shoes
+        quantity: 1
+ruby: |
+   { 
+      'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+      'bill-to' => 'Chris Dumars', 'product' =>
+      [ 
+         { 'item' => 'Super Hoop', 'quantity' => 1 },
+         { 'item' => 'Basketball', 'quantity' => 4 },
+         { 'item' => 'Big Shoes', 'quantity' => 1 } 
+      ] 
+   }
+python: |
+    [{
+        'invoice': 34843,
+        'date': yaml.timestamp('2001-01-23'),
+        'bill-to': 'Chris Dumars',
+        'product': [
+             { 'item': 'Super Hoop', 'quantity': 1 },
+             { 'item': 'Basketball', 'quantity': 4 },
+             { 'item': 'Big Shoes',  'quantity': 1 } 
+        ]
+    }]
+
+---
+test: Literal perserves newlines
+spec: C1
+yaml: |
+  --- |
+      \/|\/|
+      / |  |_
+ruby: |
+  "\\/|\\/|\n/ |  |_\n"
+python: |
+    [
+        flushLeft(
+        """
+        \/|\/|
+        / |  |_
+        """
+        )
+    ]
+
+---
+test: Folded treats newlines as a space
+spec: C2
+yaml: |
+  --- >
+      Mark McGwire's
+      year was crippled
+      by a knee injury.
+ruby: |
+  "Mark McGwire's year was crippled by a knee injury.\n"
+python: |
+    [ "Mark McGwire's year was crippled by a knee injury.\n" ]
+
+---
+test: Newlines preserved for indented and blank lines
+spec: C3
+yaml: |
+  --- >
+   Sammy Sosa completed another
+   fine season with great stats.
+  
+     63 Home Runs
+     0.288 Batting Average
+  
+   What a year!
+ruby: |
+  "Sammy Sosa completed another fine season with great stats.\n\n  63 Home Runs\n  0.288 Batting Average\n\nWhat a year!\n"
+python: |
+    [
+        flushLeft(
+        """
+        Sammy Sosa completed another fine season with great stats.
+
+          63 Home Runs
+          0.288 Batting Average
+
+        What a year!
+        """
+        )
+    ]
+
+
+---
+test: Indentation determines scope
+spec: C4
+yaml: |
+  name: Mark McGwire
+  accomplishment: >
+     Mark set a major league
+     home run record in 1998.
+  stats: |
+     65 Home Runs
+     0.278 Batting Average
+ruby: |
+  { 
+    'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n",
+    'stats' => "65 Home Runs\n0.278 Batting Average\n"
+  }
+python: |
+    [
+        {
+        'name': 'Mark McGwire',
+        'accomplishment': 
+            'Mark set a major league home run record in 1998.\n',
+        'stats': "65 Home Runs\n0.278 Batting Average\n"
+        }
+    ]
+
+---
+test: Quoted scalars
+spec: C5
+yaml: |
+  unicode: "Sosa did fine.\u263A"
+  control: "\b1998\t1999\t2000\n"
+  hexesc:  "\x0D\x0A is \r\n"
+  
+  single: '"Howdy!" he cried.'
+  quoted: ' # not a ''comment''.'
+  tie-fighter: '|\-*-/|'
+ruby: |
+  {
+    "tie-fighter" => "|\\-*-/|",
+    "control"=>"\0101998\t1999\t2000\n",
+    "unicode"=>"Sosa did fine." + ["263A".hex ].pack('U*'),
+    "quoted"=>" # not a 'comment'.",
+    "single"=>"\"Howdy!\" he cried.",
+    "hexesc"=>"\r\n is \r\n"
+  }
+python: |
+    [ {
+        'unicode': u"Sosa did fine.\u263A",
+        'control': "\b1998\t1999\t2000\n", 
+        'hexesc':  "\x0D\x0A is \r\n",
+        'single': '"Howdy!" he cried.',
+        'quoted': ' # not a \'comment\'.',
+        'tie-fighter': '|\-*-/|',
+    } ]
+
+
+---
+test: Multiline flow scalars
+spec: C6
+yaml: |
+  plain: This unquoted
+         scalar spans
+         many lines.
+  quoted: "\
+    So does this quoted
+    scalar.\n"
+ruby: |
+  { 
+    'plain' => 'This unquoted scalar spans many lines.',
+    'quoted' => "So does this quoted scalar.\n"
+  }
+python: |
+    [ {
+        'plain': 'This unquoted scalar spans many lines.',
+        'quoted': 'So does this quoted scalar.\n'
+      }
+    ]
+
+---
+test: Integers
+spec: D1
+yaml: |
+  canonical: 12345
+  decimal: +12,345
+  octal: 014
+  hexadecimal: 0xC
+ruby: |
+  { 
+    'canonical' => 12345, 
+    'decimal' => 12345, 
+    'octal' => '014'.oct, 
+    'hexadecimal' => '0xC'.hex 
+  }
+python: |
+    [ {
+        'canonical': 12345,
+        'decimal': 12345,
+        'octal': 014,
+        'hexadecimal': 0xC
+    } ]
+
+---
+test: Floating point
+spec: D2
+yaml: |
+  canonical: 1.23015e+3
+  exponential: 12.3015e+02
+  fixed: 1,230.15
+  negative infinity: (-inf)
+  not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+python: |
+    [ {
+        'canonical': 1.23015e+3,
+        'exponential': 1.23015e+3,
+        'fixed': 1230.15,
+        'negative infinity': '(-inf)',
+        'not a number': '(NaN)',
+    } ]
+
+---
+test: Miscellaneous
+spec: D3
+yaml: |
+  null: ~
+  true: +
+  false: -
+  string: '12345'
+ruby: |
+  { 
+    'null' => nil, 
+    'true' => true, 
+    'false' => false, 
+    'string' => '12345' 
+  }
+python: |
+    [ {
+        'null': None,
+        'true': 1,
+        'false': 0,
+        'string': '12345',
+    } ]
+
+---
+test: Miscellaneous
+spec: D3
+yaml: |
+  tilde: '~'
+  plus: '+'
+  minus: '-'
+  string: '12345'
+ruby: |
+  { 
+    'tilde' => '~', 
+    'plus' => '+', 
+    'minus' => '-', 
+    'string' => '12345' 
+  }
+python: |
+    [ {
+        'tilde': '~',
+        'plus': '+',
+        'minus': '-',
+        'string': '12345',
+    } ]
+
+
+---
+test: Timestamps
+spec: D4
+yaml: |
+  canonical: 2001-12-15T02:59:43.1Z
+  iso8601:  2001-12-14t21:59:43.10-05:00
+  spaced:  2001-12-14 21:59:43.10 -05:00
+  date:   2002-12-14 # Time is noon UTC 
+ruby: |
+  {
+    'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+    'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+    'date' => Date.new( 2002, 12, 14 )
+  }
+---
+test: legacy Timestamps test
+spec: legacy D4
+yaml: |
+    canonical: 2001-12-15T02:59:43.00Z
+    iso8601:  2001-02-28t21:59:43.00-05:00
+    spaced:  2001-12-14 21:59:43.00 -05:00
+    date:   2002-12-14
+python: |
+    [ {
+        'canonical': yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'iso8601':   yaml.timestamp('2001-03-01T02:59:43.00Z'),
+        'spaced':    yaml.timestamp('2001-12-15T02:59:43.00Z'),
+        'date':      yaml.timestamp('2002-12-14T00:00:00.00Z')
+    } ]
+ruby: |
+   {
+     'canonical' => Time::utc( 2001, 12, 15, 2, 59, 43, 0 ),
+     'iso8601' => YAML::mktime( 2001, 2, 28, 21, 59, 43, 0, "-05:00" ),
+     'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0, "-05:00" ),
+     'date' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Various explicit families
+spec: D5
+yaml: |
+  not-date: !str 2002-04-28
+  picture: !binary|base64 |
+   R0lGODlhDAAMAIQAAP//9/X
+   17unp5WZmZgAAAOfn515eXv
+   Pz7Y6OjuDg4J+fn5OTk6enp
+   56enmleECcgggoBADs=
+  
+  hmm: !somewhere.com,2002/type |
+   family above is short for
+   tag:somewhere.com,2002:type
+
+ruby-setup: |
+  YAML.add_domain_type( "somewhere.com,2002", /^type$/ ) { |type, val|
+    return "SOMEWHERE: #{val}"
+  }
+ruby: |
+  { 
+    'not-date' => '2002-04-28',
+    'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 
+    'hmm' => "SOMEWHERE: family above is short for\ntag:somewhere.com,2002:type\n" 
+  }
+
+---
+test: Application specific family
+spec: D6
+yaml: |
+  --- !clarkevans.com,2002/graph/^shape
+  - !^circle
+    center: &ORIGIN {x: 73, y: 129}
+    radius: 7
+  - !^line # !clarkevans.com,2002/graph/line
+    start: *ORIGIN
+    finish: { x: 89, y: 102 }
+  - !^text
+    start: *ORIGIN
+    color: 0xFFEEBB
+    value: Pretty vector drawing.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/shape/ ) { |type, val|
+    if val.type == Array
+      val << "Shape Container"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  one_shape_proc = Proc.new { |type, val|
+    if val.is_a? Kernel::Hash
+      val['TYPE'] = "Shape: #{type}"
+      return val
+    else
+      raise YAML::Error, "Invalid graph of type #{val.type}: " + val.inspect
+    end
+  }
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/circle/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/line/, &one_shape_proc )
+  YAML.add_domain_type( "clarkevans.com,2002", /^graph\/text/, &one_shape_proc )
+ruby: |
+  [
+    { 
+      "radius" => 7, 
+      "center"=>
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "TYPE" => "Shape: graph/circle"
+    }, {
+      "finish" => 
+      {
+        "x" => 89, 
+        "y" => 102
+      }, 
+      "TYPE" => "Shape: graph/line", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }
+    }, {
+      "TYPE" => "Shape: graph/text", 
+      "value" => "Pretty vector drawing.", 
+      "start" => 
+      {
+        "x" => 73, 
+        "y" => 129
+      }, 
+      "color" => 16772795
+    }, 
+    "Shape Container"
+  ]
+
+---
+test: Invoice
+spec: E1
+yaml: |
+  --- !clarkevans.com,2002/^invoice
+  invoice: 34843
+  date   : 2001-01-23
+  bill-to: &id001
+    given  : Chris
+    family : Dumars
+    address:
+      lines: |
+        458 Walkman Dr.
+        Suite #292
+      city    : Royal Oak
+      state   : MI
+      postal  : 48046
+  ship-to: *id001
+  product:
+    - sku         : BL394D
+      quantity    : 4
+      description : Basketball
+      price       : 450.00
+    - sku         : BL4438H
+      quantity    : 1
+      description : Super Hoop
+      price       : 2392.00
+  tax  : 251.42
+  total: 4443.52
+  comments: >
+    Late afternoon is best.
+    Backup contact is Nancy
+    Billsmer @ 338-4338.
+ruby-setup: |
+  YAML.add_domain_type( "clarkevans.com,2002", "invoice" ) { |type, val| val }
+  id001 = { 'given' => 'Chris', 'family' => 'Dumars', 'address' =>
+  { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak',
+    'state' => 'MI', 'postal' => 48046 } }
+ruby: |
+  { 
+     'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
+     'bill-to' => id001, 'ship-to' => id001, 'product' =>
+       [ { 'sku' => 'BL394D', 'quantity' => 4,
+           'description' => 'Basketball', 'price' => 450.00 },
+         { 'sku' => 'BL4438H', 'quantity' => 1,
+           'description' => 'Super Hoop', 'price' => 2392.00 } ],
+     'tax' => 251.42, 'total' => 4443.52,
+     'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }
+
+---
+test: Log file
+spec: E2
+yaml: |
+  ---
+  Time: 2001-11-23 15:01:42 -05:00
+  User: ed
+  Warning: >
+    This is an error message
+    for the log file
+  ---
+  Time: 2001-11-23 15:02:31 -05:00
+  User: ed
+  Warning: >
+    A slightly different error
+    message.
+  ---
+  Date: 2001-11-23 15:03:17 -05:00
+  User: ed
+  Fatal: >
+    Unknown variable "bar"
+  Stack:
+    - file: TopClass.py
+      line: 23
+      code: |
+        x = MoreObject("345\n")
+    - file: MoreClass.py
+      line: 58
+      code: |-
+        foo = bar
+ruby: |
+  y = Stream.new
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
+  y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
+           'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
+  y.add( { 'Date' => YAML::mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
+           'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
+           'Stack' => [
+           { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
+           { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
+documents: 3
+
+---
+test: Throwaway comments
+yaml: |
+   ### These are four throwaway comment  ###
+   
+   ### lines (the second line is empty). ###
+   this: |   # Comments may trail lines.
+      contains three lines of text.
+      The third one starts with a
+      # character. This isn't a comment.
+   
+   # These are three throwaway comment
+   # lines (the first line is empty).
+ruby: |
+   {
+     'this' => "contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"
+   }
+
+---
+test: Document with a single value
+yaml: |
+   --- >
+   This YAML stream contains a single text value.
+   The next stream is a log file - a sequence of
+   log entries. Adding an entry to the log is a
+   simple matter of appending it at the end.
+ruby: |
+   "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n"
+
+---
+test: Document stream
+yaml: |
+   ---
+   at: 2001-08-12 09:25:00.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/index.html'
+   ---
+   at: 2001-08-12 09:25:10.00 Z
+   type: GET
+   HTTP: '1.0'
+   url: '/toc.html'
+ruby: |
+   y = Stream.new
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 00 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/index.html'
+   } )
+   y.add( {
+      'at' => Time::utc( 2001, 8, 12, 9, 25, 10 ),
+      'type' => 'GET',
+      'HTTP' => '1.0',
+      'url' => '/toc.html'
+   } )
+documents: 2
+
+---
+test: Top level mapping
+yaml: |
+   # This stream is an example of a top-level mapping.
+   invoice : 34843
+   date    : 2001-01-23
+   total   : 4443.52
+ruby: |
+   {
+      'invoice' => 34843,
+      'date' => Date.new( 2001, 1, 23 ),
+      'total' => 4443.52
+   }
+
+---
+test: Single-line documents
+yaml: |
+  # The following is a sequence of three documents.
+  # The first contains an empty mapping, the second
+  # an empty sequence, and the last an empty string.
+  --- {}
+  --- [ ]
+  --- ''
+ruby: |
+  y = Stream.new
+  y.add( {} )
+  y.add( [] )
+  y.add( '' )
+documents: 3
+
+---
+test: Document with pause
+yaml: |
+  # A communication channel based on a YAML stream.
+  ---
+  sent at: 2002-06-06 11:46:25.10 Z
+  payload: Whatever
+  # Receiver can process this as soon as the following is sent:
+  ...
+  # Even if the next message is sent long after:
+  ---
+  sent at: 2002-06-06 12:05:53.47 Z
+  payload: Whatever
+  ...
+ruby: |
+  y = Stream.new
+  y.add(
+    { 'sent at' => YAML::mktime( 2002, 6, 6, 11, 46, 25, .10 ),
+      'payload' => 'Whatever' }
+  )
+  y.add( 
+    { "payload" => "Whatever", "sent at" => YAML::mktime( 2002, 6, 6, 12, 5, 53, .47 ) }
+  )
+  y.add( nil )
+documents: 3
+
+---
+test: Explicit typing
+yaml: |
+   integer: 12
+   also int: ! "12"
+   string: !str 12
+ruby: |
+   { 'integer' => 12, 'also int' => 12, 'string' => '12' }
+
+---
+test: Private types
+yaml: |
+  # Both examples below make use of the 'x-private:ball'
+  # type family URI, but with different semantics.
+  ---
+  pool: !!ball
+    number: 8
+    color: black
+  ---
+  bearing: !!ball
+    material: steel
+ruby: |
+  y = Stream.new
+  y.add( { 'pool' =>
+    PrivateType.new( 'ball',
+      { 'number' => 8, 'color' => 'black' } ) }
+  )
+  y.add( { 'bearing' => 
+    PrivateType.new( 'ball',
+      { 'material' => 'steel' } ) }
+  )
+documents: 2
+
+---
+test: Type family under yaml.org
+yaml: |
+  # The URI is 'tag:yaml.org,2002:str'
+  - !str a Unicode string
+python: |
+  [ [ 'a Unicode string' ] ]
+ruby: |
+  [ 'a Unicode string' ]
+
+---
+test: Type family under perl.yaml.org
+yaml: |
+  # The URI is 'tag:perl.yaml.org,2002:Text::Tabs'
+  - !perl/Text::Tabs {}
+ruby: |
+  DomainType.new( 'perl.yaml.org,2002', 'Text::Tabs', {} )
+
+---
+test: Type family under clarkevans.com
+yaml: |
+  # The URI is 'tag:clarkevans.com,2003-02:timesheet'
+  - !clarkevans.com,2003-02/timesheet
+ruby: |
+  DomainType.new( 'clarkevans.com,2003-02', 'timesheet', {} )
+
+---
+test: URI Escaping
+yaml: |
+  same:
+    - !domain.tld,2002/type%30%10 value
+    - !domain.tld,2002/type\0x30\n value
+  different: # As far as the YAML parser is concerned
+    - !domain.tld,2002/type0%10 value
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", "type%30%10" ) { |type, val|
+    "ONE: #{val}"
+  }
+  YAML.add_domain_type( "domain.tld,2002", "type0%10" ) { |type, val|
+    "TWO: #{val}"
+  }
+ruby: |
+  { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }
+
+---
+test: URI Prefixing
+yaml: |
+  # 'tag:domain.tld,2002:invoice' is some type family.
+  invoice: !domain.tld,2002/^invoice
+    # 'seq' is shorthand for 'tag:yaml.org,2002:seq'.
+    # This does not effect '^customer' below
+    # because it is does not specify a prefix.
+    customers: !seq
+      # '^customer' is shorthand for the full
+      # notation 'tag:domain.tld,2002:customer'.
+      - !^customer
+        given : Chris
+        family : Dumars
+ruby-setup: |
+  YAML.add_domain_type( "domain.tld,2002", /(invoice|customer)/ ) { |type, val|
+    if val.is_a? Kernel::Hash
+      val['type'] = "domain #{type}"
+      return val
+    else
+      raise YAML::Error, "Not a Hash in domain.tld/invoice: " + val.inspect
+    end
+  }
+ruby: |
+  { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }
+
+---
+test: Overriding anchors
+yaml: |
+  anchor : &A001 This scalar has an anchor.
+  override : &A001 >
+   The alias node below is a
+   repeated use of this value.
+  alias : *A001
+ruby: |
+  { 'anchor' => 'This scalar has an anchor.', 
+    'override' => "The alias node below is a repeated use of this value.\n", 
+    'alias' => "The alias node below is a repeated use of this value.\n" }
+
+---
+test: Flow and block formatting
+yaml: |
+  empty: []
+  flow: [ one, two, three # May span lines,
+           , four,           # indentation is
+             five ]          # mostly ignored.
+  block:
+   - First item in top sequence
+   -
+    - Subordinate sequence entry
+   - >
+    A folded sequence entry
+   - Sixth item in top sequence
+ruby: |
+  { 'empty' => [], 'flow' => [ 'one', 'two', 'three', 'four', 'five' ],
+    'block' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
+    "A folded sequence entry\n", 'Sixth item in top sequence' ] }
+
+---
+test: Complete mapping test
+yaml: |
+ empty: {}
+ flow: { one: 1, two: 2 }
+ spanning: { one: 1,
+    two: 2 }
+ block:
+  first : First entry
+  second:
+   key: Subordinate mapping
+  third:
+   - Subordinate sequence
+   - { }
+   - Previous mapping is empty.
+   - A key: value pair in a sequence.
+     A second: key:value pair.
+   - The previous entry is equal to the following one.
+   -
+    A key: value pair in a sequence.
+    A second: key:value pair.
+  !float 12 : This key is a float.
+  ? >
+   ?
+  : This key had to be protected.
+  "\a" : This key had to be escaped.
+  ? >
+   This is a
+   multi-line
+   folded key
+  : Whose value is
+    also multi-line.
+  ? this also works as a key
+  : with a value at the next line.
+  ?
+   - This key
+   - is a sequence
+  :
+   - With a sequence value.
+  ?
+   This: key
+   is a: mapping
+  :
+   with a: mapping value.
+ruby: |
+  { 'empty' => {}, 'flow' => { 'one' => 1, 'two' => 2 },
+    'spanning' => { 'one' => 1, 'two' => 2 },
+    'block' => { 'first' => 'First entry', 'second' =>
+    { 'key' => 'Subordinate mapping' }, 'third' =>
+      [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
+        'The previous entry is equal to the following one.',
+        { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
+    12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
+    "\a" => 'This key had to be escaped.',
+    "This is a multi-line folded key\n" => "Whose value is also multi-line.",
+    'this also works as a key' => 'with a value at the next line.',
+    [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }
+  # Couldn't recreate map exactly, so we'll do a detailed check to be sure it's entact
+  obj_y['block'].keys.each { |k|
+    if k.type == Hash
+      v = obj_y['block'][k]
+      if k['This'] == 'key' and k['is a'] == 'mapping' and v['with a'] == 'mapping value.'
+         obj_r['block'][k] = v
+      end
+    end
+  }
+no-round-trip:
+  - ruby
+
+---
+test: Literal explicit indentation
+yaml: |
+   # Explicit indentation must
+   # be given in all the three
+   # following cases.
+   leading spaces: |2
+         This value starts with four spaces.
+   
+   leading line break: |2
+   
+     This value starts with a line break.
+   
+   leading comment indicator: |2
+     # first line starts with a
+     # character.
+   
+   # Explicit indentation may
+   # also be given when it is
+   # not required.
+   redundant: |2
+     This value is indented 2 spaces.
+ruby: |
+   {
+      'leading spaces' => "    This value starts with four spaces.\n",
+      'leading line break' => "\nThis value starts with a line break.\n",
+      'leading comment indicator' => "# first line starts with a\n# character.\n",
+      'redundant' => "This value is indented 2 spaces.\n"
+   }
+
+---
+test: Chomping and keep modifiers
+yaml: |
+    clipped: |
+        This has one newline.
+    
+    same as "clipped" above: "This has one newline.\n"
+    
+    stripped: |-
+        This has no newline.
+    
+    same as "stripped" above: "This has no newline."
+    
+    kept: |+
+        This has two newlines.
+    
+    same as "kept" above: "This has two newlines.\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has two newlines.\n\n",
+      'same as "kept" above' => "This has two newlines.\n\n"
+    }
+
+---
+test: Literal combinations
+yaml: |
+   empty: |
+   
+   literal: |
+    The \ ' " characters may be
+    freely used. Leading white
+       space is significant.
+    
+    Line breaks are significant.
+    Thus this value contains one
+    empty line and ends with a
+    single line break, but does
+    not start with one.
+    
+   is equal to: "The \\ ' \" characters may \
+    be\nfreely used. Leading white\n   space \
+    is significant.\n\nLine breaks are \
+    significant.\nThus this value contains \
+    one\nempty line and ends with a\nsingle \
+    line break, but does\nnot start with one.\n"
+   
+   # Comments may follow a block
+   # scalar value. They must be
+   # less indented.
+   
+   # Modifiers may be combined in any order.
+   indented and chomped: |2-
+       This has no newline.
+   
+   also written as: |-2
+       This has no newline.
+   
+   both are equal to: "  This has no newline."
+ruby: |
+   {
+     'empty' => '',
+     'literal' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'is equal to' => "The \\ ' \" characters may be\nfreely used. Leading white\n   space " +
+       "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
+       "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
+     'indented and chomped' => '  This has no newline.',
+     'also written as' => '  This has no newline.',
+     'both are equal to' => '  This has no newline.'
+   }
+
+---
+test: Folded combinations
+yaml: |
+   empty: >
+   
+   one paragraph: >
+    Line feeds are converted
+    to spaces, so this value
+    contains no line breaks
+    except for the final one.
+   
+   multiple paragraphs: >2
+   
+     An empty line, either
+     at the start or in
+     the value:
+   
+     Is interpreted as a
+     line break. Thus this
+     value contains three
+     line breaks.
+   
+   indented text: >
+       This is a folded
+       paragraph followed
+       by a list:
+        * first entry
+        * second entry
+       Followed by another
+       folded paragraph,
+       another list:
+   
+        * first entry
+   
+        * second entry
+    
+       And a final folded
+       paragraph.
+   
+   above is equal to: |
+       This is a folded paragraph followed by a list:
+        * first entry
+        * second entry
+       Followed by another folded paragraph, another list:
+   
+        * first entry
+
+        * second entry
+    
+       And a final folded paragraph.
+   
+   # Explicit comments may follow
+   # but must be less indented.
+ruby: |
+   {
+     'empty' => '',
+     'one paragraph' => 'Line feeds are converted to spaces, so this value' +
+       " contains no line breaks except for the final one.\n",
+     'multiple paragraphs' => "\nAn empty line, either at the start or in the value:\n" +
+       "Is interpreted as a line break. Thus this value contains three line breaks.\n",
+     'indented text' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n",
+     'above is equal to' => "This is a folded paragraph followed by a list:\n" +
+       " * first entry\n * second entry\nFollowed by another folded paragraph, " +
+       "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n"
+   }
+
+---
+test: Single quotes
+yaml: |
+   empty: ''
+   second: '! : \ etc. can be used freely.'
+   third: 'a single quote '' must be escaped.'
+   span: 'this contains
+         six spaces
+   
+         and one
+         line break'
+   is same as: "this contains six spaces\nand one line break"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : \\ etc. can be used freely.',
+     'third' => "a single quote ' must be escaped.",
+     'span' => "this contains six spaces\nand one line break",
+     'is same as' => "this contains six spaces\nand one line break"
+   }
+
+---
+test: Double quotes
+yaml: |
+   empty: ""
+   second: "! : etc. can be used freely."
+   third: "a \" or a \\ must be escaped."
+   fourth: "this value ends with an LF.\n"
+   span: "this contains
+     four  \
+         spaces"
+   is equal to: "this contains four  spaces"
+ruby: |
+   {
+     'empty' => '',
+     'second' => '! : etc. can be used freely.',
+     'third' => 'a " or a \\ must be escaped.',
+     'fourth' => "this value ends with an LF.\n",
+     'span' => "this contains four  spaces",
+     'is equal to' => "this contains four  spaces"
+   }
+
+---
+test: Unquoted strings
+yaml: |
+   first: There is no unquoted empty string.
+   
+   second: 12          ## This is an integer.
+   
+   boolean: -          ## This is (false).
+   
+   third: !str 12      ## This is a string.
+   
+   span: this contains
+         six spaces
+   
+         and one
+         line break
+   
+   indicators: this has no comments.
+               #:foo and bar# are
+               both text.
+   
+   flow: [ can span
+              lines, # comment
+              like
+              this ]
+   
+   note: { one-line keys: but
+           multi-line values }
+   
+ruby: |
+   {
+     'first' => 'There is no unquoted empty string.',
+     'second' => 12,
+     'boolean' => false,
+     'third' => '12',
+     'span' => "this contains six spaces\nand one line break",
+     'indicators' => "this has no comments. #:foo and bar# are both text.",
+     'flow' => [ 'can span lines', 'like this' ],
+     'note' => { 'one-line keys' => 'but multi-line values' }
+   }
+
+#python: |
+#   [{
+#     'first' : 'there is not unquoted empty string.',
+#     'second': 12,
+#     'boolean': False,
+#     'third': '12',
+#     'span': "this contains six spaces\n and one line break",
+#     'indicators': "this has no comments. #:foo and bar# are both text",
+#     'flow': ['can span lines', 'like this'],
+#     'note': {'one-line keys': 'but multi-line values'} 
+#   }]
+
+---
+test: Boolean Values
+yaml: |
+    boolean true: +
+    boolean false: -
+
+python: |
+    [{
+    "boolean true": 1,
+    "boolean false": 0
+    }]
+
+---
+test: Builtin Types
+yaml: |
+    boolean true: !!bool 1
+    boolean false: !!bool 0
+
+python: |
+    [{
+    "boolean true": True,
+    "boolean false": False 
+    }]
+
+---
+test: Spanning sequences
+yaml: |
+   # The following are equal seqs
+   # with different identities.
+   flow: [ one, two ]
+   spanning: [ one,
+        two ]
+   block:
+     - one
+     - two
+ruby: |
+   {
+     'flow' => [ 'one', 'two' ],
+     'spanning' => [ 'one', 'two' ],
+     'block' => [ 'one', 'two' ]
+   }
+
+---
+test: Flow mappings
+yaml: |
+   # The following are equal maps
+   # with different identities.
+   flow: { one: 1, two: 2 }
+   block:
+       one: 1
+       two: 2
+ruby: |
+   {
+     'flow' => { 'one' => 1, 'two' => 2 },
+     'block' => { 'one' => 1, 'two' => 2 }
+   }
+
+---
+test: Representations of 12
+yaml: |
+   - 12 # An integer
+   # The following scalars
+   # are loaded to the
+   # string value '1' '2'.
+   - !str 12
+   - '12'
+   - "12"
+   - "\
+    1\
+    2\
+    "
+   # Strings containing paths and regexps can be unquoted:
+   - /foo/bar
+   - d:/foo/bar
+   - foo/bar
+   - /a.*b/
+ruby: |
+   [ 12, '12', '12', '12', '12', '/foo/bar', 'd:/foo/bar', 'foo/bar', '/a.*b/' ]
+
+---
+test: Null
+yaml: |
+   canonical: ~
+   
+   english: (null)
+   
+   # This sequence has four
+   # entries, two with values.
+   sparse:
+     - ~
+     - 2nd entry
+     - (nil)
+     - 4th entry
+   
+   four: This mapping has four keys,
+         only two with values.
+ruby: |
+   {
+     'canonical' => nil,
+     'english' => nil,
+     'sparse' => [ nil, '2nd entry', nil, '4th entry' ],
+     'four' => 'This mapping has four keys, only two with values.'
+   }
+
+---
+test: Boolean
+yaml: |
+   - : used as key  # Does not indicate a sequence.
+   canonical: +
+   logical:  (true)
+   informal: (no)
+ruby: |
+   {
+     false => 'used as key',
+     'canonical' => true,
+     'logical' => true,
+     'informal' => false
+   }
+
+---
+test: Integer
+yaml: |
+   canonical: 12345
+   decimal: +12,345
+   octal: 014
+   hexadecimal: 0xC
+ruby: |
+   {
+     'canonical' => 12345,
+     'decimal' => 12345,
+     'octal' => 12,
+     'hexadecimal' => 12 
+   }
+
+---
+test: Float
+yaml: |
+   canonical: 1.23015e+3
+   exponential: 12.3015e+02
+   fixed: 1,230.15
+   negative infinity: (-inf)
+   not a number: (NaN)
+ruby: |
+  { 
+    'canonical' => 1230.15, 
+    'exponential' => 1230.15, 
+    'fixed' => 1230.15,
+    'negative infinity' => -1.0/0.0,
+    'not a number' => 0.0/0.0
+  }
+  if obj_y['not a number'].nan?   # NaN comparison doesn't work right against 0.0/0.0
+    obj_r['not a number'] = obj_y['not a number']
+  end
+no-round-trip:
+  - ruby
+
+---
+test: Timestamp
+yaml: |
+   canonical:       2001-12-15T02:59:43.1Z
+   valid iso8601:   2001-12-14t21:59:43.10-05:00
+   space separated: 2001-12-14 21:59:43.10 -05:00
+   date (noon UTC): 2002-12-14
+ruby: |
+   {
+     'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, .10 ),
+     'valid iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'space separated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+     'date (noon UTC)' => Date.new( 2002, 12, 14 )
+   }
+
+---
+test: Binary
+yaml: |
+   canonical: !binary "\
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf\
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW\
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++\
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg\
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN\
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww\
+    EeECcgggoBADs="
+   base64: !binary |
+    R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf
+    n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW
+    NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++
+    f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg
+    d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN
+    AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww
+    EeECcgggoBADs=
+   description: >
+    The binary value above is a tiny arrow
+    encoded as a gif image.
+ruby-setup: |
+   arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005,  \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
+ruby: |
+   {
+     'canonical' => arrow_gif,
+     'base64' => arrow_gif,
+     'description' => "The binary value above is a tiny arrow encoded as a gif image.\n"
+   }
+
+---
+test: Default key
+yaml: |
+   ---     # Old schema
+   link with: 
+     - library1.dll
+     - library2.dll
+   ---     # New schema
+   link with:
+     - = : library1.dll
+       version: 1.2
+     - = : library2.dll
+       version: 2.3
+ruby: |
+   y = Stream.new
+   y.add( { 'link with' => [ 'library1.dll', 'library2.dll' ] } )
+   obj_h = YAML::SpecialHash[ 'version' => 1.2 ]
+   obj_h.default = 'library1.dll'
+   obj_h2 = YAML::SpecialHash[ 'version' => 2.3 ]
+   obj_h2.default = 'library2.dll'
+   y.add( { 'link with' => [ obj_h, obj_h2 ] } )
+documents: 2
+
+---
+test: Special keys
+yaml: |
+   "!": These three keys
+   "&": had to be quoted
+   "=": and are normal strings.
+   # NOTE: the following node should NOT be serialized this way.
+   encoded node :
+    !special '!' : '!type'
+    !special|canonical '&' : 12
+    = : value
+   # The proper way to serialize the above node is as follows:
+   node : !!type &12 value
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/docSep.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/docSep.yml	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/docSep.yml	(revision 71)
@@ -0,0 +1,103 @@
+--- #YAML:1.0
+test: Trailing Document Separator
+brief: >
+    You can separate YAML documents
+    with a string of three dashes.
+yaml: |
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: Leading Document Separator
+brief: >
+    You can explicity give an opening
+    document separator to your YAML stream.
+yaml: |
+    ---
+    - foo: 1
+      bar: 2
+    ---
+    more: stuff
+python: |
+    [
+        [ {'foo': 1, 'bar': 2}],
+        {'more': 'stuff'}
+    ]
+ruby: |
+    [ { 'foo' => 1, 'bar' => 2 } ]
+
+---
+test: YAML Header
+brief: >
+    The opening separator can contain directives
+    to the YAML parser, such as the version
+    number.
+yaml: |
+    --- #YAML:1.0
+    foo: 1
+    bar: 2
+python: |
+    [
+        { 'foo': 1, 'bar': 2 }
+    ]
+ruby: |
+    y = Stream.new
+    y.add( { 'foo' => 1, 'bar' => 2 } )
+documents: 1
+
+---
+test: Red Herring Document Separator
+brief: >
+    Separators included in blocks or strings
+    are treated as blocks or strings, as the
+    document separator should have no indentation
+    preceding it.
+yaml: |
+    foo: |
+        ---
+python: |
+    [
+        { 'foo': "---\n" }
+    ]
+ruby: |
+    { 'foo' => "---\n" }
+
+---
+test: Multiple Document Separators in Block
+brief: >
+    This technique allows you to embed other YAML
+    documents within literal blocks.
+yaml: |
+    foo: |
+        ---
+        foo: bar
+        ---
+        yo: baz
+    bar: |
+        fooness
+python: |
+    [
+        {  'foo': flushLeft("""
+            ---
+            foo: bar
+            ---
+            yo: baz
+            """),
+           'bar': "fooness\n"
+        }
+    ]
+ruby: |
+    {  
+       'foo' => "---\nfoo: bar\n---\nyo: baz\n",
+       'bar' => "fooness\n"
+    }
+
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/basic.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/basic.yml	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/basic.yml	(revision 71)
@@ -0,0 +1,242 @@
+--- #YAML:1.0
+test: Simple Sequence
+brief: >
+    You can specify a list in YAML by placing each
+    member of the list on a new line with an opening
+    dash. These lists are called sequences.
+yaml: |
+    - apple
+    - banana
+    - carrot
+perl: |
+    ['apple', 'banana', 'carrot'] 
+python: |
+    [ 
+        ['apple', 'banana', 'carrot'] 
+    ]
+ruby: |
+    ['apple', 'banana', 'carrot'] 
+
+---
+test: Nested Sequences
+brief: >
+    You can include a sequence within another
+    sequence by giving the sequence an empty
+    dash, followed by an indented list.
+yaml: |
+    -
+     - foo
+     - bar
+     - baz
+perl: |
+    [['foo', 'bar', 'baz']]
+python: |
+    [
+        [['foo', 'bar', 'baz']]
+    ]
+ruby: |
+    [['foo', 'bar', 'baz']]
+
+---
+test: Mixed Sequences
+brief: >
+    Sequences can contain any YAML data,
+    including strings and other sequences.
+yaml: |
+    - apple
+    -
+     - foo
+     - bar
+     - x123
+    - banana
+    - carrot
+perl: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+python: |
+    [
+        ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+    ]
+ruby: |
+    ['apple', ['foo', 'bar', 'x123'], 'banana', 'carrot']
+
+---
+test: Deeply Nested Sequences
+brief: >
+    Sequences can be nested even deeper, with each
+    level of indentation representing a level of
+    depth.
+yaml: |
+    -
+     -
+      - uno
+      - dos
+perl: |
+    [[['uno', 'dos']]]
+python: |
+    [
+        [[['uno', 'dos']]]
+    ]
+ruby: |
+    [[['uno', 'dos']]]
+
+---
+test: Simple Mapping
+brief: >
+    You can add a keyed list (also known as a dictionary or
+    hash) to your document by placing each member of the
+    list on a new line, with a colon seperating the key
+    from its value.  In YAML, this type of list is called
+    a mapping.
+yaml: |
+    foo: whatever
+    bar: stuff
+perl: |
+    { foo => 'whatever', bar => 'stuff' }
+python: |
+    [
+        {'foo': 'whatever', 'bar': 'stuff'}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => 'stuff' }
+
+---
+test: Sequence in a Mapping
+brief: >
+    A value in a mapping can be a sequence.
+yaml: |
+    foo: whatever
+    bar:
+     - uno
+     - dos
+perl: |
+    { foo => 'whatever', bar => [ 'uno', 'dos' ] }
+python: |
+    [
+        {'foo': 'whatever', 'bar': ['uno', 'dos']}
+    ]
+ruby: |
+    { 'foo' => 'whatever', 'bar' => [ 'uno', 'dos' ] }
+
+---
+test: Nested Mappings
+yaml: |
+    foo: whatever
+    bar:
+     fruit: apple
+     name: steve
+     sport: baseball
+brief: >
+    A value in a mapping can be another mapping.
+perl: |
+    { foo => 'whatever', 
+      bar => {
+         fruit => 'apple', 
+         name => 'steve',
+         sport => 'baseball'
+       }
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': {
+            'fruit': 'apple', 
+            'name': 'steve',
+            'sport': 'baseball'
+            }
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => {
+         'fruit' => 'apple', 
+         'name' => 'steve',
+         'sport' => 'baseball'
+       }
+    }
+
+---
+test: Mixed Mapping
+brief: >
+    A mapping can contain any assortment
+    of mappings and sequences as values.
+yaml: |
+    foo: whatever
+    bar:
+     -
+      fruit: apple
+      name: steve
+      sport: baseball
+     - more
+     -
+      python: rocks
+      perl: papers
+      ruby: scissorses
+perl: |
+    { foo => 'whatever', 
+      bar => [
+        {
+            fruit => 'apple', 
+            name => 'steve',
+            sport => 'baseball'
+        },
+        'more',
+        {
+            python => 'rocks',
+            perl => 'papers',
+            ruby => 'scissorses'
+        }
+      ]
+    }
+python: |
+    [
+        {'foo': 'whatever', 
+         'bar': [
+            {
+                'fruit': 'apple', 
+                'name': 'steve',
+                'sport': 'baseball'
+            },
+            'more',
+            {
+                'python': 'rocks',
+                'perl':  'papers',
+                'ruby': 'scissorses'
+            }
+         ]
+        }
+    ]
+ruby: |
+    { 'foo' => 'whatever', 
+      'bar' => [
+        {
+            'fruit' => 'apple', 
+            'name' => 'steve',
+            'sport' => 'baseball'
+        },
+        'more',
+        {
+            'python' => 'rocks',
+            'perl' => 'papers',
+            'ruby' => 'scissorses'
+        }
+      ]
+    }
+
+---
+test: Sequence-Mapping Shortcut
+brief: >
+     If you are adding a mapping to a sequence, you
+     can place the mapping on the same line as the
+     dash as a shortcut.
+yaml: |
+     - work on YAML.py:
+        - work on Store
+perl: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+python: |
+    [
+        [ {'work on YAML.py': ['work on Store']} ]
+    ]
+ruby: |
+    [ { 'work on YAML.py' => ['work on Store'] } ]
+
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ruby.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ruby.yml	(revision 78)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/ruby.yml	(revision 78)
@@ -0,0 +1,222 @@
+--- #YAML:1.0
+test: Symbols
+brief: >
+    Ruby Symbols can be simply serialized using
+    the !ruby/symbol transfer method, or the
+    abbreviated !ruby/sym.
+yaml: |
+    simple symbol: !ruby/symbol Simple
+    shortcut syntax: !ruby/sym Simple
+    symbols in seqs:
+      - !ruby/symbol ValOne
+      - !ruby/symbol ValTwo
+      - !ruby/symbol ValThree
+    symbols in maps:
+      !ruby/symbol MapKey: !ruby/symbol MapValue
+ruby: |
+    { 'simple symbol' => :Simple,
+      'shortcut syntax' => :Simple,
+      'symbols in seqs' => [ :ValOne, :ValTwo, :ValThree ],
+      'symbols in maps' => { :MapKey => :MapValue }
+    }
+
+---
+test: Ranges
+brief: >
+    Ranges are serialized with the !ruby/range
+    type family.
+yaml: |
+    normal range: !ruby/range 10..20
+    exclusive range: !ruby/range 11...20
+    negative range: !ruby/range -1..-5
+    ? !ruby/range 0..40
+    : range as a map key
+ruby: |
+    { 'normal range' => (10..20),
+      'exclusive range' => (11...20),
+      'negative range' => (-1..-5),
+      (0..40) => 'range as a map key'
+    }
+
+---
+test: Regexps
+brief: >
+    Regexps may be serialized to YAML, both its
+    syntax and any modifiers.
+yaml: |
+    case-insensitive: !ruby/regexp "/George McFly/i"
+    complex: !ruby/regexp "/\\A\"((?:[^\"]|\\\")+)\"/"
+    simple: !ruby/regexp '/a.b/'
+ruby: |
+    { 'simple' => /a.b/, 'complex' => /\A"((?:[^"]|\")+)"/,
+      'case-insensitive' => /George McFly/i }
+
+---
+test: Perl Regexps
+brief: >
+    Regexps may also be imported from serialized
+    Perl.
+yaml: |
+    --- !perl/regexp:
+      REGEXP: "R[Uu][Bb][Yy]$"
+      MODIFIERS: i
+ruby: |
+    /R[Uu][Bb][Yy]$/i
+
+---
+test: Struct class
+brief: >
+    The Ruby Struct class is registered as a YAML
+    builtin type through Ruby, so it can safely 
+    be serialized.  To use it, first make sure you
+    define your Struct with Struct::new.  Then,
+    you are able to serialize with Struct#to_yaml
+    and unserialize from a YAML stream.
+yaml: |
+    --- !ruby/struct:BookStruct
+      author: Yukihiro Matsumoto
+      title: Ruby in a Nutshell
+      year: 2002
+      isbn: 0-596-00214-9
+ruby-setup: |
+    book_struct = Struct::new( "BookStruct", :author, :title, :year, :isbn )
+ruby: |
+    book_struct.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" )
+
+---
+test: Nested Structs
+brief: >
+    As with other YAML builtins, you may nest the
+    Struct inside of other Structs or other data
+    types.
+yaml: |
+    - !ruby/struct:FoodStruct
+      name: Nachos
+      ingredients:
+        - Mission Chips
+        - !ruby/struct:FoodStruct
+          name: Tostitos Nacho Cheese
+          ingredients:
+            - Milk and Enzymes
+            - Jack Cheese
+            - Some Volatile Chemicals
+          taste: Angelic
+        - Sour Cream
+      taste: Zesty
+    - !ruby/struct:FoodStruct
+      name: Banana Cream Pie
+      ingredients:
+        - Bananas
+        - Creamy Stuff
+        - And Such
+      taste: Puffy
+ruby-setup: |
+    food_struct = Struct::new( "FoodStruct", :name, :ingredients, :taste )
+ruby: |
+    [
+      food_struct.new( 'Nachos', [ 'Mission Chips',
+        food_struct.new( 'Tostitos Nacho Cheese', [ 'Milk and Enzymes', 'Jack Cheese', 'Some Volatile Chemicals' ], 'Angelic' ),
+        'Sour Cream' ], 'Zesty' ),
+      food_struct.new( 'Banana Cream Pie', [ 'Bananas', 'Creamy Stuff', 'And Such' ], 'Puffy' )
+    ]
+
+---
+test: Objects
+brief: >
+    YAML has generic support for serializing objects
+    from any class available in Ruby.  If using the
+    generic object serialization, no extra code is
+    needed.
+yaml: |
+    --- !ruby/object:YAML::Zoolander
+      name: Derek
+      look: Blue Steel
+ruby-setup: |
+    class Zoolander
+      attr_accessor :name, :look
+      def initialize( look )
+        @name = "Derek"
+        @look = look
+      end
+      def ==( z )
+        self.name == z.name and self.look == z.look
+      end
+    end
+ruby: |
+    Zoolander.new( "Blue Steel" )
+
+---
+test: Extending Kernel::Array
+brief: >
+    When extending the Array class, your instances
+    of such a class will dump as YAML sequences,
+    tagged with a class name.
+yaml: |
+    --- !ruby/array:YAML::MyArray
+    - jacket
+    - sweater
+    - windbreaker
+ruby-setup: |
+    class MyArray < Kernel::Array; end
+ruby: |
+    outerwear = MyArray.new
+    outerwear << 'jacket'
+    outerwear << 'sweater'
+    outerwear << 'windbreaker'
+    outerwear
+
+---
+test: Extending Kernel::Hash
+brief: >
+    When extending the Hash class, your instances
+    of such a class will dump as YAML maps, tagged
+    with a class name.
+yaml: |
+    --- !ruby/hash:YAML::MyHash
+    Black Francis: Frank Black
+    Kim Deal: Breeders
+    Joey Santiago: Martinis
+ruby-setup: |
+    # Note that the @me attribute isn't dumped
+    # because the default to_yaml is trained
+    # to dump as a regular Hash.
+    class MyHash < Kernel::Hash
+      attr_accessor :me
+      def initialize
+        @me = "Why"
+      end
+    end
+ruby: |
+    pixies = MyHash.new
+    pixies['Black Francis'] = 'Frank Black'
+    pixies['Kim Deal'] = 'Breeders'
+    pixies['Joey Santiago'] = 'Martinis'
+    pixies
+
+---
+test: YAML::Pairs
+brief: >
+    The sequence-mapping shortcut in YAML allows you to 
+    place the first line of the mapping on the same line 
+    as the dash for the entry containing the mapping. 
+    The !ruby/pairs type takes advantage of this shortcut 
+    to create (instead of a sequence including maps) a 
+    single object of pairs which can be accessed like an 
+    ordered hash. Entries in which the last value in the 
+    pair is null can simply show the first value in the pair.
+yaml: |
+    --- !ruby/pairs
+    - Minh Thai: 22.95
+    - Guus Razous-Schultz: 24.32
+    - Zoltan Labas Hungary: 24.49
+    - Lars Petrus
+    - Ken`ichi Ueno Japan
+ruby: |
+    winners = YAML::Pairs.new
+    winners[ 'Minh Thai' ] = 22.95
+    winners[ 'Guus Razous-Schultz' ] = 24.32
+    winners[ 'Zoltan Labas Hungary' ] = 24.49
+    winners[ 'Lars Petrus' ] = nil
+    winners[ 'Ken`ichi Ueno Japan' ] = nil
+    winners
+
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/foldedScalar.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/foldedScalar.yml	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/foldedScalar.yml	(revision 71)
@@ -0,0 +1,216 @@
+--- #YAML:1.0
+test: Single ending newline
+brief: >
+    A pipe character, followed by an indented
+    block of text is treated as a literal
+    block, in which newlines are preserved
+    throughout the block, including the final
+    newline.
+yaml: |
+    ---
+    this: |
+        Foo
+        Bar
+
+ruby: |
+    { 'this' => "Foo\nBar\n" }
+python: |
+    [ 
+        { 'this': "Foo\nBar\n" }
+    ]
+---
+test: The '+' indicator
+brief: >
+    The '+' indicator says to keep newlines at the end of text
+    blocks.
+yaml: |
+    normal: |
+      extra new lines not kept
+
+    preserving: |+
+      extra new lines are kept
+
+
+    dummy: value
+ruby: |
+    {
+        'normal' => "extra new lines not kept\n",
+        'preserving' => "extra new lines are kept\n\n\n",
+        'dummy' => 'value'
+    }
+python: |
+    [ {
+        'normal': "extra new lines not kept\n",
+        'preserving': "extra new lines are kept\n\n\n",
+        'dummy': 'value'
+    } ]
+---
+test: Three trailing newlines in literals
+brief: >
+    To give you more control over how space
+    is preserved in text blocks, YAML has
+    the keep '+' and chomp '-' indicators.
+    The keep indicator will preserve all
+    ending newlines, while the chomp indicator
+    will strip all ending newlines.
+yaml: |
+    clipped: |
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: |-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: |+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+not_yet_in_python: |
+    [
+    { 
+      'clipped': "This has one newline.\n",
+      'same as "clipped" above': "This has one newline.\n",
+      'stripped': 'This has no newline.',
+      'same as "stripped" above': 'This has no newline.',
+      'kept': "This has four newlines.\n\n\n\n",
+      'same as "kept" above': "This has four newlines.\n\n\n\n"
+    }
+    ]
+
+---
+test: Extra trailing newlines with spaces
+brief: >
+    Normally, only a single newline is kept
+    from the end of a literal block, unless the
+    keep '+' character is used in combination
+    with the pipe.  The following example
+    will preserve all ending whitespace
+    since the last line of both literal blocks
+    contains spaces which extend past the indentation
+    level.
+yaml: |
+    ---
+    this: |
+        Foo
+
+          
+    kept: |+
+        Foo
+
+          
+ruby: |
+    { 'this' => "Foo\n\n  \n", 
+      'kept' => "Foo\n\n  \n" }
+
+---
+test: Folded Block in a Sequence
+brief: >
+    A greater-then character, followed by an indented
+    block of text is treated as a folded block, in
+    which lines of text separated by a single newline
+    are concatenated as a single line.
+yaml: |
+    ---
+    - apple
+    - banana
+    - >
+        can't you see
+        the beauty of yaml?
+        hmm
+    - dog
+python: |
+    [
+        [
+            'apple', 
+            'banana', 
+            "can't you see the beauty of yaml? hmm\n",
+            'dog'
+        ]
+    ]
+ruby: |
+    [
+        'apple', 
+        'banana', 
+        "can't you see the beauty of yaml? hmm\n",
+        'dog'
+    ]
+---
+test: Folded Block as a Mapping Value
+brief: >
+    Both literal and folded blocks can be
+    used in collections, as values in a 
+    sequence or a mapping.
+yaml: |
+    --- 
+    quote: >
+        Mark McGwire's
+        year was crippled
+        by a knee injury.
+    source: espn
+python: |
+    [
+        { 
+            'quote': "Mark McGwire's year was crippled by a knee injury.\n",
+            'source': 'espn'
+        }
+    ]
+ruby: |
+    { 
+        'quote' => "Mark McGwire's year was crippled by a knee injury.\n",
+        'source' => 'espn'
+    }
+
+---
+test: Three trailing newlines in folded blocks
+brief: >
+    The keep and chomp indicators can also
+    be applied to folded blocks.
+yaml: |
+    clipped: >
+        This has one newline.
+
+
+
+    same as "clipped" above: "This has one newline.\n"
+
+    stripped: >-
+        This has no newline.
+
+
+
+    same as "stripped" above: "This has no newline."
+
+    kept: >+
+        This has four newlines.
+
+
+
+    same as "kept" above: "This has four newlines.\n\n\n\n"
+ruby: |
+    { 
+      'clipped' => "This has one newline.\n",
+      'same as "clipped" above' => "This has one newline.\n",
+      'stripped' => 'This has no newline.',
+      'same as "stripped" above' => 'This has no newline.',
+      'kept' => "This has four newlines.\n\n\n\n",
+      'same as "kept" above' => "This has four newlines.\n\n\n\n"
+    }
+
Index: /pyyaml-legacy/trunk/yaml/tests/TestingSuite/types.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/TestingSuite/types.yml	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/tests/TestingSuite/types.yml	(revision 71)
@@ -0,0 +1,239 @@
+--- #YAML:1.0
+test: Strings
+brief: >
+    Any group of characters beginning with an
+    alphabetic or numeric character is a string,
+    unless it belongs to one of the groups below
+    (such as an Integer or Time).  
+yaml: |
+    String
+ruby: |
+    'String'
+
+---
+test: String characters
+brief: >
+    A string can contain any alphabetic or
+    numeric character, along with many
+    punctuation characters, including the
+    period, dash, space, quotes, exclamation, and
+    question mark.
+yaml: |
+    - What's Yaml?
+    - It's for writing data structures in plain text.
+    - And?
+    - And what? That's not good enough for you?
+    - No, I mean, "And what about Yaml?"
+    - Oh, oh yeah. Uh.. Yaml for Ruby.
+ruby: |
+    [
+      "What's Yaml?",
+      "It's for writing data structures in plain text.",
+      "And?",
+      "And what? That's not good enough for you?",
+      "No, I mean, \"And what about Yaml?\"",
+      "Oh, oh yeah. Uh.. Yaml for Ruby."
+    ]
+
+---
+test: Indicators in Strings
+brief: >
+    Be careful using indicators in strings.  In particular,
+    the comma, colon, and pound sign must be used carefully.
+yaml: |
+    the colon followed by space is an indicator: but is a string:right here
+    same for the pound sign: here we have it#in a string
+    the comma can, honestly, be used in most cases: [ but not in, inline collections ]
+ruby: |
+    {
+      'the colon followed by space is an indicator' => 'but is a string:right here',
+      'same for the pound sign' => 'here we have it#in a string',
+      'the comma can, honestly, be used in most cases' => [ 'but not in', 'inline collections' ]
+    }
+
+---
+test: Forcing Strings
+brief: >
+    Any YAML type can be forced into a string using the
+    explicit !str method.
+yaml: |
+    date string: !str 2001-08-01
+    number string: !str 192
+ruby: |
+    {
+      'date string' => '2001-08-01',
+      'number string' => '192'
+    }
+
+---
+test: Single-quoted Strings
+brief: >
+    You can also enclose your strings within single quotes,
+    which allows use of slashes, colons, and other indicators
+    freely.  Inside single quotes, you can represent a single
+    quote in your string by using two single quotes next to
+    each other.
+yaml: |
+    all my favorite symbols: '#:!/%.)'
+    a few i hate: '&(*'
+    why do i hate them?: 'it''s very hard to explain'
+ruby: |
+    {
+      'all my favorite symbols' => '#:!/%.)',
+      'a few i hate' => '&(*',
+      'why do i hate them?' => 'it\'s very hard to explain'
+    }
+
+---
+test: Double-quoted Strings
+brief: >
+    Enclosing strings in double quotes allows you
+    to use escapings to represent ASCII and
+    Unicode characters.
+yaml: |
+    i know where i want my line breaks: "one here\nand another here\n"
+ruby: |
+    {
+      'i know where i want my line breaks' => "one here\nand another here\n"
+    }
+
+---
+test: Multi-line Quoted Strings
+brief: >
+    Both single- and double-quoted strings may be
+    carried on to new lines in your YAML document.
+    They must be indented a step and indentation
+    is interpreted as a single space.
+yaml: |
+    i want a long string: "so i'm going to
+      let it go on and on to other lines
+      until i end it with a quote."
+ruby: |
+    { 'i want a long string' => "so i'm going to " +
+         "let it go on and on to other lines " +
+         "until i end it with a quote."
+    }
+
+---
+test: Null
+brief: >
+    You can use the tilde '~' character for a null value.
+yaml: |
+    name: Mr. Show
+    hosted by: Bob and David
+    date of next season: ~
+ruby: |
+    {
+      'name' => 'Mr. Show',
+      'hosted by' => 'Bob and David',
+      'date of next season' => nil
+    }
+
+---
+test: Boolean
+brief: >
+    You can use the plus sign '+' and the negative
+    sign '-' for True and False.
+yaml: |
+    Is Gus a Liar?: +
+    Do I rely on Gus for Sustenance?: -
+ruby: |
+    {
+      'Is Gus a Liar?' => true,
+      'Do I rely on Gus for Sustenance?' => false
+    }
+
+---
+test: Integers
+brief: >
+    An integer is a series of numbers, optionally
+    starting with a positive or negative sign.  Integers
+    may also contain commas for readability.
+yaml: |
+    zero: 0
+    simple: 12
+    one-thousand: 1,000
+    negative one-thousand: -1,000
+ruby: |
+    {
+      'zero' => 0,
+      'simple' => 12,
+      'one-thousand' => 1000,
+      'negative one-thousand' => -1000
+    }
+python: |
+    [ 
+        {
+            'zero': 0,
+            'simple': 12,
+            'one-thousand': 1000,
+            'negative one-thousand': -1000,
+        }
+    ]
+---
+test: Integers as Map Keys
+brief: >
+    An integer can be used a dictionary key.
+yaml: |
+    1: one
+    2: two
+    3: three
+python: |
+    [
+        {
+            1: 'one',
+            2: 'two',
+            3: 'three',
+        }
+    ]       
+ruby: |
+    {
+        1 => 'one',
+        2 => 'two',
+        3 => 'three'
+    }
+
+---
+test: Floats
+brief: >
+     Floats are represented by numbers with decimals,
+     allowing for scientific notation, as well as
+     positive and negative infinity and "not a number."
+yaml: |
+     a simple float: 2.00
+     larger float: 1,000.09
+     scientific notation: 1.00009e+3
+ruby: |
+     {
+       'a simple float' => 2.0,
+       'larger float' => 1000.09,
+       'scientific notation' => 1000.09
+     }
+
+---
+test: Time
+brief: >
+    You can represent timestamps by using
+    ISO8601 format, or a variation which
+    allows spaces between the date, time and
+    time zone.
+yaml: |
+    iso8601: 2001-12-14t21:59:43.10-05:00
+    space seperated: 2001-12-14 21:59:43.10 -05:00
+ruby: |
+    {
+      'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" ),
+      'space seperated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, .10, "-05:00" )
+    }
+
+---
+test: Date
+brief: >
+    A date can be represented by its year,
+    month and day in ISO8601 order.
+yaml: |
+    1976-07-31
+ruby: |
+    Date.new( 1976, 7, 31 )
+
+
Index: /pyyaml-legacy/trunk/yaml/tests/YamlTest.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/YamlTest.py	(revision 106)
+++ /pyyaml-legacy/trunk/yaml/tests/YamlTest.py	(revision 106)
@@ -0,0 +1,113 @@
+import unittest, sys, string
+import yaml
+from here import flushLeft
+import re
+import glob
+from test import assertEquals, assertError
+from yaml.klass import probeModule
+
+try:
+   unicode('')
+   hasUnicode = 1
+except:
+   hasUnicode = 0
+
+
+def loadFlushLeft(stream, typeResolver=None):
+    return list(yaml.load(flushLeft(stream), typeResolver))
+
+class YamlTest(unittest.TestCase):
+
+    def runTest(self):
+        # reinvent the wheel, instead of trying to 
+        # understand unittest's braindead interface
+        for name in dir(self.__class__):
+            if re.match('test', name):
+                exec('self.%s()' % name)
+
+    def verify(self, stream, results):
+        self.verifyMany(stream, [results])
+
+    def verifyMany(self, stream, expected):
+        results = loadFlushLeft(stream)
+        assertEquals(results, expected)
+
+class ClassForRuntime:
+    def __init__(self):
+        self.foo = 1
+        self.bar = 2
+
+class YamlLoader:
+    # XXX python 2.1 has weak lambda support
+    def __init__(self, doc):
+        self.doc = doc
+    def __call__(self):
+        return list(yaml.load(self.doc['yaml']))
+
+class Test(YamlTest):
+    def testFromYaml(self):
+        testFiles = glob.glob('TestingSuite/*.yml')
+        for file in testFiles:
+            print "\n\n\n\n", file
+            try:
+                docs = yaml.loadFile(file)
+            except IOError:
+                raise "See TESTING for how to set up TestingSuite"
+            for doc in docs:
+                if doc.has_key('python'):
+                    self.verifyOneDoc(doc)
+                if doc.has_key('error') and doc['error'].has_key('python'):
+                    assertError(YamlLoader(doc), doc['error']['python'])
+
+    def verifyOneDoc(self, doc):
+        if doc.has_key('python_setup'):
+            exec(doc['python_setup'])
+        data = eval(doc['python'])
+        # print data
+        assertEquals(list(yaml.load(doc['yaml'])), data)
+        if not doc.has_key('NO_ROUND_TRIP'):
+            self.assertRoundTrip(data)
+
+    def assertRoundTrip(self, data):
+        # XXX - A5 won't round trip when enclosed by 
+        # an array...need to investigate
+        for item in data:
+            # print dump(item)
+            assertEquals(item, 
+                yaml.load(yaml.dump(item)).next(), 'roundtrip')
+
+
+class TestUtils(YamlTest):    
+    class Dummy:
+        pass
+
+    def testMakeClass(self):
+        self.assertEquals(42,
+            probeModule('YamlTest', 'TestUtils.Dummy', 
+                {'a': 27, 'b': 42}).b)
+
+    class FromYaml:
+        def from_yaml(self, dict):
+            self.sum = dict['a'] + dict['b']
+            return self
+
+    def testMakeClassFromYaml(self):
+        self.assertEquals(6,
+            probeModule('YamlTest', 'TestUtils.FromYaml',
+                {'a': 2, 'b': 4}).sum)
+
+if __name__ == '__main__':
+    import testYamlBasics
+    import testNestedText
+    import testInlineTokenizer
+    import testDumper
+    ts = unittest.TestSuite()
+    ts.addTest(testYamlBasics.Test())
+    ts.addTest(testNestedText.Test())
+    ts.addTest(testInlineTokenizer.Test())
+    ts.addTest(testDumper.Test())
+    ts.addTest(Test())
+    ts.addTest(TestUtils())
+    unittest.TextTestRunner().run(ts)
+    yaml.dumpToFile(sys.stdout, {'TESTING dumpToFile': 'ok'})
+    testVersion()
Index: /pyyaml-legacy/trunk/yaml/tests/testQuery.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testQuery.py	(revision 91)
+++ /pyyaml-legacy/trunk/yaml/tests/testQuery.py	(revision 91)
@@ -0,0 +1,80 @@
+import YamlTest
+import yaml
+from test import assertEquals
+import re
+
+def Query(query, doc):
+    results = []
+    for row in yaml.ypath(query['from'],doc):
+        data = {}
+        if Where(row, query):
+            for field in query['select']:
+                data[field] = yaml.ypath(field,row).next()
+            if query.has_key('order'):
+                data['__row__'] = row
+            results.append(data)
+    return Order(results, query)
+
+def Where(row, query):
+    if query.has_key('where'):
+        where = query['where']
+        return WhereRow(row, query['where'])
+    return 1
+
+def WhereRow(row, where):
+    if type(where) == type([]):
+        return And(row, where, WhereRow)
+    if type(where) == type(''):
+        return WhereString(row, where)
+    return And(row, where.keys(), 
+        lambda row, field: where[field] == row[field])
+
+def And(row, conds, condFunc):
+    for cond in conds:
+        if not condFunc(row, cond):
+            return 0
+    return 1
+
+def WhereString(row, where):
+    where = re.sub("\[(.*?)\]", r"row['\1']", where)
+    return eval(where)
+
+def Order(results, query):
+    if not query.has_key('order'):
+        return results
+    compare = lambda x,y: Compare(x,y,query['order'])
+    results.sort(compare)
+    for result in results:
+        del result['__row__']
+    return results
+
+def Compare(x, y, order):
+    for field in order:
+        val = cmp(
+            yaml.ypath(field,x['__row__']).next(),
+            yaml.ypath(field,y['__row__']).next()
+        )
+        if val != 0: return val
+
+
+class Test(YamlTest.YamlTest):
+    def testQuery(self):
+        doc = yaml.loadFile("./yaml/tests/testQueryData.yml").next()
+        for test in doc['tests']:
+            if not test.has_key('ignore'):
+# JUST SOME PRINTS TO CHECK FUNTIONALITY
+#                import pprint
+#                print 'query--------------'
+#                pprint.pprint(test['query'])
+#                print 'data--------------'
+#                pprint.pprint(doc['data'])
+#                print 'expected--------------'
+#                pprint.pprint(test['expected'])
+#                print '=========================='
+                assertEquals(Query(test['query'], doc['data']), test['expected'], test['query'])   
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
+
+
Index: /pyyaml-legacy/trunk/yaml/tests/README
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/README	(revision 97)
+++ /pyyaml-legacy/trunk/yaml/tests/README	(revision 97)
@@ -0,0 +1,1 @@
+currently YamlTest is a legacy test suite. testrunner script in /scripts should be used. This folder needs cleaning up with utility scripts consolidated or removed depending on the need.
Index: /pyyaml-legacy/trunk/yaml/tests/testQueryData.yml
===================================================================
--- /pyyaml-legacy/trunk/yaml/tests/testQueryData.yml	(revision 90)
+++ /pyyaml-legacy/trunk/yaml/tests/testQueryData.yml	(revision 90)
@@ -0,0 +1,246 @@
+data:
+    title:
+        - &manager
+          caption: Manager
+          position: 0
+        - &programmer
+          caption: Programmer
+          position: 1
+          shadow:
+             position: 18
+        - &editor
+          caption: Editor
+          position: ~
+          shadow:
+             position: 3
+    people:
+        - &mary
+          id: mary
+          name: Mary McFoo
+          number: 333
+          title: *programmer
+        - &al
+          id: al
+          name: Al Barson
+          number: 555
+          title: *manager
+    tasks:
+        - id: make a list
+          duration: 10
+          owner: al
+          person: *al
+        - id: go to store
+          duration: 15
+          owner: mary
+          person: *mary
+        - id: buy stuff
+          duration: 25
+          owner: mary
+          person: *mary
+          tasks:
+            - id: zoom
+              owner: *mary
+              duration: 22
+            - id: fly
+              owner: *al
+              duration: 33
+        - id: drive home
+          duration: 20
+          owner: mary
+          person: *mary
+        - id: watch tv
+          duration: 20
+          owner: al
+          person: *al
+        - id: cook food
+          duration: 60
+          owner: al
+          person: *al
+        - id: eat stuff
+          duration: 35
+          owner: al
+          person: *al
+tests:
+    - query:
+        select:
+            - duration
+        from: tasks/*
+      expected:
+        - duration: 10
+        - duration: 15
+        - duration: 25
+        - duration: 20
+        - duration: 20
+        - duration: 60
+        - duration: 35
+    - query:
+        select:
+            - owner
+        from: tasks/*
+        where:
+          id: cook food
+      expected:
+        - owner: al
+    - query:
+        select:
+            - id
+        from: tasks/*
+        where:
+          duration: 20
+          owner: al
+      expected:
+        - id: watch tv
+    - query:
+        select:
+            - caption
+        from: title/*
+        where:
+          position: ~
+      expected:
+         - caption: Editor
+    - query:
+        select:
+            - position
+            - shadow/position
+        from: title/*
+        where:
+          caption: Editor
+      expected:
+         - position: ~
+           shadow/position: 3
+    - query:
+        select:
+          - id
+          - duration
+        from: tasks/*
+        where:
+            owner: mary
+        order:
+          - duration
+      expected:
+        - id: go to store
+          duration: 15
+        - id: drive home
+          duration: 20
+        - id: buy stuff
+          duration: 25
+    - query:
+        select:
+          - id
+          - owner
+        from: tasks/*
+        where: |
+          [duration] == 60
+      expected:
+        - id: cook food
+          owner: al
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where: |
+          [duration] <= 20 and [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where:
+          - [duration] <= 20 
+          - [owner] == 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+          - id
+        from: tasks/*
+        where:
+          - [duration] <= 20 
+          - owner: 'al'
+      expected:
+        - id: make a list
+        - id: watch tv
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+            - person/number
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - id: make a list
+          duration: 10
+          person/name: Al Barson
+          person/number: 555
+    - query:
+        select:
+            - person/name
+            - person/title/caption
+        from: tasks/*
+        where:
+          id: make a list
+      expected:
+        - person/name: Al Barson
+          person/title/caption: Manager
+    - query:
+        select:
+            - id
+            - duration
+            - person/name
+        from: tasks/*
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+          person/name: Al Barson
+        - id: cook food
+          duration: 60
+          person/name: Al Barson
+        - id: buy stuff
+          duration: 25
+          person/name: Mary McFoo
+      ignore: 1
+    - query:
+        select:
+            - id
+            - duration
+        from: tasks
+        where:
+          - [duration] > 20 
+        order:
+          - person/name
+          - duration
+      expected:
+        - id: eat stuff
+          duration: 35
+        - id: cook food
+          duration: 60
+        - id: buy stuff
+          duration: 25
+      ignore: 1
+    - query:
+       select:
+         - id
+       from: //tasks
+      expected:
+        - id: make a list
+        - id: go to store
+        - id: buy stuff
+        - id: zoom
+        - id: fly
+        - id: drive home
+        - id: watch tv
+        - id: cook food
+        - id: eat stuff
+      ignore: 1
Index: /pyyaml-legacy/trunk/yaml/redump.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/redump.py	(revision 74)
+++ /pyyaml-legacy/trunk/yaml/redump.py	(revision 74)
@@ -0,0 +1,14 @@
+from yaml.ordered_dict import OrderedDict
+from yaml import Parser, Dumper, StringStream
+
+def loadOrdered(stream):
+    parser = Parser(StringStream(stream))
+    parser.dictionary = OrderedDict
+    return iter(parser)
+
+def redump(stream):
+    docs = list(loadOrdered(stream))
+    dumper = Dumper()
+    dumper.alphaSort = 0
+    return dumper.dump(*docs)
+    
Index: /pyyaml-legacy/trunk/yaml/klass.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/klass.py	(revision 106)
+++ /pyyaml-legacy/trunk/yaml/klass.py	(revision 106)
@@ -0,0 +1,90 @@
+import new
+import re
+import __builtin__
+
+class DefaultResolver:
+    def resolveType(self, data, typestring):
+        assert __builtin__.bool
+        if typestring[:2] == "!!":
+            typestring = typestring[2:]
+        elif typestring[:1] == "!":
+            typestring = typestring[1:]
+
+        if "." in typestring:
+            classNodes = typestring.split('.')
+            classNodes[0] = classNodes[0]
+
+            if '' in classNodes:
+                raise "Invalid private type specifier"
+
+            klass = probeModule(classNodes)
+
+            obj = new.instance(klass) 
+            if hasMethod(obj, 'from_yaml'):
+                return obj.from_yaml(data)
+            obj.__dict__ = data
+            return obj
+
+        elif type(getattr(__builtin__,typestring)) == type:
+            builtinType = getattr(__builtin__, typestring)
+            return builtinType(data)
+
+        else:
+            raise "Invalide private type secifier"
+
+def probeModule(classNodes):
+    classStack = classNodes[:]
+    classStack.reverse()
+    while True:
+        moduleName = classStack.pop()
+        module = __import__(moduleName, globals(), locals())
+
+        if hasattr(module, classStack[-1]):
+            return loadClass(module, classStack)
+
+        if not classStack:
+            raise "Private type resolved to module" 
+
+
+def loadClass(classObj, classNodes):
+    while True:
+        nodeName = classNodes.pop()
+
+        if hasattr(classObj, nodeName):
+            classObj = getattr(classObj, nodeName)
+
+        else:
+            raise "Failed to resolve private type"
+
+        if not classNodes:
+            return classObj
+
+
+def hasMethod(object, method_name):
+    try:    
+        klass = object.__class__
+    except:
+        return 0
+    if not hasattr(klass, method_name):
+        return 0
+    method = getattr(klass, method_name)
+    if not callable(method):
+        return 0
+    return 1
+
+def isDictionary(data):
+    return isinstance(data, dict)
+
+try:
+    isDictionary({})
+except:
+    def isDictionary(data): return type(data) == type({}) # XXX python 2.1
+    
+if __name__ == '__main__':
+    print isDictionary({'foo': 'bar'})
+    try:
+        print isDictionary(dict())
+        from ordered_dict import OrderedDict
+        print isDictionary(OrderedDict())
+    except:
+        pass
Index: /pyyaml-legacy/trunk/yaml/inline.py
===================================================================
--- /pyyaml-legacy/trunk/yaml/inline.py	(revision 71)
+++ /pyyaml-legacy/trunk/yaml/inline.py	(revision 71)
@@ -0,0 +1,38 @@
+import re
+import string
+
+class InlineTokenizer:
+    def __init__(self, data):
+        self.data = data
+
+    def punctuation(self):
+        puncts = [ '[', ']', '{', '}' ]
+        for punct in puncts:
+            if self.data[0] == punct:
+                self.data = self.data[1:]
+                return punct
+
+    def up_to_comma(self):
+        match = re.match('(.*?)\s*, (.*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def up_to_end_brace(self):
+        match = re.match('(.*?)(\s*[\]}].*)', self.data)
+        if match: 
+            self.data = match.groups()[1]
+            return match.groups()[0]
+
+    def next(self):
+        self.data = string.strip(self.data)
+        productions = [
+            self.punctuation,
+            self.up_to_comma,
+            self.up_to_end_brace
+        ]
+        for production in productions:
+            token = production()
+            if token:
+                return token
+
Index: /pyyaml-legacy/trunk/patches/stream.py.patch
===================================================================
--- /pyyaml-legacy/trunk/patches/stream.py.patch	(revision 72)
+++ /pyyaml-legacy/trunk/patches/stream.py.patch	(revision 72)
@@ -0,0 +1,53 @@
+--- yaml/stream.py	2002-12-26 09:53:42.000000000 -0800
++++ yaml/stream.py	2003-12-04 13:14:41.000000000 -0800
+@@ -94,12 +94,15 @@
+         return self.commentEater.lastLineRead()
+ 
+     def reset(self):
+         self.indentLevel = 0
+         self.oldIndents = [0]
++        self.empty = 0
+ 
+     def peek(self):
++        if self.empty:
++            return
+         nextLine = self.commentEater.peek()
+         if nextLine is not None:
+             if indentLevel(nextLine) >= self.indentLevel:
+                 return nextLine[self.indentLevel:]
+             elif nextLine == '':
+@@ -107,10 +110,11 @@
+ 
+     def pop(self):
+         line = self.peek()
+         if line is None:
+             self.indentLevel = self.oldIndents.pop()
++            self.empty = 0
+             return
+         self.commentEater.pop()
+         return line
+ 
+     def popNestedLines(self):
+@@ -128,19 +132,20 @@
+ 
+     def nestToNextLine(self):
+         line = self.commentEater.peek()
+         indentation = indentLevel(line)
+         if len(self.oldIndents) > 1 and indentation <= self.indentLevel:
+-            self.error("Inadequate indentation", line)
++            self.empty = 1
++            #self.error("Inadequate indentation", line)
+         self.setNewIndent(indentation)
+ 
+     def nestBySpecificAmount(self, adjust):
+         self.setNewIndent(self.indentLevel + adjust)
+         
+     def setNewIndent(self, indentLevel):
+         self.oldIndents.append(self.indentLevel)
+-        self.indentLevel = indentLevel    
++        self.indentLevel = indentLevel
+ 
+ class YamlLoaderException(Exception):
+     def __init__(self, *args):
+         (self.msg, self.lineNum, self.line, self.filename) = args
+ 
Index: /pyyaml-legacy/trunk/patches/load.py.patch
===================================================================
--- /pyyaml-legacy/trunk/patches/load.py.patch	(revision 72)
+++ /pyyaml-legacy/trunk/patches/load.py.patch	(revision 72)
@@ -0,0 +1,103 @@
+--- yaml/load.py	2002-12-26 08:38:51.000000000 -0800
++++ yaml/load.py	2003-10-02 15:53:06.000000000 -0700
+@@ -45,10 +45,13 @@
+             if ok:
+                 return (1, result)
+ 
+ def dumpDictionary(): return {}
+ 
++_STRIP = 1
++_KEEP = 2
++
+ class Parser:
+     def __init__(self, stream, typeResolver=None):
+         try:
+             self.dictionary = dict
+         except:
+@@ -167,19 +170,16 @@
+         if alias:
+             self.aliases[alias] = value
+         return value          
+ 
+     def parse_unaliased_value(self, value):
+-        match = re.match(r"(!\S*)(.*)", value)
++        match = re.match(r"(!\S*) (.*)", value)
+         if match:
+             (url, value) = match.groups()
+-            value = self.parse_untyped_value(value)
+             if url[:2] == '!!':
+                 return self.typeResolver.resolveType(value, url)
+-            else:
+-                # XXX - allows syntax, but ignores it
+-                return value
++            return self.parse_untyped_value(value)
+         return self.parse_untyped_value(value)
+ 
+     def parseInlineArray(self, value):        
+         if re.match("\s*\[", value):
+             return self.parseInline([], value, ']', 
+@@ -231,36 +231,54 @@
+ 
+     def parseNative(self, value):
+         return (1, convertImplicit(value))
+ 
+     def parseMultiLineScalar(self, value):
++        # XXX does not handle indentation ex. >2, or |2
+         if value == '>':
+             return (1, self.parseFolded())
++        elif value == '>-':
++            return (1, self.parseFolded(_STRIP))
++        elif value == '>+':
++            return (1, self.parseFolded(_KEEP))
+         elif value == '|':
+-            return (1, joinLiteral(self.parseBlock()))
++            return (1, self.parseBlock())
++        elif value == '|-':
++            return (1, self.parseBlock(_STRIP))
+         elif value == '|+':
+-            return (1, joinLiteral(self.unprunedBlock()))
++            return (1, self.parseBlock(_KEEP))
+ 
+-    def parseFolded(self):
+-        data = self.parseBlock()
++    def parseFolded(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
+         i = 0
+         resultString = ''
+         while i < len(data)-1:
+-            resultString = resultString + data[i]
+-            resultString = resultString + foldChar(data[i], data[i+1])
+-            i = i + 1
+-        return resultString + data[-1] + "\n"        
++            resultString += data[i]
++            resultString += foldChar(data[i], data[i+1])
++            i += 1
++        resultString += data[-1]
++        if chomping ==_STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def unprunedBlock(self):
+         self.nestedDocs.nestToNextLine()
+         data = []
+         while self.nestPop():
+             data.append(self.line)
+         return data
+ 
+-    def parseBlock(self):
+-        return pruneTrailingEmpties(self.unprunedBlock())
++    def parseBlock(self, chomping = 0):
++        data = self.unprunedBlock()
++        if chomping != _KEEP:
++            data = pruneTrailingEmpties(data)
++        resultString = string.join(data, "\n")
++        if chomping == _STRIP:
++            return resultString
++        return resultString + "\n"
+ 
+     def testForAlias(self, value):
+         match = re.match("&(\S*)\s*(.*)", value)
+         if match:
+             return match.groups()
Index: /pyyaml-legacy/trunk/scripts/profileYaml.py
===================================================================
--- /pyyaml-legacy/trunk/scripts/profileYaml.py	(revision 96)
+++ /pyyaml-legacy/trunk/scripts/profileYaml.py	(revision 96)
@@ -0,0 +1,23 @@
+import profile
+import pstats
+import yaml
+import glob
+
+def loadAllFiles():
+    testFiles = glob.glob('TestingSuite/*.yml')
+    for file in testFiles:
+        docs = yaml.loadFile(file)
+        for doc in docs:
+            exercise(doc)
+
+def exercise(doc):                
+    if 'python' in doc:
+        if 'yaml' in doc:
+            for subDoc in yaml.load(doc['yaml']):
+                pass
+
+profile.run('loadAllFiles()', 'profileResults')
+
+p = pstats.Stats('profileResults')
+file = open("profile.out", "w")
+p.sort_stats('time').print_stats(25)
Index: /pyyaml-legacy/trunk/scripts/Makefile
===================================================================
--- /pyyaml-legacy/trunk/scripts/Makefile	(revision 87)
+++ /pyyaml-legacy/trunk/scripts/Makefile	(revision 87)
@@ -0,0 +1,23 @@
+test:
+	@for n in YamlTest TestYpath TestClasses TestFileNamesInErrors; do \
+		echo $$n.py; \
+		python2.1 $$n.py; \
+		python2.2 $$n.py; done
+
+clean:
+	rm -f *.pyc
+	rm -f yaml/*.pyc
+	rm -rf build
+	rm -f examples/DEMO*.TXT
+	rm -f tests/profileResults
+	rm -f tests/profile.out
+
+profile:
+	python profileYaml.py > profile.out
+
+install:
+	python setup.py install
+
+build:
+	python setup.py build
+
Index: /pyyaml-legacy/trunk/scripts/README
===================================================================
--- /pyyaml-legacy/trunk/scripts/README	(revision 87)
+++ /pyyaml-legacy/trunk/scripts/README	(revision 87)
@@ -0,0 +1,1 @@
+remove makefile and move functionality into setup.py
Index: /pyyaml-legacy/trunk/scripts/testrunner.py
===================================================================
--- /pyyaml-legacy/trunk/scripts/testrunner.py	(revision 87)
+++ /pyyaml-legacy/trunk/scripts/testrunner.py	(revision 87)
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import sys
+import types
+import unittest
+
+
+def loadModule(name):
+    m = __import__(name)
+    for n in name.split('.')[1:]:
+        m = getattr(m, n)
+    return m
+
+
+def testModule(name):
+    m = loadModule(name)
+    tests = unittest.TestLoader().loadTestsFromModule(m)
+    if tests:
+        print 'Running %s tests' % name
+        unittest.TextTestRunner().run(tests)
+        
+
+def testPackage(name):
+    m = loadModule(name)
+    pkgDir = os.path.dirname(m.__file__)
+    for fname in os.listdir(pkgDir):
+        if not os.path.isfile(os.path.join(pkgDir,fname)):
+            continue
+        n, e = os.path.splitext(fname)
+        if n.startswith('test') and e == '.py':
+            testModule('.'.join([name,n]))
+
+
+def testAnything(name):
+    m = loadModule(name)
+    if isinstance(m, types.ModuleType):
+        if os.path.basename(m.__file__).startswith('__init__.'):
+            testPackage(name)
+        else:
+            testModule(name)
+
+
+if __name__ == '__main__':
+    sys.path[:0] = ['.']
+    testAnything(sys.argv[1])
Index: /pyyaml-legacy/trunk/setup.py
===================================================================
--- /pyyaml-legacy/trunk/setup.py	(revision 98)
+++ /pyyaml-legacy/trunk/setup.py	(revision 98)
@@ -0,0 +1,9 @@
+from distutils.core import setup
+setup (name = "yaml",
+       description = "A Pure Python Yaml Parser Dumper",
+       version = "0.35",
+       packages = ["yaml"],
+       author = "Steve Howell et al",
+       author_email = "info@pyyaml.dnsalias.org",
+       url = "http://pyyaml.dnsalias.org/"
+)
Index: /pyyaml-legacy/trunk/docs/LIMITATIONS
===================================================================
--- /pyyaml-legacy/trunk/docs/LIMITATIONS	(revision 85)
+++ /pyyaml-legacy/trunk/docs/LIMITATIONS	(revision 85)
@@ -0,0 +1,29 @@
+PYTHON VERSION: >
+   PyYaml is now being develioed on version 2.3. If version 2.2 is needed
+   we're happy to look at the nescessities. There won't be unjustified 
+   uses of 2.3 if possible although at some point it's likely. Keep watching
+   for further news
+
+DISCLAIMER: > 
+   PyYaml is not ready to be used as a robust serialization tool,
+   although it is moving in that direction, and you can certainly
+   experiment with it. This sentence may still be true?
+
+   You can use it more safely for one-way applications.  You can
+   make YAML be an input-tool only, such as for configuration files
+   or data-driven programs.  You can also use YAML as an output-only
+   tool, for things like logging and debugging.
+
+   You can report bugs on http://pyyaml.dnsalias.org or through
+   lists.pollenation.dnsalias.org/mailman/listinfo/pyyaml.
+
+SOME KNOWN BUGS/LIMITATIONS:
+  These will be reveiwed (TP JUL 04)
+
+  - folded scalars can't lead with blank line
+  - emitter gives invalid YAML for multi-line scalars starting w/whitespace
+  - trailing white space after quotes not ignored
+  - support for inlined hashes and arrays very primitize--can't nest
+    structures and must use simple scalars
+  - specifiers like !str, !int, etc. are ignored
+
Index: /pyyaml-legacy/trunk/docs/TESTING
===================================================================
--- /pyyaml-legacy/trunk/docs/TESTING	(revision 85)
+++ /pyyaml-legacy/trunk/docs/TESTING	(revision 85)
@@ -0,0 +1,7 @@
+--- >
+As of July 2002, PyYaml shares its YAML-based testing suite with 
+other YAML implementations, starting with YamlForRuby.  Many
+thanks to Why The Lucky Stuff, the author of YamlForRuby, for
+setting this up.
+
+As of July 2004, Testing will be moving to a tests directory. profileYaml.py is currently runs the TestingSuite
Index: /pyyaml-legacy/trunk/docs/LICENSE
===================================================================
--- /pyyaml-legacy/trunk/docs/LICENSE	(revision 85)
+++ /pyyaml-legacy/trunk/docs/LICENSE	(revision 85)
@@ -0,0 +1,71 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+The Python library for YAML was started by Steve Howell in 
+February 2002.  Steve is the primary author of the project,
+but others have contributed.  See the README for more on 
+the project.  The term "PyYaml" refers to the entire 
+distribution of this library, including examples, documentation,
+and test files, as well as the core implementation.
+
+This library is intended for general use, and the license 
+below protects the "open source" nature of the library.  The 
+license does, however, allow for use of the library in 
+commercial applications as well, subject to the terms 
+and conditions listed.  The license below is a minor 
+rewrite of the Python 2.2 license, with no substantive 
+differences.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PyYaml
+===============================================================
+
+LICENSE AGREEMENT FOR PyYaml
+----------------------------
+
+1. This LICENSE AGREEMENT is between Stephen S. Howell ("Author"), 
+and the Individual or Organization ("Licensee") accessing and
+otherwise using PyYaml software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, Author
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use PyYaml
+alone or in any derivative version, provided, however, that Author's
+License Agreement and Author's notice of copyright, i.e., "Copyright (c)
+2001 Steve Howell and Friends; All Rights Reserved" are never removed
+from PyYaml, and are included in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates PyYaml or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to PyYaml.
+
+4. Author is making PyYaml available to Licensee on an "AS IS"
+basis.  Author MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, Author MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PyYaml WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. Author SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.2 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.2,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between Author and
+Licensee.  This License Agreement does not grant permission to use Author
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using PyYaml, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
Index: /pyyaml-legacy/trunk/docs/CHANGELOG
===================================================================
--- /pyyaml-legacy/trunk/docs/CHANGELOG	(revision 85)
+++ /pyyaml-legacy/trunk/docs/CHANGELOG	(revision 85)
@@ -0,0 +1,77 @@
+---
+- version: 0.35
+  date: 2004-07-10
+  changes:
+    - yaml.file()
+    - unit tests for all tests
+---
+- version: 0.32
+  date: 2002-12-26
+  changes:
+    - report filenames in loadFile exceptions
+    - added loadOrdered() method
+---
+- version: 0.31
+  date: 2002-11-17
+  changes:
+    - dumper doesn't quote strings just because they have dashes
+    - dumper does quote strings that look like negative numbers
+    - dumper does quote strings w/*, &, and white space on edges
+    - dumper doesn't quote strings starting with "* "
+    - loader can tolerate "* " unquoted
+    - complain about duplicate keys in dictionary
+    - complain about trailing spaces
+    - l() and d() convenience methods
+    - applied Tim Hochberg's FLOAT/SCIENTIFIC patch
+    - sync __version__ to CHANGELOG
+---
+- version: 0.30
+  date: 2002-11-06
+  changes:
+    - bunch of changes for 2.1 support
+    - fully tested on 2.1.3 and 2.2
+    - added YamlLoaderException
+    - pluggable dictionaries (2.2 only)
+    - simplified iterator interface (deprecated getNextDocument)
+    - single quote &foo properly
+    - quote "foo'bar properly
+---
+- version: 0.29
+  date: 2002-11-03
+  changes:
+    - support |+ syntax
+---
+- version: 0.28
+  date: 2002-09-25
+  changes:
+    - use compiled regexes for speed
+    - streamlined stream.py for speed
+    - added profileYaml.py
+---
+- version: 0.27
+  date: 2002-09-24
+  changes:
+    - better error handling
+    - removed spurious spaces from specs.yml
+    - use a true FileStream class vs. reading in entire file up front
+---
+- version: 0.26
+  date: 2002-09-23
+  changes:
+    - support to_yaml() when you inherit from Python's dict class
+    - move implicit and inline logic into own modules
+    - require space after comma for inline collections (Brian Dorsey)
+    - only call user's resolver for !!private types
+    - don't choke on !str, etc. (but doesn't yet respect them)
+    - fixed bugs in loader/dumper related to integer dict keys (Joel Shprentz)
+---
+- version: 0.25
+  date: 2002-08-21
+  changes:
+    - extensive refactorings on dumper
+    - Dumper class made public
+    - new interface for setIndent and setSort
+    - added Dave Kuhlman's XmlYaml stuff
+    - limiting support to Python 2.2 and above
+
+
Index: /pyyaml-legacy/trunk/README
===================================================================
--- /pyyaml-legacy/trunk/README	(revision 105)
+++ /pyyaml-legacy/trunk/README	(revision 105)
@@ -0,0 +1,121 @@
+- Introductions: >
+   Hello.  Welcome to the Python YAML parser.  This is 
+   a work in progress.   The primary author is Steve Howell,
+   with a few contributions by Clark Evans
+
+- installation: >
+   Simply type setup.py install.  If you do not have distutils
+   installed, you can simply copy the yaml sub-directory into 
+   site-packages.
+
+- testing: >
+   If you want to run all of the tests use the following
+
+   >python2.3 scripts/testrunner.py yaml.tests
+
+   if you haven't installed the module yet you might have to
+
+   >export PYTHONPATH = .
+
+   whilst in the directory above yaml
+
+   This package currently requires python2.3.  We lost Python2.1 support
+   recently, so we should be able to get that back.  Depending on interest
+   we may be able to port back to 1.5, but don't hold your breath.  2.2
+   may work, but at the time of this documentation update, it hadn't been
+   tested.
+
+- playing: >
+   The best way to play, is to start with demo.py and 
+   work from there.  Note that this implementation has quite
+   a way to go before it is compliant with the YAML specification.
+   
+   If something is failing in the tests for your platform
+   please let us know.  If something doesn't work, check the
+   tests to see if the test covering the feature you need is
+   active; if not, chances are it's not implemented.
+
+   Your feedback or any other contributions are certainly welcome.
+
+- ypath: >
+   The YPATH implementation is EXPERIMENTAL but included
+   in the yaml package beacuse it is fun and we'd like to get
+   feedback from the user community as to how they'd like it 
+   to work.  It requries Python >=2.2 since it uses iterators.
+
+- query: >
+   There is a query.py and query.yml file in the experimental directory,
+   it is currently broken as ypath was re-written.
+
+---
+contributors:
+  - who: Steve Howell
+    why?: |
+      Original author of the pure Python implementations of the 
+      YAML parser and emitter.  Many thanks to the other folks 
+      listed here, and some not listed here.  
+    email: showell@zipcon.net
+
+  - who: Brian Ingerson
+    why?: |
+      Brian got me hooked on YAML.  We have used his Perl 
+      implementation to do some really cool stuff, even on projects
+      that primarily used XML.  He also got me started on 
+      the Python project.
+
+  - who: Clark Evans
+    why?: |
+      Clark's YAML fame far precedes the Python implementation--he
+      founded the whole project.  But, he also contributed alias 
+      emitting to this project, and he's also generously allowed
+      me to bundle his very cool YPATH implementation.  Finally,
+      he's helped with module packaging issues and miscellaneous
+      features and bug fixes.
+
+  - who: Why The Lucky Stiff
+    why?: |
+      That's right, Why's the name, Ruby's the game.  Why devotes
+      most of his YAML effort to a Ruby implementation that grows
+      increasingly robust, but he's also a great team player on 
+      the YAML project.  For example, he consolidated the YAML
+      testing suites, so that multiple YAML implementations can 
+      share the same YAML test files.  If you look in this YAML
+      distribution, you will see Ruby all over the place.  Think
+      of it as a free introduction to another great scripting 
+      language.
+
+  - who: Ryan King
+    why?: |
+      Sharpener of saws and pair programmer extraordinaire.
+
+  - who: Neil Watkiss
+    why?: |
+      Donated hardware and major expertise to the project.       
+
+  - who: Oren Ben-Kiki
+    why?: |
+      YAML cofounder.  All library implementors owe a huge gratitude 
+      toward Oren for his work on the YAML spec.
+
+  - who: Lion Kimbro
+    why?: |
+      Early adopter, also known for his three-humped YAML.
+       
+  - who: Dave Kuhlman
+    why?: |
+      Dave's contributions include, but are not limited to, the 
+      XmlYaml code bundled with this distribution.  The README
+      with that code talks more about Dave.
+
+  - who: Tim Parkin
+    why?: |
+      Been using yaml for a while and wanted to use it more and see it adopted
+      more so put a little effort into a home and a spring clean
+
+  - who: Seth de l'Isle
+    why?: |
+      Love YAML. Installing syck is not always convenient and pyyaml is
+      looking very unmaintained;  I was initially motivated by security
+      vulnerabilities announced on the python mailing list.  Now I'm going to
+      focus on spec. compatibility and perhaps integrating syck.
+
Index: /pyyaml-legacy/trunk/TESTING
===================================================================
--- /pyyaml-legacy/trunk/TESTING	(revision 96)
+++ /pyyaml-legacy/trunk/TESTING	(revision 96)
@@ -0,0 +1,5 @@
+tests are located in the tests module under yaml. These can be run using
+
+python2.3 scripts/testrunner.py yaml.tests
+
+or wherever else as long as the yaml module  is in the pythonpath
Index: /pyyaml-legacy/trunk/experimental/XmlYaml/README_yaml2xml
===================================================================
--- /pyyaml-legacy/trunk/experimental/XmlYaml/README_yaml2xml	(revision 71)
+++ /pyyaml-legacy/trunk/experimental/XmlYaml/README_yaml2xml	(revision 71)
@@ -0,0 +1,76 @@
+                   Convert XML to and from YAML
+                   ============================
+
+
+===========
+Description
+===========
+
+This mini-package contains two implementations of conversion
+routines that convert XML to YAML and YAML to XML.  These two
+implementations use different canonical representations for XML in
+YAML as follows:
+
+convertyaml_map.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a
+    dictionary (mapping) containing the following key/value pairs:
+        (1) "name" (required) -- a string.
+        (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+            pairs.
+        (3) "text" (optional) -- a string.
+        (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+convertyaml_seq.py uses the following representation:
+
+    The canonical YAML representation of an XML element is a 4-tuple
+    (a sequence) containing the following:
+        (1) element name
+        (2) attributes -- a mapping
+        (3) text -- a string
+        (4) children -- a sequence of elements
+
+Basically, convertyaml_map.py uses keywords (in a dictionary) to
+represent structures and convertyaml_seq.py uses position (within a
+list).
+
+=====
+Usage
+=====
+
+There is some usage information at the top of each implementation
+file.
+
+
+=======
+Testing
+=======
+
+Here are some simple tests:
+
+    python convertyaml_map.py -x2y people.xml
+    python convertyaml_map.py -x2y people.xml > people.yml
+    python convertyaml_map.py -y2x people.yml
+
+    python convertyaml_seq.py -x2y people.xml
+    python convertyaml_seq.py -x2y people.xml > people.yml
+    python convertyaml_seq.py -y2x people.yml
+
+
+======================
+Additional Information
+======================
+
+The YAML home site is at:
+
+    http://www.yaml.org/
+
+
+
+
+
+Dave Kuhlman
+dkuhlman@rexx.com
+http://www.rexx.com/~dkuhlman
+
+
Index: /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_seq.py
===================================================================
--- /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_seq.py	(revision 71)
+++ /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_seq.py	(revision 71)
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a 4-tuple
+(a sequence) containing the following:
+    (1) element name
+    (2) attributes -- a mapping
+    (3) text -- a string
+    (4) children -- a sequence of elements
+
+For usage information, type:
+    python convertyaml_seq.py
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if (type(obj) == types.ListType or type(obj) == types.TupleType) and \
+            len(obj) == 4:
+            name = obj[0]
+            attributes = obj[1]
+            text = obj[2]
+            children = obj[3]
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = []
+    # Add the element name.
+    objDict.append(obj.nodeName)
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict.append(attrDict)
+    else:
+        objDict.append(None)
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict.append(textStr)
+    else:
+        objDict.append(None)
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict.append(children)
+    else:
+        objDict.append(None)
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_seq.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/trunk/experimental/XmlYaml/people.xml
===================================================================
--- /pyyaml-legacy/trunk/experimental/XmlYaml/people.xml	(revision 71)
+++ /pyyaml-legacy/trunk/experimental/XmlYaml/people.xml	(revision 71)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<people> 
+    <person id="1" value="abcd" ratio="3.2">
+        <name>Alberta</name>
+        <interest>gardening</interest>
+        <interest>reading</interest>
+        <category>5</category>
+    </person> 
+
+    <person id="2">
+        <name>Bernardo</name>
+        <interest>programming</interest>
+        <category></category>
+        <agent>
+            <firstname>Darren</firstname>
+            <lastname>Diddly</lastname>
+        </agent>
+
+    </person>
+
+    <person id="3">
+        <name>Charlie</name>
+        <interest>people</interest>
+        <interest>cats</interest>
+        <interest>dogs</interest>
+        <category>8</category>
+        <promoter>
+            <firstname>David</firstname>
+            <lastname>Donaldson</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+        <promoter>
+            <firstname>Edward</firstname>
+            <lastname>Eddleberry</lastname>
+            <client>
+                <fullname>Arnold Applebee</fullname>
+                <refid>10001</refid>
+            </client>
+        </promoter>
+    </person>
+
+</people>
+
Index: /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_map.py
===================================================================
--- /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_map.py	(revision 71)
+++ /pyyaml-legacy/trunk/experimental/XmlYaml/convertyaml_map.py	(revision 71)
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+"""
+Sample code to convert YAML to XML and XML to YAML using a canonical
+form.
+
+The canonical YAML representation of an XML element is a
+dictionary (mapping) containing the following key/value pairs:
+    (1) "name" (required) -- a string.
+    (2) "attributes" (optional) -- a dictionary (mapping) of name/value
+        pairs.
+    (3) "text" (optional) -- a string.
+    (4) "children" (optional) -- a sequence of dictionaries (mappings).
+
+For usage information, type:
+    python convertyaml_map.py
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+
+
+Requirements:
+    PyXML
+    PyYaml
+
+"""
+
+import sys, string, re, types
+import yaml
+
+from xml.dom import minidom
+from xml.dom import Node
+
+
+#
+# Convert a YAML file to XML and write it to stdout.
+#
+def convertYaml2Xml(inFileName):
+    inobj = yaml.loadFile(inFileName)
+    out = []
+    level = 0
+    convertYaml2XmlAux(inobj, level, out)
+    outStr = "".join(out)
+    sys.stdout.write(outStr)
+
+
+def convertYaml2XmlAux(inobj, level, out):
+    for obj in inobj:
+        if type(obj) == types.DictType and \
+            obj.has_key('name'):
+            name = obj['name']
+            attributes = None
+            if obj.has_key('attributes'):
+                attributes = obj['attributes']
+            text = None
+            if obj.has_key('text'):
+                text = obj['text']
+            children = None
+            if obj.has_key('children'):
+                children = obj['children']
+            addLevel(level, out)
+            out.append('<%s' % name)
+            if attributes:
+                for key in attributes:
+                    out.append(' %s="%s"' % (key, attributes[key]))
+            if not (children or text):
+                out.append('/>\n')
+            else:
+                if children:
+                    out.append('>\n')
+                else:
+                    out.append('>')
+                if text:
+                    out.append(text)
+                if children:
+                    convertYaml2XmlAux(children, level + 1, out)
+                    addLevel(level, out)
+                out.append('</%s>\n' % name)
+
+
+#
+# Convert an XML document (file) to YAML and write it to stdout.
+#
+def convertXml2Yaml(inFileName):
+    doc = minidom.parse(inFileName)
+    root = doc.childNodes[0]
+    # Convert the DOM tree into "YAML-able" data structures.
+    out = convertXml2YamlAux(root)
+    # Ask YAML to dump the data structures to a string.
+    outStr = yaml.dump(out)
+    # Write the string to stdout.
+    sys.stdout.write(outStr)
+
+
+def convertXml2YamlAux(obj):
+    objDict = {}
+    # Add the element name.
+    objDict['name'] = obj.nodeName
+    # Convert the attributes.
+    attrs = obj.attributes
+    if attrs.length > 0:
+        attrDict = {}
+        for idx in range(attrs.length):
+            attr = attrs.item(idx)
+            attrDict[attr.name] = attr.value
+        objDict['attributes'] = attrDict
+    # Convert the text.
+    text = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.TEXT_NODE and \
+            not isAllWhiteSpace(child.nodeValue):
+            text.append(child.nodeValue)
+    if text:
+        textStr = "".join(text)
+        objDict['text'] = textStr
+    # Convert the children.
+    children = []
+    for child in obj.childNodes:
+        if child.nodeType == Node.ELEMENT_NODE:
+            obj = convertXml2YamlAux(child)
+            children.append(obj)
+    if children:
+        objDict['children'] = children
+    return objDict
+
+
+#
+# Utility functions.
+#
+def addLevel(level, out):
+    for idx in range(level):
+        out.append('    ')
+
+
+NonWhiteSpacePattern = re.compile('\S')
+
+def isAllWhiteSpace(text):
+    if NonWhiteSpacePattern.search(text):
+        return 0
+    return 1
+
+
+USAGE_TEXT = """
+Convert a file from YAML to XML or XML to YAML and write it to stdout.
+
+Usage: python convertyaml_map.py <option> <in_file>
+
+Options:
+    -y2x    Convert YAML file to XML document.
+    -x2y    Convert XML document to YAML.
+"""
+
+def usage():
+    print USAGE_TEXT
+    sys.exit(-1)
+
+
+def main():
+    args = sys.argv[1:]
+    if len(args) != 2:
+        usage()
+    option = args[0]
+    inFileName = args[1]
+    if option == '-y2x':
+        convertYaml2Xml(inFileName)
+    elif option == '-x2y':
+        convertXml2Yaml(inFileName)
+    else:
+        usage()
+
+
+if __name__ == '__main__':
+    main()
+    #import pdb
+    #pdb.run('main()')
+
Index: /pyyaml-legacy/trunk/experimental/insert.yml
===================================================================
--- /pyyaml-legacy/trunk/experimental/insert.yml	(revision 96)
+++ /pyyaml-legacy/trunk/experimental/insert.yml	(revision 96)
@@ -0,0 +1,72 @@
+tests:
+    - data:
+        - foo
+        - bar
+      command:
+        value: baz
+      expected:
+        - foo
+        - bar
+        - baz
+    - data:
+        - apple
+        - banana
+      command:
+        value: carrot
+      expected:
+        - apple
+        - banana
+        - carrot
+    -
+      data: 
+        - foo
+      command:
+        value: 
+          name: steve
+          sport: hoops
+      expected:
+        - foo
+        - name: steve
+          sport: hoops
+    -
+      data: 
+        persons:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /persons
+        value: 
+          name: brian
+      expected:
+        persons:
+         - name: steve
+         - name: clark
+         - name: brian
+        tasks:
+          - task: eat
+          - task: sleep
+    -
+      data: 
+        folks:
+         - name: steve
+         - name: clark
+        tasks:
+          - task: eat
+          - task: sleep
+      command:
+        ypath: /folks
+        value: 
+          name: ryan
+      expected:
+        folks: 
+         - name: steve
+         - name: clark
+         - name: ryan
+        tasks:
+          - task: eat
+          - task: sleep
+
+      
Index: /pyyaml-legacy/trunk/experimental/bnfyaml/yamlspec.html
===================================================================
--- /pyyaml-legacy/trunk/experimental/bnfyaml/yamlspec.html	(revision 82)
+++ /pyyaml-legacy/trunk/experimental/bnfyaml/yamlspec.html	(revision 82)
@@ -0,0 +1,7200 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+    <title>
+      YAML Ain't Markup Language (YAML) 1.0
+    </title>
+    <link rel="stylesheet" href="single_html.css" type="text/css" />
+    <meta name="generator" content="DocBook XSL Stylesheets V1.62.3" />
+    <style type="text/css">
+body { background-image: url('http://docbook.sourceforge.net/release/images/draft.png');
+       background-repeat: no-repeat;
+       background-position: top left;
+       /* The following properties make the watermark &quot;fixed&quot; on the page. */
+       /* I think that's just a bit too distracting for the reader... */
+       /* background-attachment: fixed; */
+       /* background-position: center center; */
+     }</style>
+  </head>
+  <body>
+    <div class="book" lang="en" xml:lang="en">
+      <div class="titlepage">
+        <div>
+          <div>
+            <h1 class="title"><a id="id2439396"></a>
+      YAML Ain't Markup Language (<span class="trademark">YAML</span>&#8482;) 1.0
+    </h1>
+          </div>
+          <div>
+            <h2 class="subtitle">
+      Working Draft 2004-JAN-29
+    </h2>
+          </div>
+          <div>
+            <div class="authorgroup">
+              <div class="author">
+                <h3 class="author"><span class="firstname">Oren</span> <span class="surname">Ben-Kiki</span></h3>
+                <tt class="email">&lt;<a href="mailto:oren@ben-kiki.org">oren@ben-kiki.org</a>&gt;</tt>
+              </div>
+              <div class="author">
+                <h3 class="author"><span class="firstname">Clark</span> <span class="surname">Evans</span></h3>
+                <tt class="email">&lt;<a href="mailto:cce@clarkevans.com">cce@clarkevans.com</a>&gt;</tt>
+              </div>
+              <div class="author">
+                <h3 class="author"><span class="firstname">Brian</span> <span class="surname">Ingerson</span></h3>
+                <tt class="email">&lt;<a href="mailto:ingy@ttul.org">ingy@ttul.org</a>&gt;</tt>
+              </div>
+            </div>
+          </div>
+          <div>
+            <p class="releaseinfo">
+      <span class="emphasis"><em>This version:</em></span>
+      <a href="http://www.yaml.org/spec/29jan2004.html" target="_top">http://www.yaml.org/spec/29jan2004.html</a><br />
+      <span class="emphasis"><em>Latest version:</em></span>
+      <a href="http://www.yaml.org/spec" target="_top">http://www.yaml.org/spec</a>
+    </p>
+          </div>
+          <div>
+            <p class="copyright">Copyright © 2001-2004 Oren Ben-Kiki, Clark Evans, Brian Ingerson</p>
+          </div>
+          <div>
+            <div class="legalnotice">
+      This document may be freely copied provided it is not modified.
+    </div>
+          </div>
+          <div>
+            <div class="abstract">
+              <p class="title">
+                <b>Status of this Document</b>
+              </p>
+              <p>
+        This is an intermediate working draft and is being actively 
+        revised.  Hopefully the next draft will be a release canidate.
+      </p>
+              <p>
+        We wish to thank implementers who have tirelessly tracked earlier
+        versions of this specification, and our fabulous user community
+        whose feedback has both validated and clarified our direction.
+      </p>
+            </div>
+          </div>
+          <div>
+            <div class="abstract">
+              <p class="title">
+                <b>Abstract</b>
+              </p>
+              <p>
+        <span class="trademark">YAML</span>&#8482; (rhymes with &#8220;<span class="quote">camel</span>&#8221;) is a
+        human friendly, cross language, unicode based data serialization
+        language designed around the common native structures of agile
+        programming languages. It is broadly useful for programming needs
+        ranging from configuration files to Internet messaging to object
+        persistence to data auditing. Together with the <a href="http://www.unicode.org/" target="_top">Unicode</a> standard for
+        characters, this specification provides all the information
+        necessary to understand YAML Version 1.0 and to construct programs
+        that process YAML information.
+      </p>
+            </div>
+          </div>
+        </div>
+        <div></div>
+        <hr />
+      </div>
+      <div class="toc">
+        <p>
+          <b>Table of Contents</b>
+        </p>
+        <dl>
+          <dt>
+            <span class="chapter">
+              <a href="#id2488852">1. Introduction</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2488873">1.1. Goals</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2488920">1.2. Prior Art</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2489434">1.3. Relation to XML</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2489458">1.4. Terminology</a>
+                </span>
+              </dt>
+            </dl>
+          </dd>
+          <dt>
+            <span class="chapter">
+              <a href="#id2489715">2. Preview</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2489726">2.1. Collections</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2489959">2.2. Structures</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2490752">2.3. Scalars</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2490971">2.4. Tags</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2491218">2.5. Full Length Example</a>
+                </span>
+              </dt>
+            </dl>
+          </dd>
+          <dt>
+            <span class="chapter">
+              <a href="#id2491269">3. Processing YAML Information</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2491480">3.1. Processes</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2491492">3.1.1. Represent</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2491548">3.1.2. Serialize</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2491561">3.1.3. Present</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2491593">3.1.4. Parse</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2488466">3.1.5. Compose</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2488484">3.1.6. Construct</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2488498">3.2. Information Models</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2491684">3.2.1. Node Graph
+        Representation</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2558535">3.2.2. Event / Tree Serialization</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2558635">3.2.3. Character Stream
+        Presentation</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2558898">3.3. Completeness</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559025">3.3.1. Well-Formed</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559057">3.3.2. Resolved</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559189">3.3.3. 
+               Recognized and Valid</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559324">3.3.4. Available</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+            </dl>
+          </dd>
+          <dt>
+            <span class="chapter">
+              <a href="#id2559358">4. Syntax</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2559506">4.1. Characters</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559514">4.1.1. Character Set</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559676">4.1.2. Encoding</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2559720">4.1.3. Indicators</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2560349">4.1.4. Line Breaks</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2560684">4.1.5. Miscellaneous</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2560916">4.2. Space Processing</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2560933">4.2.1. Indentation</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2561162">4.2.2. Throwaway comments</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2561559">4.3. YAML Stream</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2561718">4.3.1. Document</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2562252">4.3.2. Directive</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2562430">4.3.3. Presentation Node</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2562637">4.3.4. Node Property</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2562713">4.3.5. Tag</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2563853">4.3.6. Anchor</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2563922">4.4. Alias</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2564024">4.5. Collection</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2564419">4.5.1. Sequence</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2564813">4.5.2. Mapping</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2565334">4.6. Scalar</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2565848">4.6.1. 
+          
+          End Of line Normalization
+        </a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2565992">4.6.2. Block Modifiers</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2566128">4.6.3. 
+          
+          Explicit Indentation
+        </a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2566343">4.6.4. Chomping</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2566720">4.6.5. Literal</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2566944">4.6.6. Folding</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2567537">4.6.7. Folded</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2567973">4.6.8. Single Quoted</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2568446">4.6.9. Escaping</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2569354">4.6.10. Double Quoted</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="sect2">
+                      <a href="#id2569840">4.6.11. Plain</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+            </dl>
+          </dd>
+          <dt>
+            <span class="appendix">
+              <a href="#id2570645">A. Tag Repository</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2570745">A.1. Sequence</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2570829">A.2. Mapping</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="sect1">
+                  <a href="#id2570910">A.3. String</a>
+                </span>
+              </dt>
+            </dl>
+          </dd>
+          <dt>
+            <span class="appendix">
+              <a href="#id2571072">B. YAML Terms</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="index">
+                  <a href="#id2571080"></a>
+                </span>
+              </dt>
+            </dl>
+          </dd>
+        </dl>
+      </div>
+      <div class="chapter" lang="en" xml:lang="en">
+        <div class="titlepage">
+          <div>
+            <div>
+              <h2 class="title"><a id="id2488852"></a>Chapter 1. <a id="intro"></a>Introduction</h2>
+            </div>
+          </div>
+          <div></div>
+        </div>
+        <p>
+      &quot;YAML Ain't Markup Language&quot; (abbreviated YAML) is a data
+      serialization language designed to be human friendly and work well
+      with modern programming languages for common everyday tasks. This
+      specification is both an introduction to the YAML language and the
+      concepts supporting it; and also a complete reference of the
+      information needed to develop applications for processing YAML.
+    </p>
+        <p>
+      Open, interoperable and readily understandable tools have advanced
+      computing immensely. YAML was designed from the start to be useful and
+      friendly to the people working with data. It uses printable unicode
+      characters, some of which provide structural information and the rest
+      representing the data itself. YAML achieves a unique cleanness by
+      minimizing the amount of structural characters, and allowing the data
+      to show itself in a natural and meaningful way. For example,
+      indentation is used for structure, colons separate pairs, and dashes
+      are used for bulleted lists.
+    </p>
+        <p>
+      There are myriad flavors of data structures, but they can all be
+      adequately represented with three basic primitives: mappings
+      (hashes/dictionaries), sequences (arrays/lists) and scalars
+      (strings/numbers). YAML leverages these primitives and adds a simple
+      typing system and aliasing mechanism to form a complete language for
+      encoding any data structure. While most programming languages
+      can use YAML for data serialization, YAML excels in those languages
+      that are fundamentally built around the three basic primitives. These
+      include the new wave of agile languages such as Perl, Python, PHP,
+      Ruby and Javascript.
+    </p>
+        <p>
+      There are hundreds of different languages for programming, but only a
+      handful of languages for storing and transferring data. Even though its
+      potential is virtually boundless, YAML was specifically created to work
+      well for common use cases such as: configuration files, log files,
+      interprocess messaging, cross-langauge data sharing, object persistence
+      and debugging of complex data structures. When data is well organized
+      and easy to understand, programming becomes a simpler task.
+    </p>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2488873"></a>1.1. <a id="intro-goals"></a>Goals</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        The design goals for YAML are:
+      </p>
+          <div class="orderedlist">
+            <ol type="1">
+              <li>
+          YAML documents are easily readable by humans.
+        </li>
+              <li>
+          YAML uses the native data structures of agile languages.
+        </li>
+              <li>
+          YAML data is portable between programming languages.
+        </li>
+              <li>
+          YAML has a consistent model to support generic tools.
+        </li>
+              <li>
+          YAML enables stream-based processing.
+        </li>
+              <li>
+          YAML is expressive and extensible.
+        </li>
+              <li>
+          YAML is easy to implement and use.
+        </li>
+            </ol>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2488920"></a>1.2. <a id="intro-prior"></a>Prior Art</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        YAML's initial direction was set by the data serialization and markup
+        language discussions among <a href="http://www.docuverse.com/smldev/" target="_top">SML-DEV</a> members.
+        Later on it directly incorporated experience from Brian Ingerson's
+        Perl module <a href="http://search.cpan.org/doc/INGY/Data-Denter-0.13/Denter.pod" target="_top">Data::Denter</a>. Since then YAML has matured through ideas
+        and support from its user community.
+      </p>
+          <p>
+        YAML integrates and builds upon concepts described by
+        <a href="http://cm.bell-labs.com/cm/cs/cbook/index.html" target="_top">C</a>,
+        <a href="http://java.sun.com/" target="_top">Java</a>, <a href="http://www.perl.org/" target="_top">Perl</a>, <a href="http://www.python.org/" target="_top">Python</a>, <a href="http://www.ruby-lang.org/" target="_top">Ruby</a>, <a href="http://www.ietf.org/rfc/rfc0822.txt" target="_top">RFC0822</a> (MAIL),
+        <a href="http://www.ics.uci.edu/pub/ietf/html/rfc1866.txt" target="_top">RFC1866</a>
+        (HTML), <a href="http://www.ietf.org/rfc/rfc2045.txt" target="_top">RFC2045</a> (MIME),
+        <a href="http://www.ietf.org/rfc/rfc2396.txt" target="_top">RFC2396</a> (URI),
+        <a href="http://www.w3.org/TR/REC-xml.html" target="_top">XML</a>,
+        <a href="http://www.saxproject.org/" target="_top">SAX</a> and <a href="http://www.w3.org/TR/SOAP" target="_top">SOAP</a>.
+      </p>
+          <p>
+        The syntax of YAML was motivated by Internet Mail (RFC0822) and
+        remains partially compatible with that standard. Further, YAML
+        borrows the idea of having <a href="#c-l-yaml-stream">multiple
+        documents</a> from MIME (RFC2045). YAML's top-level production
+        is a <a href="#preview-struct">stream</a> of independent
+        documents; ideal for message-based distributed processing
+        systems.
+      </p>
+          <p>
+        YAML's indentation based <a href="#syntax-indentation">block
+            scoping</a> is similar to Python's (without the ambiguities
+        caused by tabs). Indented blocks facilitate easy inspection of a
+        document's structure. YAML's <a href="#syntax-scalar-literal">literal</a> scalar leverages
+        this by enabling formatted text to be cleanly mixed within an indented
+        structure without troublesome escaping.
+      </p>
+          <p>
+        YAML's <a href="#syntax-scalar-double">double quoted</a>
+        scalar uses familar C-style <a href="#syntax-escape">escape sequences</a>. This enables
+        ASCII representation of non-printable or 8-bit (ISO 8859-1)
+        characters such as <a href="#ns-esc-8-bit">&#8220;<span class="quote"><b class="userinput"><tt>\x3B</tt></b></span>&#8221;</a>. 16-bit Unicode
+        and 32-bit (ISO/IEC 10646) characters are supported with escape
+        sequences such as <a href="#ns-esc-16-bit">&#8220;<span class="quote"><b class="userinput"><tt>\u003B</tt></b></span>&#8221;</a> and <a href="#ns-esc-32-bit">&#8220;<span class="quote"><b class="userinput"><tt>\U0000003B</tt></b></span>&#8221;</a>.
+      </p>
+          <p>
+        Motivated by HTML's end-of-line normalization, YAML's <a href="#syntax-scalar-folded">folded</a> scalar employs an
+        intuitive method of handling white space. In YAML, single line breaks
+        may be <a href="#syntax-scalar-folding">folded</a> into a
+        single space, while empty lines represent line break characters.
+        This technique allows for paragraphs to be word-wrapped without
+        affecting the canonical form of the content.
+      </p>
+          <p>
+        YAML's core type system is based on the requirements
+        of Perl, Python and Ruby. YAML directly supports both <a href="#preview-collect">collection</a> (<a href="#type-map">hash</a>, <a href="#type-seq">array</a>) values and <a href="#preview-scalar">scalar</a> (<a href="#type-str">string</a>) values. Support for common types
+        enables programmers to use their language's native data constructs
+        for YAML manipulation, instead of requiring a special document
+        object model (DOM).
+      </p>
+          <p>
+        Like XML's SOAP, YAML supports serializing native graph structures
+        through a rich <a href="#model-alias">alias</a>
+        mechanism. Also like SOAP, YAML provides for <a href="#model-tag">application-defined types</a>. This
+        allows YAML to encode rich data structures required for modern
+        distributed computing. YAML provides unique global <a href="#syntax-tag">type names</a> using a namespace
+        mechanism inspired by Java's DNS based package naming convention and
+        XML's URI based namespaces.
+      </p>
+          <p>
+        YAML was designed to have an incremental interface that includes
+        both a pull-style input stream and a push-style (SAX-like) output
+        stream interfaces. Together this enables YAML to support the
+        processing of large documents, such as a transaction log, or
+        continuous streams, such as a feed from a production machine.
+      </p>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2489434"></a>1.3. <a id="intro-xml"></a>Relation to XML</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        Newcomers to YAML often search for its correlation to the eXtensible
+        Markup Language (XML). While the two languages may actually compete
+        in several application domains, there is no direct correlation
+        between them.
+      </p>
+          <p>
+        YAML is primarily a data serialization language. XML was designed to
+        be backwards compatible with the Standard Generalized Markup
+        Language (SGML) and thus had many design constraints placed on it
+        that YAML does not share. Inheriting SGML's legacy, XML is designed
+        to support structured documents, where YAML is more closely targeted
+        at messaging and native data structures. Where XML is a pioneer in
+        many domains, YAML is the result of lessons learned from XML and
+        other technologies.
+      </p>
+          <p>
+        It should be mentioned that there are ongoing efforts to define
+        standard XML/YAML mappings. This generally requires that a subset of
+        each language be used. For more information on using both XML and
+        YAML, please visit <a href="http://yaml.org/xml/" target="_top">http://yaml.org/xml/</a>.
+      </p>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2489458"></a>1.4. <a id="intro-term"></a>Terminology</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        This specification uses key words in accordance with <a href="http://www.ietf.org/rfc/rfc2119.txt" target="_top">RFC2119</a> to
+        indicate requirement level. In particular, the following words are
+        used to describe the actions of a YAML processor:
+      </p>
+          <div class="variablelist">
+            <dl>
+              <dt>
+                <span class="term">
+                  <a id="id2489482" class="indexterm"></a>
+                  <i class="firstterm">may</i>
+                </span>
+              </dt>
+              <dd>
+            This word, or the adjective
+            &#8220;<span class="quote"><a id="id2489496" class="indexterm"></a><i class="firstterm">optional</i></span>&#8221;, mean that
+            conformant YAML processors are permitted, but need not behave as
+            described.
+          </dd>
+              <dt>
+                <span class="term">
+                  <a id="id2489510" class="indexterm"></a>
+                  <i class="firstterm">should</i>
+                </span>
+              </dt>
+              <dd>
+              This word, or the adjective
+              &#8220;<span class="quote"><a id="id2489524" class="indexterm"></a><i class="firstterm">recommended</i></span>&#8221;, mean that
+              there could be reasons for a YAML processor to deviate from
+              the behavior described, but that such deviation could hurt
+              interoperability and should therefore be advertised with
+              appropriate notice.
+            </dd>
+              <dt>
+                <span class="term">
+                  <a id="id2489539" class="indexterm"></a>
+                  <i class="firstterm">must</i>
+                </span>
+              </dt>
+              <dd>
+              This word, or the term
+              &#8220;<span class="quote"><a id="id2489689" class="indexterm"></a><i class="firstterm">required</i></span>&#8221; or
+              &#8220;<span class="quote"><a id="id2489700" class="indexterm"></a><i class="firstterm">shall</i></span>&#8221;, mean that the
+              behavior described is an absolute requirement of the
+              specification.
+            </dd>
+            </dl>
+          </div>
+        </div>
+      </div>
+      <div class="chapter" lang="en" xml:lang="en">
+        <div class="titlepage">
+          <div>
+            <div>
+              <h2 class="title"><a id="id2489715"></a>Chapter 2. <a id="preview"></a>Preview</h2>
+            </div>
+          </div>
+          <div></div>
+        </div>
+        <p>
+      This section provides a quick glimpse into the expressive power of
+      YAML. It is not expected that the first-time reader grok all of the
+      examples. Rather, these selections are used as motivation for the
+      remainder of the specification.
+    </p>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2489726"></a>2.1. <a id="preview-collect"></a>Collections</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        YAML's block collections use indentation for scope and begin each
+        member on its own line. Block sequences indicate each member with a
+        dash (&#8220;<span class="quote"><b class="userinput"><tt>-</tt></b></span>&#8221;). Block mappings
+        use a colon to mark each (key: value) pair.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2489821"></a><p class="title"><b>Example 2.1. 
+              Sequence of scalars<br />
+              (ball players)
+            </b></p><pre class="programlisting">
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2489842"></a><p class="title"><b>Example 2.2. 
+              Mapping of scalars to scalars<br />
+              (player statistics)
+            </b></p><pre class="programlisting">
+hr:  65
+avg: 0.278
+rbi: 147
+</pre></div>
+        </td>
+            </tr>
+            <tr>
+              <td>
+          <div class="example"><a id="id2489861"></a><p class="title"><b>Example 2.3. 
+              Mapping of scalars to sequences<br />
+              (ball clubs in each league)
+            </b></p><pre class="programlisting">
+american:
+  - Boston Red Sox
+  - Detroit Tigers
+  - New York Yankees
+national:
+  - New York Mets
+  - Chicago Cubs
+  - Atlanta Braves
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2489880"></a><p class="title"><b>Example 2.4. 
+              Sequence of mappings<br />
+              (players' statistics)
+            </b></p><pre class="programlisting">
+-
+  name: Mark McGwire
+  hr:   65
+  avg:  0.278
+-
+  name: Sammy Sosa
+  hr:   63
+  avg:  0.288
+</pre></div>
+        </td>
+            </tr>
+          </table>
+          <p>
+        YAML also has in-line flow styles for compact notation. The flow
+        sequence is written as a comma separated list within square
+        brackets. In a similar manner, the flow mapping uses curley braces.
+        In YAML, the space after the &#8220;<span class="quote"><b class="userinput"><tt>-</tt></b></span>&#8221;
+        and  &#8220;<span class="quote"><b class="userinput"><tt>:</tt></b></span>&#8221; and
+        &#8220;<span class="quote"><b class="userinput"><tt>:</tt></b></span>&#8221; is mandatory.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2489929"></a><p class="title"><b>Example 2.5. Sequence of sequences</b></p><pre class="programlisting">
+- [name        , hr, avg  ]
+- [Mark McGwire, 65, 0.278]
+- [Sammy Sosa  , 63, 0.288]
+
+
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2489944"></a><p class="title"><b>Example 2.6. Mapping of mappings</b></p><pre class="programlisting">
+Mark McGwire: {hr: 65, avg: 0.278}
+Sammy Sosa: {
+    hr: 63,
+    avg: 0.288
+  }
+</pre></div>
+        </td>
+            </tr>
+          </table>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2489959"></a>2.2. <a id="preview-struct"></a>Structures</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        YAML uses three
+        dashes (&#8220;<span class="quote"><b class="userinput"><tt>---</tt></b></span>&#8221;) to separate
+        documents within a stream. Comment lines begin with the pound
+        sign (&#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221;). Three
+        dots (&#8220;<span class="quote"><b class="userinput"><tt>...</tt></b></span>&#8221;) indicate the
+        end of a document without starting a new one, for use in
+        communication channels.
+      </p>
+          <p>
+        Repeated nodes are first marked with the
+        ampersand (&#8220;<span class="quote"><b class="userinput"><tt>&amp;</tt></b></span>&#8221;) and
+        then referenced with an
+        asterisk (&#8220;<span class="quote"><b class="userinput"><tt>*</tt></b></span>&#8221;) thereafter.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2490016"></a><p class="title"><b>Example 2.7. 
+              Two documents in a stream<br />
+              each with a leading comment
+            </b></p><pre class="programlisting">
+# Ranking of 1998 home runs
+---
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+
+# Team ranking
+---
+- Chicago Cubs
+- St Louis Cardinals
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490581"></a><p class="title"><b>Example 2.8. 
+              Play by play feed<br />
+              from a game
+            </b></p><pre class="programlisting">
+---
+time: 20:03:20
+player: Sammy Sosa
+action: strike (miss)
+...
+---
+time: 20:03:47
+player: Sammy Sosa
+action: grand slam
+...
+</pre></div>
+        </td>
+            </tr>
+            <tr>
+              <td>
+          <div class="example"><a id="id2490600"></a><p class="title"><b>Example 2.9. 
+              Single document with two comments<br />
+               
+            </b></p><pre class="programlisting">
+---
+hr: # 1998 hr ranking
+  - Mark McGwire
+  - Sammy Sosa
+rbi:
+  # 1998 rbi ranking
+  - Sammy Sosa
+  - Ken Griffey
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490619"></a><p class="title"><b>Example 2.10. 
+              Node for &#8220;<span class="quote"><b class="userinput"><tt>Sammy Sosa</tt></b></span>&#8221;<br />
+              appears twice in this document
+            </b></p><pre class="programlisting">
+---
+hr:
+  - Mark McGwire
+  # Following node labeled SS
+  - &amp;SS Sammy Sosa
+rbi:
+  - *SS # Subsequent occurance
+  - Ken Griffey
+</pre></div>
+        </td>
+            </tr>
+          </table>
+          <p>
+        The question mark indicates a complex key. Within a block sequence,
+        mapping pairs can start immediately following the dash.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2490722"></a><p class="title"><b>Example 2.11. Mapping between sequences</b></p><pre class="programlisting">
+? # PLAY SCHEDULE
+  - Detroit Tigers
+  - Chicago Cubs
+:
+  - 2001-07-23
+
+? [ New York Yankees,
+    Atlanta Braves ]
+: [ 2001-07-02, 2001-08-12,
+    2001-08-14 ]
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490737"></a><p class="title"><b>Example 2.12. Sequence key shortcut</b></p><pre class="programlisting">
+---
+# products purchased
+- item    : Super Hoop
+  quantity: 1
+- item    : Basketball
+  quantity: 4
+- item    : Big Shoes
+  quantity: 1
+
+
+</pre></div>
+        </td>
+            </tr>
+          </table>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2490752"></a>2.3. <a id="preview-scalar"></a>Scalars</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        Scalar values can be written in block form using a literal
+        style (&#8220;<span class="quote"><b class="userinput"><tt>|</tt></b></span>&#8221;) where all new
+        lines count. Or they can be written with the folded
+        style (&#8220;<span class="quote"><b class="userinput"><tt>&gt;</tt></b></span>&#8221;) for content
+        that can be word wrapped. In the folded style, newlines are treated as
+        a space unless they are part of a blank or indented line.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2490853"></a><p class="title"><b>Example 2.13. 
+              In literals,<br />
+              newlines are preserved
+            </b></p><pre class="programlisting">
+# ASCII Art
+--- |
+  \//||\/||
+  // ||  ||__
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490872"></a><p class="title"><b>Example 2.14. 
+              In the plain scalar,<br />
+              newlines are treated as a space
+            </b></p><pre class="programlisting">
+---
+  Mark McGwire's
+  year was crippled
+  by a knee injury.
+</pre></div>
+        </td>
+            </tr>
+            <tr>
+              <td>
+          <div class="example"><a id="id2490892"></a><p class="title"><b>Example 2.15. 
+              Folded newlines preserved<br />
+              for indented and blank lines
+            </b></p><pre class="programlisting">
+--- &gt;
+ Sammy Sosa completed another
+ fine season with great stats.
+
+   63 Home Runs
+   0.288 Batting Average
+
+ What a year!
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490912"></a><p class="title"><b>Example 2.16. 
+              Indentation determines scope<br />
+               
+            </b></p><pre class="programlisting">
+name: Mark McGwire
+accomplishment: &gt;
+  Mark set a major league
+  home run record in 1998.
+stats: |
+  65 Home Runs
+  0.278 Batting Average
+
+</pre></div>
+        </td>
+            </tr>
+          </table>
+          <p>
+        YAML's flow scalars include the plain style (most examples thus far)
+        and quoted styles. The double quoted style provides escape sequences.
+        Single quoted style is useful when escaping is not needed. All flow
+        scalars can span multiple lines; intermediate whitespace is trimmed to
+        a single space.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2490941"></a><p class="title"><b>Example 2.17. Quoted scalars</b></p><pre class="programlisting">
+unicode: &quot;Sosa did fine.\u263A&quot;
+control: &quot;\b1998\t1999\t2000\n&quot;
+hexesc:  &quot;\x13\x10 is \r\n&quot;
+
+single: '&quot;Howdy!&quot; he cried.'
+quoted: ' # not a ''comment''.'
+tie-fighter: '|\-*-/|'
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2490956"></a><p class="title"><b>Example 2.18. Multiline flow scalars</b></p><pre class="programlisting">
+plain:
+  This unquoted scalar
+  spans many lines.
+
+quoted: &quot;So does this
+  quoted scalar.\n&quot;
+
+</pre></div>
+        </td>
+            </tr>
+          </table>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2490971"></a>2.4. <a id="preview-tag"></a>Tags</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        In YAML, plain (unquoted) scalars are given an implicit type
+        depending on the application. The examples in this specification use
+        types from YAML's <a href="#tag-repository">tag
+        repository</a>, which includes types like integers, floating point
+        values, timestamps, null, boolean, and string values.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2490997"></a><p class="title"><b>Example 2.19. Integers</b></p><pre class="programlisting">
+canonical: 12345
+decimal: +12,345
+sexagecimal: 3:25:45
+octal: 014
+hexadecimal: 0xC
+
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2491012"></a><p class="title"><b>Example 2.20. Floating point</b></p><pre class="programlisting">
+canonical: 1.23015e+3
+exponential: 12.3015e+02
+sexagecimal: 20:30.15
+fixed: 1,230.15
+negative infinity: (-inf)
+not a number: (NaN)
+</pre></div>
+        </td>
+            </tr>
+            <tr>
+              <td>
+          <div class="example"><a id="id2491027"></a><p class="title"><b>Example 2.21. Miscellaneous</b></p><pre class="programlisting">
+null: ~
+true: y
+false: n
+string: '12345'
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2491043"></a><p class="title"><b>Example 2.22. Timestamps</b></p><pre class="programlisting">
+canonical: 2001-12-15T02:59:43.1Z
+iso8601:  2001-12-14t21:59:43.10-05:00
+spaced:  2001-12-14 21:59:43.10 -05:00
+date:   2002-12-14
+</pre></div>
+        </td>
+            </tr>
+          </table>
+          <p>
+        Explicit typing is denoted with a tag using the
+        bang (&#8220;<span class="quote"><b class="userinput"><tt>!</tt></b></span>&#8221;) symbol. Application
+        tags should include a domain name and may use the
+        caret (&#8220;<span class="quote"><b class="userinput"><tt>^</tt></b></span>&#8221;) to abbreviate
+        subsequent tags. 
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2491082"></a><p class="title"><b>Example 2.23. Various explicit tags</b></p><pre class="programlisting">
+---
+not-date: !str 2002-04-28
+
+picture: !binary |
+ R0lGODlhDAAMAIQAAP//9/X
+ 17unp5WZmZgAAAOfn515eXv
+ Pz7Y6OjuDg4J+fn5OTk6enp
+ 56enmleECcgggoBADs=
+
+application specific tag: !!something |
+ The semantics of the tag
+ above may be different for
+ different documents.
+
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2491097"></a><p class="title"><b>Example 2.24. Application specific tag</b></p><pre class="programlisting">
+# Establish a tag prefix
+--- !clarkevans.com,2002/graph/^shape
+  # Use the prefix: shorthand for
+  # !clarkevans.com,2002/graph/circle
+- !^circle
+  center: &amp;ORIGIN {x: 73, y: 129}
+  radius: 7
+- !^line
+  start: *ORIGIN
+  finish: { x: 89, y: 102 }
+- !^label
+  start: *ORIGIN
+  color: 0xFFEEBB
+  value: Pretty vector drawing.
+</pre></div>
+        </td>
+            </tr>
+          </table>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2491188"></a><p class="title"><b>Example 2.25. Unorderd set</b></p><pre class="programlisting">
+# sets are represented as a
+# mapping where each key is
+# associated with the empty string
+--- !set
+? Mark McGwire
+? Sammy Sosa
+? Ken Griff
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2491203"></a><p class="title"><b>Example 2.26. Ordered mappings</b></p><pre class="programlisting">
+# ordered maps are represented as
+# a sequence of mappings, with
+# each mapping having one key
+--- !omap
+- Mark McGwire: 65
+- Sammy Sosa: 63
+- Ken Griffy: 58
+</pre></div>
+        </td>
+            </tr>
+          </table>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2491218"></a>2.5. <a id="preview-full"></a>Full Length Example</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        Below are two full-length examples of YAML. On the left is a sample
+        invoice; on the right is a sample log file.
+      </p>
+          <table class="simplelist" border="0" summary="Simple list">
+            <tr>
+              <td>
+          <div class="example"><a id="id2491238"></a><p class="title"><b>Example 2.27. Invoice</b></p><pre class="programlisting">
+--- !clarkevans.com,2002/^invoice
+invoice: 34843
+date   : 2001-01-23
+bill-to: &amp;id001
+    given  : Chris
+    family : Dumars
+    address:
+        lines: |
+            458 Walkman Dr.
+            Suite #292
+        city    : Royal Oak
+        state   : MI
+        postal  : 48046
+ship-to: *id001
+product:
+    - sku         : BL394D
+      quantity    : 4
+      description : Basketball
+      price       : 450.00
+    - sku         : BL4438H
+      quantity    : 1
+      description : Super Hoop
+      price       : 2392.00
+tax  : 251.42
+total: 4443.52
+comments:
+    Late afternoon is best.
+    Backup contact is Nancy
+    Billsmer @ 338-4338.
+</pre></div>
+        </td>
+              <td>
+          <div class="example"><a id="id2491253"></a><p class="title"><b>Example 2.28. Log file</b></p><pre class="programlisting">
+---
+Time: 2001-11-23 15:01:42 -05:00
+User: ed
+Warning:
+  This is an error message
+  for the log file
+---
+Time: 2001-11-23 15:02:31 -05:00
+User: ed
+Warning:
+  A slightly different error
+  message.
+---
+Date: 2001-11-23 15:03:17 -05:00
+User: ed
+Fatal:
+  Unknown variable &quot;bar&quot;
+Stack:
+  - file: TopClass.py
+    line: 23
+    code: |
+      x = MoreObject(&quot;345\n&quot;)
+  - file: MoreClass.py
+    line: 58
+    code: |-
+      foo = bar
+
+
+
+</pre></div>
+        </td>
+            </tr>
+          </table>
+        </div>
+      </div>
+      <div class="chapter" lang="en" xml:lang="en">
+        <div class="titlepage">
+          <div>
+            <div>
+              <h2 class="title"><a id="id2491269"></a>Chapter 3. <a id="model"></a>Processing YAML Information</h2>
+            </div>
+          </div>
+          <div></div>
+        </div>
+        <p>
+      YAML is both a text format and a method for representing native
+      language data structures in this format. This specification defines
+      two concepts: a class of data objects called YAML representations, and
+      a syntax for encoding YAML representations as a series of
+      characters, called a YAML stream. A YAML
+      <a id="id2491280" class="indexterm"></a><i class="firstterm">processor</i> is a tool for converting information
+      between these complementary views. It is assumed that a YAML processor
+      does its work on behalf of another module, called an
+      <a id="id2491289" class="indexterm"></a><i class="firstterm">application</i>. This chapter describes the
+      information structures a processor must provide to or obtain from the
+      application.
+    </p>
+        <p>
+      YAML information is used in two ways: for machine processing, and
+      for human consumption. The challange of reconciling these two
+      perspectives is best done in three distinct translation stages:
+      representation, serialization, and presentation. Representation
+      addresses how YAML views native language data structures to achieve
+      portability between programming environments. Serialization
+      concerns itself with turning a YAML representation into a serial
+      form, that is, a form with sequential access constraints.
+      Presentation deals with the formatting of a YAML serialization as a
+      stream of characters, in a manner friendly to humans.
+    </p>
+        <div class="figure">
+          <a id="id2491303"></a>
+          <p class="title">
+            <b>Figure 3.1. YAML Overview</b>
+          </p>
+          <div class="mediaobject">
+            <img src="overview.png" alt="YAML Overview" />
+          </div>
+        </div>
+        <p>
+      A processor need not expose the serialization or representation
+      stages. It may translate directly between native objects and
+      a character stream and (&#8220;<span class="quote">dump</span>&#8221; and &#8220;<span class="quote">load</span>&#8221;
+      in the diagram above). However, such a direct translation should
+      take place so that the native objects are constructed only from
+      information available in the representation.
+    </p>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2491480"></a>3.1. <a id="model-processes"></a>Processes</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        This section details the processes shown in the 
+        diagram above.
+      </p>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2491492"></a>3.1.1. <a id="model-processes-represent"></a>Represent</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          YAML representations model the data constructs from agile
+          programming languages, such as Perl, Python, or Ruby. YAML
+          representations view native language data objects in a generic
+          manner, allowing data to be portable between various programming
+          languages and implementations. Strings, arrays, hashes, and other
+          user-defined types are supported. This specification formalizes
+          what it means to be a YAML representatation and suggests how
+          native language objects can be viewed as a YAML representation.
+        </p>
+            <p>
+          YAML representations are constructed with three primitives: the
+          <a href="#model-sequence">sequence</a>, the <a href="#model-mapping">mapping</a> and the <a href="#model-scalar">scalar</a>. By sequence we mean
+          an ordered collection, by mapping we mean an unordered association
+          of unique keys to values, and by scalar we mean any object with
+          opaque structure yet expressable as a series of unicode
+          characters. When used generatively, these primitives construct
+          directed graph structures. These primitives were chosen beacuse
+          they are both powerful and familiar: the sequence corresponds to a
+          Perl array and a Python list, the mapping corresponds to a Perl
+          hashtable and a Python dictionary. The scalar represents strings,
+          integers, dates and other atomic data types.
+        </p>
+            <p>
+          YAML represents any native language data object as one of these
+          three primitives, together with a type specifier called a
+          <a id="id2491525" class="indexterm"></a><i class="firstterm">tag</i>. Type specifiers are either global,
+          using a syntax based on the domain name and registration date, or
+          private in scope. For example, an integer is represented in YAML
+          with a scalar plus a globally scoped
+          <b class="userinput"><tt>tag:yaml.org,2002/int</tt></b> tag. Similarly, an
+          invoice object, particular to a given organization, could be
+          represented as a mapping together with a
+          <b class="userinput"><tt>tag:private.yaml.org,2002:invoice</tt></b> tag. This
+          simple model, based on the sequence and mapping and scalar
+          together with a type specifier, can represent any data structure
+          independent of programming language.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2491548"></a>3.1.2. <a id="model-processes-serialize"></a>Serialize</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          For sequential access mediums, such as an
+          event callback API, a YAML representation must be serialized to an
+          ordered tree. Serialization is necessary since nodes in a YAML
+          representation may be referenced more than once (more than one
+          incoming arrow) and since mapping keys are unordered. Serialization
+          is accomplished by imposing an ordering on mapping keys and by
+          replacing the second and subsequent references to a given node with
+          place holders called aliases. The result of this process, the YAML
+          serialization tree, can then be traversed to produce a series of
+          event calls for one-pass processing of YAML data.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2491561"></a>3.1.3. <a id="model-processes-present"></a>Present</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          YAML <a id="id2491572" class="indexterm"></a><i class="firstterm">character streams</i> (or documents)
+          encode YAML representations into a series of characters. Some of
+          the characters in a YAML stream represent the content of the
+          source information, while other characters are used for
+          presentation style. Not only must YAML character streams store
+          YAML representations, they must do so in a manner which is human
+          friendly.
+        </p>
+            <p>
+          To address human presentation, the YAML syntax has a rich set of
+          stylistic options which go far beyond the needs of data
+          serialization. YAML has two approaches for expressing a node's
+          nesting, one that uses indentation to designate depth in the
+          serialization tree and another which uses begin and end
+          delimiters. Depending upon escaping and how line breaks should be
+          treated, YAML scalars may be written with many different styles.
+          YAML syntax also has a comment mechanism for annotations othogonal
+          to the &#8220;<span class="quote">content</span>&#8221; of a YAML representation. These
+          presentation level details provide sufficient variety of
+          expression.
+        </p>
+            <p>
+          In a similar manner, for human readable text, it is frequently
+          desirable to omit data typing information which is often obvious
+          to the human reader and not needed. This is especially true if the
+          information is created by hand, expecting humans to bother with
+          data typing detail is optimistic. Implicit type information may be
+          restored using a data schema or similar mechanisms.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2491593"></a>3.1.4. <a id="model-processes-parse"></a>Parse</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Parsing is the inverse process of presentation, it takes
+          a stream of characters and produces a series of events.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2488466"></a>3.1.5. <a id="model-processes-compose"></a>Compose</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Composing takes a series of events and produces a node graph
+          representation.  See <a href="#model-complete">completeness</a> for more detail
+          on the constraints composition must follow.  When composing,
+          one must deal with broken aliases and anchors, and other
+          things of this sort.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2488484"></a>3.1.6. <a id="model-processes-construct"></a>Construct</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Construction converts construct YAML representations into native
+          language objects.
+        </p>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2488498"></a>3.2. <a id="model-models"></a>Information Models</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        This section has the formal details of the results of
+        the processes.
+      </p>
+          <div class="figure">
+            <a id="id2488509"></a>
+            <p class="title">
+              <b>Figure 3.2. YAML Information Models</b>
+            </p>
+            <div class="mediaobject">
+              <img src="model.png" alt="YAML Information Models" />
+            </div>
+          </div>
+          <p>
+        To maximize data portability between programming languages and
+        implementations, users of YAML should be mindful of the distinction
+        between serialization or presentation properties and those which are
+        part of the YAML representation. While imposing a order on mapping
+        keys is necessary for flattening YAML representations to a
+        sequential access medium, the specific ordering of a mapping should
+        not be used to convey application level information. In a similar
+        manner, while indentation technique or the specific scalar style is
+        needed for character level human presentation, this syntax detail is
+        not part of a YAML serialization nor a YAML representation. By
+        carefully separating properties needed for serialization and
+        presentation, YAML representations of native language information
+        will be consistent and portable between various programming
+        environments.
+      </p>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2491684"></a>3.2.1. <a id="model-representation"></a>Node Graph
+        Representation</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          In YAML's view, native data is represented as a directed
+          graph of <a href="#model-tag">tagged</a> <a href="#model-node">nodes</a>. Nodes that are defined in
+          terms of other nodes are <a href="#model-collection">collections</a> and nodes that are
+          defined independent of any other nodes are <a href="#model-scalar">scalars</a>. YAML supports two
+          kinds of collection nodes, <a href="#model-sequence">sequence</a> and <a href="#model-mapping">mappings</a>. Mapping nodes
+          are somewhat tricky beacuse its keys are considered to be unordered
+          and <a href="#model-equality">unique</a>.
+        </p>
+            <div class="figure">
+              <a id="id2491804"></a>
+              <p class="title">
+                <b>Figure 3.3. YAML Representation</b>
+              </p>
+              <div class="mediaobject">
+                <img src="represent.png" alt="YAML Representation" />
+              </div>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2491835"></a>3.2.1.1. <a id="model-node"></a>Nodes</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            A YAML representation is a rooted, connected, directed graph. By
+            &#8220;<span class="quote">directed graph</span>&#8221; we mean a set of nodes and arrows,
+            where arrows connect one node to another (<a href="http://www.nist.gov/dads/HTML/directedgraph.html" target="_top"> a formal
+            definition </a>). Note that the YAML graph may include cycles,
+            and a node may have more than one incoming arrow.
+         </p>
+              <p>
+            YAML nodes have a <a href="#model-tag">tag</a> and
+            can be of one of three kinds: scalar, sequence, or mapping. The
+            node's tag serves to restrict the set of possible values
+            which the node can have.
+          </p>
+              <div class="variablelist">
+                <dl>
+                  <dt>
+                    <span class="term">
+                <a id="model-scalar"></a>
+                <a id="id2492218" class="indexterm"></a><i class="firstterm">scalar</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                  A scalar is a series of zero or more Unicode characters.
+                  YAML places no restriction on the length or content of the
+                  series.
+                </p>
+                  </dd>
+                  <dt>
+                    <span class="term">
+                <a id="model-sequence"></a>
+                <a id="id2492243" class="indexterm"></a><i class="firstterm">sequence</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                  A sequence is a series of zero or more nodes. In
+                  particular, a sequence may contain the same node more than
+                  once or it could even contain itself (directly or indirectly).
+                </p>
+                  </dd>
+                  <dt>
+                    <span class="term">
+                <a id="model-mapping"></a>
+                <a id="id2492269" class="indexterm"></a><i class="firstterm">mapping</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                  A mapping is an unordered set of key/value node pairs, with
+                  the restriction that each of the keys is unique. This
+                  restriction has non-trivial implications detailed
+                  <a href="#model-equality">below</a>.
+                  YAML places no further restrictions on the nodes. In
+                  particular, keys may be arbitrary nodes, the same node may
+                  be used as a value in several pairs, and a mapping could
+                  even contain itself as a key or a value (directly or
+                  indirectly).
+                </p>
+                  </dd>
+                </dl>
+              </div>
+              <p>
+            <a id="model-collection"></a>When appropriate, it is convient
+            to consider sequences and mappings together, as a
+            <a id="id2492369" class="indexterm"></a><i class="firstterm">collection</i>. In this view, sequences are
+            treated as mappings with integer keys starting at zero. Having a
+            unified collections view for sequences and mappings is helpful for
+            both constructing practical YAML tools and APIs and for
+            theoretical analysis.
+          </p>
+              <p>
+            YAML allows several representations to be encoded
+            to the same character stream. Representations appearing in the
+            same character stream are independent. That is, a given node may
+            not appear in more than one representation graph.
+          </p>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2492384"></a>3.2.1.2. <a id="model-tag"></a>Tags</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            YAML represents type information of native objects with a simple
+            identifier, called a <a id="id2492394" class="indexterm"></a><i class="firstterm">tag</i>. These identifiers
+            are <a href="http://www.ietf.org/rfc/rfc2396.txt" target="_top">URIs</a>,
+            using a subset of the &#8220;<span class="quote"><b class="userinput"><tt>tag</tt></b></span>&#8221;
+            URI scheme. YAML tags use only the domain based form,
+            <b class="userinput"><tt>tag:</tt></b><tt class="varname">domain</tt><b class="userinput"><tt>,</tt></b><tt class="varname">date</tt><b class="userinput"><tt>:</tt></b><tt class="varname">identifier</tt>,
+            for example, <b class="userinput"><tt>tag:yaml.org,2002:str</tt></b>. YAML
+            presentations provide several <a href="#syntax-tag">mechanisms</a> to make this less
+            verbose. Tags may be minted by those who own the domain at the
+            specified date. The day must be omitted if it is the 1st of the
+            month, and the month and day must be omitted for January 1st.
+            The year is never omitted. Thus, each YAML tag has a single
+            globally unique representation. More information on this URI
+            scheme can be found at <a href="http://www.taguri.org" target="_top">http://www.taguri.org</a>
+            (<a href="http://yaml.org/spec/taguri.txt" target="_top">mirror</a>).
+          </p>
+              <p>
+            <a id="model-private"></a>YAML tags can be either globally
+            unique, or private to a single representation graph. Private tags
+            start with <b class="userinput"><tt>tag:private.yaml.org,2002:</tt></b>.
+            Clearly private tags are not globally unique, since the domain
+            name and the date are fixed.
+          </p>
+              <p>
+            YAML does not mandate any special relationship between different
+            tags that begin with the same substring.  Tags ending URI fragments
+            (containing &#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221;) are no
+            exception. Tags that share the same base URI but differ in their
+            fragment part are considered to be different, independent tags. By
+            convention, fragments are used to identify different
+            &#8220;<span class="quote">versions</span>&#8221; of a tag, while
+            &#8220;<span class="quote"><b class="userinput"><tt>/</tt></b></span>&#8221; is used to define nested
+            tag &#8220;<span class="quote">namespace</span>&#8221; hierarchies. However, this is merely
+            a convention, and each tag may employ its own rules.
+            For example,
+            <b class="userinput"><tt>tag:perl.yaml.org,2002:</tt></b> tags
+            use &#8220;<span class="quote"><b class="userinput"><tt>::</tt></b></span>&#8221; to express namespace
+            hierarchies,
+            <b class="userinput"><tt>tag:java.yaml.org,2002:</tt></b> tags
+            use &#8220;<span class="quote"><b class="userinput"><tt>.</tt></b></span>&#8221;, etc.
+          </p>
+              <p>
+            YAML tags are used to associate meta information with each node.
+            In particular, each tag is required to specify a the <a href="#model-node">kind</a> (scalar, sequence, or mapping)
+            it applies to. Scalar tags must also provide mechanism for
+            converting values to a <a href="#model-canonical">canonical
+            form</a> for supporting <a href="#model-equality">equality testing</a>. Furthermore, a
+            tag may provide additional information such as the set of
+            allowed values for validation, a mechanism for <a href="#model-resolve">implicit typing</a>, or any other
+            data that is applicable to all of the tag's nodes.
+          </p>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558016"></a>3.2.1.3. <a id="model-equality"></a>Equality</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            Since YAML mappings require key uniqueness, representations must
+            include a mechanism for testing the equality of nodes. This is
+            non-trivial since YAML <a href="#model-presentation">presentations</a> allow various
+            ways to write a given <a href="#model-scalar">scalar</a>.
+            For example, the integer ten can be written as
+            <b class="userinput"><tt>10</tt></b> or <b class="userinput"><tt>0xA</tt></b> (hex). If
+            both forms are used as a key in the same mapping, only a YAML
+            processor which &#8220;<span class="quote">knows</span>&#8221; about integer tags and their
+            presentation formats would correctly flag the duplicate key
+            as an error.
+          </p>
+              <div class="variablelist">
+                <dl>
+                  <dt>
+                    <span class="term">
+                <a id="model-canonical"></a>
+                <a id="id2558132" class="indexterm"></a><i class="firstterm">canonical form</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                  YAML supports the need for scalar equality by requiring that
+                  every scalar <a href="#model-tag">tag</a> have a
+                  mechanism to produce a canonical form
+                  of its scalars. By canonical form, we mean a Unicode
+                  character string which represents the scalar's content and
+                  can be used for equality testing. While this requirement is
+                  stronger than a well defined equality operator, it has other
+                  uses, such as the production of digital signatures.
+                </p>
+                  </dd>
+                  <dt>
+                    <span class="term">
+                <a id="model-equal"></a>
+                <a id="id2558369" class="indexterm"></a><i class="firstterm">equality</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                   Two nodes must have the same <a href="#model-tag">tag</a> and value to be equal. Since
+                   each tag applies to exactly one kind, this implies that the
+                   two nodes must have the same kind to be equal. Two <a href="#model-scalar">scalar</a> nodes are equal only
+                   when their <a href="#model-canonical">canonical</a>
+                   values are character-by-character equivalent. Equality of
+                   <a href="#model-collection">collections</a> is
+                   defined recursively. Two <a href="#model-sequence">sequences</a> are equal only
+                   when they have the same length and each node in one
+                   sequence is equal to the corresponding node in the other
+                   sequence. Two <a href="#model-mapping">mappings</a>
+                   are equal only when they have equal sets of keys, and each
+                   key in this set is associated with equal values in both
+                   mappings.
+                </p>
+                  </dd>
+                  <dt>
+                    <span class="term">
+                <a id="model-identity"></a>
+                <a id="id2558499" class="indexterm"></a><i class="firstterm">identity</i>
+              </span>
+                  </dt>
+                  <dd>
+                    <p>
+                  Node equality should not be confused with node
+                  <a id="id2558514" class="indexterm"></a><i class="firstterm">identity</i>. Two nodes are identical
+                  only when they represent the same native object. Typically,
+                  this corresponds to a single memory address. During
+                  <a href="" target="_top">serialization</a>, equal
+                  scalar nodes may be treated as if they were identical. In
+                  contrast, the seperate identity of two distinct, but equal,
+                  collection nodes must be preserved.
+                </p>
+                  </dd>
+                </dl>
+              </div>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2558535"></a>3.2.2. <a id="model-serialize"></a>Event / Tree Serialization</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          To express a YAML representation using a serial API, it necessary to
+          impose an order on mapping keys and employ alias nodes to indicate a
+          subsequent occurence of a previously encountered node. The result of
+          this serialization process is a tree structure, where each branch
+          has an ordered set of children. This tree can be traversed for a
+          serial event based API. Construction of native structures from the
+          serial interface should not use key order or anchors for the
+          preservation of important data.
+        </p>
+            <div class="figure">
+              <a id="id2558547"></a>
+              <p class="title">
+                <b>Figure 3.4. YAML Serialization</b>
+              </p>
+              <div class="mediaobject">
+                <img src="serialize.png" alt="YAML Serialization" />
+              </div>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558578"></a>3.2.2.1. <a id="model-key-order"></a>Key Order</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            In the representation model, keys in a
+            <a href="#model-mapping">mapping</a> do not have order.
+            To serialize a mapping, it is necessary to impose an ordering on
+            its keys. This order should not be used when composing a
+            representation graph from serialized events.
+          </p>
+              <p>
+            In every case where node order is significant, a sequence must be
+            used. For example, an ordered mapping can be represented by a
+            sequence of mappings, where each mapping is a single key/value
+            pair. YAML presentations provide convient shorthand syntax
+            for this case.
+          </p>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558599"></a>3.2.2.2. <a id="model-alias"></a>Aliases</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            In the representation model, a node may appear in more than one
+            context. When serializing such nodes, the first occurance of the
+            node is serialized with an <a id="id2558610" class="indexterm"></a><i class="firstterm">anchor</i> and
+            subsequent occurances are serialized as an
+            <a id="id2558619" class="indexterm"></a><i class="firstterm">alias</i> which specifies the same anchor.
+            Anchors need not be unique within a serialization. When composing a
+            representation graph from serialized events, alias nodes refer to
+            the most recent node in the serialization having the specified anchor.
+          </p>
+              <p>
+            An anchored node need not have an alias referring to it. It is
+            therefore possible to provide an anchor for all nodes in
+            serialization. After composing a representation graph, the
+            anchors are discarded. Hence, anchors must not be used for
+            encoding application data.
+          </p>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2558635"></a>3.2.3. <a id="model-presentation"></a>Character Stream
+        Presentation</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          YAML presentations make use of styles, comments, directives and
+          other syntactical details. Although the processor may provide this
+          information, these features should not be used when constructing
+          native structures.
+        </p>
+            <div class="figure">
+              <a id="id2558648"></a>
+              <p class="title">
+                <b>Figure 3.5. YAML Presentation</b>
+              </p>
+              <div class="mediaobject">
+                <img src="present.png" alt="YAML Presentation" />
+              </div>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558679"></a>3.2.3.1. <a id="model-style"></a>Styles</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            In the syntax, each node has an additional
+            <a id="id2558690" class="indexterm"></a><i class="firstterm">style</i> property, depending on its <a href="#model-node">node</a>. There are two types of styles,
+            <a id="id2558706" class="indexterm"></a><i class="firstterm">block</i> and <a id="id2558715" class="indexterm"></a><i class="firstterm">flow</i>.
+            Block styles use indentation to denote nesting and scope within
+            the presentation. In contrast, flow styles rely on explicit
+            markers to denote nesting and scope.
+          </p>
+              <p>
+            YAML provides several shorthand forms for collection styles,
+            allowing for compact nesting of collections in common cases. For
+            compact set notation, null mapping values may be omitted. For
+            compact ordered mapping notation, a mapping with a single
+            key:value pair may be specified directly inside a flow sequence
+            collection. Also, simple block collections may begin in-line
+            rather than the next line.
+          </p>
+              <p>
+            YAML provides a rich set of scalar style variants. Scalar block
+            styles include the literal and folded styles; scalar flow styles
+            include the plain, single quoted and double quoted styles. These
+            styles offer a range of tradeoffs between expressive power and
+            readability.
+          </p>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558733"></a>3.2.3.2. <a id="model-comment"></a>Comments</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            The syntax allows optional <a id="id2558745" class="indexterm"></a><i class="firstterm">comment</i> blocks
+            to be interleaved with the node blocks. Comment blocks may appear
+            before or after any node block. A comment block can't appear
+            inside a scalar node value.
+          </p>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2558757"></a>3.2.3.3. <a id="model-directive"></a>Directives</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            Each document may be associated with a set of directives. A
+            <a id="id2558768" class="indexterm"></a><i class="firstterm">directive</i> is a key:value pair where both
+            the key and the value are simple strings. Directives are
+            instructions to the YAML processor, allowing for extending YAML in
+            the future. This version of YAML defines a single directive,
+            &#8220;<span class="quote"><b class="userinput"><tt>YAML</tt></b></span>&#8221;. Additional directives
+            may be added in future versions of YAML. A processor should ignore
+            unknown directives with an appropriate warning. There is no
+            provision for specifying private directives. This is intentional.
+          </p>
+              <p>
+            The &#8220;<span class="quote"><b class="userinput"><tt>YAML</tt></b></span>&#8221; directive specifies
+            the version of YAML the document adheres to. This specification
+            defines version <b class="userinput"><tt>1.0</tt></b>. A version 1.0
+            processor should accept documents with an explicit
+            &#8220;<span class="quote"><b class="userinput"><tt>%YAML:1.0</tt></b></span>&#8221; directive, as well
+            as documents lacking a &#8220;<span class="quote"><b class="userinput"><tt>YAML</tt></b></span>&#8221;
+            directive. Documents with a directive specifying a higher minor
+            version (e.g. &#8220;<span class="quote"><b class="userinput"><tt>%YAML:1.1</tt></b></span>&#8221;)
+            should be processed with an appropriate warning. Documents with a
+            directive specifying a higher major version (e.g.
+            &#8220;<span class="quote"><b class="userinput"><tt>%YAML:2.0</tt></b></span>&#8221;) should be
+            rejected with an appropriate error message.
+          </p>
+            </div>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2558898"></a>3.3. <a id="model-complete"></a>Completeness</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        The process of converting YAML information from a character
+        stream presentation to a native data structure has several
+        potential failure points. The character stream may be ill-formed,
+        implicit tags may be unresolvable, tags may be unrecognized,
+        the content may be invalid, and a native type may be unavailable.
+        Each of these failures results with an incomplete conversion.
+      </p>
+          <p><a id="model-partial"></a>
+        A <a id="id2558983" class="indexterm"></a><i class="firstterm">partial representation</i> need not specify the
+        tag of each node, and the canonical form of scalar values need not
+        be available.  This weaker representation is useful for cases of
+        incomplete knowledge of tags used in the document.
+      </p>
+          <div class="figure">
+            <a id="id2558994"></a>
+            <p class="title">
+              <b>Figure 3.6. YAML Completeness</b>
+            </p>
+            <div class="mediaobject">
+              <img src="validity.png" alt="YAML Completeness" />
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559025"></a>3.3.1. <a id="model-well-formed"></a>Well-Formed</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A <a id="id2559035" class="indexterm"></a><i class="firstterm">well-formed</i> character stream must match
+          the productions specified in the next chapter. A YAML processor
+          should reject <a id="id2559045" class="indexterm"></a><i class="firstterm">ill-formed</i> input. A
+          processor may recover from syntax errors, but it must provide a
+          mechanism for reporting such errors.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559057"></a>3.3.2. <a id="model-resolve"></a>Resolved</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          It is not required that all tags in a complete YAML representation
+          be explicitly specified in the character stream presentation. In
+          this case, these <a id="id2559067" class="indexterm"></a><i class="firstterm">implicit tags</i> must be
+          <a id="id2559077" class="indexterm"></a><i class="firstterm">resolved</i>.
+        </p>
+            <p>
+          When resolving tags, a YAML processor must only rely upon
+          representation details, with one notable exception. It may
+          consider whether a scalar was written in the plain style when
+          resolving the scalar's tag. Other than this exception, the
+          processor must not rely upon presentation or serialization
+          details. In particular, it must not consider key order, anchors,
+          styles, spacing, indentation or comments.
+        </p>
+            <p>
+          The plain scalar style exception allows unquoted values to signify
+          numbers, dates, or other typed data, while quoted values are
+          treated as generic strings. With this exception, a processor may
+          match plain scalars against a set of regular expressions, to
+          provide automatic resolution of such types without an explict tag.
+        </p>
+            <p>
+          If a document contains <a id="id2559097" class="indexterm"></a><i class="firstterm">unresolved</i> nodes,
+          the processor is unable to compose a complete representation
+          graph. However, the processor may compose an <a href="#model-partial">partial representation</a>, based on
+          each node's <a href="#model-node">kind</a> (mapping,
+          sequence, scalar) and allowing for unresolved tags.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559189"></a>3.3.3. <a id="model-recognized"></a>
+               <a id="model-valid"></a>Recognized and Valid</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          To be <a id="id2559204" class="indexterm"></a><i class="firstterm">valid</i>, a node must have a tag which
+          is <a id="id2559214" class="indexterm"></a><i class="firstterm">recognized</i> by the processor and its
+          value must satisfy the constraints imposed by its tag. If a
+          document contains a scalar node with an
+          <a id="id2559224" class="indexterm"></a><i class="firstterm">unrecognized</i> tag or an
+          <a id="id2559234" class="indexterm"></a><i class="firstterm">invalid</i> value, only a <a href="#model-partial">partial representation</a> may be
+          composed. In constrast, a processor can always compose a complete
+          YAML representation for an unrecognized or an invalid collection,
+          since collection <a href="#model-equality">equality</a>
+          does not depend upon the collection's data type.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559324"></a>3.3.4. <a id="model-available"></a>Available</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          In a given processing environment, there may not be an
+          <a id="id2559335" class="indexterm"></a><i class="firstterm">available</i> native type corresponding to a
+          given tag. If a node's tag is <a id="id2559345" class="indexterm"></a><i class="firstterm">unavailable</i>,
+          a YAML processor will not be able to construct a native data
+          structure for it. In this case, a complete YAML representation may
+          still be composed, and an application may wish to use this
+          representation directly.
+        </p>
+          </div>
+        </div>
+      </div>
+      <div class="chapter" lang="en" xml:lang="en">
+        <div class="titlepage">
+          <div>
+            <div>
+              <h2 class="title"><a id="id2559358"></a>Chapter 4. <a id="syntax"></a>Syntax</h2>
+            </div>
+          </div>
+          <div></div>
+        </div>
+        <p>
+        Following are the BNF productions defining the syntax of YAML
+        character streams. The productions introduce the relevant character
+        classes, describe the processing of white space, and then follow
+        with the decomposition of the stream into logical chunks. To make
+        this chapter easier to follow, production names use Hungarian-style
+        notation:
+      </p>
+        <div class="variablelist">
+          <dl>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>c-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single special character
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>b-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single line break
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>nb-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single non-break character
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>s-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single non-break space character
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>ns-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single non-break non-space character
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>i-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching indentation spaces
+          </dd>
+            <dt>
+              <span class="term">
+                <tt class="varname">X</tt>
+                <b class="userinput">
+                  <tt>-</tt>
+                </b>
+                <tt class="varname">Y</tt>
+                <b class="userinput">
+                  <tt>-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a sequence of characters, starting with an
+            <tt class="varname">X</tt><b class="userinput"><tt>-</tt></b> production and ending
+            with a <tt class="varname">Y</tt><b class="userinput"><tt>-</tt></b> production
+          </dd>
+            <dt>
+              <span class="term">
+                <b class="userinput">
+                  <tt>l-</tt>
+                </b>
+              </span>
+            </dt>
+            <dd>
+            a production matching a single line (shorthand for
+            <b class="userinput"><tt>i-b-</tt></b>)
+          </dd>
+          </dl>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2559506"></a>4.1. <a id="syntax-char"></a>Characters</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559514"></a>4.1.1. <a id="syntax-char-set"></a>Character Set</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          YAML streams use a subset of the Unicode character set. On input,
+          a YAML processor must accept all printable ASCII characters, the
+          space, tab, line break, and all Unicode characters beyond 0x9F. On
+          output, a YAML processor must only produce those acceptable
+          characters, and should also <a href="#syntax-escape">escape</a> all non-printable
+          Unicode characters.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[1]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-printable"></a>c-printable</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                #x9 | #xA | #xD<br />
+              | [#x20-#x7E] | #x85<br />
+              | [#xA0-#xD7FF]<br />
+              | [#xE000-#xFFFD]<br />
+              | [#x10000-#x10FFFF]
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* characters as defined by the Unicode standard,
+              excluding most control characters and the surrogate
+              blocks */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <p>
+          This character range explicitly excludes the surrogate block
+          <b class="userinput"><tt>[#xD800-#xDFFF]</tt></b>, DEL
+          <b class="userinput"><tt>0x7F</tt></b>, the C0 control block
+          <b class="userinput"><tt>[#x0-#x1F]</tt></b>, the C1 control block
+          <b class="userinput"><tt>[#x80-#x9F]</tt></b>, <b class="userinput"><tt>#xFFFE</tt></b>
+          and <b class="userinput"><tt>#xFFFF</tt></b>. Note that in UTF-16, characters
+          above <b class="userinput"><tt>#xFFFF</tt></b> are represented with a surrogate
+          pair. When present, DEL and characters in the C0 and C1 control block
+          must be represented in a YAML stream using escape sequences.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559676"></a>4.1.2. <a id="syntax-encode"></a>Encoding</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A YAML processor must support the UTF-16 and UTF-8 character
+          encodings. If an input stream does not begin with a <a href="#c-byte-order-mark">byte order mark</a>, the encoding
+          shall be UTF-8. UTF-16 (LE or BE) or UTF-8, as signaled by the
+          byte order mark. Since YAML files may only contain
+          printable characters, this does not raise any ambiguities. For
+          more information about the byte order mark and the Unicode
+          character encoding schemes see the Unicode <a href="http://www.unicode.org/unicode/faq/utf_bom.html" target="_top">FAQ</a>.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[2]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-byte-order-mark"></a>c-byte-order-mark</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #xFEFF
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* unicode BOM */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2559720"></a>4.1.3. <a id="syntax-indicator"></a>Indicators</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Indicators are special characters that are used to describe the
+          structure of a YAML document. In general, they cannot be used as
+          the first character of a <a href="#syntax-scalar-plain">plain
+          scalar</a>.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[3]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-sequence-start"></a>c-sequence-start</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">[</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* starts a flow sequence
+              collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[4]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-sequence-end"></a>c-sequence-end</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">]</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* ends a flow sequence collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[5]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-mapping-start"></a>c-mapping-start</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">{</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* starts a flow mapping
+              collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[6]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-mapping-end"></a>c-mapping-end</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">}</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* ends a flow mapping collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[7]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-sequence-entry"></a>c-sequence-entry</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">-</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* indicates a sequence entry */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[8]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-mapping-entry"></a>c-mapping-entry</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">:</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* separates a key from its value */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[9]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-collect-entry"></a>c-collect-entry</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">,</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* separates flow collection
+              entries */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[10]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-complex-key"></a>c-complex-key</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">?</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a complex key */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[11]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-tag"></a>c-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">!</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* indicates a tag property */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[12]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-anchor"></a>c-anchor</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">&amp;</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* an anchor property */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[13]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-alias"></a>c-alias</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">*</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* an alias node */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[14]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-literal"></a>c-literal</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">|</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a literal scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[15]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-folded"></a>c-folded</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">&gt;</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a folded scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[16]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-single-quote"></a>c-single-quote</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">'</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a single quoted scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[17]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-double-quote"></a>c-double-quote</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">&quot;</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a double quoted scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[18]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-throwaway"></a>c-throwaway</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">#</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a throwaway comment */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[19]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-directive"></a>c-directive</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">%</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a directive */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[20]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-reserved"></a>c-reserved</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">@</span>&#8221; | &#8220;<span class="quote">`</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* reserved for future use */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[21]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-indicators"></a>c-indicators</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#c-sequence-start">&#8220;<span class="quote">[</span>&#8221;</a>
+              | <a href="#c-sequence-end">&#8220;<span class="quote">]</span>&#8221;</a>
+              | <a href="#c-mapping-start">&#8220;<span class="quote">{</span>&#8221;</a>
+              | <a href="#c-mapping-end">&#8220;<span class="quote">}</span>&#8221;</a><br />
+              | <a href="#c-sequence-entry">&#8220;<span class="quote">-</span>&#8221;</a>
+              | <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a>
+              | <a href="#c-complex-key">&#8220;<span class="quote">?</span>&#8221;</a>
+              | <a href="#c-collect-entry">&#8220;<span class="quote">,</span>&#8221;</a><br />
+              | <a href="#c-tag">&#8220;<span class="quote">!</span>&#8221;</a>
+              | <a href="#c-alias">&#8220;<span class="quote">*</span>&#8221;</a>
+              | <a href="#c-anchor">&#8220;<span class="quote">&amp;</span>&#8221;</a><br />
+              | <a href="#c-literal">&#8220;<span class="quote">|</span>&#8221;</a>
+              | <a href="#c-folded">&#8220;<span class="quote">&gt;</span>&#8221;</a>
+              | <a href="#c-single-quote">&#8220;<span class="quote">'</span>&#8221;</a>
+              | <a href="#c-double-quote">&#8220;<span class="quote">&quot;</span>&#8221;</a><br />
+              | <a href="#c-throwaway">&#8220;<span class="quote">#</span>&#8221;</a>
+              | <a href="#c-directive">&#8220;<span class="quote">%</span>&#8221;</a>
+              | <a href="#c-reserved">&#8220;<span class="quote">@</span>&#8221; | &#8220;<span class="quote">`</span>&#8221;</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* indicator characters */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2560349"></a>4.1.4. <a id="syntax-char-break"></a>Line Breaks</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          The Unicode standard defines several <a href="#b-char">line
+          break characters</a>. These line breaks can be grouped into two
+          categories. <a href="#b-specific">Specific line breaks</a>
+          have well-defined semantics for breaking text into lines and
+          paragraphs. <a href="#b-generic">Generic line
+          breaks</a> are not given meaning beyond &#8220;<span class="quote">ending a
+          line</span>&#8221;.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[22]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-line-feed"></a>b-line-feed</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #xA
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* aSCII line feed (LF) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[23]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-carriage-return"></a>b-carriage-return</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #xD
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* aSCII carriage return (CR) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[24]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-next-line"></a>b-next-line</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #x85
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* unicode next line (NEL) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[25]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-line-separator"></a>b-line-separator</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #x2028
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* unicode line separator (LS) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[26]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-paragraph-separator"></a>b-paragraph-separator</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #x2029
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* unicode paragraph separator (PS) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[27]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-char"></a>b-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#b-line-feed">b-line-feed</a><br />
+              | <a href="#b-carriage-return">b-carriage-return</a><br />
+              | <a href="#b-next-line">b-next-line</a><br />
+              | <a href="#b-line-separator">b-line-separator</a><br />
+              | <a href="#b-paragraph-separator">b-paragraph-separator</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* line break characters */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[28]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-generic"></a>b-generic</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                ( <a href="#b-carriage-return">b-carriage-return</a><br />
+                  <a href="#b-line-feed">b-line-feed</a> )<br />
+              | <a href="#b-carriage-return">b-carriage-return</a><br />
+              | <a href="#b-line-feed">b-line-feed</a><br />
+              | <a href="#b-next-line">b-next-line</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* line break with non-specific
+              semantics */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[29]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-specific"></a>b-specific</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#b-line-separator">b-line-separator</a><br />
+              | <a href="#b-paragraph-separator">b-paragraph-separator</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* line break with specific
+              semantics */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[30]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-any"></a>b-any</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#b-generic">b-generic</a> | <a href="#b-specific">b-specific</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* any non-content line break */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <p>
+          Outside scalar text content, YAML allows <a href="#b-any">any
+          line break</a> to be used to terminate lines, and in most cases
+          also allows such line breaks to be preceded by <a href="#s-b-trailing-comment">trailing comment</a> characters.
+          On output, a YAML processor is free to emit such line breaks using
+          whatever convention is most appropriate. YAML output should avoid
+          using trailing line spaces.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2560684"></a>4.1.5. <a id="syntax-char-misc"></a>Miscellaneous</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          This section includes several common character range definitions.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[31]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="nb-char"></a>nb-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-printable">c-printable</a> - <a href="#b-char">b-char</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* characters valid in a line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[32]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="s-char"></a>s-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #x9 | #x20
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* white space valid in a line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[33]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-char"></a>ns-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#nb-char">nb-char</a> - <a href="#s-char">s-char</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* non-space characters valid in a
+              line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[34]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ascii-letter"></a>ns-ascii-letter</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              [#x41-#x5A] | [#x61-#x7A]
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* aSCII letters, A-Z or a-z */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[35]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-decimal-digit"></a>ns-decimal-digit</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              [#x30-#x39]
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* 0-9 */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[36]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-hex-digit"></a>ns-hex-digit</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-decimal-digit">ns-decimal-digit</a><br />
+              | [#x41-#x46] | [#x61-#x66]
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* 0-9, A-F or a-f */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[37]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-word-char"></a>ns-word-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-decimal-digit">ns-decimal-digit</a><br />
+              | <a href="#ns-ascii-letter">ns-ascii-letter</a> | &#8220;<span class="quote">-</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* characters valid in a word */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2560916"></a>4.2. <a id="syntax-space"></a>Space Processing</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        YAML streams use lines and spaces to convey structure. This requires
+        special processing rules for white space (<a href="#s-char">space
+        and tab</a>).
+      </p>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2560933"></a>4.2.1. <a id="syntax-indentation"></a>Indentation</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          In a YAML character stream, structure is often determined from
+          indentation, where indentation is defined as a line break
+          character followed by zero or more space characters. With one
+          notable exception, a node must be more indented than its parent
+          node. All sibling nodes must use the exact same indentation level,
+          however the content of each such node could be further indented.
+          Indentation is used exclusively to delineate structure and is
+          otherwise ignored; in particular, indentation characters must
+          never be considered part of the document's content.
+        </p>
+            <p>
+          Tab characters are not allowed in indentation since different
+          systems treat tabs differently. To maintain portability, YAML's
+          tab policy is conservative; they shall not be used. Note that most
+          modern editors may be configured so that pressing the tab key
+          results in the insertion of an appropriate number of spaces.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[38]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="i-spaces(n)"></a>i-spaces(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              #x20 x n
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* specific level of indentation */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <p>
+          Since the YAML stream depends upon indentation level to delineate
+          blocks, many productions are a function of an integer, based on
+          the <a href="#i-spaces(n)"><b class="userinput"><tt>i-spaces(n)</tt></b></a>
+          production above. In some cases, the notations
+          <b class="userinput"><tt>production(&lt;n)</tt></b>,
+          <b class="userinput"><tt>production(&#8804;n)</tt></b> and
+          <b class="userinput"><tt>production(&gt;n)</tt></b> are used; these are
+          shorthands for &#8220;<span class="quote"><b class="userinput"><tt>production(m)</tt></b> for some
+          specific <tt class="varname">m</tt> such that <tt class="varname">m</tt> is less
+          than/less than or equal/greater than <tt class="varname">n</tt></span>&#8221;,
+          respectively. The notation <b class="userinput"><tt>production(any)</tt></b> is
+          a shorthand for &#8220;<span class="quote"><b class="userinput"><tt>production(m)</tt></b> for some
+          specific value of <tt class="varname">m</tt> such that
+          <tt class="varname">m</tt> &#8805; 0</span>&#8221;.
+        </p>
+            <p>
+          The &#8220;<span class="quote"><b class="userinput"><tt>-</tt></b></span>&#8221; <a href="#c-sequence-entry">sequence entry</a>,
+          &#8220;<span class="quote"><b class="userinput"><tt>?</tt></b></span>&#8221; <a href="#c-complex-key">complex key</a> and
+          &#8220;<span class="quote"><b class="userinput"><tt>:</tt></b></span>&#8221; <a href="#c-mapping-entry">mapping entry</a> indicators are
+          perceived by people to be part of the indentation. Hence the
+          indentation rules are slightly more flexible when dealing with these
+          indicators. First, a block sequence need not be indented relative to
+          its parent node, unless that node is a block sequence entry. For
+          example:
+        </p>
+            <div class="example">
+              <a id="id2561141"></a>
+              <p class="title">
+                <b>Example 4.1. </b>
+              </p>
+              <pre class="programlisting">
+a key in a mapping at indentation level 0:
+# The value for this key is a block sequence.
+- This sequence is also at indentation level 0.
+-   Another entry in the sequence.
+- # The value of this entry is a nested sequence.
+ - This nested sequence must be
+  indented at least to level 1.
+ - Another entry in the nested sequence.
+- Last entry in block sequence at indentation level 0.
+second key in mapping: at indentation level 0.
+</pre>
+            </div>
+            <p>
+          In addition, in the special case when the value of a sequence
+          entry or complex key:value pair is a block collection, and neither
+          the nested block collection nor its first entry have any
+          properties specified (tag or anchor), then this first entry may be
+          specified in the same line as the indicator of the containing
+          sequence entry. In this case both the indicator and any following
+          spaces are counted as part of the indentation. For example:
+        </p>
+            <div class="example">
+              <a id="id2561153"></a>
+              <p class="title">
+                <b>Example 4.2. </b>
+              </p>
+              <pre class="programlisting">
+- This sequence is not indented.
+-   inline-map: further indented by four.
+    this key: is also further indented by four.
+    ? - nested sequence used as key
+      - indented by eight spaces
+    : nested map: used as value
+      indented by: six spaces
+-  - inline-seq; further indented by three.
+   -    second entry in nested sequence.
+- Last entry in top sequence.
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2561162"></a>4.2.2. <a id="syntax-space-comment"></a>Throwaway comments</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Throwaway comments have no effect whatsoever on the document's
+          representation graph.  The usual purpose of a comment is to
+          communicate between the human maintainers of the file. A typical
+          example is comments in a configuration file.
+        </p>
+            <p>
+          A throwaway comment is marked by a <a href="#c-throwaway">&#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221;</a>
+          indicator and always spans to the end of a line. Comments can be
+          indented  on their own line, or may, in some cases, follow other
+          syntax elements with leading spaces.
+        </p>
+            <p>
+          Outside text content, empty lines or lines containing only white
+          space are taken to be implicit throwaway comment lines. Lines
+          containing indentation followed by
+          &#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221; and comment characters are
+          taken to be explicit throwaway comment lines.
+        </p>
+            <p>
+          A throwaway comment may appear before a document's top level node or
+          following any node. It may not appear inside a scalar node,  but may
+          precede or follow it.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[39]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-nb-throwaway-comment"></a>c-nb-throwaway-comment</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-throwaway">&#8220;<span class="quote">#</span>&#8221;</a> <a href="#nb-char">nb-char</a>*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* comment trailing a line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[40]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-comment(n)"></a>l-comment(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                  <a href="#l-empty-comment(n)">l-empty-comment(n)</a><br />
+                | <a href="#l-text-comment(n)">l-text-comment(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* types of comment lines */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[41]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-empty-comment(n)"></a>l-empty-comment(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(&#8804;n)</a> <a href="#b-any">b-any</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* empty throwaway comment line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[42]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-text-comment(n)"></a>l-text-comment(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(&lt;n)</a><br />
+              <a href="#c-nb-throwaway-comment">c-nb-throwaway-comment</a><br />
+              <a href="#b-any">b-any</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* explicit throwaway comment line */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[43]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="s-b-trailing-comment"></a>s-b-trailing-comment</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              ( <a href="#s-char">s-char</a>+<br />
+                <a href="#c-nb-throwaway-comment">c-nb-throwaway-comment</a>? )?<br />
+              <a href="#b-any">b-any</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* trailing non-content spaces, comment and line
+              break */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2561548"></a>
+              <p class="title">
+                <b>Example 4.3. </b>
+              </p>
+              <pre class="programlisting">
+###The first tree lines of this stream
+
+## are comments (the second one is empty).
+this: |   # Comments may trail block indicators.
+    contains three lines of text.
+    The third one starts with a
+    # character. This isn't a comment.
+
+# The last three lines of this stream
+# are comments (the first line is empty).
+</pre>
+            </div>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2561559"></a>4.3. <a id="syntax-stream"></a>YAML Stream</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        A sequence of bytes is a YAML stream if, taken as a whole, it complies
+        with the following production. Note that an empty stream is a valid
+        YAML stream containing no documents.
+      </p>
+          <p>
+        <a href="#syntax-encode">Encoding</a> is assumed to be
+        UTF-8 unless explicitly specified by including a byte order mark as the
+        first character of the stream. While a byte order mark may also appear
+        before additional document headers, the same encoding must be used for
+        all documents contained in a YAML stream.
+      </p>
+          <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+            <tr>
+              <td>
+                <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[44]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="c-l-yaml-stream"></a>c-l-yaml-stream</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#c-l-before-document">c-l-before-document</a><br />
+              <a href="#l-l-implicit-document">l-l-implicit-document</a><br />
+              <a href="#l-l-after-document">l-l-after-document</a>? )?<br />
+            ( <a href="#c-l-before-document">c-l-before-document</a><br />
+              <a href="#l-l-explicit-document">l-l-explicit-document</a><br />
+              <a href="#l-l-after-document">l-l-after-document</a>? )*
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* document stream */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[45]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="c-l-before-document"></a>c-l-before-document</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#c-byte-order-mark">c-byte-order-mark</a>?<br />
+            <a href="#l-comment(n)">#l-comment(any)</a>*
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* comments before actual document
+            starts */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[46]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="l-l-implicit-document"></a>l-l-implicit-document</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#l-l-collect-blk-value(n)">l-l-collect-blk-value(any)</a><br />
+            | <a href="#l-l-collect-top-flow-node(n)">l-l-collect-top-flow-node(any)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* first document with an implicit header
+            line */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[47]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="l-l-explicit-document"></a>l-l-explicit-document</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#ns-ns-document-header">ns-ns-document-header</a><br />
+            ( <a href="#s-l-scalar-top-node(n)">s-l-scalar-top-node(any)</a><br />
+            | <a href="#s-l-collect-top-node(n)">s-l-collect-top-node(any)</a> )
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* stream document with an explicit
+            header */<br /></td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2561718"></a>4.3.1. <a id="syntax-stream-doc"></a>Document</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A YAML stream may contain several independent YAML documents. A
+          document header line may be used to start a document and must be used
+          to separate documents within a stream. This line must start with a
+          document separator: <a href="#ns-ns-document-start">&#8220;<span class="quote"><b class="userinput"><tt>---</tt></b></span>&#8221;</a> followed by a line
+          break or a sequence of space characters. If no explicit header line
+          is specified at the start of the stream, the processor should behave
+          as if a header line containing an unadorned
+          &#8220;<span class="quote"><b class="userinput"><tt>---</tt></b></span>&#8221; was specified.
+        </p>
+            <p>
+          When YAML is used as the format for a communication stream, it is
+          useful to be able to indicate the end of a document independent of
+          starting the next one without closing the data stream. Lacking
+          such a marker, the YAML processor reading the stream would be
+          forced to wait for the header of the next document (that may be
+          long time in coming) in order to detect the end of the previous
+          document. To support this scenario, a YAML document may be
+          terminated by a <a href="#ns-ns-document-end">&#8220;<span class="quote"><b class="userinput"><tt>...</tt></b></span>&#8221;</a> line. Nothing
+          but throwaway comments may appear between this line and the
+          (mandatory) header line of the following document.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[48]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-document-header"></a>ns-ns-document-header</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-ns-document-start">ns-ns-document-start</a><br />
+              ( <a href="#s-char">s-char</a>+ <a href="#c-ns-directive">c-ns-directive</a> )*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document header */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[49]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-document-start"></a>ns-ns-document-start</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                &#8220;<span class="quote">-</span>&#8221; &#8220;<span class="quote">-</span>&#8221; &#8220;<span class="quote">-</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document start indicator */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[50]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-after-document"></a>l-l-after-document</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-ns-document-end">ns-ns-document-end</a> <a href="#b-any">b-any</a><br />
+              <a href="#l-comment(n)">l-comment(any)</a>*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document trailer */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[51]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-document-end"></a>ns-ns-document-end</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">.</span>&#8221; &#8220;<span class="quote">.</span>&#8221; &#8220;<span class="quote">.</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document end indicator */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <p>
+          Since &#8220;<span class="quote"><b class="userinput"><tt>---</tt></b></span>&#8221; and
+          &#8220;<span class="quote"><b class="userinput"><tt>...</tt></b></span>&#8221; indicate document
+          boundaries, these character strings are forbidden as content
+          lines unless they are indented.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[52]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-forbidden-non-indented"></a>l-forbidden-non-indented</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                  ( <a href="#ns-ns-document-start">ns-ns-document-start</a><br />
+                    <a href="#s-char">s-char</a> <a href="#nb-char">nb-char</a>* )<br />
+                | <a href="#ns-ns-document-end">ns-ns-document-end</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* forbidden non-indented content
+              line */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2562132"></a>
+              <p class="title">
+                <b>Example 4.4. </b>
+              </p>
+              <pre class="programlisting">
+--- &gt;
+This YAML stream contains a single text value.
+The next stream is a log file - a sequence of
+log entries. Adding an entry to the log is a
+simple matter of appending it at the end.
+</pre>
+            </div>
+            <div class="example">
+              <a id="id2562140"></a>
+              <p class="title">
+                <b>Example 4.5. </b>
+              </p>
+              <pre class="programlisting">
+---
+at: 2001-08-12 09:25:00.00 Z
+type: GET
+HTTP: '1.0'
+url: '/index.html'
+---
+at: 2001-08-12 09:25:10.00 Z
+type: GET
+HTTP: '1.0'
+url: '/toc.html'
+</pre>
+            </div>
+            <div class="example">
+              <a id="id2562149"></a>
+              <p class="title">
+                <b>Example 4.6. </b>
+              </p>
+              <pre class="programlisting">
+# This stream is an example of a top-level mapping.
+invoice : 34843
+date    : 2001-01-23
+total   : 4443.52
+</pre>
+            </div>
+            <div class="example">
+              <a id="id2562157"></a>
+              <p class="title">
+                <b>Example 4.7. </b>
+              </p>
+              <pre class="programlisting">
+# A one-line alternative syntax for the above document.
+{ invoice: 34843, date: 2001-01-23, total: 4443.52 }
+</pre>
+            </div>
+            <div class="example">
+              <a id="id2562166"></a>
+              <p class="title">
+                <b>Example 4.8. </b>
+              </p>
+              <pre class="programlisting">
+# The following is a stream of three documents. TODO
+# The first is an empty mapping, the second an
+# empty sequence, and the last an empty string.
+--- {}
+--- [ ]
+--- ''
+</pre>
+            </div>
+            <div class="example">
+              <a id="id2562174"></a>
+              <p class="title">
+                <b>Example 4.9. </b>
+              </p>
+              <pre class="programlisting">
+# A communication channel based on a YAML stream.
+---
+sent at: 2002-06-06 11:46:25.10 Z
+payload: Whatever
+# Receiver can process this as soon as the following is sent:
+...
+# Even if the next message is sent long after:
+---
+sent at: 2002-06-06 12:05:53.47 Z
+payload: Whatever
+...
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2562252"></a>4.3.2. <a id="syntax-directive"></a>Directive</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          <a href="#model-directive">Directives</a> are instructions
+          to the YAML processor. Like <a href="#syntax-space-comment">throwaway comments</a>,
+          directives are not reflected in the document's representation
+          graph. Directives apply to a single document. It is an error for
+          the same directive to be specified more than once for the same
+          document.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[53]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-ns-directive"></a>c-ns-directive</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-directive">&#8220;<span class="quote">%</span>&#8221;</a> <a href="#ns-ns-directive-name">ns-ns-directive-name</a><br />
+              <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a> <a href="#ns-ns-directive-value">ns-ns-directive-value</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document directive */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[54]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-directive-name"></a>ns-ns-directive-name</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              ( <a href="#ns-char">ns-char</a> - <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a> )+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document directive name */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[55]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-directive-value"></a>ns-ns-directive-value</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-char">ns-char</a>+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* document directive value */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2562430"></a>4.3.3. <a id="syntax-node"></a>Presentation Node</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A presentation node begins at a particular level of indentation,
+          <tt class="varname">n</tt>, and its content is indented at some level
+          &gt; <tt class="varname">n</tt>. A presentation node can be a <a href="#syntax-collect">collection</a>, a <a href="#syntax-scalar">scalar</a> or an <a href="#syntax-alias">alias</a>.
+        </p>
+            <p>
+          A YAML document is a normal node. However a document can't be an
+          alias (there is nothing it may refer to). Also if the header line is
+          omitted the first document must be a collection.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[56]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="s-l-top-node(n)"></a>s-l-top-node(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#s-l-alias-top-node">s-l-alias-top-node</a><br />
+              | <a href="#s-l-collect-top-node(n)">s-l-collect-top-node(n)</a><br />
+              | <a href="#s-l-scalar-top-node(n)">s-l-scalar-top-node(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* node outside flow
+              collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[57]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-flow-value-node(n)"></a>ns-ns-flow-value-node(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-ns-alias-flow-node">ns-ns-alias-flow-node</a><br />
+              | <a href="#c-c-collect-flow-node(n)">c-c-collect-flow-node(n)</a><br />
+              | <a href="#ns-ns-scalar-flow-value-node(n)">ns-ns-scalar-flow-value-node(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* value node inside flow
+              collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[58]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-flow-key-node(n)"></a>ns-ns-flow-key-node(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-ns-alias-flow-node">ns-ns-alias-flow-node</a><br />
+              | <a href="#c-c-collect-flow-node(n)">c-c-collect-flow-node(n)</a><br />
+              | <a href="#ns-ns-scalar-flow-key-node(n)">ns-ns-scalar-flow-key-node(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* key node inside flow collection */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2562637"></a>4.3.4. <a id="syntax-stream-property"></a>Node Property</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Each presentation node may have <a href="#syntax-anchor">anchor</a> and <a href="#syntax-tag">tag</a> properties. These properties
+          are specified in a properties list appearing before the node value
+          itself. For a root node (a document), the properties appear in the
+          document header line, following the directives (if any). It is an
+          error for the same property to be specified more than once for the
+          same node.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[59]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-ns-properties"></a>c-ns-properties</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                ( <a href="#c-ns-tag-property">c-ns-tag-property</a><br />
+                  ( <a href="#s-char">s-char</a>+ <a href="#c-ns-anchor-property">c-ns-anchor-property</a> )? )<br />
+              | ( <a href="#c-ns-anchor-property">c-ns-anchor-property</a><br />
+                  ( <a href="#s-char">s-char</a>+ <a href="#c-ns-tag-property">c-ns-tag-property</a> )? )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* properties list */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2562713"></a>4.3.5. <a id="syntax-tag"></a>Tag</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          <a href="#model-tag">Tags</a> can be presented in the
+          character stream with the tag indicator, <a href="#c-tag">&#8220;<span class="quote"><b class="userinput"><tt>!</tt></b></span>&#8221;</a>.
+          Unlike <a href="#syntax-anchor">anchors</a>, tags are
+          part of the document's representation graph. The YAML processor
+          is responsible for <a href="#model-resolve">resolving</a> 
+          tags which are not present in the character stream.
+        </p>
+            <div class="example">
+              <a id="id2562750"></a>
+              <p class="title">
+                <b>Example 4.10. </b>
+              </p>
+              <pre class="programlisting">
+a string: '12'
+another string: &quot;12&quot;
+explicit string: !str 12
+explicit integer: !int 12
+implicit integer: 12
+</pre>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2562759"></a>4.3.5.1. <a id="syntax-tag-short"></a>Shorthands</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            To increase readability, YAML does not use the full URI notation
+            in the character stream. Instead, it provides several shorthand
+            notations for different groups of tags. If a tag may be written
+            using more than one shorthand, the shortest format must be used.
+            A processor need not expand shorthand tags to a full URI form.
+            However, in such a case the processor must still perform <a href="#syntax-tag-escape">escaping</a>. These rules ensure
+            that each tag's shorthand is a globally unique.
+          </p>
+              <div class="itemizedlist">
+                <ul type="disc">
+                  <li>
+                    <p>
+                If a tag property is of the form
+                <b class="userinput"><tt>!</tt></b><tt class="varname">foo</tt>, it is a
+                shorthand for the <a href="#model-private">private</a> tag URI
+                <b class="userinput"><tt>tag:private.yaml.org,2002:</tt></b><tt class="varname">foo</tt>.
+              </p>
+                    <div class="example">
+                      <a id="id2562873"></a>
+                      <p class="title">
+                        <b>Example 4.11. </b>
+                      </p>
+                      <pre class="programlisting">
+# Both examples below make use of the 
+# 'tag:private.yaml.org,2002:ball'
+# tag, but with different semantics.
+---
+pool: !!ball { number: 8 }
+---
+bearing: !!ball { material: steel }
+</pre>
+                    </div>
+                  </li>
+                  <li>
+                    <p>
+                If a tag property <tt class="varname">foo</tt> contains neither
+                &#8220;<span class="quote"><b class="userinput"><tt>:</tt></b></span>&#8221; nor
+                &#8220;<span class="quote"><b class="userinput"><tt>/</tt></b></span>&#8221; characters, it is a
+                shorthand for the tag URI
+                <b class="userinput"><tt>tag:yaml.org,2002:</tt></b><tt class="varname">foo</tt>.
+                The <b class="userinput"><tt>yaml.org</tt></b> domain is used to define
+                the core and universal YAML data types.
+              </p>
+                    <div class="example">
+                      <a id="id2562919"></a>
+                      <p class="title">
+                        <b>Example 4.12. </b>
+                      </p>
+                      <pre class="programlisting">
+# The URI is 'tag:yaml.org,2002:str'
+- !str is a Unicode string
+</pre>
+                    </div>
+                  </li>
+                  <li>
+                    <p>
+                If the tag property is of the form
+                <tt class="varname">vocabulary</tt><b class="userinput"><tt>/</tt></b><tt class="varname">foo</tt>
+                where <tt class="varname">vocabulary</tt> is a single word, it is
+                a shorthand for the tag URI
+                <b class="userinput"><tt>tag:</tt></b><tt class="varname">vocabulary</tt><b class="userinput"><tt>.yaml.org,2002:</tt></b><tt class="varname">foo</tt>.
+                Each domain
+                <tt class="varname">vocabulary</tt><b class="userinput"><tt>.yaml.org</tt></b>
+                is used for tags specific to the given vocabulary, such as a
+                particular programming language.
+              </p>
+                    <div class="example">
+                      <a id="id2562969"></a>
+                      <p class="title">
+                        <b>Example 4.13. </b>
+                      </p>
+                      <pre class="programlisting">
+# The URI is 'tag:perl.yaml.org,2002:Text::Tabs'
+- !perl/Text::Tabs {}
+</pre>
+                    </div>
+                  </li>
+                  <li>
+                    <p>
+                Otherwise, the tag property must be of the form
+                <tt class="varname">domain</tt><b class="userinput"><tt>,</tt></b><tt class="varname">date</tt><b class="userinput"><tt>/</tt></b><tt class="varname">foo</tt>,
+                which is a shorthand for the tag URI
+                <b class="userinput"><tt>tag:</tt></b><tt class="varname">domain</tt><b class="userinput"><tt>,</tt></b><tt class="varname">date</tt><b class="userinput"><tt>/</tt></b><tt class="varname">foo</tt>.
+                To ensure uniqueness, the day must be omitted if it is the
+                1st of the month, and the month and day must be omitted for
+                January 1st. Such tags may be freely minted by the owners of
+                the domain at the specified date.
+              </p>
+                    <div class="example">
+                      <a id="id2563020"></a>
+                      <p class="title">
+                        <b>Example 4.14. </b>
+                      </p>
+                      <pre class="programlisting">
+# The URI is 'tag:clarkevans.com,2003-02:timesheet'
+- !clarkevans.com,2003-02/timesheet
+</pre>
+                    </div>
+                  </li>
+                </ul>
+              </div>
+              <p>
+            Following are several examples which are not valid tag
+            shorthands.
+          </p>
+              <div class="example">
+                <a id="id2563034"></a>
+                <p class="title">
+                  <b>Example 4.15. Invalid Shorthands</b>
+                </p>
+                <table class="simplelist" border="0" summary="Simple list">
+                  <tr>
+                    <td>
+  <pre class="screen">
+- !http://www.yaml.org/bing invalid
+- !tag:yaml.org,2002:str
+  </pre>
+              </td>
+                    <td>
+  <pre class="screen">
+Only the tag shorthand is allowed in 
+a character stream, URIs, including
+the taguri is forbidden.
+  </pre>
+              </td>
+                  </tr>
+                </table>
+              </div>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2563066"></a>4.3.5.2. <a id="syntax-tag-escape"></a>Escaping</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            YAML allows arbitrary Unicode characters to be used in a tag
+            with <a href="#syntax-escape">escape sequences</a>. The
+            processor must expand such escape sequences before reporting the
+            tag's shorthand or URI to the application.
+          </p>
+              <p>
+            Sometimes it may be helpful for a YAML tag to be expanded to its
+            full URI form. A YAML processor may provide a mechanism to
+            perform such expansion. Since URIs support a limited ASCII-based
+            character set, this expansion requires all characters outside
+            this set to be encoded in UTF-8 and the resulting bytes to be
+            encoded using &#8220;<span class="quote"><b class="userinput"><tt>%</tt></b></span>&#8221; notation
+            with upper-case hexadecimal digits. Further details on the URI
+            encoding requirements are given in <a href="http://www.ietf.org/rfc/rfc2396.txt" target="_top">RFC2396</a>.
+          </p>
+              <div class="example">
+                <a id="id2563099"></a>
+                <p class="title">
+                  <b>Example 4.16. </b>
+                </p>
+                <pre class="programlisting">
+# The following values have the same tag URI:
+# 'tag:domain.tld,2002/a%3C%0A%25b'.
+- !domain.tld,2002/a&lt;\n%b value
+- !domain.tld,2002/a\x3c\x0A%b value
+</pre>
+              </div>
+            </div>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2563109"></a>4.3.5.3. <a id="syntax-tag-prefix"></a>Prefixing</h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            YAML provides a convenient prefix mechanism for the common case
+            where a node and (most of) its descendents have globally unique
+            tags, whose shorthand forms share a common prefix. If a node's
+            tag property is of the form
+            <tt class="varname">prefix</tt><b class="userinput"><tt>^</tt></b><tt class="varname">suffix</tt>,
+            the &#8220;<span class="quote"><b class="userinput"><tt>^</tt></b></span>&#8221; character is
+            discarded from the tag. If a descendent node's tag property is
+            of the form <b class="userinput"><tt>^</tt></b><tt class="varname">foo</tt>, it
+            is treated as if it was written
+            <tt class="varname">prefix</tt><tt class="varname">foo</tt> where
+            <tt class="varname">prefix</tt> comes from the most recent ancestor
+            that established a prefix. Note that this mechanism is purely
+            syntactical and does not imply any additional semantics. In
+            particular, the prefix must not be assumed to be an identifier
+            for anything. It is possible to include a
+            &#8220;<span class="quote"><b class="userinput"><tt>^</tt></b></span>&#8221; character in a tag by
+            <a href="#syntax-escape">escaping</a> it. It is an error
+            for a node's tag property to contain more than one unescaped
+            &#8220;<span class="quote"><b class="userinput"><tt>^</tt></b></span>&#8221; character, or for the
+            tag property to begin with
+            &#8220;<span class="quote"><b class="userinput"><tt>^</tt></b></span>&#8221; unless the node is a
+            descendent of an ancestor that established a tag prefix.
+          </p>
+              <div class="example">
+                <a id="id2563248"></a>
+                <p class="title">
+                  <b>Example 4.17. </b>
+                </p>
+                <pre class="programlisting">
+# 'tag:domain.tld,2002:invoice' is some tag.
+invoice: !domain.tld,2002/^invoice
+  # 'seq' is shorthand for 'tag:yaml.org,2002:seq'.
+  # This does not effect '^customer' below
+  # because it is does not specify a prefix.
+  customers: !seq
+    # '^customer' is shorthand for the full notation
+    # '!domain.tld,2002/customer' that stands for the
+    # URI 'tag:domain.tld,2002:customer'.
+    - !^customer
+      given : Chris
+      family : Dumars
+</pre>
+              </div>
+            </div>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[60]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-prefix"></a>c-prefix</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">^</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* seperate prefix from type */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[61]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-tag-char"></a>ns-tag-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-esc-sequence">ns-esc-sequence</a><br />
+              | ( &#8220;<span class="quote">%</span>&#8221; <a href="#ns-hex-digit">ns-hex-digit</a> x 2 )<br />
+              | ( <a href="#ns-char">ns-char</a> - <a href="#c-escape">&#8220;<span class="quote">\</span>&#8221;</a> - <a href="#c-prefix">&#8220;<span class="quote">^</span>&#8221;</a> - &#8220;<span class="quote">%</span>&#8221; )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* characters valid in a tag */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[62]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-mundane-tag-char"></a>ns-mundane-tag-char</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-tag-char">ns-tag-char</a> - &#8220;<span class="quote">:</span>&#8221; - &#8220;<span class="quote">/</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* non-magical URI character */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[63]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-ns-tag-property"></a>c-ns-tag-property</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-tag">&#8220;<span class="quote">!</span>&#8221;</a><br />
+              ( /* empty (implicit) */<br />
+              | <a href="#c-ns-private-tag">c-ns-private-tag</a><br />
+              | <a href="#ns-ns-global-tag">ns-ns-global-tag</a><br />
+              | ( Prefix-of-above?<br />
+                  <a href="#c-prefix">&#8220;<span class="quote">^</span>&#8221;</a><br />
+                  Suffix-of-above ) )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* collection tag */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[64]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-ns-private-tag"></a>c-ns-private-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-tag">&#8220;<span class="quote">!</span>&#8221;</a> <a href="#ns-tag-char">ns-tag-char</a>+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* private tags */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[65]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-global-tag"></a>ns-ns-global-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-ns-core-tag">ns-ns-core-tag</a><br />
+              | <a href="#ns-ns-vocabulary-tag">ns-ns-vocabulary-tag</a><br />
+              | <a href="#ns-ns-domain-tag">ns-ns-domain-tag</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* global tags */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[66]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-core-tag"></a>ns-ns-core-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              ( <a href="#ns-mundane-tag-char">ns-mundane-tag-char</a><br />
+              - <a href="#c-tag">&#8220;<span class="quote">!</span>&#8221;</a> )<br />
+              <a href="#ns-mundane-tag-char">ns-mundane-tag-char</a>*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* shorthand for
+              <b class="userinput"><tt>tag:yaml.org,2002:</tt></b><tt class="varname">type</tt>
+              names */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[67]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-vocabulary-tag"></a>ns-ns-vocabulary-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-word-char">ns-word-char</a>+ &#8220;<span class="quote">/</span>&#8221; <a href="#ns-tag-char">ns-tag-char</a>*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* shorthand for
+              <b class="userinput"><tt>tag:vocabulary.yaml.org,2002:</tt></b><tt class="varname">type</tt>
+              names */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[68]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-domain-tag"></a>ns-ns-domain-tag</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-word-char">ns-word-char</a>+<br />
+              ( &#8220;<span class="quote">.</span>&#8221; <a href="#ns-word-char">ns-word-char</a>+ )<br />
+              &#8220;<span class="quote">,</span>&#8221; <a href="#ns-ns-domain-year">ns-ns-domain-year</a><br />
+              ( &#8220;<span class="quote">-</span>&#8221; <a href="#ns-ns-domain-day-month">ns-ns-domain-day-month</a><br />
+                ( &#8220;<span class="quote">-</span>&#8221; <a href="#ns-ns-domain-day-month">ns-ns-domain-day-month</a> )? )?<br />
+              &#8220;<span class="quote">/</span>&#8221; <a href="#ns-tag-char">ns-tag-char</a>*
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* shorthand for
+              <b class="userinput"><tt>tag:domain,date:</tt></b><tt class="varname">type</tt>
+              names */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[69]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-domain-year"></a>ns-ns-domain-year</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-decimal-digit">ns-decimal-digit</a> x 4
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* tag domain ownership year */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[70]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-domain-day-month"></a>ns-ns-domain-day-month</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-decimal-digit">ns-decimal-digit</a> x 2
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* tag domain ownership day or month (01 by
+              default) */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2563853"></a>4.3.6. <a id="syntax-anchor"></a>Anchor</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          An anchor is a property that can be used to mark a node for future
+          reference. An <a href="#syntax-alias">alias node</a> can then
+          be used to indicate additional inclusions of an anchored node by
+          specifying the node's anchor.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[71]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-ns-anchor-property"></a>c-ns-anchor-property</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-anchor">&#8220;<span class="quote">&amp;</span>&#8221;</a> <a href="#ns-ns-anchor-name">ns-ns-anchor-name</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* associates an anchor with a given
+              node */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[72]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-anchor-name"></a>ns-ns-anchor-name</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-char">ns-char</a>+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* unique anchor name */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2563922"></a>4.4. <a id="syntax-alias"></a>Alias</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        An alias node is a place holder for subsequent occurrences of a
+        previously serialized node. The first occurence of the node must be
+        marked by an <a href="#syntax-anchor">anchor</a> to allow
+        subsequent occurences to be represented as alias nodes.
+      </p>
+          <p>
+        An alias refers to the most recent <a href="#model-key-order">preceding</a> node having the same
+        anchor. It is an error to have an alias use an anchor that does not
+        occur previously in the serialization of the documeht. It is not an
+        error to have an anchor that is not used by any alias node.
+      </p>
+          <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+            <tr>
+              <td>
+                <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[73]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-alias-top-node"></a>s-l-alias-top-node</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#s-char">s-char</a> <a href="#ns-ns-alias-flow-node">ns-ns-alias-flow-node</a><br />
+            <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+            <a href="#l-comment(n)">l-comment(any)</a>*
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* alias node outside flow
+            collection */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[74]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-alias-flow-node"></a>ns-ns-alias-flow-node</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#c-alias">&#8220;<span class="quote">*</span>&#8221;</a> <a href="#ns-ns-anchor-name">ns-ns-anchor-name</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* alias node inside flow collection */<br /></td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <div class="example">
+            <a id="id2564014"></a>
+            <p class="title">
+              <b>Example 4.18. </b>
+            </p>
+            <pre class="programlisting">
+anchor : &amp;A001 This scalar has an anchor.
+override : &amp;A001 The alias node below is a repeated use of this value.
+alias : *A001
+</pre>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2564024"></a>4.5. <a id="syntax-collect"></a>Collection</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        Collection nodes come in two kinds, <a href="#syntax-collect-seq">sequence</a> and <a href="#syntax-collect-map">mapping</a>. Each kind has two styles,
+        block and flow. Block styles begin on the next line and use indentation
+        for internal structure. Flow collection styles start on the current
+        line, may span multiple lines, and rely on indicators to represent
+        internal structure.
+      </p>
+          <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+            <tr>
+              <td>
+                <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[75]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-collect-top-node(n)"></a>s-l-collect-top-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#s-l-collect-blk-node(n)">s-l-collect-blk-node(n)</a><br />
+            | ( <a href="#s-s-required(n)">s-s-required(n)</a><br />
+                <a href="#c-c-collect-flow-node(n)">c-c-collect-flow-node(n)</a><br />
+                <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+                <a href="#l-comment(n)">l-comment(any)</a>* )
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* collection node outside flow
+            collection */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[76]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="l-l-collect-top-flow-node(n)"></a>l-l-collect-top-flow-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#i-spaces(n)">i-spaces(n)</a><br />
+            <a href="#c-c-collect-flow-node(n)">c-c-collect-flow-node(n)</a><br />
+            <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+            <a href="#l-comment(n)">l-comment(any)</a>*
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* top-level (document) flow collection
+            node */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[77]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="c-c-collect-flow-node(n)"></a>c-c-collect-flow-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#c-ns-properties">c-ns-properties</a> <a href="#s-char">s-char</a>+ )?<br />
+            <a href="#c-c-collect-flow-value(n)">c-c-collect-flow-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* collection node in flow style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[78]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-collect-blk-node(n)"></a>s-l-collect-blk-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#s-char">s-char</a>+ <a href="#c-ns-properties">c-ns-properties</a> )?<br />
+            <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+            <a href="#l-comment(n)">l-comment(any)</a>*<br />
+            <a href="#l-l-collect-blk-value(n)">l-l-collect-blk-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* collection node in block style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[79]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="l-l-collect-blk-value(n)"></a>l-l-collect-blk-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#l-l-blk-seq-value(n)">l-l-blk-seq-value(n)</a><br />
+            | <a href="#l-l-blk-map-value(n)">l-l-blk-map-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* collection value in block style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[80]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="c-c-collect-flow-value(n)"></a>c-c-collect-flow-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#c-c-flow-seq-value(n)">c-c-flow-seq-value(n)</a><br />
+            | <a href="#c-c-flow-map-value(n)">c-c-flow-map-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* collection value in flow style */<br /></td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <p>
+        To enable line spanning in flow collections, wherever tokens may be
+        separated by white space it is possible to end the line (with an
+        optional throwaway comment) and continue the collection in the next
+        line. Line spanning functionality is indicated by the use of the <a href="#s-s-optional(n)"><b class="userinput"><tt>s-s-optional(n)</tt></b></a>
+        space and the <a href="#s-s-required(n)"><b class="userinput"><tt>s-s-required(n)</tt></b></a>
+        space productions.
+      </p>
+          <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+            <tr>
+              <td>
+                <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[81]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-s-optional(n)"></a>s-s-optional(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#s-char">s-char</a>*<br />
+            | ( <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+                <a href="#i-spaces(n)">i-spaces(n)</a> <a href="#s-char">s-char</a>+ )
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* optional white space separating
+            tokens */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[82]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-s-required(n)"></a>s-s-required(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#s-char">s-char</a>+<br />
+            | ( <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+                <a href="#i-spaces(n)">i-spaces(n)</a> <a href="#s-char">s-char</a>+ )
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* required white space separating
+            tokens */<br /></td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2564419"></a>4.5.1. <a id="syntax-collect-seq"></a>Sequence</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A sequence node is an ordered collection of sub-nodes, where each
+          subordinate node has a higher indentation level. A flow  style is
+          available for short, simple sequences. For syntax compactness, if a
+          sub-sequence node has no properties, and its  first entry is
+          specified without any properties, the sub-sequence may immediately
+          follow the sequence entry indicator.
+        </p>
+            <p>
+          TODO: Talk about the single-key map.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[83]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-blk-seq-value(n)"></a>l-l-blk-seq-value(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              ( <a href="#i-spaces(n)">i-spaces(n-1)</a><br />
+                <a href="#c-l-blk-seq-entry(n)">c-l-blk-seq-entry(n-1)</a> )+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* sequence value in block style;
+              <b class="userinput"><tt>-1</tt></b> unless the block sequence is the value
+              of an entry of a parent block sequence */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[84]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-l-blk-seq-entry(n)"></a>c-l-blk-seq-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-sequence-entry">&#8220;<span class="quote">-</span>&#8221;</a>
+              <a href="#s-l-inline-node(n)">s-l-inline-node(n)</a><br />
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* block sequence node entry */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[85]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="s-l-inline-node(n)"></a>s-l-inline-node(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#s-l-top-node(n)">s-l-top-node(&gt;n)</a><br />
+              | <a href="#i-l-inline-seq(n)">i-l-inline-seq(n)</a><br />
+              | <a href="#i-l-inline-map(n)">i-l-inline-map(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* top node or a shorthand inline
+              collection */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[86]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="i-l-inline-seq(n)"></a>i-l-inline-seq(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(m)</a><br />
+              <a href="#c-l-blk-seq-entry(n)">c-l-blk-seq-entry(n+m+1)</a><br />
+              <a href="#l-l-blk-seq-value(n)">l-l-blk-seq-value(n+m+1)</a>?
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* inline sequence node with no properties
+              (where <tt class="varname">m</tt> &gt; 0) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[87]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-c-flow-seq-value(n)"></a>c-c-flow-seq-value(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-sequence-start">&#8220;<span class="quote">[</span>&#8221;</a><br />
+              <a href="#s-s-optional(n)">s-s-optional(n)</a><br />
+              ( <a href="#ns-ns-flow-seq-entry(n)">ns-ns-flow-seq-entry(n)</a><br />
+                <a href="#s-s-optional(n)">s-s-optional(n)</a><br />
+                ( <a href="#c-collect-entry">&#8220;<span class="quote">,</span>&#8221;</a>
+              <a href="#s-s-required(n)">s-s-required(n)</a><br />
+                  <a href="#ns-ns-flow-seq-entry(n)">ns-ns-flow-seq-entry(n)</a><br />
+                  <a href="#s-s-optional(n)">s-s-optional(n)</a> )* )?<br />
+              <a href="#c-sequence-end">&#8220;<span class="quote">]</span>&#8221;</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* sequence value in flow style */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[88]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-flow-seq-entry(n)"></a>ns-ns-flow-seq-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#ns-ns-flow-value-node(n)">ns-ns-flow-value-node(n)</a><br />
+              | <a href="#ns-ns-flow-pair-map(n)">ns-ns-flow-pair-map(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* flow style sequence entry */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2564804"></a>
+              <p class="title">
+                <b>Example 4.19. </b>
+              </p>
+              <pre class="programlisting">
+empty: []
+flow: [ one, two, three # May span lines,
+         , four,        # indentation is
+           five ]       # mostly ignored.
+block:
+- Note indicator is not indented.
+-
+ - Subordinate sequence entry (note must be indented).
+ - Another entry in subordinate sequence
+- - Another way to write a sub-sequence
+  - Another entry in sub-sequence
+- &gt;
+ A folded sequence entry (fifth entry)
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2564813"></a>4.5.2. <a id="syntax-collect-map"></a>Mapping</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A mapping node is an unordered association of unique keys with
+          values. It is an error for two <a href="#model-equality">equal</a> key entries to
+          appear in the same mapping node. In such a case the processor may
+          continue, ignoring the second key and issuing an appropriate warning.
+          This strategy preserves a consistent information model for streaming
+          and random access applications.
+        </p>
+            <p>
+          A flow form is available for short, simple mapping nodes. For syntax
+          compactness, if a mapping node has no properties, and its  first key
+          is specified as a flow scalar without any properties,  this first key
+          may immediately follow the sequence entry indicator.
+        </p>
+            <p>
+          TODO: Talk about optional ':'.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[89]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-blk-map-value(n)"></a>l-l-blk-map-value(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              ( <a href="#i-spaces(n)">i-spaces(n)</a><br />
+                <a href="#ns-l-blk-map-entry(n)">ns-l-blk-map-entry(n)</a> )+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* mapping value in block style */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[90]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="i-l-inline-map(n)"></a>i-l-inline-map(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(m)</a><br />
+              <a href="#ns-ns-scalar-key-value(n)">ns-ns-scalar-key-value(n+m+1)</a><br />
+              <a href="#s-char">s-char</a>*
+              <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a><br />
+              <a href="#s-l-top-node(n)">s-l-top-node(&gt;n+m+1)</a><br />
+              <a href="#l-l-blk-map-value(n)">l-l-blk-map-value(n+m+1)</a>?
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* inline mapping node with no properties
+              (where <tt class="varname">m</tt> &gt; 0) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[91]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-l-blk-map-entry(n)"></a>ns-l-blk-map-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-l-simple-map-entry(n)">ns-l-simple-map-entry(n)</a><br />
+              <a href="#ns-l-complex-map-entry(n)">ns-l-complex-map-entry(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* block key:value pair */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[92]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-l-simple-map-entry(n)"></a>ns-l-simple-map-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-ns-flow-key-node(n)">ns-ns-flow-key-node(n)</a>
+              <a href="#s-char">s-char</a>*
+              <br />
+              <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a>
+              <a href="#s-l-top-node(n)">s-l-top-node(&gt;n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* simple key:value pair */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[93]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-l-complex-map-entry(n)"></a>ns-l-complex-map-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-complex-key">&#8220;<span class="quote">?</span>&#8221;</a>
+              <a href="#s-l-inline-node(n)">s-l-inline-node(n)</a><br />
+              ( <a href="#i-spaces(n)">i-spaces(n)</a><br />
+                <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a>
+              <a href="#s-l-inline-node(n)">s-l-inline-node(n)</a> )?
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* complex key:value pair */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[94]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-c-flow-map-value(n)"></a>c-c-flow-map-value(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-mapping-start">&#8220;<span class="quote">{</span>&#8221;</a><br />
+              <a href="#s-s-optional(n)">s-s-optional(n)</a><br />
+              ( <a href="#ns-ns-flow-map-entry(n)">ns-ns-flow-map-entry(n)</a><br />
+                <a href="#s-s-optional(n)">s-s-optional(n)</a><br />
+                ( <a href="#c-collect-entry">&#8220;<span class="quote">,</span>&#8221;</a>
+              <a href="#s-s-required(n)">s-s-required(n)</a><br />
+                  <a href="#ns-ns-flow-map-entry(n)">ns-ns-flow-map-entry(n)</a><br />
+                  <a href="#s-s-optional(n)">s-s-optional(n)</a> )* )?<br />
+              <a href="#c-mapping-end">&#8220;<span class="quote">}</span>&#8221;</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* mapping value in flow style */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[95]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-flow-map-entry(n)"></a>ns-ns-flow-map-entry(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-ns-flow-key-node(n)">ns-ns-flow-key-node(n)</a><br />
+              ( <a href="#s-char">s-char</a>*
+              <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a><br />
+                <a href="#s-s-required(n)">s-s-required(n)</a><br />
+                <a href="#ns-ns-flow-value-node(n)">ns-ns-flow-value-node(n)</a> )?
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* flow key:value pair */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[96]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-flow-pair-map(n)"></a>ns-ns-flow-pair-map(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-ns-flow-key-node(n)">ns-ns-flow-key-node(n)</a><br />
+              <a href="#s-char">s-char</a>*
+              <a href="#c-mapping-entry">&#8220;<span class="quote">:</span>&#8221;</a><br />
+              <a href="#s-s-required(n)">s-s-required(n)</a><br />
+              <a href="#ns-ns-flow-value-node(n)">ns-ns-flow-value-node(n)</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* single key:value pair map in flow sequence */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2565323"></a>
+              <p class="title">
+                <b>Example 4.20. </b>
+              </p>
+              <pre class="programlisting">
+empty: {}
+null values: { one, two }
+flow: { one: 1, two: 2 }
+two equal maps in a sequence: [ key: value, { &quot;key&quot; : value } ]
+spanning: { one: 1,
+   two: 2 }
+block:
+ key : value
+ nested mapping:
+  key: Subordinate mapping
+ nested sequence:
+  - Subordinate sequence
+!float 12 : This key is a float.
+&quot;\a&quot; : This key had to be escaped.
+? '?'
+: This key had to be quoted.
+? &gt;
+ This is a multi
+ line folded key
+: Whose value is
+  also multi-line.
+? This key has implicit null value
+?
+ - This key
+ - is a sequence
+: - With a sequence value.
+? This: key
+  is a: mapping
+:
+ with a: mapping value.
+---
+- A key: value pair in a sequence.
+  A second: key:value pair.
+- The previous entry is equal to the following one.
+-
+ A key:
+     value pair in a sequence.
+ A second:
+     key:value pair.
+</pre>
+            </div>
+          </div>
+        </div>
+        <div class="sect1" lang="en" xml:lang="en">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title" style="clear: both"><a id="id2565334"></a>4.6. <a id="syntax-scalar"></a>Scalar</h2>
+              </div>
+            </div>
+            <div></div>
+          </div>
+          <p>
+        While most of the document productions are fairly strict, the scalar
+        production is generous. It offers three flow style variants and two
+        block style variants to choose from, depending upon the readability
+        requirements.
+      </p>
+          <p>
+        Additionally, <a href="#syntax-space-comment">Throwaway
+        comments</a> may follow a scalar  node, but may not appear inside
+        one. The comment lines following a  block scalar node must be less
+        indented than the block scalar value. Empty lines in a scalar node
+        that are followed by a non-empty content  line are interpreted as
+        content rather than as implicit comments. Such lines may be less
+        indented than the text content.
+      </p>
+          <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+            <tr>
+              <td>
+                <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[97]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-scalar-top-node(n)"></a>s-l-scalar-top-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#s-l-scalar-top-blk-node(n)">s-l-scalar-top-blk-node(n)</a><br />
+            | <a href="#s-l-scalar-top-flow-node(n)">s-l-scalar-top-flow-node(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar node outside flow
+            collection */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[98]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-scalar-top-blk-node(n)"></a>s-l-scalar-top-blk-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#s-char">s-char</a>+ <a href="#c-ns-properties">c-ns-properties</a> )?<br />
+            <a href="#s-char">s-char</a>+ <a href="#c-l-scalar-blk-value(n)">c-l-scalar-blk-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar node outside flow collection, in block
+            style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[99]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="s-l-scalar-top-flow-node(n)"></a>s-l-scalar-top-flow-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            <a href="#s-s-required(n)">s-s-required(n)</a><br />
+            ( <a href="#c-ns-properties">c-ns-properties</a> <a href="#s-char">s-char</a>+ )?<br />
+            <a href="#ns-ns-scalar-top-value(n)">ns-ns-scalar-top-value(n)</a><br />
+            <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+            <a href="#l-comment(n)">l-comment(any)</a>*
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar node outside flow collection, in flow
+            style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[100]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-scalar-flow-value-node(n)"></a>ns-ns-scalar-flow-value-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#c-ns-properties">c-ns-properties</a> <a href="#s-char">s-char</a>+ )?<br />
+            <a href="#ns-ns-scalar-flow-value(n)">ns-ns-scalar-flow-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar node inside flow collection, used as
+            value */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[101]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-scalar-flow-key-node(n)"></a>ns-ns-scalar-flow-key-node(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+            ( <a href="#c-ns-properties">c-ns-properties</a> <a href="#s-char">s-char</a>+ )?<br />
+            <a href="#ns-ns-scalar-key-value(n)">ns-ns-scalar-key-value(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar node inside flow collection, used as
+            key */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[102]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="c-l-scalar-blk-value(n)"></a>c-l-scalar-blk-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#c-l-literal(n)">c-l-literal(n)</a><br />
+            | <a href="#c-l-folded(n)">c-l-folded(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar value in block style */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[103]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-scalar-flow-value(n)"></a>ns-ns-scalar-flow-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#c-c-single-quoted(n)">c-c-single-quoted(n)</a><br />
+            | <a href="#c-c-double-quoted(n)">c-c-double-quoted(n)</a><br />
+            | <a href="#ns-ns-plain-flow(n)">ns-ns-plain-flow(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar value in flow style, used as value, inside
+            flow collection */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[104]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-scalar-top-value(n)"></a>ns-ns-scalar-top-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#c-c-single-quoted(n)">c-c-single-quoted(n)</a><br />
+            | <a href="#c-c-double-quoted(n)">c-c-double-quoted(n)</a><br />
+            | <a href="#ns-ns-plain-top(n)">ns-ns-plain-top(n)</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar value in flow style, used as value, outside
+            flow collection */<br /></td>
+                  </tr>
+                  <tr>
+                    <td align="left" valign="top" class="productioncounter">[105]</td>
+                    <td align="right" valign="top" class="productionlhs"><a id="ns-ns-scalar-key-value(n)"></a>ns-ns-scalar-key-value(n)</td>
+                    <td valign="top" class="productionseperator" align="center">
+                      <tt>::=</tt>
+                    </td>
+                    <td valign="top" class="productionrhs">
+            
+              <a href="#c-c-single-quoted(n)">c-c-single-quoted(n)</a><br />
+            | <a href="#c-c-double-quoted(n)">c-c-double-quoted(n)</a><br />
+            | <a href="#ns-ns-plain-key">ns-ns-plain-key</a>
+          </td>
+                    <td align="left" valign="top" class="productioncomment">/* scalar value in flow style, used as
+            key */<br /></td>
+                  </tr>
+                </table>
+              </td>
+            </tr>
+          </table>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2565848"></a>4.6.1. 
+          <a id="syntax-scalar-norm"></a>
+          End Of line Normalization
+        </h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Inside all scalar nodes, a compliant YAML processor must translate
+          the two-character combination <a href="#b-carriage-return">CR</a> <a href="#b-line-feed">LF</a>, any <a href="#b-carriage-return">CR</a> that is not followed by an
+          <a href="#b-line-feed">LF</a>, and any <a href="#b-next-line">NEL</a> into a single <a href="#b-line-feed">LF</a> (this does not apply to <a href="#syntax-escape">escaped characters</a>). <a href="#b-line-separator">LS</a> and <a href="#b-paragraph-separator">PS</a> characters are preserved.
+          These rules are compatible with Unicode's <a href="http://www.unicode.org/unicode/reports/tr13/" target="_top">newline
+          guidelines</a>.
+        </p>
+            <p>
+          Normalization functionality is indicated by the use of the <a href="#b-as-line-feed"><b class="userinput"><tt>b-as-line-feed</tt></b></a>
+          production defined below.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[106]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-as-line-feed"></a>b-as-line-feed</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#b-generic">b-generic</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* line break converted to a line
+              feed */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[107]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="b-normalized"></a>b-normalized</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#b-as-line-feed">b-as-line-feed</a> | <a href="#b-specific">b-specific</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* a normalized end of line marker */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <p>
+          On output, a YAML processor is free to serialize end of line markers
+          using whatever convention is most appropriate, though again <a href="#b-line-separator">LS</a> and <a href="#b-paragraph-separator">PS</a> must be preserved.
+        </p>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2565992"></a>4.6.2. <a id="syntax-scalar-mod"></a>Block Modifiers</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Each block scalar may have <a href="#syntax-scalar-indent">explicit indentation</a> and
+          <a href="#syntax-scalar-chomp">chomping</a> modifiers.
+          These modifiers are specified following the block style indicator.
+          It is an error for the same modifier to be specified more than
+          once for the same node.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[108]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-ns-blk-modifiers"></a>ns-ns-blk-modifiers</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                ( <a href="#ns-explicit-indent">ns-explicit-indent</a><br />
+                  <a href="#c-chomp-control">c-chomp-control</a>? )<br />
+              | ( <a href="#c-chomp-control">c-chomp-control</a><br />
+                  <a href="#ns-explicit-indent">ns-explicit-indent</a>? )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* block scalar modifiers */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2566128"></a>4.6.3. 
+          <a id="syntax-scalar-indent"></a>
+          Explicit Indentation
+        </h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Typically the indentation level of a block scalar node is detected
+          from its first non-empty content line. This detection fails when this
+          first non-empty line contains leading white space characters. Note
+          that content lines, including the first non-empty content line, may
+          begin with a &#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221; character.
+        </p>
+            <p>
+          When the first non-empty content line begins with spaces, YAML
+          requires that the indentation level for the scalar node text content
+          be given explicitly. This level is specified as the integer number of
+          the additional indentation spaces used for the text content.
+        </p>
+            <p>
+          If the block scalar begins with lines containing only spaces, and no
+          explicit indentation is given, the processor assumes such lines are
+          empty lines. It is an error for any such leading empty line to
+          contain more spaces than the indentation level that is deduced from
+          the first non-empty content line.
+        </p>
+            <p>
+          The indentation level is always non-zero, except for the top level
+          node of each document. This node is commonly indented by zero spaces
+          (not indented). When the content is not indented, all lines up to the
+          next document separator, document terminator, or end of the stream
+          are assumed to be content lines, even if they begin with a
+          &#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221; character. Note that in this
+          case, all lines up to the next document seperator are assumed to be
+          content lines, even if they begin with a
+          &#8220;<span class="quote"><b class="userinput"><tt>#</tt></b></span>&#8221; character.
+        </p>
+            <p>
+          It is always valid to specify an explicit indentation level, though a
+          YAML processor should only do so in cases where detection fails. It
+          is an error for detection to fail when there is no explicit
+          indentation specified.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[109]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="ns-explicit-indent"></a>ns-explicit-indent</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#ns-decimal-digit">ns-decimal-digit</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* explicit additional indentation
+              level */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2566333"></a>
+              <p class="title">
+                <b>Example 4.21. </b>
+              </p>
+              <pre class="programlisting">
+# Explicit indentation must be given
+# in both the following cases.
+leading spaces: |2
+      This value starts with four spaces.
+
+leading spaces after empty lines: |2
+
+      This value starts with four spaces.
+
+# The following is valid:
+leading comment indicator: |
+
+  # Content line starts with a '#'
+  character, and follows empty lines.
+
+# This is a comment because it is not
+# more indented than the base level.
+# Since blocks may not contain comments,
+# this ends the block and the following
+# empty line is not a content line.
+
+# Explicit indentation may
+# also be given when it is
+# not required.
+redundant: |2
+  This value is indented 2 spaces.
+
+# Indentation applies to top level nodes.
+--- |
+Usually top level nodes are not indented.
+--- |
+  This text is indented two spaces.
+  It contains no leading spaces.
+--- |0
+  This text contains two leading spaces.
+---
+This text is not indented, so
+# this is a content line and
+--- |
+  However, this is indented two spaces
+# So this is a comment ending the block.
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2566343"></a>4.6.4. <a id="syntax-scalar-chomp"></a>Chomping</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Typically the final line break of a block scalar is considered to be
+          a part of its value, and any trailing empty lines are taken to be
+          <a href="#l-empty-comment(n)">comment lines</a>. This default
+          <a id="id2566359" class="indexterm"></a><i class="firstterm">clip</i> chomping behavior can be overriden by
+          specifying a chomp control modifier.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[110]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-chomp-control"></a>c-chomp-control</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#c-strip-chomp">c-strip-chomp</a><br />
+              | <a href="#c-keep-chomp">c-keep-chomp</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* override the default &quot;clip&quot;
+              chomping */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[111]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-strip-chomp"></a>c-strip-chomp</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">-</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* strip final line break from
+              value */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[112]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-keep-chomp"></a>c-keep-chomp</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              &#8220;<span class="quote">+</span>&#8221;
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* keep trailing line breaks in
+              value */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="variablelist">
+              <dl>
+                <dt>
+                  <span class="term">
+                <a id="id2566444" class="indexterm"></a><i class="firstterm">strip</i>
+                (&#8220;<span class="quote"><b class="userinput"><tt>-</tt></b></span>&#8221;)
+            </span>
+                </dt>
+                <dd>
+              The &#8220;<span class="quote"><b class="userinput"><tt>-</tt></b></span>&#8221; chomp control
+              specifies that the final line break character of the block scalar
+              should be stripped from its value.
+            </dd>
+                <dt>
+                  <span class="term">
+                <a id="id2566476" class="indexterm"></a><i class="firstterm">keep</i>
+                (&#8220;<span class="quote"><b class="userinput"><tt>+</tt></b></span>&#8221;)
+            </span>
+                </dt>
+                <dd>
+              The &#8220;<span class="quote"><b class="userinput"><tt>+</tt></b></span>&#8221; chomp control
+              specifies that any trailing empty lines following the block
+              scalar should be considered to be a part of its value. If this
+              modifier is not specified, such lines are considered to be empty
+              throwaway comment lines and are ignored.
+            </dd>
+              </dl>
+            </div>
+            <p>
+          When this functionality is implied, the <a href="#l-l-empty-trailing(n)"><b class="userinput"><tt>l-l-empty-trailing(n)</tt></b></a> production will
+          be used.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[113]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-empty-trailing(n)"></a>l-l-empty-trailing(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                <a href="#l-empty-comment(n)">l-empty-comment(n)</a>+<br />
+              | <a href="#l-blk-empty-line-feed(n)">l-blk-empty-line-feed(n)</a>+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* trailing line feeds or comment lines, depending
+              on chomp control) */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[114]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-blk-empty-line-feed(n)"></a>l-blk-empty-line-feed(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(&#8804;n)</a> <a href="#b-as-line-feed">b-as-line-feed</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* empty block line */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2566710"></a>
+              <p class="title">
+                <b>Example 4.22. </b>
+              </p>
+              <pre class="programlisting">
+clipped: |
+    This has one newline.
+
+same as &quot;clipped&quot; above: &quot;This has one newline.\n&quot;
+
+stripped: |-
+    This has no newline.
+
+same as &quot;stripped&quot; above: &quot;This has no newline.&quot;
+
+kept: |+
+    This has two newlines.
+
+same as &quot;kept&quot; above: &quot;This has two newlines.\n\n&quot;
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2566720"></a>4.6.5. <a id="syntax-scalar-literal"></a>Literal</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          A literal scalar is the simplest scalar style. No processing is
+          performed on literal scalar characters aside from <a href="#syntax-scalar-norm">end of line normalization</a> and
+          stripping away the <a href="#syntax-indentation">indentation</a>. Indentation is
+          detected from the first non-empty content line. <a href="#syntax-scalar-indent">Explicit indentation</a> must be
+          specified in case this yields the wrong result.
+        </p>
+            <p>
+          Since escaping is not done, the literal style is restricted to <a href="#c-printable">printable characters</a> and long lines
+          cannot be wrapped. In exchange for these restrictions, literal
+          scalars are the  most readable format for source code or other text
+          values with  significant use of indicators, quotes, escape sequences,
+          and  line breaks.
+        </p>
+            <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+              <tr>
+                <td>
+                  <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[115]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="c-l-literal(n)"></a>c-l-literal(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#c-literal">&#8220;<span class="quote">|</span>&#8221;</a>
+              <a href="#ns-ns-blk-modifiers">ns-ns-blk-modifiers</a>?<br />
+              <a href="#s-b-trailing-comment">s-b-trailing-comment</a><br />
+              <a href="#l-l-literal-value(n)">l-l-literal-value(n)</a>?<br />
+              <a href="#l-l-empty-trailing(n)">l-l-empty-trailing(n)</a>?<br />
+              ( <a href="#l-text-comment(n)">l-text-comment(&lt;n)</a><br />
+                <a href="#l-comment(n)">l-comment(any)</a>* )?
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* literal scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[116]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-literal-value(n)"></a>l-l-literal-value(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#l-l-literal-chunk(n)">l-l-literal-chunk(n)</a>+
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* value of literal scalar */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[117]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-l-literal-chunk(n)"></a>l-l-literal-chunk(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#l-blk-empty-line-feed(n)">l-blk-empty-line-feed(n)</a>*<br />
+              ( <a href="#l-literal-text(n)">l-literal-text(n)</a><br />
+              | <a href="#l-blk-empty-specific(n)">l-blk-empty-specific(n)</a> )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* chunk of literal scalar lines */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[118]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-blk-empty-specific(n)"></a>l-blk-empty-specific(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+              <a href="#i-spaces(n)">i-spaces(&#8804;n)</a> <a href="#b-specific">b-specific</a>
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* empty block line with preserved specific line
+              break */<br /></td>
+                    </tr>
+                    <tr>
+                      <td align="left" valign="top" class="productioncounter">[119]</td>
+                      <td align="right" valign="top" class="productionlhs"><a id="l-literal-text(n)"></a>l-literal-text(n)</td>
+                      <td valign="top" class="productionseperator" align="center">
+                        <tt>::=</tt>
+                      </td>
+                      <td valign="top" class="productionrhs">
+              
+                ( <a href="#i-spaces(n)">i-spaces(n)</a> <a href="#nb-char">nb-char</a>+ <a href="#b-normalized">b-normalized</a> )<br />
+              - ( <a href="#l-forbidden-non-indented">l-forbidden-non-indented</a> <a href="#b-any">b-any</a> )
+            </td>
+                      <td align="left" valign="top" class="productioncomment">/* literal line character data */<br /></td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+            <div class="example">
+              <a id="id2566934"></a>
+              <p class="title">
+                <b>Example 4.23. </b>
+              </p>
+              <pre class="programlisting">
+empty: |
+
+literal: |
+ The \ ' &quot; characters may be
+ freely used. Leading white
+    space is significant.
+
+ Line breaks are significant. Thus this value
+ contains one empty line and ends with a single
+ line break, but does not start with one.
+
+is equal to: &quot;The \\ ' \&quot; characters may \
+ be\nfreely used. Leading white\n   space \
+ is significant.\n\nLine breaks are \
+ significant. Thus this value\ncontains \
+ one empty line and ends with a single\nline \
+ break, but does not start with one.\n&quot;
+
+# Comments may follow a block scalar value.
+# They must be less indented.
+
+# Modifiers may be combined in any order.
+indented and chomped: |2-
+    This has no newline.
+
+also written as: |-2
+    This has no newline.
+
+both are equal to: &quot;  This has no newline.&quot;
+</pre>
+            </div>
+          </div>
+          <div class="sect2" lang="en" xml:lang="en">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="id2566944"></a>4.6.6. <a id="syntax-scalar-folding"></a>Folding</h3>
+                </div>
+              </div>
+              <div></div>
+            </div>
+            <p>
+          Folding supports scenarios where word-wrapping is useful for
+          presentation, where the serialized content does not contain line
+          breaks at convenient places.
+
+          <i><span class="remark">
+            TODO: Rephrase.
+          </span></i>
+        </p>
+            <p>
+          When folding is done, a single <a href="#b-as-line-feed">normalized line feed</a> is converted to
+          a single space (<b class="userinput"><tt>#x20</tt></b>). When two or more
+          consecutive (possibly indented) normalized line feeds are
+          encountered, the processor does not convert them into spaces.
+          Instead, the parser ignores the first line feed and preserves the
+          rest. Thus a single line feed can be serialized as two, two line
+          feeds can be serialized as three, etc. In this process, <a href="#b-specific">specific line breaks</a> are preserved and
+          may be safely used to convey text structure.
+        </p>
+            <p>
+          Since scalars come in both a block and flow variants, folding
+          behavior must be defined in both contexts.
+
+        </p>
+            <div class="sect3" lang="en" xml:lang="en">
+              <div class="titlepage">
+                <div>
+                  <div>
+                    <h4 class="title"><a id="id2567052"></a>4.6.6.1. 
+            <a id="syntax-scalar-folding-block"></a>
+            Folding in a block context
+          </h4>
+                  </div>
+                </div>
+                <div></div>
+              </div>
+              <p>
+            When folding block scalars, space conversion only applies to  line
+            feeds separating text lines having a non-space starting  character.
+            Hence, folding does not apply to leading line feeds, line feeds
+            surrounding a specific line break, or line feeds adjacent to a text
+            line that starts with a space character.
+          </p>
+              <p>
+            The combined effect of the processing rules above is that each
+            &quot;paragraph&quot; is interpreted as a single line, empty lines are used
+            to represent a line feed, and &quot;more indented&quot; lines are preserved.
+            Also, specific line breaks may be safely used to indicate text
+            structure.
+          </p>
+              <table width="100%" cellpadding="5" class="productionset" summary="EBNF">
+                <tr>
+                  <td>
+                    <table border="0" width="99%" cellpadding="0" class="productionset" summary="EBNF productions">
+                      <tr>
+                        <td align="left" valign="top" class="productioncounter">[120]</td>
+                        <td align="right" valign="top" class="productionlhs"><a id="b-as-space"></a>b-as-space</td>
+                        <td valign="top" class="productionseperator" align="center">
+                          <tt>::=</tt>
+                        </td>
+                        <td valign="top" class="productionrhs">
+                
+                <a href="#b-generic">b-generic</a>
+              </td>
+                        <td align="left" valign="top" class="productioncomment">/* line feed converted to a
+                space */<br /></td>
+                      </tr>
+                      <tr>
+                        <td align="left" valign="top" class="productioncounter">[121]</td>
+                        <td align="right" valign="top" class="productionlhs"><a id="b-ignored"></a>b-ignored</td>
+                        <td valign="top" class="productionseperator" align="center">
+                          <tt>::=</tt>
+                        </td>
+                        <t