text: from flask import Flask, Blueprint, Markup, request, current_app
  import flask
  import flask.views
  from flask_bootstrap import Bootstrap
  from flask_babelex import Babel, Domain
  from flask_wtf import CsrfProtect
  from appshell.menu import MenuEntry, MainMenu
  from appshell.urls import url_for, url_or_url_for, res_url, url_or_res_url
  from appshell.templates import single_view, render_template
  from appshell.utils import push_block, get_pushed_blocks
  from appshell.locals import current_appshell
  from appshell.skins import DefaultSkin
  import importlib
  from werkzeug.local import LocalProxy
  from appshell.assets import assets
  from hashlib import sha256
  from .internals.l10n import gettext, ngettext
  from flask_babelex import Babel
  
  def endpoint_accessible(target, values):
      return current_appshell.endpoint_accessible(target, values)
  
  template_globals = {"url_for": url_for, 
                      "url_or_url_for": url_or_url_for,
                      "url_or_res_url": url_or_res_url,
                      "res_url": res_url,
                      "push_block": push_block,
                      "appshell_gettext": gettext,
                      "appshell_ngettext": ngettext,
                      "get_pushed_blocks": get_pushed_blocks,
                      "endpoint_accessible": endpoint_accessible}
  
  def parse_menu_path(path):
      menu, discard, item = path.partition('/')
      if item == '':
          return menu, None, None
      group, discard, item = item.rpartition(':')
      return menu, group, item
  
  
  class TopLevelMenu(object):
      def __init__(self, *args, **kwargs):
          super(TopLevelMenu, self).__init__(*args, **kwargs)
          self.menu_entry_class = MenuEntry
  
      def add_menu_entry(self, path, entry, postion=None):
          raise NotImplementedError
  
      def add_menu_label(self, path, text, position=None):
          raise NotImplementedError
    
      def add_menu(self, entries, position=None):
          for i in entries:
              self.add_menu_entry_from_desc(*i, position=position)
        
  
  class AppShell(TopLevelMenu):
      def __init__(self, app_name, root_view,
                   app=None,
                   components=[],
                   babel=None,
                   skin=None):
          TopLevelMenu.__init__(self)
          self.app_name = app_name
  
          if skin is None:
              skin = DefaultSkin()
          
          self.system_module = None
          self.root_view = root_view
          self.component_config = components
          self.search_view = None
          self.base_templates = {}
          self.access_map = {}
          self.skin = skin
          self.default_menu_position = 'left'
          self.subendpoint_aliases = {}
  
          self.skin.initialize(self)
  
          self.gettext = gettext
          self.ngettext = ngettext
  
          if babel is not None:
              self.babel = babel
          else:
              self.babel = Babel()
          
          self.menu = {i: MainMenu() for i in skin.menu_positions}
  
          
          if app:
              self.init_app(app)
          
      def use_component(self, app, module, cfg):
          mod = importlib.import_module("."+module, 'appshell')
          d = mod.register_in_app(self, app, **cfg)
          setattr(self, module, d)
          return d
  
      def add_base_template(self, name, filename):
          self.base_templates[name] = filename
  
      def is_active_for_menu(self, endpoint):
          if request.endpoint == endpoint:
              return True
  
          if request.endpoint in self.subendpoint_aliases:
              return endpoint in self.subendpoint_aliases[request.endpoint]
          
          return False
  
      def add_subendpoint_alias(self, endpoint, alias):
          if endpoint not in self.subendpoint_aliases:
              self.subendpoint_aliases[endpoint] = []
              
          self.subendpoint_aliases[endpoint].append(alias)
          
      
      @property
      def base_template(self):
          t = None
          
          if "__view" in request.args:
              vn = request.args["__view"]
              if vn in self.base_templates:
                  t = self.base_templates[vn]
                  
          if t is None:
              t = self.skin.get_base_template(self.current_module)
              
          return t
  
      @property
      def current_module(self):
          try:
              return current_app.blueprints[request.blueprint]
          except KeyError:
              return None
  
      def init_app(self, app):
          if not hasattr(app, 'extensions'):
              app.extensions = {}
          app.extensions['appshell'] = self
          bp = Blueprint('appshell', __name__, 
                         template_folder='templates',
                         static_folder='static',
                         static_url_path=app.static_url_path + '/appshell')
          app.register_blueprint(bp)
  
          assets.init_app(app)
  
          app.config['SESSION_COOKIE_NAME'] = "as_session_{}"\
             .format(sha256("{}, {}, {}"
                            .format(self.app_name,
                                    app.config['APPLICATION_ROOT'],
                                    app.name).encode('utf-8')).hexdigest())
          
          @app.context_processor
          def context_processor():
              return {"appshell": self}
  
          @app.before_request
          def check_access():
              if not self.endpoint_accessible(request.endpoint, request.args):
                  return self.handle_forbidden_endpoint()
  
  
          for n, f in template_globals.items():
              app.add_template_global(f, name=n)
  
          Bootstrap(app)
          app.config['BOOTSTRAP_SERVE_LOCAL'] = True
  
          self.babel.init_app(app)
          
          for k, v in self.component_config.items():
              self.use_component(app, k, v)
              
      
      def root_view_url(self):
          return url_or_url_for(self.root_view)
  
      def add_menu_entry_from_desc(self, path, text=None, entry=None, 
                                   position=None, klass=None):
          menu, group, item = parse_menu_path(path)
          
          if not position:
              position = self.default_menu_position
  
          if not entry:
              target = item or menu
  
              if '/' in target:
                  if not klass:
                      klass = MenuEntry
                  entry = klass(text, url=url)
              else:
                  if not klass:
                      klass = self.menu_entry_class
  
                  entry = klass(text, target=target)
  
          self.add_menu_entry(menu, group, item, entry, position=position)
  
      def add_menu_entry(self, menu, group, item, entry, position=None):
          if position is None:
              position = self.default_menu_position
          if not item:
              self.menu[position].add_top_entry(menu, entry)
          else:
              self.menu[position].add_entry(menu, item, entry, group=group)
  
      def add_menu_label(self, path, text, position=None):
          menu, discard, group = path.partition('/')
          if position == None:
              position = self.default_menu_position
          m = self.menu[position]
          if group:
              m.ensure_group(menu, group, text)
          else:
              m.ensure_menu(menu, text)
  
      def build_menu(self):
          return {k: v.build_real_menu() for k,v in self.menu.items()}
          
      def add_access_rule(self, endpoint, proc):
          if endpoint not in self.access_map:
              self.access_map[endpoint] = []
  
          self.access_map[endpoint].append(proc)
  
      def endpoint_accessible(self, endpoint, values):
          if endpoint not in self.access_map:
              return True
          rules = self.access_map[endpoint]
          for i in rules:
              if not i(**values):
                  return False
          return True
  
      def handle_forbidden_endpoint(self):
          if self.system_module:
              return self.system_module.handle_forbidden_endpoint()
          return flask.abort(403)
  
  
  class Module(TopLevelMenu, Blueprint):
      def __init__(self, *args, **kwargs):
          super(Module, self).__init__(*args, **kwargs)
          self.default_menu = self.name
          self.default_group = ''
          self.default_position = None
          self.menuentries = []
          self.menulabels = []
          self.base_templates = {}
          self.local_nav = {}
          self.title_text = None
          self.access_rules = []
          self.subendpoint_aliases = []
          
      def has_local_nav(self):
          return len(self.local_nav) > 0
  
      @property
      def local_nav_menu(self):
          ln = self.local_nav
          return [ [ln[k][j] for j in sorted(ln[k].keys())]
                   for k in sorted(self.local_nav.keys())]
      
      def entrypoint_for_view(self, view):
          return self.name + '.' + view.__name__
  
      def menu_entry_for_view(self, view, text, values={}):
          return self.menu_entry_class(text,
                                       target=self.entrypoint_for_view(view),
                                       values=values)
  
      def menu(self,  text, path=None, values={}, position=None):
          if not position:
              position = self.default_position
  
          def wrap(view):
              name = self.name + '.' + view.__name__
  
              if not path:
                  menu = self.default_menu
                  group = self.default_group
              else:
                  menu, discard, group = path.partition('/')
                  
              if not menu:
                  menu = name
                  item = None
              else:
                  item = name
  
              entry = self.menu_entry_for_view(view, text, values=values)
  
              self.add_menu_entry(menu, group, item, entry, position=position)
              return view
          return wrap
  
      def local_menu(self, text, group="", sort_key=None):
          def wrap(view):
              name = self.name + '.' + view.__name__
              self.add_local_menu_entry(name, text, group, sort_key)
              return view
          return wrap
  
      def label(self, text):
          self.title_text = text
          self.add_menu_label(self.default_menu + '/' + self.default_group, 
                              text, position=self.default_position)
  
      def add_menu_entry(self, menu, group, item, entry, position=None):
          if not position:
              position = self.default_position
          self.menuentries.append((menu, group, item, entry, position))
  
      def add_menu_label(self, path, text, position=None):
          if not position:
              position = self.default_position
          self.menulabels.append((path, text, position))
  
      def add_local_menu_entry(self, endpoint, text, group=None, sort_key=None):
          if sort_key == None:
              sort_key = text
          
          if group not in self.local_nav:
              self.local_nav[group] = {}
  
          self.local_nav[group][sort_key] = (endpoint, text)
          
      def add_base_template(self, name, filename):
          self.base_templates[name] = filename
  
      def register(self, app, *args, **kwargs):
          super(Module, self).register(app, *args, **kwargs)
          
          if not hasattr(app, 'extensions'):
              raise ValueError('Registering appshell module into non-appshell flask application')
          if not 'appshell' in app.extensions:
              raise ValueError('Registering appshell module into non-appshell flask application')
  
          ash = app.extensions['appshell']
          for i in self.menuentries:
              ash.add_menu_entry(*i)
          for i in self.menulabels:
              ash.add_menu_label(*i)
          for k, v in self.base_templates.items():
              ash.add_base_template(k, v)
          for endpoint, proc in self.access_rules:
              ash.add_access_rule(self.name + "." + endpoint, proc)
          for ep, a in self.subendpoint_aliases:
              ash.add_subendpoint_alias(self.name + "." + ep, a)
  
              
      def add_access_rule(self, endpoint, proc):
          self.access_rules.append((endpoint, proc))
  
      def access(self, proc):
          def wrap(f):
              self.add_access_rule(f.__name__, proc)
              return f
          return wrap
  
      def add_subendpoint_alias(self, endpoint, alias):
          if alias[0] == '.':
              alias = self.name + alias
          self.subendpoint_aliases.append((endpoint, alias))
          
      def subendpoint(self, endpoint):
          def wrap(f):
              self.add_subendpoint_alias(f.__name__, endpoint)
              return f
          return wrap
          
  
  class SystemModule(Module):
      def register(self, app, *args, **kwargs):
          if not hasattr(app, 'extensions'):
              return
          if not 'appshell' in app.extensions:
              return
  
          ash = app.extensions['appshell']
          if ash.system_module != None:
              raise ValueError("Multiple system modules in one application")
          ash.system_module = self
  
          super(Module, self).register(app, *args, **kwargs)
          
      def get_system_menu(self):
          return None
  
      def handle_forbidden_endpoint(self):
          return flask.abort(403)
  
  
  
  class View(flask.views.View):
      def __init__(self):
          self.page_args = {}
      
      @classmethod
      def route(cls, blueprint, route,
                name=None,
                decorators=[],
                **kwargs):
          if name is None:
              name = cls.__name__
  
          view = cls.as_view(name, **kwargs)
  
          for i in decorators:
              view = i(view)
          
          blueprint.add_url_rule(route, view_func=view)
  
      def render_template(self, form):
          return single_view(form, **self.page_args)
  