Beispiel #1
0
 def app(self):
     app = Sanic(__name__)
     self.jinja = SanicJinja2(
         app,
         loader=FileSystemLoader(
             [str(app_root / 'datasette' / 'templates')]),
         autoescape=True,
     )
     self.jinja.add_env('escape_css_string', escape_css_string, 'filters')
     self.jinja.add_env('quote_plus', lambda u: urllib.parse.quote_plus(u),
                        'filters')
     self.jinja.add_env('escape_table_name', escape_sqlite_table_name,
                        'filters')
     app.add_route(IndexView.as_view(self), '/<as_json:(.jsono?)?$>')
     # TODO: /favicon.ico and /-/static/ deserve far-future cache expires
     app.add_route(favicon, '/favicon.ico')
     app.static('/-/static/', str(app_root / 'datasette' / 'static'))
     app.add_route(DatabaseView.as_view(self),
                   '/<db_name:[^/\.]+?><as_json:(.jsono?)?$>')
     app.add_route(DatabaseDownload.as_view(self),
                   '/<db_name:[^/]+?><as_db:(\.db)$>')
     app.add_route(TableView.as_view(self),
                   '/<db_name:[^/]+>/<table:[^/]+?><as_json:(.jsono?)?$>')
     app.add_route(
         RowView.as_view(self),
         '/<db_name:[^/]+>/<table:[^/]+?>/<pk_path:[^/]+?><as_json:(.jsono?)?$>'
     )
     return app
Beispiel #2
0
    def test_template_basics(self):
        app = get_app()
        jinja = SanicJinja2(app, autoescape=True)
        babel.Babel(app, default_locale='de_DE')

        t = lambda x, request: jinja.render_source('{{ %s }}' % x, request)

        request, response = app.test_client.get('/')
        assert t("gettext('Hello %(name)s!', name='Peter')", request) == \
            'Hallo Peter!'
        assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)",
                 request) == '3 Äpfel'
        assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)",
                 request) == '1 Apfel'
        assert jinja.render_source('''
            {% trans %}Hello {{ name }}!{% endtrans %}
        ''',
                                   request,
                                   name='Peter').strip() == 'Hallo Peter!'
        assert jinja.render_source('''
            {% trans num=3 %}{{ num }} Apple
            {%- pluralize %}{{ num }} Apples{% endtrans %}
        ''',
                                   request,
                                   name='Peter').strip() == '3 Äpfel'
Beispiel #3
0
 def add_routes(self):
     """TBD."""
     self.jinja = SanicJinja2(
         self.app,
         # enable_async=False,
         auto_reload=False)
     self.app.static(
         '/static',
         os.path.dirname(os.path.abspath(sys.modules['__main__'].__file__))
         + '/static')
     self.app.add_route(self.handle, '/', methods=['GET', 'POST'])
     self.app.add_route(
         self.async_good,
         '/good',
     )
     self.app.add_route(
         self.action_bad,
         '/bad',
     )
     self.app.add_route(
         self.action_ugly,
         '/ugly',
     )
     self.app.add_route(
         self.action_about,
         '/about',
     )
     self.app.add_route(self.stickers_api, '/stickers')
     self.app.add_route(self.stickers_api_packs, '/stickers/<packs>')
     self.app.add_route(self.stickers_api_packs_stickers,
                        '/stickers/<packs>/<stickers>')
Beispiel #4
0
    def _setup_jinja2_renderer(self):
        spf, plugin_name, plugin_prefix = self.spf_reg
        loader = PackageLoader(__name__, 'templates')
        enable_async = cur_py_version >= async_req_version
        context = restplus.get_context_from_spf(self.spf_reg)
        # Don't try to use an already registered Jinja2-plugin, it causes too much incompatibility with template
        # loaders. Just use a new one of our own.
        j2 = SanicJinja2(context.app,
                         loader=loader,
                         pkg_name=plugin_name,
                         enable_async=enable_async)

        def swagger_static(filename):
            nonlocal self
            spf, plugin_name, plugin_prefix = self.spf_reg
            endpoint = '{}.static'.format(str(self._uid))
            return restplus.spf_resolve_url_for(spf,
                                                endpoint,
                                                filename=filename)

        def config():
            nonlocal self, context
            app = context.app
            if isinstance(app, Blueprint):
                return {}
            return app.config

        if enable_async:

            async def api_renderer(request, api, request_context):
                """Render a SwaggerUI for a given API"""
                nonlocal j2, swagger_static, config
                j2.add_env('swagger_static', swagger_static)
                j2.add_env('config', config())
                return await j2.render_async('swagger-ui.html',
                                             request,
                                             title=api.title,
                                             specs_url=api.specs_url,
                                             additional_css=api.additional_css)
        else:

            def api_renderer(request, api, request_context):
                """Render a SwaggerUI for a given API"""
                nonlocal j2, swagger_static, config
                j2.add_env('swagger_static', swagger_static)
                j2.add_env('config', config())
                return j2.render('swagger-ui.html',
                                 request,
                                 title=api.title,
                                 specs_url=api.specs_url,
                                 additional_css=api.additional_css)

        return api_renderer
Beispiel #5
0
def run(args):
    app = Sanic('brego')
    app.static('/static/', 'brego/client/')
    jinja = SanicJinja2(app, pkg_name='brego')
    db = SensorDB()

    http_sensor_stream_route(app, args.sensors_socket)
    websocket_sensor_stream_route(app, args.sensors_socket)
    dashboard_route(app, jinja)
    devices_route(app, db)

    app.run(host=args.host,
            port=args.port,
            debug=True,
            protocol=WebSocketProtocol)
Beispiel #6
0
from sanic_jinja2 import SanicJinja2
from peewee_async import Manager, PooledMySQLDatabase

jinja2 = SanicJinja2()

database = PooledMySQLDatabase('gateway',
                               host='10.39.34.123',
                               port=3306,
                               user='******',
                               password='******')
objects = Manager(database)
Beispiel #7
0
from jinja2 import PackageLoader, select_autoescape
from sanic_session import InMemorySessionInterface, RedisSessionInterface
import asyncio_redis
import asyncio
import json, logging
import traceback as tb

logging.basicConfig(
    level=logging.INFO,
    format=
    '%(asctime)s - %(name)s - %(filename)s[%(lineno)d] - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

jinja = SanicJinja2(
    loader=PackageLoader('templates'),
    autoescape=select_autoescape(['html', 'xml']),
)

app = Sanic(__name__)
app.static('/static', './static')

HOST = {}


class Redis:
    _pool = None

    async def get_redis_pool(self):
        if not self._pool:
            self._pool = await asyncio_redis.Pool.create(host='localhost',
                                                         port=6379,
Beispiel #8
0
        self.registered = True

    @property
    def config(self):
        if self.app:
            return self.app.config
        return {}

    def url_for(self, *args, **kwargs):
        return self.app.url_for(*args, **kwargs)


apidoc = Apidoc('restplus_doc', None)

loader = PackageLoader(__name__, 'templates')
j2 = SanicJinja2(apidoc, loader)

module_path = os.path.abspath(os.path.dirname(__file__))
module_static = os.path.join(module_path, 'static')
if os.path.isdir(module_static):
    apidoc.static('/swaggerui', module_static)
else:
    apidoc.static('/swaggerui', './sanic_restplus/static')


def swagger_static(filename):
    #url = j2.app.url_for('restplus_doc.static')
    return '/swaggerui/bower/swagger-ui/dist/{0}'.format(filename)


def config():
Beispiel #9
0
        if not self._pool:
            self._pool = await asyncio_redis.Pool.create(host='localhost',
                                                         port=6379,
                                                         poolsize=10)

        return self._pool


config = configparser.ConfigParser()
config.read('config.ini')
app = Sanic()
app.config.REQUEST_MAX_SIZE = 100 * 1024 * 1024  # 100MB
app.static('/r', './resources')
app.static('/static', './static')

jinja = SanicJinja2(app)
redis_connection = Redis()
q = Queue(connection=redis_connection)
dynamodb = boto3.resource('dynamodb')

redis = Redis_pool()
# pass the getter method for the connection pool into the session
session_interface = RedisSessionInterface(redis.get_redis_pool)

es = Elasticsearch([config['ELASTICSEARCH']['HOST']],
                   use_ssl=True,
                   ca_certs=certifi.where())


@app.middleware('request')
async def add_session_to_request(request):
from sanic import Sanic
from sanic.response import text, json
from sanic.exceptions import RequestTimeout, ServerError
from sanic_jinja2 import SanicJinja2, PackageLoader
from graphql.execution.executors.asyncio import AsyncioExecutor

from a_tuin.constants import SESSION, EXCEPTIONS_TRAPPED
from glod.configuration import configuration
from glod.db.engine import Session  # it is important to import from glod.db.engine in order that the session is bound to a db engine
from glod.api.schema import schema
from glod.server.graphql_compatibility_wrapper import GraphQLCompatibilityWrapper

LOG = logging.getLogger(__file__)
app = Sanic(__name__)
jinja = SanicJinja2(app, PackageLoader('glod', 'crudl/templates'))


@app.middleware('request')
async def add_session_to_request(request):
    # before each request initialize a session
    # using the client's request
    request[SESSION] = Session()


@app.middleware('response')
async def commit_session(request, response):
    if request.get(EXCEPTIONS_TRAPPED):
        raise ServerError(request[EXCEPTIONS_TRAPPED])

    # after each request commit and close the session
Beispiel #11
0
from sanic import Sanic
from sanic_jinja2 import SanicJinja2

jinja = SanicJinja2()


def create_app(config):
    app = Sanic(__name__)
    app.config.from_object(config)
    app.static(config.STATIC_URL, config.STATIC_PATH)

    jinja.init_app(app, pkg_name=__name__)

    register_blueprints(app)

    @app.route('/')
    @jinja.template('index.html')
    async def index(request):
        return

    return app


def register_blueprints(app):
    # Import bp-s from app modules
    from app.sample_module import sample_module

    # Register bp-s
    app.blueprint(sample_module)
Beispiel #12
0
from sanic import Sanic, response
from sanic.response import json
from password_generator import PasswordGenerator
from sanic_jinja2 import SanicJinja2

app = Sanic("OnIn Password Generator")
app.config.from_pyfile('generator.conf')
app.static('/static', './static')
jinja = SanicJinja2(app, pkg_name="main")


@app.route("/")
async def instructions(request):
    api_url = app.url_for('generate')
    return jinja.render("index.html",
                        request,
                        api_url=api_url,
                        policies=app.config.POLICY)


@app.route("/generate_password", version=1)
async def generate(request):
    pwo = PasswordGenerator()

    # Получаем политику, если передали в запросе
    if 'policy' in request.args and request.args['policy'][0]:
        if request.args['policy'][0].upper() in app.config.POLICY:
            # Есть в списке, выбираем ее
            policy = request.args['policy'][0].upper()
        else:
            # Не нашли, выбираем политику по-умолчанию
Beispiel #13
0
def create_template_env():
    jinja = SanicJinja2()
    jinja.env.filters['datetimefilter'] = datetimefilter
    return jinja
Beispiel #14
0
@time: 2019/7/24 4:32 PM
@desc:
'''

import time
from sanic import response
from sanic import request
from sanic.request import json_loads
import xmltodict
import random
from sanic.response import json_dumps, text, json
from sanic import Sanic
from sanic_jinja2 import SanicJinja2

app = Sanic(__name__)
jinja = SanicJinja2(app, loader=None, pkg_name='', pkg_path='')

from sanic import Blueprint

#
# 客户码:  (拉单)秘钥:    管理账号:K12478670  (初始)密码:Uy0La9NE(!qazxsW2)  (重量)秘钥:
# K11122126  重量秘钥  7d35f6f98e025b85b75c283260af5d09

config = {
    "YTO": "YTO",
    "UrlOrder":
    "http://service.yto56.net.cn/CommonOrderModeBPlusServlet.action",
    "UrlWeight":
    "http://116.228.115.225:6183/3rdface/open-service/persist/weight",
    "ClientID": "K11122126",
    "ClientSec": "D570nY8Y",
Beispiel #15
0
from urllib.parse import urlunparse

from aiocache import cached, caches
from sanic import Sanic
from sanic.response import redirect
from sanic_compress import Compress
from sanic_jinja2 import SanicJinja2

from victims.data import Data
from victims.settings import CACHE, DEBUG, STATIC_DIR, TITLE

app = Sanic("vitimas_da_intolerancia")
app.static("/static", str(STATIC_DIR))
jinja = SanicJinja2(app, pkg_name="victims")
caches.set_config(CACHE)
Compress(app)


@app.middleware("request")
def force_https(request):
    if DEBUG:
        return None

    host = request.headers.get("Host", "")
    protocol = "https" if request.transport.get_extra_info(
        "sslcontext") else "http"

    if request.headers.get("x-forwarded-proto", protocol) == "http":
        args = ("https", host, request.path, None, request.query_string, None)
        url = urlunparse(args)
        return redirect(url)
Beispiel #16
0
from jinja2 import select_autoescape, FileSystemLoader
from sanic_jinja2 import SanicJinja2
import os

jinja2 = SanicJinja2(
    enable_async=True,
    autoescape=select_autoescape(['html', 'xml']),
)

path = os.path.dirname(os.path.dirname(__file__))
bp_path = os.path.join(path, 'blueprints')
tpl_path = [
    os.path.join(p, 'templates') for p in os.listdir(bp_path)
    if not p.startswith('__')
]
tpl_path.append(os.path.join(path, 'templates'))


def init(app):
    jinja2.init_app(app, loader=FileSystemLoader(tpl_path))
from sanic import Sanic
from sanic_jinja2 import SanicJinja2

from violence.data import Data


app = Sanic()
jinja = SanicJinja2(app, pkg_name='violence')
app_data = Data(refresh_cache=True)
app_data.reload_from_google_spreadsheet()


@app.route("/")
@jinja.template('index.html')
async def test(request):
    return {'cases': app_data.cases}
Beispiel #18
0
    context["objects"] = cfg.user_models
    context["url_prefix"] = cfg.route
    context["admin_panel_version"] = __version__
    context["round_number"] = cfg.round_number
    context["admin_users_route"] = cfg.admin_users_table_name
    context["cfg"] = cfg
    return html(
        self.render_string(template, request, **context),
        status=status,
        headers=headers,
    )


SanicJinja2.render = render_with_updated_context

jinja = SanicJinja2(loader=loader)


class CompositeCsvSettings(BaseModel):
    ...
    # todo


class App:
    """ class to store links to main app data app.config and DB"""

    config = {}
    db = None


class ColorSchema(BaseModel):
Beispiel #19
0
import asyncio
import json
from concurrent.futures import ThreadPoolExecutor

from sanic import Sanic, response
from sanic_jinja2 import SanicJinja2
from sanic_httpauth import HTTPBasicAuth

import b2browser
import config

app = Sanic("b2browser")
app.static("/static", "./static")
auth = HTTPBasicAuth()
jinja = SanicJinja2(app, pkg_name="b2browser")

b2browser.B2.setup(config.application_key_id, config.application_key,
                   config.bucket_name)


@auth.verify_password
def verify_password(username, password):
    # and b2browser.utils.hash_password(config.app_salt, password) == config.password
    return (username == config.username and password == config.password)


@app.listener("after_server_start")
def create_task_queues(app, loop):
    app.threaded_executor = ThreadPoolExecutor(config.thread_pool_size)

    app.updates_queue = asyncio.Queue(maxsize=1_000)
Beispiel #20
0
from urllib.parse import urlparse

from aiocache import cached, caches
from sanic import Sanic
from sanic_compress import Compress
from sanic_jinja2 import SanicJinja2

from victims.data import Data
from victims.settings import (CACHE_DATA_FOR, REDIS_DB, REDIS_URL,
                              REFRESH_CACHE_ON_LOAD, STATIC_DIR, TITLE)

app = Sanic('vitimas_da_intolerancia')
app.static('/static', str(STATIC_DIR))
Compress(app)

jinja = SanicJinja2(app, pkg_name='victims')
app_data = Data(refresh_cache=REFRESH_CACHE_ON_LOAD)
redis = urlparse(REDIS_URL)
caches.set_config({
    'default': {
        'cache': 'aiocache.RedisCache',
        'namespace': 'sanic-cache',
        'timeout': CACHE_DATA_FOR,
        'endpoint': redis.hostname,
        'port': redis.port,
        'db': REDIS_DB,
        'serializer': {
            'class': 'aiocache.serializers.PickleSerializer'
        },
    }
})
Beispiel #21
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from sanic import Sanic
from sanic_session import Session, InMemorySessionInterface
from sanic_jinja2 import SanicJinja2

app = Sanic()

session = Session(app, interface=InMemorySessionInterface())
jinja = SanicJinja2(app, session=session)


@app.route("/")
async def index(request):
    jinja.flash(request, "success message", "success")
    jinja.flash(request, "info message", "info")
    jinja.flash(request, "warning message", "warning")
    jinja.flash(request, "error message", "error")
    jinja.session(request)["user"] = "******"
    return jinja.render("index.html", request, greetings="Hello, sanic!")


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=True)
Beispiel #22
0
import asyncio
from pathlib import Path

import log
from markdown import markdown
from sanic import Sanic, response
from sanic_jinja2 import SanicJinja2
from sanic_openapi import doc

from app import helpers, settings, utils

app = Sanic(name="memegen")
helpers.configure(app)
jinja = SanicJinja2(app, pkg_name="app")


@app.get("/")
@doc.exclude(True)
@jinja.template("index.html")
async def index(request):
    html = markdown(
        text=Path("README.md").read_text(),
        extensions=["pymdownx.magiclink", "markdown.extensions.tables"],
    )
    html = html.replace("<code></code>", "<code>&nbsp</code>")
    html = html.replace(
        "https://api.memegen.link/docs",
        f"{settings.SCHEME}://{settings.SERVER_NAME}/docs",
    )
    return {"content": html}
import sanic.exceptions
import sanic.request
import sanic.response
from jinja2 import FileSystemLoader
from sanic_jinja2 import SanicJinja2
from sanic_session import InMemorySessionInterface, Session

from sanic_openid_connect_provider import setup_client

oicp_logger = logging.getLogger("oicp")
oicp_logger.setLevel(logging.INFO)
oicp_logger.addHandler(logging.StreamHandler())

app = sanic.Sanic()
session = Session(app, interface=InMemorySessionInterface())
jinja = SanicJinja2(app, loader=FileSystemLoader("./templates"), enable_async=True)

oicp_client = setup_client(
    app=app,
    callback_path="/callback",
    client_id=os.environ["AZURE_CLIENT_ID"],
    client_secret=os.environ["AZURE_CLIENT_SECRET"],
    signature_type="RS256",  # Azure only supports RS256
    autodiscover_base=os.environ["AZURE_BASE"],
    scopes=("openid", "profile", "email", "User.Read"),
)


@app.route("/secret", methods=["GET"])
@oicp_client.login_required()
async def secret(request: sanic.request.Request) -> sanic.response.BaseHTTPResponse:
Beispiel #24
0
from os import environ
from os.path import join, dirname
from sanic_jinja2 import SanicJinja2
from dotenv import load_dotenv

envpath = join(dirname(__file__), '.env')
load_dotenv(envpath)

DB_USER = environ.get('POSTGRES_USER')
DB_PASSWORD = environ.get('POSTGRES_PASSWORD')
DB_NAME = environ.get('POSTGRES_DB')
DB_PORT = environ.get('POSTGRES_PORT', 5432)
DB_HOST = environ.get('POSTGRES_HOST')
DB_URL = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}'

JINJA = SanicJinja2()
SECRET_KEY = environ.get('SECRET_KEY')
SESSION_TIME = 1800
LEEWAY_SESSION_TIME = 25

__all__ = [
    'JINJA',
    'DB_URL',
    'SECRET_KEY',
    'SESSION_TIME',
    'LEEWAY_SESSION_TIME',
]
Beispiel #25
0
from sanic.websocket import WebSocketProtocol
from sanic_auth import Auth, User
from sanic_jinja2 import SanicJinja2
import asyncio_redis

from channel import Channel, response_message
from redis_handle import redis_pub_sub
from db_driver import redis_set_get, pg_set_get
from ws_handle import receive_ws_channel, ws_room_send_chat

session = {}
app = Sanic(__name__)
app: asyncio_redis.Pool
app.config.AUTH_LOGIN_ENDPOINT = 'login'
auth = Auth(app)
jinja = SanicJinja2(app, pkg_path='template')


@app.listener('before_server_start')
async def setup(app, loop):
    app.conn = await redis_pub_sub.create_connection_pool()


@app.listener('after_server_stop')
async def close_db(app, loop):
    await app.close()


@app.middleware('request')
async def add_session(request):
    request['session'] = session
Beispiel #26
0
from errors_handling import CustomError

from sanic.exceptions import abort

from sanic import Sanic
from sanic import response, request
from sanic_jinja2 import SanicJinja2

from two_phase_commit import TwoPhaseCommit
from response_caching import ResponseCaching
from time import sleep
import json

app = Sanic(__name__)

jinja = SanicJinja2(app, autoescape=True)

# if this is set to false and in docker flask_env is not development, the "debug" logging will not be shown
app.config['DEBUG'] = True

# Setup elk stack
# host_logger = 'localhost'
host_logger = 'logstash'
port_logger = 5000

# Get you a test logger
test_logger = logging.getLogger('python-logstash-logger')
# Set it to whatever level you want - default will be info
test_logger.setLevel(logging.DEBUG)
# Create a handler for it
async_handler = AsynchronousLogstashHandler(host_logger,
Beispiel #27
0
import os
import re
from sanic import Sanic
from sanic.response import json, html
from draw import draw
from sanic_jinja2 import SanicJinja2

static_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                           '../static')
templates_path = os.path.join(
    os.path.join(os.path.dirname(__file__), 'templates'))

app = Sanic()
jinja = SanicJinja2(app)  # Use jinja2 for template engine
app.static('/static', static_path)  # Images
app.static('/', templates_path)


@app.route('/')
async def test(request):
    return jinja.render('index.html')


@app.route('/draw')
async def handle(request):
    if not 'word2' in request.args or not 'word3' in request.args:
        return json({"message": "word2 and word3 must be provided!"})
    pattern = re.compile(r'^[A-Z0-9]{1}$')

    word1 = 'I'  # request.args['word1'][0]
    word2 = request.args['word2'][0]
Beispiel #28
0
from sanic import Sanic
from sanic_jinja2 import SanicJinja2

from gino.ext.sanic import Gino

app = Sanic(__name__)
app.config.from_pyfile('config')

jinja = SanicJinja2(app, pkg_path=f'../{app.config.FRONTEND_PATH}/templates')

db = Gino()
db.init_app(app)

app.static('static', app.config.FRONTEND_PATH)

import libreban.routes
import libreban.model
Beispiel #29
0
import os

from sanic import Sanic
from sanic.response import json
from sanic_jinja2 import SanicJinja2

_dir = os.path.dirname(os.path.dirname(__file__))
# 一定要 才能读取绝对路径, 如果是相对路径呢
app = Sanic('my_project')
app.static('/static', f'./static')
jinja = SanicJinja2(app, pkg_name='main', pkg_path='./templates')


@app.route('/')
async def index(request):
    # calc
    # 30s
    return jinja.render('index.html', request, my_title='Hello, sanic!')


# api
@app.route('/get_user_name')
async def get_user_name(request):
    return json({'name': 'Tom'})


# api
@app.route('/get_data')
async def get_data(request):
    # calc
    a = {b
Beispiel #30
0
app.config.from_pyfile(config_file)

app.config.SESSION_COOKIE_SECRET_KEY = app.config.SECRET
app.config.SESSION_COOKIE_SECURE = False
app.config.SESSION_COOKIE_MAX_AGE = 3600 * 24 * 15

sanic_cookiesession.setup(app)


os.chdir(os.path.dirname(__file__))
app.static('/static', './static')
app.static('/favicon.ico', './static/images/favicon.ico')
app.static('/robots.txt', './static/robots.txt')


jinja = SanicJinja2(app, enable_async=False, autoescape=True)
render = jinja.render
render_async = jinja.render_async


pagination = {
    '_head': '<ul class="pagination">',
    '_end': '</ul>',
    '_normal': '<li><a href="{href}" rel="prev" style="text-decoration: none">{label}</a></li>',
    '_actived': '<li class="active"><a href="{href}" rel="prev" style="text-decoration: none">{label}</a></li>',
    '_gap': '<li class="disabled"><span>{gap}</span></li>',
    '_prev_label': '<i class="left arrow icon"></i>',
    '_next_label': '<i class="right arrow icon"></i>',
    '_prev_disabled': '<li class="disabled"><span>«</span></li>',
    '_next_disabled': '<li class="disabled"><span>»</span></li>',
    '_prev_normal': '<li><a href="{href}" rel="prev" style="text-decoration: none">«</a></li>',