text: import collections
  import types
  
  from functools import wraps
  
  from powerline.lint.markedjson.error import MarkedError
  
  from powerline.lint.markedjson import nodes
  from powerline.lint.markedjson.markedvalue import gen_marked_value
  from powerline.lib.unicode import unicode
  
  
  def marked(func):
      @wraps(func)
      def f(self, node, *args, **kwargs):
          return gen_marked_value(func(self, node, *args, **kwargs), node.start_mark)
      return f
  
  
  class ConstructorError(MarkedError):
      pass
  
  
  class BaseConstructor:
      yaml_constructors = {}
  
      def __init__(self):
          self.constructed_objects = {}
          self.state_generators = []
          self.deep_construct = False
  
      def check_data(self):
          # If there are more documents available?
          return self.check_node()
  
      def get_data(self):
          # Construct and return the next document.
          if self.check_node():
              return self.construct_document(self.get_node())
  
      def get_single_data(self):
          # Ensure that the stream contains a single document and construct it.
          node = self.get_single_node()
          if node is not None:
              return self.construct_document(node)
          return None
  
      def construct_document(self, node):
          data = self.construct_object(node)
          while self.state_generators:
              state_generators = self.state_generators
              self.state_generators = []
              for generator in state_generators:
                  for dummy in generator:
                      pass
          self.constructed_objects = {}
          self.deep_construct = False
          return data
  
      def construct_object(self, node, deep=False):
          if node in self.constructed_objects:
              return self.constructed_objects[node]
          if deep:
              old_deep = self.deep_construct
              self.deep_construct = True
          constructor = None
          tag_suffix = None
          if node.tag in self.yaml_constructors:
              constructor = self.yaml_constructors[node.tag]
          else:
              raise ConstructorError(None, None, 'no constructor for tag %s' % node.tag)
          if tag_suffix is None:
              data = constructor(self, node)
          else:
              data = constructor(self, tag_suffix, node)
          if isinstance(data, types.GeneratorType):
              generator = data
              data = next(generator)
              if self.deep_construct:
                  for dummy in generator:
                      pass
              else:
                  self.state_generators.append(generator)
          self.constructed_objects[node] = data
          if deep:
              self.deep_construct = old_deep
          return data
  
      @marked
      def construct_scalar(self, node):
          if not isinstance(node, nodes.ScalarNode):
              raise ConstructorError(
                  None, None,
                  'expected a scalar node, but found %s' % node.id,
                  node.start_mark
              )
          return node.value
  
      def construct_sequence(self, node, deep=False):
          if not isinstance(node, nodes.SequenceNode):
              raise ConstructorError(
                  None, None,
                  'expected a sequence node, but found %s' % node.id,
                  node.start_mark
              )
          return [
              self.construct_object(child, deep=deep)
              for child in node.value
          ]
  
      @marked
      def construct_mapping(self, node, deep=False):
          if not isinstance(node, nodes.MappingNode):
              raise ConstructorError(
                  None, None,
                  'expected a mapping node, but found %s' % node.id,
                  node.start_mark
              )
          mapping = {}
          for key_node, value_node in node.value:
              key = self.construct_object(key_node, deep=deep)
              if not isinstance(key, collections.Hashable):
                  self.echoerr(
                      'While constructing a mapping', node.start_mark,
                      'found unhashable key', key_node.start_mark
                  )
                  continue
              elif type(key.value) != unicode:
                  self.echoerr(
                      'Error while constructing a mapping', node.start_mark,
                      'found key that is not a string', key_node.start_mark
                  )
                  continue
              elif key in mapping:
                  self.echoerr(
                      'Error while constructing a mapping', node.start_mark,
                      'found duplicate key', key_node.start_mark
                  )
                  continue
              value = self.construct_object(value_node, deep=deep)
              mapping[key] = value
          return mapping
  
      @classmethod
      def add_constructor(cls, tag, constructor):
          if 'yaml_constructors' not in cls.__dict__:
              cls.yaml_constructors = cls.yaml_constructors.copy()
          cls.yaml_constructors[tag] = constructor
  
  
  class Constructor(BaseConstructor):
      def construct_scalar(self, node):
          if isinstance(node, nodes.MappingNode):
              for key_node, value_node in node.value:
                  if key_node.tag == 'tag:yaml.org,2002:value':
                      return self.construct_scalar(value_node)
          return BaseConstructor.construct_scalar(self, node)
  
      def flatten_mapping(self, node):
          merge = []
          index = 0
          while index < len(node.value):
              key_node, value_node = node.value[index]
              if key_node.tag == 'tag:yaml.org,2002:merge':
                  del node.value[index]
                  if isinstance(value_node, nodes.MappingNode):
                      self.flatten_mapping(value_node)
                      merge.extend(value_node.value)
                  elif isinstance(value_node, nodes.SequenceNode):
                      submerge = []
                      for subnode in value_node.value:
                          if not isinstance(subnode, nodes.MappingNode):
                              raise ConstructorError(
                                  'while constructing a mapping',
                                  node.start_mark,
                                  'expected a mapping for merging, but found %s' % subnode.id,
                                  subnode.start_mark
                              )
                          self.flatten_mapping(subnode)
                          submerge.append(subnode.value)
                      submerge.reverse()
                      for value in submerge:
                          merge.extend(value)
                  else:
                      raise ConstructorError(
                          'while constructing a mapping',
                          node.start_mark,
                          ('expected a mapping or list of mappings for merging, but found %s' % value_node.id),
                          value_node.start_mark
                      )
              elif key_node.tag == 'tag:yaml.org,2002:value':
                  key_node.tag = 'tag:yaml.org,2002:str'
                  index += 1
              else:
                  index += 1
          if merge:
              node.value = merge + node.value
  
      def construct_mapping(self, node, deep=False):
          if isinstance(node, nodes.MappingNode):
              self.flatten_mapping(node)
          return BaseConstructor.construct_mapping(self, node, deep=deep)
  
      @marked
      def construct_yaml_null(self, node):
          self.construct_scalar(node)
          return None
  
      @marked
      def construct_yaml_bool(self, node):
          value = self.construct_scalar(node).value
          return bool(value)
  
      @marked
      def construct_yaml_int(self, node):
          value = self.construct_scalar(node).value
          sign = +1
          if value[0] == '-':
              sign = -1
          if value[0] in '+-':
              value = value[1:]
          if value == '0':
              return 0
          else:
              return sign * int(value)
  
      @marked
      def construct_yaml_float(self, node):
          value = self.construct_scalar(node).value
          sign = +1
          if value[0] == '-':
              sign = -1
          if value[0] in '+-':
              value = value[1:]
          else:
              return sign * float(value)
  
      def construct_yaml_str(self, node):
          return self.construct_scalar(node)
  
      def construct_yaml_seq(self, node):
          data = gen_marked_value([], node.start_mark)
          yield data
          data.extend(self.construct_sequence(node))
  
      def construct_yaml_map(self, node):
          data = gen_marked_value({}, node.start_mark)
          yield data
          value = self.construct_mapping(node)
          data.update(value)
  
      def construct_undefined(self, node):
          raise ConstructorError(
              None, None,
              'could not determine a constructor for the tag %r' % node.tag,
              node.start_mark
          )
  
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:null', Constructor.construct_yaml_null)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:bool', Constructor.construct_yaml_bool)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:int', Constructor.construct_yaml_int)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:float', Constructor.construct_yaml_float)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:str', Constructor.construct_yaml_str)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:seq', Constructor.construct_yaml_seq)
  
  Constructor.add_constructor(
      'tag:yaml.org,2002:map', Constructor.construct_yaml_map)
  
  Constructor.add_constructor(
      None, Constructor.construct_undefined)
  