text: //- bemto
  //- Copyright(c) 2012 Roman Komarov <kizu@kizu.ru>
  //- MIT Licensed
  
  //- Some global variables
  - var bemto_chain = []
  - var bemto_chain_contexts = ['block']
  
  //- Block
  mixin b(options)
    - var settings = get_bemto_settings()
    //- TODO: should we make it generic way for other settings too?
    if options && options.prefix !== undefined
      - settings.prefix = options.prefix
  
    //- Rewriting the class for elements and modifiers
    - var tag = options && options.tag || ( typeof options == 'string' ? options : '')
    - var isElement = options && options.isElement
    - var tagMetadata = options && options.metadata
    - var block_sets_context = false
    if attributes.class
      //- Creating and normalizing bemto classes
      - var bemto_classes = attributes.class
      if bemto_classes instanceof Array
        - bemto_classes = bemto_classes.join(' ')
      - bemto_classes = bemto_classes.split(' ')
  
  
      - var bemto_objects = []
      - var is_first_object = true
      - var new_context = []
  
      each klass, i in bemto_classes
        - var bemto_object = {}
        - var prev_object = bemto_objects[bemto_objects.length - 1]
        - var sets_context = false
  
        //- Catching the optional tag class
        if klass.match(/^[A-Z-]+[A-Z0-9-]?$/)
          - tag = klass.toLowerCase()
          - continue
  
  
        //- Use block as a context for the first class if we're at element
        if is_first_object && isElement
          - bemto_object['context'] = bemto_chain[bemto_chain.length - 1]
  
  
        //- If the class is a modifier, add it to the previous object
        - var modifier_class = klass.match(new RegExp('^(?!' + settings['element'] + '[A-Za-z0-9])' + settings['modifier'] + "(.+)$"))
        //- FIXME: `+b._mod._mod` — raw classes should be treated as raw ones
        if modifier_class && prev_object && prev_object.name
          if !prev_object['modifiers']
            - prev_object['modifiers'] = []
          - prev_object.modifiers.push(modifier_class[1])
          - continue
  
  
        //- Use block as a context for the following classes if we have element delimiter at the start
        - var element_class = klass.match(new RegExp('^(?!' + settings['modifier'] + '[A-Za-z0-9])' + settings['element'] + "(.+)$"))
        if element_class
          - bemto_object['context'] = bemto_chain[bemto_chain.length - 1]
          - klass = element_class[1]
  
  
        //- Set custom context for nested items
        - var name_with_context = klass.match(new RegExp('^(.*[A-Za-z0-9])(?!' + settings['modifier'] + "$)" + settings['element'] + "$"))
        if name_with_context
          - klass = name_with_context[1]
          - bemto_object['is_context'] = true
          - sets_context = true
          - block_sets_context = true
          - isElement = false
  
  
        //- Apply the modifier from the classname if exist
        - var name_with_modifier = klass.match(new RegExp('^(.*?[A-Za-z0-9])(?!' + settings['element'] + '[A-Za-z0-9])' + settings['modifier'] + "(.+)$"))
        if name_with_modifier
          - klass = name_with_modifier[1]
  
          if !bemto_object['modifiers']
            - bemto_object['modifiers'] = []
          - bemto_object.modifiers.push(name_with_modifier[2])
  
        - var found_prefix = ''
        - var prefix_regex_string = '()?'
        if settings.prefix
          - var prefix = settings.prefix
          if typeof prefix === 'string'
            - prefix = { '': prefix }
  
          - var prefix_regex_test = []
          if prefix instanceof Object
            each value, key in prefix
              if typeof key === 'string' && key != '' && prefix_regex_test.indexOf(key) == -1
                - prefix_regex_test.push(key)
              if typeof value === 'string' && value != '' && prefix_regex_test.indexOf(value) == -1
                - prefix_regex_test.push(value)
  
            - prefix_regex_string = '(' + prefix_regex_test.join('|') + ')?'
  
          - var name_with_prefix = klass.match(new RegExp('^' + prefix_regex_string + "([A-Za-z0-9]+.*)$"))
          if name_with_prefix
            - klass = name_with_prefix[2]
            - found_prefix = name_with_prefix[1] || ''
            - found_prefix = prefix[found_prefix]
            if found_prefix === undefined || found_prefix === true
              - found_prefix = name_with_prefix[1]
        - bemto_object['prefix'] = (found_prefix || '').replace(/\-/g, '%DASH%').replace(/\_/g, '%UNDERSCORE%')
  
  
        if sets_context && klass.match(/^[a-zA-Z0-9]+.*/)
          - new_context.push(bemto_object.context ? (bemto_object.context + settings['element'] + klass) : (bemto_object.prefix + klass))
  
        - bemto_object['name'] = klass
        - is_first_object = false
  
        if bemto_object.context && bemto_object.context.length > 1
          each subcontext, i in bemto_object.context
            - var sub_object = clone(bemto_object)
            - sub_object['context'] = [subcontext]
            - bemto_objects.push(sub_object)
        else
          - bemto_objects.push(bemto_object)
  
      //- If no custom context is set, use the first proper object
      if !isElement && !new_context.length && bemto_objects[0] && bemto_objects[0].name && bemto_objects[0].name.match(/^[a-zA-Z0-9]+.*/)
        - bemto_objects[0]['is_context'] = true
        - new_context.push(bemto_objects[0].context ? (bemto_objects[0].context + settings['element'] + bemto_objects[0].name) : (bemto_objects[0].prefix + bemto_objects[0].name))
        - block_sets_context = true
  
      if new_context.length
        //- Use only the block's name for context if we're at strict setting
        if settings.flat_elements
          each subcontext, i in new_context
            - var context_with_element = subcontext.match(new RegExp('^(.*?[A-Za-z0-9])(?!' + settings['modifier'] + '[A-Za-z0-9])' + settings['element'] + ".+$"))
            if context_with_element
              - new_context[i] = context_with_element[1]
        - bemto_chain[bemto_chain.length] = new_context
  
      //- Rendering the classes
      if bemto_objects.length
        - var new_classes = []
        each bemto_object in bemto_objects
          if bemto_object.name
            - var start = bemto_object.prefix
            if bemto_object.context
              - start = bemto_object.context + settings.output_element
            - new_classes.push(start + bemto_object.name)
            if bemto_object.modifiers
              each modifier in bemto_object.modifiers
                - new_classes.push(start + bemto_object.name + settings.output_modifier + modifier)
  
        - var delimiter = settings.class_delimiter
        - delimiter = delimiter ? (' ' + delimiter + ' ') : ' '
        - attributes.class = new_classes.join(delimiter).replace(/%DASH%/g, '-').replace(/%UNDERSCORE%/g, '_')
      else
        - attributes.class = undefined
  
    if block
      +bemto_tag(tag, tagMetadata)&attributes(attributes)
        block
    else
      +bemto_tag(tag, tagMetadata)&attributes(attributes)
  
    //- Closing actions (remove the current block from the chain)
    if !isElement && block_sets_context
      - bemto_chain = bemto_chain.splice(0,bemto_chain.length-1)
    - bemto_chain_contexts = bemto_chain_contexts.splice(0,bemto_chain_contexts.length-1)
  
  //- Element
  mixin e(options)
    if options && typeof options == 'string'
      - options = { 'tag': options }
    else
      - options = options || {}
    - options['isElement'] = true
    +b(options)&attributes(attributes): block
  