text: import sys
  import os
  import os.path as op
  import tempfile
  import shutil
  from subprocess import Popen
  from datetime import datetime
  
  from . import globalvars
  from .base import CodeTemplate, GeneratedItem, owner, NSApp, const, defaults
  from .types import Action, NLSTR
  from .control import ControlSize, TextAlignment
  from .view import View, Box, Pack, Size, Rect
  from .font import Font, FontFamily, FontSize, FontTrait
  from .color import Color
  from .formatter import NumberFormatter, NumberStyle
  from .menu import Menu, MainMenu
  from .window import Window, Panel, PanelStyle
  from .button import Button, Checkbox
  from .textfield import TextField, Label, SearchField
  from .textview import TextView
  from .popup import Popup
  from .combo import Combobox
  from .radio import RadioButtons
  from .progress import ProgressIndicator
  from .image import ImageView
  from .tabview import TabView
  from .table import TableView, ListView, OutlineView
  from .splitview import SplitView
  from .segment import SegmentedControl
  from .slider import Slider
  from .layout import HLayout, VLayout, VHLayout
  from .util import modified_after
  
  try:
      execfile
  except NameError:
      # We're in Python 3
      def execfile(file, globals=globals(), locals=locals()):
          with open(file, "rt", encoding='utf-8') as fh:
              exec(fh.read()+"\n", globals, locals)
  
  AUTOGEN_COMMENT = "/* This unit was automatically generated by xibless v{version} on {timestamp}. */\n\n" 
  
  HEADER_TMPL = """
  #import "XiblessSupport.h"
  $ownerimport$
  
  $funcsig$;
  """
  
  UNIT_TMPL = """
  $mainimport$
  $ownerimport$
  
  $funcsig$
  {
  $contents$
  return result;
  }
  """
  
  # When running a UI (in `runmode`), we take one UI script out of its context, so
  # any owner assignment will make code compilation fail. Since we just want to preview the UI, we
  # don't need those assignments, so we skip them. Moreover, we revert all instance which had their
  # OBJC_CLASS attribute set because this is also going to make complication fail.
  def generate(modulePath, dest, runmode=False, localizationTable=None, args=None):
      if args is None:
          args = {}
      dest_basename, dest_ext = op.splitext(op.basename(dest))
      if dest_ext == '.h':
          dest_header = None
      else:
          if not dest_ext:
              dest += '.m'
          dest_header = op.splitext(dest)[0] + '.h'
      globalvars.globalLocalizationTable = localizationTable
      globalvars.globalRunMode = runmode
      globalvars.globalGenerationCounter.reset()
      to_include = {'owner', 'NSApp', 'const', 'defaults', 'View', 'Box', 'Size', 'Rect',
          'ControlSize', 'Menu', 'MainMenu', 'Action', 'Window', 'Panel', 'PanelStyle', 'Button',
          'Checkbox', 'Label', 'TextField', 'TextView', 'SearchField', 'Popup', 'Combobox',
          'RadioButtons', 'ProgressIndicator', 'ImageView', 'TabView', 'TableView', 'ListView',
          'OutlineView', 'SplitView', 'Font', 'FontFamily', 'FontSize', 'FontTrait', 'Color', 'Pack',
          'TextAlignment', 'HLayout', 'VLayout', 'VHLayout', 'SegmentedControl', 'Slider',
          'NumberFormatter', 'NumberStyle', 'NLSTR',
      }
      module_globals = {name: globals()[name] for name in to_include}
      module_globals['args'] = args
      module_locals = {}
      sys.path.insert(0, op.dirname(modulePath))
      execfile(modulePath, module_globals, module_locals)
      del sys.path[0]
      assert 'result' in module_locals
      tmpl = CodeTemplate(UNIT_TMPL)
      if runmode:
          owner._clear()
          owner._name = 'nil'
          ownerclass = 'id'
          ownerimport = None
          # We do this to avoid custom OBJC classes definition from preventing compilation.
          for value in module_locals.values():
              if hasattr(value, 'OBJC_CLASS') and hasattr(value.__class__, 'OBJC_CLASS'):
                  value.OBJC_CLASS = value.__class__.OBJC_CLASS
      else:
          ownerclass = module_locals.get('ownerclass', 'id')
          ownerimport = module_locals.get('ownerimport')
      if ownerimport:
          ownerimport = "#import \"%s\"" % ownerimport
      else:
          ownerimport = ''
      if ownerclass == 'id':
          ownerdecl = "id owner"
      else:
          ownerdecl = "%s *owner" % ownerclass
      if dest_header:
          tmpl.mainimport = "#import \"{}.h\"".format(dest_basename)
      else:
          tmpl.mainimport = "#import \"XiblessSupport.h\""
          tmpl.ownerimport = ownerimport
      for key, value in module_locals.items():
          if isinstance(value, GeneratedItem) and value.varname.startswith('_tmp'):
              value.varname = key
      toGenerate = globalvars.globalGenerationCounter.createdItems
      codePieces = []
      for item in toGenerate:
          if item.generated:
              continue
          code = item.generate()
          if code:
              codePieces.append(code)
      for item in toGenerate:
          code = item.generateFinalize()
          if code:
              codePieces.append(code)    
      result = module_locals['result']
      funcsig = "{}* create{}({})".format(result.OBJC_CLASS, dest_basename, ownerdecl)
      tmpl.funcsig = funcsig
      tmpl.contents = '\n'.join(codePieces)
      from xibless import __version__ # We have to import it here to avoid circular references
      autogen_comment = AUTOGEN_COMMENT.format(version=__version__, timestamp=datetime.now().strftime('%c'))
      with open(dest, 'wb') as fp:
          fp.write(autogen_comment.encode('utf-8'))
          fp.write(tidyCode(tmpl.render()).encode('utf-8'))
      if dest_header:
          tmpl = CodeTemplate(HEADER_TMPL)
          tmpl.funcsig = funcsig
          tmpl.ownerimport = ownerimport
          with open(dest_header, 'wt') as fp:
              fp.write(autogen_comment)
              fp.write(tidyCode(tmpl.render()))
      copy_support_unit(op.dirname(dest))
  
  def runUI(modulePath):
      runtemplatePath = op.join(op.dirname(op.abspath(__file__)), 'runtemplate')
      assert op.exists(runtemplatePath)
      tmpPath = tempfile.mkdtemp()
      destPath = op.join(tmpPath, 'runtemplate')
      shutil.copytree(runtemplatePath, destPath)
      wscriptPath = op.join(destPath, 'wscript')
      with open(wscriptPath, 'rt') as fp:
          wscriptContent = fp.read()
      wscriptContent = wscriptContent.replace('{{script_path}}', op.abspath(modulePath))
      with open(wscriptPath, 'wt') as fp:
          fp.write(wscriptContent)
      cmd = 'cd "%s" && python ./waf configure && python ./waf && open build/RunUI.app -W && cd ../.. && rm -r "%s"' % (destPath, tmpPath)
      p = Popen(cmd, shell=True)
      p.wait()
  
  def tidyCode(code):
      lines = (l.strip() for l in code.split('\n'))
      result = []
      level = 0
      for line in lines:
          if not line:
              if result and result[-1] != '':
                  result.append('')
              continue
          level -= line.count('}')
          result.append((' ' * (level * 4)) + line)
          level += line.count('{')
      return '\n'.join(result)
  
  def copy_support_unit(destfolder):
      DATA_PATH = op.join(op.dirname(__file__), 'data')
      if not op.exists(destfolder):
          os.makedirs(destfolder)
      if modified_after(op.join(DATA_PATH, 'XiblessSupport.h'), op.join(destfolder, 'XiblessSupport.h')):
          shutil.copy(op.join(DATA_PATH, 'XiblessSupport.h'), destfolder)
      if modified_after(op.join(DATA_PATH, 'XiblessSupport.m'), op.join(destfolder, 'XiblessSupport.m')):
          shutil.copy(op.join(DATA_PATH, 'XiblessSupport.m'), destfolder)
  