hunk.code_window:         setTimeout(function() {
               $body.removeClass('o_wow_marked');
           }, 1000);
       }
   });
  
hunk.labels: keep replace keep keep keep
hunk.after_edit:             $body.removeClass(class_to_add);
  
hunk.file_path: addons/web/static/src/js/views/form_widgets.js
hunk.type: replace
file: # -*- coding: utf-8 -*-
  import os.path
  import posixpath
  import re
  import urllib
  
  from docutils import nodes
  from sphinx import addnodes, util
  from sphinx.locale import admonitionlabels
  
  
  def _parents(node):
      while node.parent:
          node = node.parent
          yield node
  
  class BootstrapTranslator(nodes.NodeVisitor, object):
      head_prefix = 'head_prefix'
      head = 'head'
      stylesheet = 'stylesheet'
      body_prefix = 'body_prefix'
      body_pre_docinfo = 'body_pre_docinfo'
      docinfo = 'docinfo'
      body_suffix = 'body_suffix'
      subtitle = 'subtitle'
      header = 'header'
      footer = 'footer'
      html_prolog = 'html_prolog'
      html_head = 'html_head'
      html_title = 'html_title'
      html_subtitle = 'html_subtitle'
  
      # <meta> tags
      meta = [
          '<meta http-equiv="X-UA-Compatible" content="IE=edge">',
          '<meta name="viewport" content="width=device-width, initial-scale=1">'
      ]
  
      def __init__(self, builder, document):
          super(BootstrapTranslator, self).__init__(document)
          self.builder = builder
          self.body = []
          self.fragment = self.body
          self.html_body = self.body
          # document title
          self.title = []
          self.start_document_title = 0
          self.first_title = False
  
          self.context = []
          self.section_level = 0
  
          self.highlightlang = self.highlightlang_base = self.builder.config.highlight_language
          self.highlightopts = getattr(builder.config, 'highlight_options', {})
  
          self.first_param = 1
          self.optional_param_level = 0
          self.required_params_left = 0
          self.param_separator = ','
  
      def encode(self, text):
          return unicode(text).translate({
              ord('&'): u'&amp;',
              ord('<'): u'&lt;',
              ord('"'): u'&quot;',
              ord('>'): u'&gt;',
              0xa0: u'&nbsp;'
          })
  
      def starttag(self, node, tagname, **attributes):
          tagname = unicode(tagname).lower()
  
          # extract generic attributes
          attrs = {name.lower(): value for name, value in attributes.iteritems()}
          attrs.update(
              (name, value) for name, value in node.attributes.iteritems()
              if name.startswith('data-')
          )
  
          prefix = []
          postfix = []
  
          # handle possibly multiple ids
          assert 'id' not in attrs, "starttag can't be passed a single id attribute, use a list of ids"
          ids = node.get('ids', []) + attrs.pop('ids', [])
          if ids:
              _ids = iter(ids)
              attrs['id'] = next(_ids)
              postfix.extend(u'<i id="{}"></i>'.format(_id) for _id in _ids)
  
          # set CSS class
          classes = set(node.get('classes', []) + attrs.pop('class', '').split())
          if classes:
              attrs['class'] = u' '.join(classes)
  
          return u'{prefix}<{tag} {attrs}>{postfix}'.format(
              prefix=u''.join(prefix),
              tag=tagname,
              attrs=u' '.join(u'{}="{}"'.format(name, self.attval(value))
                              for name,  value in attrs.iteritems()),
              postfix=u''.join(postfix),
          )
      # only "space characters" SPACE, CHARACTER TABULATION, LINE FEED,
      # FORM FEED and CARRIAGE RETURN should be collapsed, not al White_Space
      def attval(self, value, whitespace=re.compile(u'[ \t\n\f\r]')):
          return self.encode(whitespace.sub(u' ', unicode(value)))
  
      def astext(self):
          return u''.join(self.body)
  
      def unknown_visit(self, node):
          print "unknown node", node.__class__.__name__
          self.body.append(u'[UNKNOWN NODE {}]'.format(node.__class__.__name__))
          raise nodes.SkipNode
  
      def visit_highlightlang(self, node):
          self.highlightlang = node['lang']
      def depart_highlightlang(self, node):
          pass
  
      def visit_document(self, node):
          self.first_title = True
      def depart_document(self, node):
          pass
  
      def visit_section(self, node):
          # close "parent" or preceding section, unless this is the opening of
          # the first section
          if self.section_level:
              self.body.append(u'</section>')
          self.section_level += 1
  
          self.body.append(self.starttag(node, 'section'))
      def depart_section(self, node):
          self.section_level -= 1
          # close last section of document
          if not self.section_level:
              self.body.append(u'</section>')
  
      def is_compact_paragraph(self, node):
          parent = node.parent
          if isinstance(parent, (nodes.document, nodes.compound,
                                 addnodes.desc_content,
                                 addnodes.versionmodified)):
              # Never compact paragraphs in document or compound.
              return False
  
          for key, value in node.attlist():
              # we can ignore a few specific classes, all other non-default
              # attributes require that a <p> node remains
              if key != 'classes' or value not in ([], ['first'], ['last'], ['first', 'last']):
                  return False
  
          first = isinstance(node.parent[0], nodes.label)
          for child in parent.children[first:]:
              # only first paragraph can be compact
              if isinstance(child, nodes.Invisible):
                  continue
              if child is node:
                  break
              return False
          parent_length = len([
              1 for n in parent
              if not isinstance(n, (nodes.Invisible, nodes.label))
          ])
          return parent_length == 1
  
      def visit_paragraph(self, node):
          if self.is_compact_paragraph(node):
              self.context.append(u'')
              return
          self.body.append(self.starttag(node, 'p'))
          self.context.append(u'</p>')
      def depart_paragraph(self, node):
          self.body.append(self.context.pop())
      def visit_compact_paragraph(self, node):
          pass
      def depart_compact_paragraph(self, node):
          pass
  
      def visit_literal_block(self, node):
          if node.rawsource != node.astext():
              # most probably a parsed-literal block -- don't highlight
              self.body.append(self.starttag(node, 'pre'))
              return
          lang = self.highlightlang
          highlight_args = node.get('highlight_args', {})
          if 'language' in node:
              # code-block directives
              lang = node['language']
              highlight_args['force'] = True
          linenos = node.get('linenos', False)
          if lang is self.highlightlang_base:
              # only pass highlighter options for original language
              opts = self.highlightopts
          else:
              opts = {}
  
          def warner(msg):
              self.builder.warn(msg, (self.builder.current_docname, node.line))
          highlighted = self.builder.highlighter.highlight_block(
              node.rawsource, lang, opts=opts, warn=warner, linenos=linenos,
              **highlight_args)
          self.body.append(self.starttag(node, 'div', CLASS='highlight-%s' % lang))
          self.body.append(highlighted)
          self.body.append(u'</div>\n')
          raise nodes.SkipNode
      def depart_literal_block(self, node):
          self.body.append(u'</pre>')
  
      def visit_bullet_list(self, node):
          self.body.append(self.starttag(node, 'ul'))
      def depart_bullet_list(self, node):
          self.body.append(u'</ul>')
      def visit_enumerated_list(self, node):
          self.body.append(self.starttag(node, 'ol'))
      def depart_enumerated_list(self, node):
          self.body.append(u'</ol>')
      def visit_list_item(self, node):
          self.body.append(self.starttag(node, 'li'))
      def depart_list_item(self, node):
          self.body.append(u'</li>')
      def visit_definition_list(self, node):
          self.body.append(self.starttag(node, 'dl'))
      def depart_definition_list(self, node):
          self.body.append(u'</dl>')
      def visit_definition_list_item(self, node):
          pass
      def depart_definition_list_item(self, node):
          pass
      def visit_term(self, node):
          self.body.append(self.starttag(node, 'dt'))
      def depart_term(self, node):
          self.body.append(u'</dt>')
      def visit_termsep(self, node):
          self.body.append(self.starttag(node, 'br'))
          raise nodes.SkipNode
      def visit_definition(self, node):
          self.body.append(self.starttag(node, 'dd'))
      def depart_definition(self, node):
          self.body.append(u'</dd>')
  
      def visit_admonition(self, node, type=None):
          clss = {
              # ???: 'alert-success',
  
              'note': 'alert-info',
              'hint': 'alert-info',
              'tip': 'alert-info',
              'seealso': 'alert-info',
  
              'warning': 'alert-warning',
              'attention': 'alert-warning',
              'caution': 'alert-warning',
              'important': 'alert-warning',
  
              'danger': 'alert-danger',
              'error': 'alert-danger',
  
              'exercise': 'alert-exercise',
          }
          self.body.append(self.starttag(node, 'div', role='alert', CLASS='alert {}'.format(
              clss.get(type, '')
          )))
          if 'alert-dismissible' in node.get('classes', []):
              self.body.append(
                  u'<button type="button" class="close" data-dismiss="alert" aria-label="Close">'
                  u'<span aria-hidden="true">&times;</span>'
                  u'</button>')
          if type:
              node.insert(0, nodes.title(type, admonitionlabels[type]))
      def depart_admonition(self, node):
          self.body.append(u'</div>')
      visit_note = lambda self, node: self.visit_admonition(node, 'note')
      visit_warning = lambda self, node: self.visit_admonition(node, 'warning')
      visit_attention = lambda self, node: self.visit_admonition(node, 'attention')
      visit_caution = lambda self, node: self.visit_admonition(node, 'caution')
      visit_danger = lambda self, node: self.visit_admonition(node, 'danger')
      visit_error = lambda self, node: self.visit_admonition(node, 'error')
      visit_hint = lambda self, node: self.visit_admonition(node, 'hint')
      visit_important = lambda self, node: self.visit_admonition(node, 'important')
      visit_tip = lambda self, node: self.visit_admonition(node, 'tip')
      visit_exercise = lambda self, node: self.visit_admonition(node, 'exercise')
      visit_seealso = lambda self, node: self.visit_admonition(node, 'seealso')
      depart_note = depart_admonition
      depart_warning = depart_admonition
      depart_attention = depart_admonition
      depart_caution = depart_admonition
      depart_danger = depart_admonition
      depart_error = depart_admonition
      depart_hint = depart_admonition
      depart_important = depart_admonition
      depart_tip = depart_admonition
      depart_exercise = depart_admonition
      depart_seealso = depart_admonition
      def visit_versionmodified(self, node):
          self.body.append(self.starttag(node, 'div', CLASS=node['type']))
      def depart_versionmodified(self, node):
          self.body.append(u'</div>')
  
      def visit_title(self, node):
          parent = node.parent
          closing = u'</p>'
          if isinstance(parent, nodes.Admonition):
              self.body.append(self.starttag(node, 'p', CLASS='alert-title'))
          elif isinstance(node.parent, nodes.document):
              self.body.append(self.starttag(node, 'h1'))
              closing = u'</h1>'
              self.start_document_title = len(self.body)
          else:
              assert isinstance(parent, nodes.section), "expected a section node as parent to the title, found {}".format(parent)
              if self.first_title:
                  self.first_title = False
                  raise nodes.SkipNode()
              nodename = 'h{}'.format(self.section_level)
              self.body.append(self.starttag(node, nodename))
              closing = u'</{}>'.format(nodename)
          self.context.append(closing)
      def depart_title(self, node):
          self.body.append(self.context.pop())
          if self.start_document_title:
              self.title = self.body[self.start_document_title:-1]
              self.start_document_title = 0
              del self.body[:]
  
      # the rubric should be a smaller heading than the current section, up to
      # h6... maybe "h7" should be a ``p`` instead?
      def visit_rubric(self, node):
          self.body.append(self.starttag(node, 'h{}'.format(min(self.section_level + 1, 6))))
      def depart_rubric(self, node):
          self.body.append(u'</h{}>'.format(min(self.section_level + 1, 6)))
  
      def visit_block_quote(self, node):
          self.body.append(self.starttag(node, 'blockquote'))
      def depart_block_quote(self, node):
          self.body.append(u'</blockquote>')
      def visit_attribution(self, node):
          self.body.append(self.starttag(node, 'footer'))
      def depart_attribution(self, node):
          self.body.append(u'</footer>')
  
      def visit_container(self, node):
          self.body.append(self.starttag(node, 'div'))
      def depart_container(self, node):
          self.body.append(u'</div>')
      def visit_compound(self, node):
          self.body.append(self.starttag(node, 'div'))
      def depart_compound(self, node):
          self.body.append(u'</div>')
  
      def visit_image(self, node):
          uri = node['uri']
          if uri in self.builder.images:
              uri = posixpath.join(self.builder.imgpath,
                                   self.builder.images[uri])
          attrs = {'src': uri, 'class': 'img-responsive'}
          if 'alt' in node:
              attrs['alt'] = node['alt']
          if 'align' in node:
              if node['align'] == 'center':
                  attrs['class'] += ' center-block'
              else:
                  doc = None
                  if node.source:
                      doc = node.source
                      if node.line:
                          doc += ':%d' % node.line
                  self.builder.app.warn(
                      "Unsupported alignment value \"%s\"" % node['align'],
                      location=doc
                  )
          # todo: explicit width/height/scale?
          self.body.append(self.starttag(node, 'img', **attrs))
      def depart_image(self, node): pass
      def visit_figure(self, node):
          self.body.append(self.starttag(node, 'div'))
      def depart_figure(self, node):
          self.body.append(u'</div>')
      def visit_caption(self, node):
          # first paragraph of figure content
          self.body.append(self.starttag(node, 'h4'))
      def depart_caption(self, node):
          self.body.append(u'</h4>')
      def visit_legend(self, node): pass
      def depart_legend(self, node): pass
  
      def visit_line(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='line'))
          # ensure the line still takes the room it needs
          if not len(node): self.body.append(u'<br />')
      def depart_line(self, node):
          self.body.append(u'</div>')
  
      def visit_line_block(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='line-block'))
      def depart_line_block(self, node):
          self.body.append(u'</div>')
  
      def visit_table(self, node):
          self.body.append(self.starttag(node, 'table', CLASS='table'))
      def depart_table(self, node):
          self.body.append(u'</table>')
      def visit_tgroup(self, node): pass
      def depart_tgroup(self, node): pass
      def visit_colspec(self, node): raise nodes.SkipNode
      def visit_thead(self, node):
          self.body.append(self.starttag(node, 'thead'))
      def depart_thead(self, node):
          self.body.append(u'</thead>')
      def visit_tbody(self, node):
          self.body.append(self.starttag(node, 'tbody'))
      def depart_tbody(self, node):
          self.body.append(u'</tbody>')
      def visit_row(self, node):
          self.body.append(self.starttag(node, 'tr'))
      def depart_row(self, node):
          self.body.append(u'</tr>')
      def visit_entry(self, node):
          if isinstance(node.parent.parent, nodes.thead):
              tagname = 'th'
          else:
              tagname = 'td'
          self.body.append(self.starttag(node, tagname))
          self.context.append(tagname)
      def depart_entry(self, node):
          self.body.append(u'</{}>'.format(self.context.pop()))
  
      def visit_Text(self, node):
          self.body.append(self.encode(node.astext()))
      def depart_Text(self, node):
          pass
      def visit_literal(self, node):
          self.body.append(self.starttag(node, 'code'))
      def depart_literal(self, node):
          self.body.append(u'</code>')
      visit_literal_emphasis = visit_literal
      depart_literal_emphasis = depart_literal
      def visit_emphasis(self, node):
          self.body.append(self.starttag(node, 'em'))
      def depart_emphasis(self, node):
          self.body.append(u'</em>')
      def visit_strong(self, node):
          self.body.append(self.starttag(node, 'strong'))
      def depart_strong(self, node):
          self.body.append(u'</strong>')
      visit_literal_strong = visit_strong
      depart_literal_strong = depart_strong
      def visit_inline(self, node):
          self.body.append(self.starttag(node, 'span'))
      def depart_inline(self, node):
          self.body.append(u'</span>')
      def visit_abbreviation(self, node):
          attrs = {}
          if 'explanation' in node:
              attrs['title'] = node['explanation']
          self.body.append(self.starttag(node, 'abbr', **attrs))
      def depart_abbreviation(self, node):
          self.body.append(u'</abbr>')
  
      def visit_reference(self, node):
          attrs = {
              'class': 'reference',
              'href': node['refuri'] if 'refuri' in node else '#' + node['refid']
          }
          attrs['class'] += ' internal' if (node.get('internal') or 'refuri' not in node) else ' external'
          if any(isinstance(ancestor, nodes.Admonition) for ancestor in _parents(node)):
              attrs['class'] += ' alert-link'
  
          if 'reftitle' in node:
              attrs['title'] = node['reftitle']
  
          self.body.append(self.starttag(node, 'a', **attrs))
      def depart_reference(self, node):
          self.body.append(u'</a>')
      def visit_target(self, node): pass
      def depart_target(self, node): pass
      def visit_footnote(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='footnote'))
          self.footnote_backrefs(node)
      def depart_footnote(self, node):
          self.body.append(u'</div>')
      def visit_footnote_reference(self, node):
          self.body.append(self.starttag(
              node, 'a', href='#' + node['refid'], CLASS="footnote-ref"))
      def depart_footnote_reference(self, node):
          self.body.append(u'</a>')
      def visit_label(self, node):
          self.body.append(self.starttag(node, 'span', CLASS='footnote-label'))
          self.body.append(u'%s[' % self.context.pop())
      def depart_label(self, node):
          # Context added in footnote_backrefs.
          self.body.append(u']%s</span> %s' % (self.context.pop(), self.context.pop()))
      def footnote_backrefs(self, node):
          # should store following data on context stack (in that order since
          # they'll be popped so LIFO)
          #
          # * outside (after) label
          # * after label text
          # * before label text
          backrefs = node['backrefs']
          if not backrefs:
              self.context.extend(['', '', ''])
          elif len(backrefs) == 1:
              self.context.extend([
                  '',
                  '</a>',
                  '<a class="footnote-backref" href="#%s">' % backrefs[0]
              ])
          else:
              backlinks = (
                  '<a class="footnote-backref" href="#%s">%s</a>' % (backref, i)
                  for i, backref in enumerate(backrefs, start=1)
              )
              self.context.extend([
                  '<em class="footnote-backrefs">(%s)</em> ' % ', '.join(backlinks),
                  '',
                  ''
              ])
  
      def visit_desc(self, node):
          self.body.append(self.starttag(node, 'section', CLASS='code-' + node['objtype']))
      def depart_desc(self, node):
          self.body.append(u'</section>')
      def visit_desc_signature(self, node):
          self.body.append(self.starttag(node, 'h6'))
          self.body.append(u'<code>')
      def depart_desc_signature(self, node):
          self.body.append(u'</code>')
          self.body.append(u'</h6>')
      def visit_desc_addname(self, node): pass
      def depart_desc_addname(self, node): pass
      def visit_desc_type(self, node): pass
      def depart_desc_type(self, node): pass
      def visit_desc_returns(self, node):
          self.body.append(u' → ')
      def depart_desc_returns(self, node):
          pass
      def visit_desc_name(self, node): pass
      def depart_desc_name(self, node): pass
      def visit_desc_parameterlist(self, node):
          self.body.append(u'(')
          self.first_param = True
          self.optional_param_level = 0
          # How many required parameters are left.
          self.required_params_left = sum(isinstance(c, addnodes.desc_parameter) for c in node.children)
          self.param_separator = node.child_text_separator
      def depart_desc_parameterlist(self, node):
          self.body.append(u')')
      # If required parameters are still to come, then put the comma after
      # the parameter.  Otherwise, put the comma before.  This ensures that
      # signatures like the following render correctly (see issue #1001):
      #
      #     foo([a, ]b, c[, d])
      #
      def visit_desc_parameter(self, node):
          if self.first_param:
              self.first_param = 0
          elif not self.required_params_left:
              self.body.append(self.param_separator)
          if self.optional_param_level == 0:
              self.required_params_left -= 1
          if 'noemph' not in node: self.body.append(u'<em>')
      def depart_desc_parameter(self, node):
          if 'noemph' not in node: self.body.append(u'</em>')
          if self.required_params_left:
              self.body.append(self.param_separator)
      def visit_desc_optional(self, node):
          self.optional_param_level += 1
          self.body.append(u'[')
      def depart_desc_optional(self, node):
          self.optional_param_level -= 1
          self.body.append(u']')
      def visit_desc_annotation(self, node):
          self.body.append(self.starttag(node, 'em'))
      def depart_desc_annotation(self, node):
          self.body.append(u'</em>')
      def visit_desc_content(self, node): pass
      def depart_desc_content(self, node): pass
      def visit_field_list(self, node):
           self.body.append(self.starttag(node, 'div', CLASS='code-fields'))
      def depart_field_list(self, node):
          self.body.append(u'</div>')
      def visit_field(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='code-field'))
      def depart_field(self, node):
          self.body.append(u'</div>')
      def visit_field_name(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='code-field-name'))
      def depart_field_name(self, node):
          self.body.append(u'</div>')
      def visit_field_body(self, node):
          self.body.append(self.starttag(node, 'div', CLASS='code-field-body'))
      def depart_field_body(self, node):
          self.body.append(u'</div>')
  
      def visit_glossary(self, node): pass
      def depart_glossary(self, node): pass
  
      def visit_comment(self, node): raise nodes.SkipNode
      def visit_toctree(self, node):
          # div class=row {{ section_type }}
          #   h2 class=col-sm-12
          #     {{ section title }}
          #   div class=col-sm-6 col-md-3
          #     figure class=card
          #       a href=current_link style=background-image: document-image-attribute class=card-img
          #         figcaption
          #           {{ card title }}
          env = self.builder.env
          conf = self.builder.app.config
          for title, ref in ((e[0], e[1]) for e in node['entries']):
              # external URL, no toc, can't recurse into
              if ref not in env.tocs:
                  continue
              toc = env.tocs[ref].traverse(addnodes.toctree)
  
              classes = env.metadata[ref].get('types', 'tutorials')
              classes += ' toc-single-entry' if not toc else ' toc-section'
              self.body.append(self.starttag(node, 'div', CLASS="row " + classes))
              self.body.append(u'<h2 class="col-sm-12">')
              self.body.append(title if title else util.nodes.clean_astext(env.titles[ref]))
              self.body.append(u'</h2>')
  
              entries = [(title, ref)] if not toc else ((e[0], e[1]) for e in toc[0]['entries'])
              for subtitle, subref in entries:
                  baseuri = self.builder.get_target_uri(node['parent'])
  
                  if subref in env.metadata:
                      cover = env.metadata[subref].get('banner', conf.odoo_cover_default)
                  elif subref in conf.odoo_cover_external:
                      cover = conf.odoo_cover_external[subref]
                  else:
                      cover = conf.odoo_cover_default_external
  
                  if cover:
                      banner = '_static/' + cover
                      base, ext = os.path.splitext(banner)
                      small = "{}.small{}".format(base, ext)
                      if os.path.isfile(urllib.url2pathname(small)):
                          banner = small
                      style = u"background-image: url('{}')".format(
                          util.relative_uri(baseuri, banner) or '#')
                  else:
                      style = u''
  
                  self.body.append(u"""
                  <div class="col-sm-6 col-md-3">
                  <figure class="card">
                      <a href="{link}" class="card-img">
                          <span style="{style}"></span>
                          <figcaption>{title}</figcaption>
                      </a>
                  </figure>
                  </div>
                  """.format(
                      link=subref if util.url_re.match(subref) else util.relative_uri(
                          baseuri, self.builder.get_target_uri(subref)),
                      style=style,
                      title=subtitle if subtitle else util.nodes.clean_astext(env.titles[subref]),
                  ))
  
              self.body.append(u'</div>')
          raise nodes.SkipNode
  
      def visit_index(self, node): raise nodes.SkipNode
  
      def visit_raw(self, node):
          if 'html' in node.get('format', '').split():
              t = 'span' if isinstance(node.parent, nodes.TextElement) else 'div'
              if node['classes']:
                  self.body.append(self.starttag(node, t))
              self.body.append(node.astext())
              if node['classes']:
                  self.body.append('</%s>' % t)
          # Keep non-HTML raw text out of output:
          raise nodes.SkipNode
  
      # internal node
      def visit_substitution_definition(self, node): raise nodes.SkipNode
  