├── .gitattributes ├── .gitignore ├── .preview.gif ├── Dockerfile ├── LICENSE ├── MANIFEST.in ├── README.md ├── README.rst ├── docker-compose.yml ├── everbug ├── __init__.py ├── middleware.py ├── shortcuts.py └── utils │ ├── __init__.py │ ├── context.py │ ├── manager.py │ ├── pstats.py │ ├── queries.py │ └── serilalize.py ├── extension ├── chrome │ ├── css │ │ ├── hljs.theme.css │ │ └── plugin.css │ ├── fonts │ │ ├── Ubuntu.ttf │ │ └── UbuntuMono.ttf │ ├── html │ │ ├── devtools.html │ │ └── panel.html │ ├── img │ │ ├── down.png │ │ ├── icons │ │ │ ├── icon_16.png │ │ │ ├── icon_32.png │ │ │ ├── icon_64.png │ │ │ └── logo.png │ │ └── up.png │ ├── js │ │ ├── ext │ │ │ ├── background.js │ │ │ ├── devtools.js │ │ │ └── panel.js │ │ └── lib │ │ │ ├── highlight.js │ │ │ ├── jquery-3.2.1.min.js │ │ │ ├── languages │ │ │ ├── json.js │ │ │ └── sql.js │ │ │ └── sql-formatter.min.js │ └── manifest.json └── firefox │ ├── css │ ├── hljs.theme.css │ └── plugin.css │ ├── fonts │ ├── Ubuntu.ttf │ └── UbuntuMono.ttf │ ├── html │ ├── devtools.html │ └── panel.html │ ├── img │ ├── down.png │ ├── dropdown.png │ ├── icons │ │ ├── icon_16.png │ │ ├── icon_32.png │ │ └── icon_64.png │ └── up.png │ ├── js │ ├── ext │ │ ├── background.js │ │ ├── devtools.js │ │ └── panel.js │ └── lib │ │ ├── highlight.js │ │ ├── jquery-3.2.1.min.js │ │ ├── languages │ │ ├── json.js │ │ └── sql.js │ │ └── sql-formatter.min.js │ └── manifest.json ├── setup.py ├── tests ├── __init__.py ├── db │ ├── alt_db │ └── def_db ├── runtests.py ├── stub │ ├── forms.py │ ├── index.html │ ├── models.py │ ├── router.py │ ├── settings.py │ ├── urls.py │ └── views.py ├── test_context.py ├── test_manager.py ├── test_middleware.py ├── test_profile.py ├── test_pstats.py ├── test_queries.py └── test_serializer.py └── tox.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.py linguist-vendored=false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | develop-eggs/ 5 | dist/ 6 | downloads/ 7 | eggs/ 8 | .eggs/ 9 | parts/ 10 | sdist/ 11 | var/ 12 | wheels/ 13 | *.egg-info/ 14 | .installed.cfg 15 | *.egg 16 | pip-log.txt 17 | pip-delete-this-directory.txt 18 | htmlcov/ 19 | .tox/ 20 | .coverage 21 | .coverage.* 22 | .cache 23 | .idea 24 | nosetests.xml 25 | coverage.xml 26 | MANIFEST 27 | *.cover 28 | .hypothesis/ 29 | .pytest_cache/ 30 | *.log -------------------------------------------------------------------------------- /.preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/.preview.gif -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM buildpack-deps:stretch 2 | MAINTAINER Igor Tolkachnikov 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | ENV LANG C.UTF-8 6 | 7 | WORKDIR /opt/data 8 | SHELL ["/bin/bash", "-c"] 9 | 10 | # Using mirror - official repository was blocked for me, sorry. 11 | RUN truncate -s 0 /etc/apt/sources.list \ 12 | && bash -c 'echo -e "deb http://mirror.yandex.ru/debian stretch main\ndeb-src http://mirror.yandex.ru/debian stretch main" | tee /etc/apt/sources.list' 13 | 14 | RUN apt-get update && apt-get install -y --no-install-recommends \ 15 | build-essential \ 16 | python-dev \ 17 | python3-dev \ 18 | libssl-dev \ 19 | zlib1g-dev \ 20 | libdb5.3-dev \ 21 | libbz2-dev \ 22 | libexpat1-dev \ 23 | liblzma-dev \ 24 | libncursesw5-dev \ 25 | libreadline-dev \ 26 | libsqlite3-dev \ 27 | libgdbm-dev \ 28 | libncurses5-dev \ 29 | libffi-dev \ 30 | libxml2-dev \ 31 | libxslt1-dev \ 32 | && apt-get clean && rm -rf /var/lib/apt/lists/* 33 | 34 | # Adding Python 3.6 35 | RUN wget "https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz" \ 36 | && tar -xvf Python-3.6.5.tar.xz \ 37 | && cd ./Python-3.6.5 \ 38 | && ./configure && make && make install 39 | 40 | # Clean up 41 | RUN apt-get clean && rm -rf /tmp/* /var/tmp/* /opt/data/Python-3.6.5 /opt/data/Python-3.6.5.tar.xz 42 | 43 | # Tox 44 | RUN pip3 install --upgrade pip && pip3 install tox 45 | CMD ["/bin/sh"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 everhide 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | recursive-include everbug/ * -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Everbug - Debugger for Django projects 2 | 3 | ![](https://img.shields.io/badge/build-passing-brightgreen.svg) ![](https://img.shields.io/badge/coverage-98%25-green.svg) 4 | 5 | The Everbug is a lightweight Django middleware for Chrome/Firefox extension with easy install. 6 | One of the advantages: the response body of target page remains clean and unchanged. 7 | 8 | Special summary: 9 | * Database queries with explains (Multiple database support) 10 | * Context variables 11 | * Profiles functions (cProfile through decorator) 12 | * Support ajax requests 13 | 14 | ### Demo 15 | ![Demo](.preview.gif) 16 | 17 | ## Installing 18 | 19 | For Django: 20 | ``` 21 | Run "pip install everbug". 22 | Add "everbug" to your INSTALLED_APPS in settings.py. 23 | Append "everbug.middleware.Tracer" to MIDDLEWARE or MIDDLEWARE_CLASSES in settings.py. 24 | ``` 25 | 26 | For browser: 27 | * [Chrome extension](https://chrome.google.com/webstore/search/everbug) 28 | * [Firefox extension](https://addons.mozilla.org/ru/firefox/addon/everbug/) 29 | 30 | ## Usage 31 | Context variables displayed as-is, except admin views, DRF views and all views without a context_data. Queries works for all databases and requests (include ajax) in "DATABASES" section. Profile works for all methods through decorator (based on builtin cProfile). By default, profile output is truncated to 20 lines. 32 | 33 | Example usage: 34 | ```python 35 | from everbug.shortcuts import profile 36 | 37 | @profile 38 | def sample_method(): 39 | # some code here ... 40 | ``` 41 | Call @profile with argument for full view, for example: 42 | ```python 43 | @profile(short=False) 44 | def sample_method(): 45 | # some code here ... 46 | ``` 47 | 48 | ## Running the tests 49 | ```shell 50 | docker-compose up -d 51 | docker exec -it everbug tox 52 | ``` 53 | 54 | ## Requirements 55 | Python >= 3.5 56 | Django >= 1.11 57 | 58 | ## License 59 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 60 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Everbug - Debugger for Django projects 2 | ====================================== 3 | 4 | The Everbug is a lightweight Django middleware for Chrome extension with easy install. One of the advantages: the response body of target page remains clean 5 | and unchanged. 6 | 7 | Special summary: 8 | * Database queries with explains (Multiple database support) 9 | * Context variables 10 | * Profiles functions (cProfile through decorator) 11 | * Support ajax requests 12 | 13 | 14 | Installing 15 | ----------------- 16 | 17 | For Django: 18 | 19 | :: 20 | 21 | Run "pip install everbug". 22 | Add "everbug" to your INSTALLED_APPS in settings.py. 23 | Append "everbug.middleware.Tracer" to MIDDLEWARE or MIDDLEWARE_CLASSES in settings.py. 24 | 25 | For Chrome: _chrome_ext_ 26 | For Firefox: _firefox_ext_ 27 | 28 | Usage 29 | ----------------- 30 | 31 | “Context” works for any view which has a “context_data”. “Queries” works 32 | as-is for all databases in “DATABASES” section. “Profile” works through 33 | decorator (based on builtin cProfile). By default, profile output is 34 | truncated to 20 lines. 35 | 36 | Example usage: 37 | 38 | :: 39 | 40 | from everbug.shortcuts import profile 41 | 42 | @profile 43 | def sample_method(): 44 | // some code here ... 45 | 46 | Call @profile with argument for full view, for example: 47 | 48 | :: 49 | 50 | @profile(short=False) 51 | def sample_method(): 52 | // some code here ... 53 | 54 | Running the tests 55 | ----------------- 56 | 57 | :: 58 | 59 | docker-compose up -d 60 | docker exec -it everbug tox 61 | 62 | Requirements 63 | ----------------- 64 | 65 | | Python >= 3.5 66 | | Django >= 1.11 67 | 68 | License 69 | ----------------- 70 | 71 | This project is licensed under the MIT License - see the `LICENSE`_ file 72 | for details 73 | 74 | .. _chrome_ext: https://chrome.google.com/webstore/search/everbug 75 | .. _firefox_ext: https://addons.mozilla.org/ru/firefox/addon/everbug 76 | .. _LICENSE: LICENSE -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | everbug: 6 | restart: always 7 | container_name: "everbug" 8 | tty: true 9 | build: 10 | context: . 11 | dockerfile: Dockerfile 12 | image: "everbug:v1.0" 13 | volumes: 14 | - "./:/opt/data" 15 | - "./tests:/opt/data/tests:ro" 16 | - "./everbug:/opt/data/everbug:ro" 17 | -------------------------------------------------------------------------------- /everbug/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.24' -------------------------------------------------------------------------------- /everbug/middleware.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.cache import cache 3 | from django.core.exceptions import MiddlewareNotUsed 4 | from django.http import JsonResponse 5 | from django.utils.deprecation import MiddlewareMixin 6 | 7 | from everbug.utils.context import wrap_context 8 | from everbug.utils.manager import ProfileManager 9 | from everbug.utils.queries import wrap_queries 10 | from everbug.utils.serilalize import serial 11 | 12 | 13 | class Header: 14 | REQUEST = 'HTTP_REQUEST_ID' 15 | TRACE = 'HTTP_TRACE_ID' 16 | HAS_TRACE = 'HTTP_HAS_TRACE' 17 | 18 | 19 | class Field: 20 | CONTEXT = 'context' 21 | QUERIES = 'queries' 22 | PROFILES = 'profiles' 23 | 24 | 25 | class Tracer(MiddlewareMixin): 26 | 27 | def __init__(self, get_response=None): 28 | if not getattr(settings, 'DEBUG', False): 29 | raise MiddlewareNotUsed 30 | super().__init__() 31 | self.get_response = get_response 32 | self.request_id = 0 33 | self.manager = ProfileManager() 34 | self.data = {} 35 | 36 | def process_request(self, request): 37 | if Header.TRACE in request.META: 38 | trace_id = request.META.get(Header.TRACE, 0) 39 | cached_data = cache.get(trace_id, {}) 40 | json_response = { 41 | 'data': cached_data, 42 | 'status': 200 if cached_data else 404, 43 | 'json_dumps_params': {'default': serial} 44 | } 45 | return JsonResponse(**json_response) 46 | elif Header.REQUEST in request.META: 47 | self.manager.clear() 48 | self.data = {} 49 | self.request_id = request.META.get(Header.REQUEST, 0) 50 | 51 | def process_template_response(self, request, response): 52 | if self.request_id and not request.path.startswith('/admin/'): 53 | if getattr(response, 'context_data', None): 54 | self.data[Field.CONTEXT] = wrap_context(response.context_data) 55 | return response 56 | 57 | def process_response(self, request, response): 58 | if Header.REQUEST in request.META and self.request_id: 59 | self.data[Field.QUERIES] = wrap_queries() 60 | if self.manager.count > 0: 61 | self.data[Field.PROFILES] = self.manager.profiles() 62 | self.data = {k: v for k, v in self.data.items() if v} 63 | if self.data: 64 | cache.set(self.request_id, self.data) 65 | response[Header.HAS_TRACE] = self.request_id 66 | else: 67 | response[Header.HAS_TRACE] = 0 68 | return response 69 | -------------------------------------------------------------------------------- /everbug/shortcuts.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from cProfile import Profile 3 | from functools import partial, wraps 4 | 5 | from everbug.utils.manager import ProfileManager 6 | from everbug.utils.pstats import StatsDict 7 | 8 | 9 | def profile(method=None, *, short=True): 10 | if not method: 11 | return partial(profile, short=short) 12 | 13 | manager = ProfileManager() 14 | 15 | @wraps(method) 16 | def wrapper(*args, **kwargs): 17 | prof = Profile() 18 | try: 19 | prof.enable() 20 | execute = method(*args, **kwargs) 21 | prof.disable() 22 | return execute 23 | finally: 24 | stats = StatsDict(prof) 25 | prof_data = stats.sort_stats('cumtime').dump(short) 26 | prof_data['method'] = method.__name__ 27 | prof_data['module'] = sys.modules[method.__module__].__file__ 28 | manager.add(prof_data) 29 | return wrapper 30 | -------------------------------------------------------------------------------- /everbug/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/everbug/utils/__init__.py -------------------------------------------------------------------------------- /everbug/utils/context.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Model, QuerySet 2 | from django.forms import Form 3 | from django.views import View 4 | 5 | 6 | TYPE_DJANGO = (QuerySet, Form, Model) 7 | 8 | TYPE_BUILTINS = ( 9 | int, 10 | float, 11 | complex, 12 | bool, 13 | bytes, 14 | bytearray, 15 | str, 16 | tuple, 17 | set, 18 | frozenset, 19 | list, 20 | dict 21 | ) 22 | 23 | 24 | class Ext: 25 | SIMPLE, ITERABLE, DJANGO, CLASS = 0, 1, 2, 3 26 | 27 | 28 | def wrap_context(context): 29 | """ Wraps a django context dict into list of tuples 30 | :param context: django context dict 31 | :return: (list) 32 | """ 33 | 34 | def wrap(key, val): 35 | """ Wraps a context element in a tuple. 36 | Result tuple contains: 37 | * name - name of context element 38 | * value - value of context element 39 | * class - repr class name of a value 40 | * ext - flag of type group for extension 41 | * count - length of value if it's possible or makes sense 42 | :param key: name of context element. 43 | :param val: value of context element. 44 | :return: (tuple) 45 | """ 46 | 47 | cls, ext, count = val.__class__.__name__, Ext.CLASS, 0 48 | if isinstance(val, TYPE_BUILTINS): 49 | if not hasattr(val, '__len__') and not hasattr(val, '__iter__'): 50 | ext = Ext.SIMPLE 51 | else: 52 | ext, count = Ext.ITERABLE, len(val) 53 | elif isinstance(val, TYPE_DJANGO): 54 | ext = Ext.DJANGO 55 | if isinstance(val, QuerySet): 56 | count = len(val) 57 | cls = 'QuerySet: %s' % val.model.__name__ 58 | elif isinstance(val, Model): 59 | cls, count = 'Model: %s' % val.__class__.__name__, 1 60 | elif isinstance(val, Form): 61 | cls, count = 'Form: %s' % val.__class__.__name__, 1 62 | else: 63 | if hasattr(val, '__name__'): 64 | cls = 'Class: %s' % val.__name__ 65 | else: 66 | cls = 'Instance: %s' % val.__class__.__name__ 67 | # for ugly representation other classes and instances 68 | val = val if len(str(val)) < 50 else '%s...' % str(val)[:50] 69 | 70 | return key, val, cls, ext, count 71 | 72 | items = [wrap(k, v) for k, v in context.items() if not isinstance(v, View)] 73 | return sorted(items, key=lambda item: item[3]) 74 | -------------------------------------------------------------------------------- /everbug/utils/manager.py: -------------------------------------------------------------------------------- 1 | class _Manager(type): 2 | """ Singletone for cProfile manager """ 3 | _inst = {} 4 | 5 | def __call__(cls, *args, **kwargs): 6 | if cls not in cls._inst: 7 | cls._inst[cls] = super(_Manager, cls).__call__(*args, **kwargs) 8 | return cls._inst[cls] 9 | 10 | 11 | class ProfileManager(metaclass=_Manager): 12 | 13 | def __init__(self): 14 | self._profiles = list() 15 | 16 | def clear(self): 17 | self._profiles.clear() 18 | 19 | def add(self, profile): 20 | self._profiles.append(profile) 21 | 22 | def profiles(self): 23 | return self._profiles 24 | 25 | @property 26 | def count(self): 27 | return len(self._profiles) 28 | -------------------------------------------------------------------------------- /everbug/utils/pstats.py: -------------------------------------------------------------------------------- 1 | from pstats import Stats 2 | from pstats import func_std_string as fss 3 | 4 | 5 | class StatsDict(Stats): 6 | 7 | def dump(self, short=False): 8 | """ lines is a list of tuples: (ncalls, tottime, cumtime, func) """ 9 | fns = self.fcn_list 10 | if not fns: 11 | return None 12 | prof = { 13 | 'total_calls': self.total_calls, 14 | 'total_time': round(self.total_tt, 3), 15 | 'lines': [] 16 | } 17 | if short: 18 | fns, *_ = self.eval_print_amount(20, self.fcn_list, '') 19 | for f in fns: 20 | cc, nc, tt, ct, callers = self.stats[f] 21 | nc = nc if nc == cc else '%s/%s' % (nc, cc) 22 | prof['lines'].append((nc, round(tt, 3), round(ct, 3), fss(f))) 23 | return prof 24 | -------------------------------------------------------------------------------- /everbug/utils/queries.py: -------------------------------------------------------------------------------- 1 | from django.db import connections 2 | from django.db.utils import OperationalError 3 | 4 | 5 | def wrap_queries(): 6 | """ Wraps queries with their explains 7 | For example: {alias: [list of queries with explains], ...} 8 | List of queries like: [{'time': ..., 'explain': ..., 'sql': ...}, ...] 9 | :return: (None or dict) 10 | """ 11 | 12 | def query_explain(connection, raw_sql): 13 | if connection.vendor == 'sqlite': 14 | sql = "EXPLAIN QUERY PLAN %s" % raw_sql 15 | elif connection.vendor == 'postgresql': 16 | sql = "EXPLAIN ANALYZE %s" % raw_sql 17 | elif connection.vendor == 'oracle': 18 | sql = "EXPLAIN PLAN FOR %s" % raw_sql 19 | else: 20 | sql = "EXPLAIN %s" % raw_sql 21 | try: 22 | with connections[connection.alias].cursor() as cursor: 23 | cursor.execute(sql) 24 | return cursor.fetchall() 25 | except OperationalError: 26 | return [] 27 | 28 | active_connections = [c for c in connections.all() if c.queries] 29 | if not active_connections: 30 | return None 31 | 32 | queries = {connection.alias: [] for connection in active_connections} 33 | for connection in active_connections: 34 | for query in connection.queries: 35 | explain = {'explain': query_explain(connection, query['sql'])} 36 | queries[connection.alias].append(dict(query, **explain)) 37 | return queries 38 | -------------------------------------------------------------------------------- /everbug/utils/serilalize.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch 2 | 3 | from django.core.serializers import serialize 4 | from django.db.models import Model, QuerySet 5 | from django.forms import Form 6 | from django.forms.models import model_to_dict 7 | 8 | 9 | @singledispatch 10 | def serial(obj): 11 | """ JSON Encoder 12 | Returns (for all nested elements of lists and dicts): 13 | * int, float, str, bool - as is 14 | * tuple, set and frozenset - as list 15 | * django form and model - as dict 16 | * django queryset via builtin django serializer 17 | * others - as str 18 | """ 19 | if isinstance(obj, (int, float, str, bool)): 20 | return obj 21 | return str(obj) 22 | 23 | 24 | @serial.register(dict) 25 | def _(obj): 26 | return {k: serial(v) for k, v in obj.items()} 27 | 28 | 29 | @serial.register(set) 30 | @serial.register(list) 31 | @serial.register(tuple) 32 | @serial.register(frozenset) 33 | def _(obj): 34 | return [serial(i) for i in obj] 35 | 36 | 37 | @serial.register(Form) 38 | def _(obj): 39 | fields = obj.fields 40 | return {f: type(fields[f]).__name__ for f in fields} 41 | 42 | 43 | @serial.register(QuerySet) 44 | def _(obj): 45 | return serialize('python', obj) 46 | 47 | 48 | @serial.register(Model) 49 | def _(obj): 50 | return model_to_dict(obj) 51 | -------------------------------------------------------------------------------- /extension/chrome/css/hljs.theme.css: -------------------------------------------------------------------------------- 1 | .hljs { 2 | display: block; 3 | overflow-x: auto; 4 | padding: .5em; 5 | background: #eaeef3; 6 | color: #00193a; 7 | } 8 | 9 | .hljs-keyword,.hljs-selector-tag,.hljs-title,.hljs-section,.hljs-doctag,.hljs-name,.hljs-strong { 10 | font-weight: 700; 11 | } 12 | 13 | .hljs-comment { 14 | color: #738191; 15 | } 16 | 17 | .hljs-string,.hljs-title,.hljs-section,.hljs-built_in,.hljs-literal,.hljs-type,.hljs-addition,.hljs-tag,.hljs-quote,.hljs-name,.hljs-selector-id,.hljs-selector-class { 18 | color: #0048ab; 19 | } 20 | 21 | .hljs-meta,.hljs-subst,.hljs-symbol,.hljs-regexp,.hljs-attribute,.hljs-deletion,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-bullet { 22 | color: #4c81c9; 23 | } 24 | 25 | .hljs-emphasis { 26 | font-style: italic; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /extension/chrome/css/plugin.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Ubuntu'; 3 | src: url(../fonts/Ubuntu.ttf); 4 | } 5 | 6 | @font-face { 7 | font-family:'UbuntuMono'; 8 | src:url(../fonts/UbuntuMono.ttf); 9 | } 10 | 11 | * { 12 | margin: 0; 13 | padding: 0; 14 | } 15 | 16 | html { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | background: #F5F5F5; 22 | font: 12px Ubuntu; 23 | color: #333; 24 | padding-top: 2px; 25 | overflow-y: auto; 26 | overflow-x: hidden; 27 | } 28 | 29 | a { 30 | color: #333; 31 | } 32 | 33 | #extension { 34 | width: 100%; 35 | min-height: 50px; 36 | padding: 0; 37 | margin: 0; 38 | } 39 | 40 | #tabs { 41 | user-select: none; 42 | float: left; 43 | margin: 0; 44 | padding: 0; 45 | height: 28px; 46 | width: 100%; 47 | list-style: none; 48 | border: 0; 49 | border-bottom: 1px solid #999; 50 | border-left: 0; 51 | background: #f5f5f5; 52 | } 53 | 54 | #tabs li { 55 | float: left; 56 | margin: 0; 57 | padding: 0; 58 | height: 27px; 59 | line-height: 27px; 60 | border: 1px solid #999; 61 | border-left: none; 62 | overflow: hidden; 63 | position: relative; 64 | background: #e0e0e0; 65 | } 66 | 67 | #tabs li a { 68 | text-decoration: none; 69 | display: block; 70 | padding: 0 20px; 71 | outline: none; 72 | } 73 | 74 | #tabs li:first-child { 75 | border-left: 0; 76 | } 77 | 78 | #tabs li:active,#tabs li:active { 79 | background: #F5F5F5; 80 | border-bottom: 1px solid #F5F5F5; 81 | } 82 | 83 | #tabs li a:hover { 84 | background: #fafafa; 85 | } 86 | 87 | #tabs .active,#tabs .active a:hover { 88 | background: #F5F5F5; 89 | border-bottom: 1px solid #F5F5F5; 90 | } 91 | 92 | #tabs .has_unread { 93 | background: #DDF2CE; 94 | } 95 | 96 | #panels { 97 | background: #F5F5F5; 98 | padding: 5px; 99 | height: 100%; 100 | } 101 | 102 | #panels .wrapper { 103 | margin-top: 30px; 104 | background: #FFF; 105 | border: solid 1px #aaa; 106 | border-bottom: 0; 107 | } 108 | 109 | .context-view { 110 | list-style: none; 111 | margin: 0; 112 | padding: 0; 113 | width: 100%; 114 | } 115 | 116 | .context-view li { 117 | margin: 1px; 118 | margin-bottom: 0; 119 | background: #FCFCFC; 120 | border-bottom: 1px solid #CCC; 121 | position: relative; 122 | padding: 0; 123 | padding-left: 5px; 124 | padding-right: 5px; 125 | } 126 | 127 | .context-view .item { 128 | margin: 0; 129 | padding: 0; 130 | width: 100%; 131 | height: 30px; 132 | user-select: none; 133 | display: inline-table; 134 | cursor: default; 135 | } 136 | 137 | .context-view .item span { 138 | line-height: 20px; 139 | display: inline-block; 140 | margin-left: 0; 141 | } 142 | 143 | .context-view .ext { 144 | margin: 0; 145 | margin-top: 3px; 146 | background: #d5d5d5; 147 | border-radius: 3px; 148 | font-size: 12px!important; 149 | height: 18px; 150 | line-height: 18px; 151 | padding: 1px 6px 2px 4px; 152 | } 153 | 154 | .context-view .ext_0 { 155 | background: #F2F2C4; 156 | border: 1px solid #CDCDA6; 157 | color: #8D8118; 158 | } 159 | 160 | .context-view .ext_1 { 161 | background: #DDF3FB; 162 | border: 1px solid #9FC9D7; 163 | color: #1E6CA8; 164 | } 165 | 166 | .context-view .ext_2 { 167 | background: #DDF2CE; 168 | border: 1px solid #C4D7B7; 169 | color: #449609; 170 | } 171 | 172 | .context-view .ext_3 { 173 | background: #E0E0E0; 174 | border: 1px solid #D3D3D3; 175 | color: #575757; 176 | } 177 | 178 | .context-view .name { 179 | color: gray; 180 | padding-left: 10px; 181 | } 182 | 183 | .context-view .value { 184 | padding-left: 5px; 185 | color: #555; 186 | } 187 | 188 | .context-view .expand { 189 | float: right; 190 | padding-right: 10px; 191 | height: 30px; 192 | width: 30px; 193 | } 194 | 195 | .context-view .content { 196 | width: 100%; 197 | background: #fff; 198 | border: 1px solid #CCC; 199 | margin-bottom: 5px; 200 | line-height: 20px; 201 | } 202 | 203 | .context-view .content .inner { 204 | padding: 5px; 205 | padding-left: 10px; 206 | background: #EAEEF3; 207 | color: #6f7e8b; 208 | white-space: pre; 209 | } 210 | 211 | .context-view .wrap_text { 212 | white-space: normal!important; 213 | } 214 | 215 | #tab_queries { 216 | overflow: hidden; 217 | } 218 | 219 | #tab_queries .info { 220 | float: right; 221 | margin-top: 8px; 222 | margin-right: 16px; 223 | color: #555; 224 | font-size: 12px; 225 | user-select: none; 226 | } 227 | 228 | #tab_queries .db-select { 229 | width: 500px; 230 | padding: 6px; 231 | padding-top: 3px; 232 | user-select: none; 233 | } 234 | 235 | #tab_queries .db label { 236 | user-select: none; 237 | color: #555; 238 | font-size: 12px; 239 | } 240 | 241 | #tab_queries .db { 242 | user-select: none; 243 | width: 100%; 244 | height: 30px; 245 | border-bottom: 1px solid #CCC; 246 | background: #FAFAFA; 247 | } 248 | 249 | #tab_queries .db select { 250 | margin-left: 10px; 251 | background: #FFF; 252 | min-width: 150px; 253 | text-align: right; 254 | height: 24px; 255 | border: 1px solid #9d9d9d; 256 | color: #444; 257 | } 258 | 259 | #tab_queries .db option { 260 | user-select: none; 261 | background: #FFF; 262 | text-align: right; 263 | } 264 | 265 | .queries { 266 | overflow: hidden; 267 | } 268 | 269 | .queries table { 270 | width: 100%; 271 | min-width: 500px; 272 | border-collapse: collapse; 273 | font-size: 12px; 274 | color: #6b6b6b; 275 | } 276 | 277 | .queries table tr { 278 | line-height: 24px; 279 | background: #fdfdfd; 280 | border-bottom: 1px solid #b6bbbf; 281 | } 282 | 283 | .queries thead tr { 284 | height: 24px; 285 | background: #e3e3e3; 286 | font-size: 12px; 287 | text-transform: uppercase; 288 | color: #727272; 289 | border: 0; 290 | border-bottom: 1px solid #CCC; 291 | user-select: none; 292 | } 293 | 294 | .queries td { 295 | box-sizing: border-box; 296 | padding-left: 10px; 297 | vertical-align: top; 298 | } 299 | 300 | .queries tbody td:nth-child(3) { 301 | color: #000; 302 | white-space: pre; 303 | } 304 | 305 | .profile-view { 306 | margin: 0; 307 | padding: 0; 308 | width: 100%; 309 | } 310 | 311 | .profile-view ul { 312 | margin: 0; 313 | padding: 0; 314 | list-style: none; 315 | } 316 | 317 | .profile-view li { 318 | padding: 0; 319 | margin: 1px; 320 | margin-bottom: 0; 321 | background: #FCFCFC; 322 | border-bottom: 1px solid #ccc; 323 | position: relative; 324 | height: auto; 325 | overflow: hidden; 326 | } 327 | 328 | .profile-view .name div { 329 | float: right; 330 | display: inline-block; 331 | } 332 | 333 | .profile-view li .name { 334 | cursor: pointer; 335 | height: 30px; 336 | line-height: 30px; 337 | user-select: none; 338 | overflow: hidden; 339 | } 340 | 341 | .profile-view li .content { 342 | height: 50px; 343 | display: inline-table; 344 | width: 100%; 345 | } 346 | 347 | .profile-view table { 348 | display: inline-table; 349 | color: #333; 350 | border-collapse: collapse; 351 | width: 100%; 352 | } 353 | 354 | .profile-view table thead { 355 | height: 24px; 356 | line-height: 24px; 357 | background: #e3e3e3; 358 | font-size: 13px; 359 | text-transform: uppercase; 360 | color: #727272; 361 | border: 0; 362 | border-top: 1px solid #CCC; 363 | border-bottom: 1px solid #CCC; 364 | user-select: none; 365 | } 366 | 367 | .profile-view table thead td { 368 | padding-left: 10px; 369 | } 370 | 371 | .profile-view table tbody { 372 | background: #fff; 373 | } 374 | 375 | .profile-view table tbody td { 376 | padding-left: 10px; 377 | line-height: 20px; 378 | background: #FDFDFD; 379 | color: #555; 380 | } 381 | 382 | .profile-view table tbody tr { 383 | border-bottom: 1px solid #dcdfe4; 384 | } 385 | 386 | .profile-view table tbody tr:last-child { 387 | border-bottom: 0; 388 | } 389 | 390 | .profile-view table tbody tr td:nth-last-child(1) { 391 | background: #EAEEF3; 392 | color: #6f7e8b; 393 | } 394 | 395 | .profile-view span { 396 | padding-left: 10px; 397 | } 398 | 399 | .profile-view .totals { 400 | color: #727272; 401 | } 402 | 403 | .profile-view .module { 404 | color: #9b9b9b; 405 | } 406 | 407 | .profile-view .func { 408 | margin-left: 4px; 409 | padding: 4px 7px 4px 5px; 410 | background: #e5e1f6; 411 | border: 1px solid #d9cce9; 412 | border-radius: 3px; 413 | color: #6a3a99; 414 | } 415 | 416 | .profile-view .expand { 417 | float: right; 418 | padding-right: 11px; 419 | height: 24px; 420 | width: 24px; 421 | background-size: 28%!important; 422 | } 423 | 424 | #tab_help .menu { 425 | width: 100%; 426 | font-size: 14px; 427 | border-bottom: 1px solid #a5a5a5; 428 | padding-bottom: 20px; 429 | padding-top: 10px; 430 | } 431 | 432 | #tab_help hr { 433 | border: 0; 434 | border-bottom: 1px solid #e3e3e3; 435 | margin-bottom: 5px; 436 | } 437 | 438 | #tab_help h2 { 439 | font-size: 22px; 440 | font-weight: 400!important; 441 | color: #4c81c9; 442 | background: url(../img/icons/icon_32.png) no-repeat top left; 443 | background-position: 10px 0; 444 | padding-top: 4px; 445 | padding-left: 55px; 446 | height: 40px; 447 | } 448 | 449 | #tab_help h3 { 450 | font-size: 18px; 451 | font-weight: 400!important; 452 | color: #7ca3d4; 453 | padding-left: 10px; 454 | } 455 | 456 | #tab_help p { 457 | padding-left: 10px; 458 | color: #6b6b6b; 459 | } 460 | 461 | .close { 462 | background: url(../img/up.png) top left no-repeat; 463 | background-position: 20px 8px; 464 | background-size: 30%; 465 | display: inline-block; 466 | } 467 | 468 | .open { 469 | background: url(../img/down.png) top left no-repeat; 470 | background-position: 20px 8px; 471 | background-size: 30%; 472 | display: inline-block; 473 | } 474 | 475 | .expandable { 476 | cursor: pointer!important; 477 | } 478 | 479 | -------------------------------------------------------------------------------- /extension/chrome/fonts/Ubuntu.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/fonts/Ubuntu.ttf -------------------------------------------------------------------------------- /extension/chrome/fonts/UbuntuMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/fonts/UbuntuMono.ttf -------------------------------------------------------------------------------- /extension/chrome/html/devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /extension/chrome/html/panel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 29 | 30 |
31 |
32 | 33 |
34 |
    35 |
    36 | 37 |
    38 |
    39 |
    40 |
    41 | 42 | 43 |
    44 |
    45 |
    46 |
    47 | 48 |
    49 |
    50 |
      51 |
      52 |
      53 | 54 |
      55 | 56 | 70 | 71 |
      72 | 73 |
      74 |
      75 | 76 | 77 |
      78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /extension/chrome/img/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/down.png -------------------------------------------------------------------------------- /extension/chrome/img/icons/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/icons/icon_16.png -------------------------------------------------------------------------------- /extension/chrome/img/icons/icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/icons/icon_32.png -------------------------------------------------------------------------------- /extension/chrome/img/icons/icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/icons/icon_64.png -------------------------------------------------------------------------------- /extension/chrome/img/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/icons/logo.png -------------------------------------------------------------------------------- /extension/chrome/img/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/chrome/img/up.png -------------------------------------------------------------------------------- /extension/chrome/js/ext/background.js: -------------------------------------------------------------------------------- 1 | var connections = {}; 2 | 3 | function isTraced(headers) { 4 | for (var i = 0; i < headers.length; ++i) { 5 | if (headers[i].name === 'HTTP_HAS_TRACE') { 6 | return headers[i].value 7 | } 8 | } 9 | return 0 10 | } 11 | 12 | chrome.runtime.onConnect.addListener(function (port){ 13 | var extensionListener = function (message, sender, sendResponse){ 14 | if (message.name === "init"){ 15 | connections[message.tab_id] = port; 16 | connections[message.tab_id].postMessage({ 17 | 'status': 'initiated', 18 | 'tab_id': message.tab_id 19 | }); 20 | return null 21 | } 22 | }; 23 | port.onMessage.addListener(extensionListener); 24 | port.onDisconnect.addListener(function(port){ 25 | port.onMessage.removeListener(extensionListener); 26 | var tabs = Object.keys(connections); 27 | for (var i = 0, len = tabs.length; i < len; i++){ 28 | if (connections[tabs[i]] === port){ 29 | delete connections[tabs[i]]; 30 | break 31 | } 32 | } 33 | }) 34 | }); 35 | 36 | chrome.webRequest.onHeadersReceived.addListener(function callback(details) { 37 | if (details.tabId in connections) { 38 | if ((details.frameId >= 0) && ((details.type === 'main_frame') || (details.type === 'xmlhttprequest'))) { 39 | if (details.type === 'main_frame') { 40 | connections[details.tabId].postMessage({ 41 | status: 'clear', 42 | tab_id: details.tabId 43 | }) 44 | } 45 | var trace_id = isTraced(details.responseHeaders); 46 | if (trace_id >= 1 && trace_id !== 'undefined'){ 47 | connections[details.tabId].postMessage({ 48 | 'status': 'trace', 49 | 'tab_id': details.tabId, 50 | 'trace_id': trace_id, 51 | 'url': details.url 52 | }) 53 | } 54 | } 55 | } 56 | }, 57 | { 58 | urls: [''], 59 | types: ['main_frame', 'xmlhttprequest'] 60 | }, ['responseHeaders']); 61 | 62 | chrome.webRequest.onBeforeSendHeaders.addListener(function(details){ 63 | if (details.frameId >= 0){ 64 | if (!('TRACE-ID' in details.requestHeaders)){ 65 | details.requestHeaders.push({ 66 | name: 'REQUEST-ID', 67 | value: details.requestId 68 | }) 69 | } 70 | } 71 | return {requestHeaders: details.requestHeaders} 72 | }, { urls: [""]}, ["blocking", "requestHeaders"]); 73 | 74 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 75 | if (tabId in connections){ 76 | switch (changeInfo.status){ 77 | case 'complete': 78 | connections[tabId].postMessage({ 79 | 'status': 'complete', 80 | 'tab_id': tabId 81 | }); 82 | break; 83 | case 'loading': 84 | connections[tabId].postMessage({ 85 | 'status': 'loading', 86 | 'tab_id': tabId 87 | }); 88 | break 89 | } 90 | } 91 | }) 92 | -------------------------------------------------------------------------------- /extension/chrome/js/ext/devtools.js: -------------------------------------------------------------------------------- 1 | var hwd = null; 2 | var port = null; 3 | var tab = chrome.devtools.inspectedWindow.tabId; 4 | 5 | chrome.devtools.panels.create("Everbug", "../img/icons/icon_32.png", "../html/panel.html", function (plugin){ 6 | plugin.onShown.addListener(function captureHandle(handleWindow){ 7 | hwd = handleWindow; 8 | port = chrome.runtime.connect({name: 'everbug-devtool'}); 9 | port.postMessage({name: 'init', tab_id: tab}); 10 | port.onMessage.addListener(messageDispatcher) 11 | }) 12 | }); 13 | 14 | function getTrace(url, trace_id){ 15 | $.ajax({ 16 | type: "GET", 17 | url: url, 18 | dataType: "json", 19 | data: {'trace': !0}, 20 | beforeSend: function (xhr){ 21 | xhr.setRequestHeader("Accept", "application/json, text/plain, */*"); 22 | xhr.setRequestHeader("TRACE-ID", trace_id) 23 | }, 24 | success: function (data){ 25 | append(hwd, JSON.stringify(data)) 26 | } 27 | }) 28 | } 29 | 30 | function messageDispatcher(msg){ 31 | if (msg.tab_id === tab){ 32 | switch (msg.status){ 33 | case 'initiated': 34 | init(hwd); 35 | break; 36 | case 'clear': 37 | clear(hwd); 38 | break; 39 | case 'loading': 40 | break; 41 | case 'complete': 42 | break; 43 | case 'trace': 44 | append(hwd, getTrace(msg.url, msg.trace_id)); 45 | break 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /extension/chrome/js/ext/panel.js: -------------------------------------------------------------------------------- 1 | var queries_count = 0; 2 | var queries_time = 0; 3 | var current_alias = '__all__'; 4 | var aliases = [current_alias]; 5 | 6 | function isJSON(val) { 7 | if (typeof val !== 'string') 8 | val = JSON.stringify(val); 9 | try { 10 | JSON.parse(val); 11 | return !0 12 | } catch (e) { 13 | return !1 14 | } 15 | } 16 | 17 | function init(handle) { 18 | handle.$('#tabs li').hide(); 19 | handle.$('.tb_help').show().addClass('active'); 20 | handle.$(".panel").hide(); 21 | handle.$('#tab_help').show(); 22 | handle.$("ul#tabs li").click(function() { 23 | handle.$("ul#tabs li").removeClass("active"); 24 | $(this).addClass("active").removeClass('has_unread'); 25 | handle.$(".panel").hide(); 26 | var actTab = $(this).find("a").attr("href"); 27 | handle.$(actTab).show(); 28 | return !1 29 | }); 30 | clear(handle) 31 | } 32 | 33 | function clear(handle) { 34 | handle.$('#tabs li').hide(); 35 | handle.$('.tb_help').show(); 36 | queries_count = 0; 37 | queries_time = 0; 38 | aliases = ['__all__']; 39 | handle.$('.context-view').empty(); 40 | handle.$('#tab_queries .info').empty(); 41 | handle.$('#db_filter').empty().append($("").attr("value", '__all__').text('ALL')); 42 | handle.$('.queries').empty(); 43 | handle.$('.profile-view').empty() 44 | } 45 | 46 | function filterQueries(handle, alias) { 47 | var rows = handle.$('.queries > table > tbody > tr'); 48 | if (alias === '__all__') { 49 | rows.show() 50 | } else { 51 | rows.hide(); 52 | handle.$('.queries .' + alias).show() 53 | } 54 | } 55 | 56 | function appendContext(handle, data) { 57 | handle.$('.tb_context').addClass('has_unread'); 58 | var ul = handle.$('.context-view'); 59 | $.each(data, function(index, obj) { 60 | var name = obj[0], 61 | value = obj[1], 62 | cls = obj[2], 63 | ext = obj[3], 64 | cnt = obj[4]; 65 | var is_inline = !((ext === 1) || (ext === 2)); 66 | var item = $('
    • ').append($('
      ', { 67 | 'class': 'item' 68 | }).append($('', { 69 | 'class': 'ext' 70 | }).append(cls)).append($('', { 71 | 'class': 'name' 72 | }).append(name + ' = ')).append($('', { 73 | 'class': 'value' 74 | }))); 75 | if ((ext === 1) || (ext === 2)) { 76 | if (isJSON(value)) { 77 | value = JSON.stringify(value, null, '\t') 78 | } 79 | } 80 | item.find('.ext').addClass('ext_' + ext); 81 | if (is_inline !== !0) { 82 | item.find('.item').addClass('expandable').append($('').addClass('expand').addClass('open')); 83 | item.append($('
      ', { 84 | 'class': 'content' 85 | }).append($('
      ', { 86 | 'class': 'inner' 87 | }).append(value))); 88 | item.find('.value').text('[ items: ' + cnt + ' ]') 89 | } else { 90 | item.find('.value').text(value) 91 | } 92 | if (cls === 'str') { 93 | if (value.length < 50) { 94 | item.find('.value').empty().text(value); 95 | item.find('.content').remove(); 96 | item.find('.expand').remove(); 97 | item.find('.item').removeClass('expandable') 98 | } else { 99 | item.find('.value').empty().text('[ length: ' + value.length + ' ]'); 100 | item.find('.inner').addClass('wrap_text') 101 | } 102 | } 103 | if ((ext >= 1) && (ext <= 3) && (isJSON(value) === !0)) { 104 | item.find('.inner').addClass('json_code') 105 | } 106 | ul.append(item) 107 | }); 108 | hljs.initHighlightingOnLoad(); 109 | handle.$('.json_code').each(function(i, block) { 110 | hljs.highlightBlock(block) 111 | }); 112 | handle.$(".context-view .content").hide(); 113 | handle.$(".context-view .item").click(function() { 114 | var item = $(this).parent(); 115 | if (item.hasClass('active')) { 116 | item.removeClass('active'); 117 | item.find('.expand').removeClass('close').addClass('open'); 118 | item.find('.content').hide() 119 | } else { 120 | item.addClass('active'); 121 | item.find('.expand').removeClass('open').addClass('close'); 122 | item.find('.content').show() 123 | } 124 | return !1 125 | }) 126 | } 127 | 128 | function appendQueries(handle, data) { 129 | handle.$('.tb_queries').addClass('has_unread'); 130 | if (handle.$('.queries').text().length === 0) { 131 | var create_table = $('').append($('').append($('').append($('')); 132 | handle.$('.queries').append(create_table) 133 | } 134 | var filter = handle.$('#db_filter'); 135 | var table_body = handle.$('.queries table').find('tbody'); 136 | $.each(data, function(alias, queries) { 137 | if (!aliases.includes(alias)) { 138 | aliases.push(alias); 139 | filter.append($("").attr("value", alias).text(':: ' + alias)) 140 | } 141 | $.each(queries, function(index, query) { 142 | queries_time += parseFloat(query.time); 143 | queries_count += 1; 144 | var explains = ''; 145 | $.each(query.explain, function(index, expl) { 146 | explains = explains + expl + '\n' 147 | }); 148 | table_body.append($('', { 149 | 'class': alias 150 | }).append($('
      ').text('Time')).append($('').text('Explain')).append($('').text('Sql')))).append($('
      ').text(query.time)).append($('').text(explains)).append($('', { 151 | 'class': 'sql_code' 152 | }).text(query.sql))) 153 | }) 154 | }); 155 | hljs.initHighlightingOnLoad(); 156 | var info = handle.$('#tab_queries .info'); 157 | info.text('Total queries: ' + queries_count + ', total time: ' + queries_time + ' ms'); 158 | handle.$(".queries > table > tbody > tr").each(function() { 159 | var cell = $(this).find("td").eq(2); 160 | cell.text(sqlFormatter.format(cell.text(), { 161 | language: 'sql', 162 | indent: "\t" 163 | })) 164 | }); 165 | if (!aliases.includes(current_alias)) { 166 | current_alias = '__all__' 167 | } 168 | filter.val(current_alias); 169 | filterQueries(handle, current_alias); 170 | filter.click(function() { 171 | var sel = $(this).find('option:selected').val(); 172 | if (sel !== current_alias) { 173 | current_alias = sel 174 | } 175 | filterQueries(handle, current_alias); 176 | return !1 177 | }); 178 | handle.$('.sql_code').each(function(i, block) { 179 | hljs.highlightBlock(block) 180 | }) 181 | } 182 | 183 | function appendProfiles(handle, data) { 184 | handle.$('.tb_profile').addClass('has_unread'); 185 | if (handle.$('.profile-view').find('ul').text().length === 0) { 186 | handle.$('.profile-view').append('
        ') 187 | } 188 | var list = handle.$('.profile-view').find('ul'); 189 | $.each(data, function(i, profile) { 190 | var li = $('
      • ', { 191 | 'class': 'profile' 192 | }).append($('
        ', { 193 | 'class': 'name' 194 | }).append($('', { 195 | 'class': 'func' 196 | }).text('Method: ' + profile.method)).append($('', { 197 | 'class': 'module' 198 | }).text(profile.module)).append($('
        ').append($('', { 199 | 'class': 'totals' 200 | }).text('Total calls: ' + profile.total_calls + ', total time: ' + profile.total_time)).append($('', { 201 | 'class': 'expand close' 202 | })))).append($('
        ', { 203 | 'class': 'content' 204 | }).hide().append($('').append($('').append($('').append($('')))); 205 | var rows = li.find('tbody'); 206 | $.each(profile.lines, function(i, line) { 207 | rows.append($('').append($('
        ').text('ncalls')).append($('').text('tottime')).append($('').text('cumtime')).append($('').text('call')))).append($('
        ').text(line[0])).append($('').text(line[1])).append($('').text(line[2])).append($('').text(line[3]))) 208 | }); 209 | list.append(li) 210 | }); 211 | handle.$(".profile-view .name").unbind('click'); 212 | handle.$(".profile-view .name").click(function() { 213 | var item = $(this).parent(); 214 | if (item.hasClass('active')) { 215 | item.removeClass('active'); 216 | item.find('.expand').removeClass('close').addClass('open'); 217 | item.find('.content').hide() 218 | } else { 219 | item.addClass('active'); 220 | item.find('.expand').removeClass('open').addClass('close'); 221 | item.find('.content').show() 222 | } 223 | return !1 224 | }) 225 | } 226 | 227 | function append(handle, data) { 228 | if (data !== undefined && data !== null) { 229 | var trace = JSON.parse(data); 230 | if ('context' in trace) { 231 | appendContext(handle, trace.context); 232 | handle.$('.tb_context').show() 233 | } 234 | if ('queries' in trace) { 235 | appendQueries(handle, trace.queries); 236 | handle.$('.tb_queries').show() 237 | } 238 | if ('profiles' in trace) { 239 | appendProfiles(handle, trace.profiles); 240 | handle.$('.tb_profile').show() 241 | } 242 | } 243 | if (handle.$('#tabs > li:visible').length > 1) { 244 | if (handle.$("ul#tabs").find('li.active').text() === 'Help') { 245 | handle.$("ul#tabs").find('li:visible:first').click() 246 | } 247 | } 248 | handle.$("ul#tabs").find('li.active').removeClass('has_unread') 249 | } -------------------------------------------------------------------------------- /extension/chrome/js/lib/highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Syntax highlighting with language autodetection. 3 | https://highlightjs.org/ 4 | */ 5 | 6 | (function(factory) { 7 | 8 | // Setup highlight.js for different environments. First is Node.js or 9 | // CommonJS. 10 | if(typeof exports !== 'undefined') { 11 | factory(exports); 12 | } else { 13 | // Export hljs globally even when using AMD for cases when this script 14 | // is loaded with others that may still expect a global hljs. 15 | window.hljs = factory({}); 16 | 17 | // Finally register the global hljs with AMD. 18 | if(typeof define === 'function' && define.amd) { 19 | define([], function() { 20 | return window.hljs; 21 | }); 22 | } 23 | } 24 | 25 | }(function(hljs) { 26 | 27 | /* Utility functions */ 28 | 29 | function escape(value) { 30 | return value.replace(/&/gm, '&').replace(//gm, '>'); 31 | } 32 | 33 | function tag(node) { 34 | return node.nodeName.toLowerCase(); 35 | } 36 | 37 | function testRe(re, lexeme) { 38 | var match = re && re.exec(lexeme); 39 | return match && match.index == 0; 40 | } 41 | 42 | function isNotHighlighted(language) { 43 | return /no-?highlight|plain|text/.test(language); 44 | } 45 | 46 | function blockLanguage(block) { 47 | var i, language, length, 48 | classes = block.className + ' '; 49 | 50 | classes += block.parentNode ? block.parentNode.className : ''; 51 | classes = classes.split(/\s+/); 52 | 53 | for(i = 0, length = classes.length; i < length; i++) { 54 | language = classes[i].replace(/^lang(uage)?-/, ''); 55 | 56 | if(getLanguage(language) || isNotHighlighted(language)) { 57 | return language; 58 | } 59 | } 60 | } 61 | 62 | function inherit(parent, obj) { 63 | var result = {}, key; 64 | for (key in parent) 65 | result[key] = parent[key]; 66 | if (obj) 67 | for (key in obj) 68 | result[key] = obj[key]; 69 | return result; 70 | } 71 | 72 | /* Stream merging */ 73 | 74 | function nodeStream(node) { 75 | var result = []; 76 | (function _nodeStream(node, offset) { 77 | for (var child = node.firstChild; child; child = child.nextSibling) { 78 | if (child.nodeType == 3) 79 | offset += child.nodeValue.length; 80 | else if (child.nodeType == 1) { 81 | result.push({ 82 | event: 'start', 83 | offset: offset, 84 | node: child 85 | }); 86 | offset = _nodeStream(child, offset); 87 | // Prevent void elements from having an end tag that would actually 88 | // double them in the output. There are more void elements in HTML 89 | // but we list only those realistically expected in code display. 90 | if (!tag(child).match(/br|hr|img|input/)) { 91 | result.push({ 92 | event: 'stop', 93 | offset: offset, 94 | node: child 95 | }); 96 | } 97 | } 98 | } 99 | return offset; 100 | })(node, 0); 101 | return result; 102 | } 103 | 104 | function mergeStreams(original, highlighted, value) { 105 | var processed = 0; 106 | var result = ''; 107 | var nodeStack = []; 108 | 109 | function selectStream() { 110 | if (!original.length || !highlighted.length) { 111 | return original.length ? original : highlighted; 112 | } 113 | if (original[0].offset != highlighted[0].offset) { 114 | return (original[0].offset < highlighted[0].offset) ? original : highlighted; 115 | } 116 | 117 | /* 118 | To avoid starting the stream just before it should stop the order is 119 | ensured that original always starts first and closes last: 120 | 121 | if (event1 == 'start' && event2 == 'start') 122 | return original; 123 | if (event1 == 'start' && event2 == 'stop') 124 | return highlighted; 125 | if (event1 == 'stop' && event2 == 'start') 126 | return original; 127 | if (event1 == 'stop' && event2 == 'stop') 128 | return highlighted; 129 | 130 | ... which is collapsed to: 131 | */ 132 | return highlighted[0].event == 'start' ? original : highlighted; 133 | } 134 | 135 | function open(node) { 136 | function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"';} 137 | result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attr_str).join('') + '>'; 138 | } 139 | 140 | function close(node) { 141 | result += ''; 142 | } 143 | 144 | function render(event) { 145 | (event.event == 'start' ? open : close)(event.node); 146 | } 147 | 148 | while (original.length || highlighted.length) { 149 | var stream = selectStream(); 150 | result += escape(value.substr(processed, stream[0].offset - processed)); 151 | processed = stream[0].offset; 152 | if (stream == original) { 153 | /* 154 | On any opening or closing tag of the original markup we first close 155 | the entire highlighted node stack, then render the original tag along 156 | with all the following original tags at the same offset and then 157 | reopen all the tags on the highlighted stack. 158 | */ 159 | nodeStack.reverse().forEach(close); 160 | do { 161 | render(stream.splice(0, 1)[0]); 162 | stream = selectStream(); 163 | } while (stream == original && stream.length && stream[0].offset == processed); 164 | nodeStack.reverse().forEach(open); 165 | } else { 166 | if (stream[0].event == 'start') { 167 | nodeStack.push(stream[0].node); 168 | } else { 169 | nodeStack.pop(); 170 | } 171 | render(stream.splice(0, 1)[0]); 172 | } 173 | } 174 | return result + escape(value.substr(processed)); 175 | } 176 | 177 | /* Initialization */ 178 | 179 | function compileLanguage(language) { 180 | 181 | function reStr(re) { 182 | return (re && re.source) || re; 183 | } 184 | 185 | function langRe(value, global) { 186 | return new RegExp( 187 | reStr(value), 188 | 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '') 189 | ); 190 | } 191 | 192 | function compileMode(mode, parent) { 193 | if (mode.compiled) 194 | return; 195 | mode.compiled = true; 196 | 197 | mode.keywords = mode.keywords || mode.beginKeywords; 198 | if (mode.keywords) { 199 | var compiled_keywords = {}; 200 | 201 | var flatten = function(className, str) { 202 | if (language.case_insensitive) { 203 | str = str.toLowerCase(); 204 | } 205 | str.split(' ').forEach(function(kw) { 206 | var pair = kw.split('|'); 207 | compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; 208 | }); 209 | }; 210 | 211 | if (typeof mode.keywords == 'string') { // string 212 | flatten('keyword', mode.keywords); 213 | } else { 214 | Object.keys(mode.keywords).forEach(function (className) { 215 | flatten(className, mode.keywords[className]); 216 | }); 217 | } 218 | mode.keywords = compiled_keywords; 219 | } 220 | mode.lexemesRe = langRe(mode.lexemes || /\b\w+\b/, true); 221 | 222 | if (parent) { 223 | if (mode.beginKeywords) { 224 | mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b'; 225 | } 226 | if (!mode.begin) 227 | mode.begin = /\B|\b/; 228 | mode.beginRe = langRe(mode.begin); 229 | if (!mode.end && !mode.endsWithParent) 230 | mode.end = /\B|\b/; 231 | if (mode.end) 232 | mode.endRe = langRe(mode.end); 233 | mode.terminator_end = reStr(mode.end) || ''; 234 | if (mode.endsWithParent && parent.terminator_end) 235 | mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end; 236 | } 237 | if (mode.illegal) 238 | mode.illegalRe = langRe(mode.illegal); 239 | if (mode.relevance === undefined) 240 | mode.relevance = 1; 241 | if (!mode.contains) { 242 | mode.contains = []; 243 | } 244 | var expanded_contains = []; 245 | mode.contains.forEach(function(c) { 246 | if (c.variants) { 247 | c.variants.forEach(function(v) {expanded_contains.push(inherit(c, v));}); 248 | } else { 249 | expanded_contains.push(c == 'self' ? mode : c); 250 | } 251 | }); 252 | mode.contains = expanded_contains; 253 | mode.contains.forEach(function(c) {compileMode(c, mode);}); 254 | 255 | if (mode.starts) { 256 | compileMode(mode.starts, parent); 257 | } 258 | 259 | var terminators = 260 | mode.contains.map(function(c) { 261 | return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin; 262 | }) 263 | .concat([mode.terminator_end, mode.illegal]) 264 | .map(reStr) 265 | .filter(Boolean); 266 | mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(/*s*/) {return null;}}; 267 | } 268 | 269 | compileMode(language); 270 | } 271 | 272 | /* 273 | Core highlighting function. Accepts a language name, or an alias, and a 274 | string with the code to highlight. Returns an object with the following 275 | properties: 276 | 277 | - relevance (int) 278 | - value (an HTML string with highlighting markup) 279 | 280 | */ 281 | function highlight(name, value, ignore_illegals, continuation) { 282 | 283 | function subMode(lexeme, mode) { 284 | for (var i = 0; i < mode.contains.length; i++) { 285 | if (testRe(mode.contains[i].beginRe, lexeme)) { 286 | return mode.contains[i]; 287 | } 288 | } 289 | } 290 | 291 | function endOfMode(mode, lexeme) { 292 | if (testRe(mode.endRe, lexeme)) { 293 | while (mode.endsParent && mode.parent) { 294 | mode = mode.parent; 295 | } 296 | return mode; 297 | } 298 | if (mode.endsWithParent) { 299 | return endOfMode(mode.parent, lexeme); 300 | } 301 | } 302 | 303 | function isIllegal(lexeme, mode) { 304 | return !ignore_illegals && testRe(mode.illegalRe, lexeme); 305 | } 306 | 307 | function keywordMatch(mode, match) { 308 | var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; 309 | return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str]; 310 | } 311 | 312 | function buildSpan(classname, insideSpan, leaveOpen, noPrefix) { 313 | var classPrefix = noPrefix ? '' : options.classPrefix, 314 | openSpan = ''; 318 | 319 | return openSpan + insideSpan + closeSpan; 320 | } 321 | 322 | function processKeywords() { 323 | if (!top.keywords) 324 | return escape(mode_buffer); 325 | var result = ''; 326 | var last_index = 0; 327 | top.lexemesRe.lastIndex = 0; 328 | var match = top.lexemesRe.exec(mode_buffer); 329 | while (match) { 330 | result += escape(mode_buffer.substr(last_index, match.index - last_index)); 331 | var keyword_match = keywordMatch(top, match); 332 | if (keyword_match) { 333 | relevance += keyword_match[1]; 334 | result += buildSpan(keyword_match[0], escape(match[0])); 335 | } else { 336 | result += escape(match[0]); 337 | } 338 | last_index = top.lexemesRe.lastIndex; 339 | match = top.lexemesRe.exec(mode_buffer); 340 | } 341 | return result + escape(mode_buffer.substr(last_index)); 342 | } 343 | 344 | function processSubLanguage() { 345 | if (top.subLanguage && !languages[top.subLanguage]) { 346 | return escape(mode_buffer); 347 | } 348 | var result = top.subLanguage ? highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) : highlightAuto(mode_buffer); 349 | // Counting embedded language score towards the host language may be disabled 350 | // with zeroing the containing mode relevance. Usecase in point is Markdown that 351 | // allows XML everywhere and makes every XML snippet to have a much larger Markdown 352 | // score. 353 | if (top.relevance > 0) { 354 | relevance += result.relevance; 355 | } 356 | if (top.subLanguageMode == 'continuous') { 357 | continuations[top.subLanguage] = result.top; 358 | } 359 | return buildSpan(result.language, result.value, false, true); 360 | } 361 | 362 | function processBuffer() { 363 | return top.subLanguage !== undefined ? processSubLanguage() : processKeywords(); 364 | } 365 | 366 | function startNewMode(mode, lexeme) { 367 | var markup = mode.className? buildSpan(mode.className, '', true): ''; 368 | if (mode.returnBegin) { 369 | result += markup; 370 | mode_buffer = ''; 371 | } else if (mode.excludeBegin) { 372 | result += escape(lexeme) + markup; 373 | mode_buffer = ''; 374 | } else { 375 | result += markup; 376 | mode_buffer = lexeme; 377 | } 378 | top = Object.create(mode, {parent: {value: top}}); 379 | } 380 | 381 | function processLexeme(buffer, lexeme) { 382 | 383 | mode_buffer += buffer; 384 | if (lexeme === undefined) { 385 | result += processBuffer(); 386 | return 0; 387 | } 388 | 389 | var new_mode = subMode(lexeme, top); 390 | if (new_mode) { 391 | result += processBuffer(); 392 | startNewMode(new_mode, lexeme); 393 | return new_mode.returnBegin ? 0 : lexeme.length; 394 | } 395 | 396 | var end_mode = endOfMode(top, lexeme); 397 | if (end_mode) { 398 | var origin = top; 399 | if (!(origin.returnEnd || origin.excludeEnd)) { 400 | mode_buffer += lexeme; 401 | } 402 | result += processBuffer(); 403 | do { 404 | if (top.className) { 405 | result += ''; 406 | } 407 | relevance += top.relevance; 408 | top = top.parent; 409 | } while (top != end_mode.parent); 410 | if (origin.excludeEnd) { 411 | result += escape(lexeme); 412 | } 413 | mode_buffer = ''; 414 | if (end_mode.starts) { 415 | startNewMode(end_mode.starts, ''); 416 | } 417 | return origin.returnEnd ? 0 : lexeme.length; 418 | } 419 | 420 | if (isIllegal(lexeme, top)) 421 | throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '') + '"'); 422 | 423 | /* 424 | Parser should not reach this point as all types of lexemes should be caught 425 | earlier, but if it does due to some bug make sure it advances at least one 426 | character forward to prevent infinite looping. 427 | */ 428 | mode_buffer += lexeme; 429 | return lexeme.length || 1; 430 | } 431 | 432 | var language = getLanguage(name); 433 | if (!language) { 434 | throw new Error('Unknown language: "' + name + '"'); 435 | } 436 | 437 | compileLanguage(language); 438 | var top = continuation || language; 439 | var continuations = {}; // keep continuations for sub-languages 440 | var result = '', current; 441 | for(current = top; current != language; current = current.parent) { 442 | if (current.className) { 443 | result = buildSpan(current.className, '', true) + result; 444 | } 445 | } 446 | var mode_buffer = ''; 447 | var relevance = 0; 448 | try { 449 | var match, count, index = 0; 450 | while (true) { 451 | top.terminators.lastIndex = index; 452 | match = top.terminators.exec(value); 453 | if (!match) 454 | break; 455 | count = processLexeme(value.substr(index, match.index - index), match[0]); 456 | index = match.index + count; 457 | } 458 | processLexeme(value.substr(index)); 459 | for(current = top; current.parent; current = current.parent) { // close dangling modes 460 | if (current.className) { 461 | result += ''; 462 | } 463 | } 464 | return { 465 | relevance: relevance, 466 | value: result, 467 | language: name, 468 | top: top 469 | }; 470 | } catch (e) { 471 | if (e.message.indexOf('Illegal') != -1) { 472 | return { 473 | relevance: 0, 474 | value: escape(value) 475 | }; 476 | } else { 477 | throw e; 478 | } 479 | } 480 | } 481 | 482 | /* 483 | Highlighting with language detection. Accepts a string with the code to 484 | highlight. Returns an object with the following properties: 485 | 486 | - language (detected language) 487 | - relevance (int) 488 | - value (an HTML string with highlighting markup) 489 | - second_best (object with the same structure for second-best heuristically 490 | detected language, may be absent) 491 | 492 | */ 493 | function highlightAuto(text, languageSubset) { 494 | languageSubset = languageSubset || options.languages || Object.keys(languages); 495 | var result = { 496 | relevance: 0, 497 | value: escape(text) 498 | }; 499 | var second_best = result; 500 | languageSubset.forEach(function(name) { 501 | if (!getLanguage(name)) { 502 | return; 503 | } 504 | var current = highlight(name, text, false); 505 | current.language = name; 506 | if (current.relevance > second_best.relevance) { 507 | second_best = current; 508 | } 509 | if (current.relevance > result.relevance) { 510 | second_best = result; 511 | result = current; 512 | } 513 | }); 514 | if (second_best.language) { 515 | result.second_best = second_best; 516 | } 517 | return result; 518 | } 519 | 520 | /* 521 | Post-processing of the highlighted markup: 522 | 523 | - replace TABs with something more useful 524 | - replace real line-breaks with '
        ' for non-pre containers 525 | 526 | */ 527 | function fixMarkup(value) { 528 | if (options.tabReplace) { 529 | value = value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1 /*..., offset, s*/) { 530 | return p1.replace(/\t/g, options.tabReplace); 531 | }); 532 | } 533 | if (options.useBR) { 534 | value = value.replace(/\n/g, '
        '); 535 | } 536 | return value; 537 | } 538 | 539 | function buildClassName(prevClassName, currentLang, resultLang) { 540 | var language = currentLang ? aliases[currentLang] : resultLang, 541 | result = [prevClassName.trim()]; 542 | 543 | if (!prevClassName.match(/\bhljs\b/)) { 544 | result.push('hljs'); 545 | } 546 | 547 | if (prevClassName.indexOf(language) === -1) { 548 | result.push(language); 549 | } 550 | 551 | return result.join(' ').trim(); 552 | } 553 | 554 | /* 555 | Applies highlighting to a DOM node containing code. Accepts a DOM node and 556 | two optional parameters for fixMarkup. 557 | */ 558 | function highlightBlock(block) { 559 | var language = blockLanguage(block); 560 | if (isNotHighlighted(language)) 561 | return; 562 | 563 | var node; 564 | if (options.useBR) { 565 | node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 566 | node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(//g, '\n'); 567 | } else { 568 | node = block; 569 | } 570 | var text = node.textContent; 571 | var result = language ? highlight(language, text, true) : highlightAuto(text); 572 | 573 | var originalStream = nodeStream(node); 574 | if (originalStream.length) { 575 | var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 576 | resultNode.innerHTML = result.value; 577 | result.value = mergeStreams(originalStream, nodeStream(resultNode), text); 578 | } 579 | 580 | if (options.lineNumbers) { 581 | var resultPre = document.createElement('pre'); 582 | resultPre.innerHTML = result.value; 583 | var linesPre = document.createElement('pre'); 584 | var lines = escape(text).replace(/^/gm, ''); 585 | linesPre.innerHTML = lines; 586 | result.value = mergeStreams(nodeStream(linesPre), nodeStream(resultPre), text); 587 | } 588 | 589 | result.value = fixMarkup(result.value); 590 | block.innerHTML = result.value; 591 | block.className = buildClassName(block.className, language, result.language); 592 | block.result = { 593 | language: result.language, 594 | re: result.relevance 595 | }; 596 | if (result.second_best) { 597 | block.second_best = { 598 | language: result.second_best.language, 599 | re: result.second_best.relevance 600 | }; 601 | } 602 | } 603 | 604 | var options = { 605 | classPrefix: 'hljs-', 606 | tabReplace: null, 607 | useBR: false, 608 | lineNumbers: false, 609 | languages: undefined 610 | }; 611 | 612 | /* 613 | Updates highlight.js global options with values passed in the form of an object 614 | */ 615 | function configure(user_options) { 616 | options = inherit(options, user_options); 617 | } 618 | 619 | /* 620 | Applies highlighting to all
        ..
        blocks on a page. 621 | */ 622 | function initHighlighting() { 623 | if (initHighlighting.called) 624 | return; 625 | initHighlighting.called = true; 626 | 627 | var blocks = document.querySelectorAll('pre code'); 628 | Array.prototype.forEach.call(blocks, highlightBlock); 629 | } 630 | 631 | /* 632 | Attaches highlighting to the page load event. 633 | */ 634 | function initHighlightingOnLoad() { 635 | addEventListener('DOMContentLoaded', initHighlighting, false); 636 | addEventListener('load', initHighlighting, false); 637 | } 638 | 639 | var languages = {}; 640 | var aliases = {}; 641 | 642 | function registerLanguage(name, language) { 643 | var lang = languages[name] = language(hljs); 644 | if (lang.aliases) { 645 | lang.aliases.forEach(function(alias) {aliases[alias] = name;}); 646 | } 647 | } 648 | 649 | function listLanguages() { 650 | return Object.keys(languages); 651 | } 652 | 653 | function getLanguage(name) { 654 | return languages[name] || languages[aliases[name]]; 655 | } 656 | 657 | /* Interface definition */ 658 | 659 | hljs.highlight = highlight; 660 | hljs.highlightAuto = highlightAuto; 661 | hljs.fixMarkup = fixMarkup; 662 | hljs.highlightBlock = highlightBlock; 663 | hljs.configure = configure; 664 | hljs.initHighlighting = initHighlighting; 665 | hljs.initHighlightingOnLoad = initHighlightingOnLoad; 666 | hljs.registerLanguage = registerLanguage; 667 | hljs.listLanguages = listLanguages; 668 | hljs.getLanguage = getLanguage; 669 | hljs.inherit = inherit; 670 | 671 | // Common regexps 672 | hljs.IDENT_RE = '[a-zA-Z]\\w*'; 673 | hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; 674 | hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; 675 | hljs.C_NUMBER_RE = '\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float 676 | hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... 677 | hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; 678 | 679 | // Common modes 680 | hljs.BACKSLASH_ESCAPE = { 681 | begin: '\\\\[\\s\\S]', relevance: 0 682 | }; 683 | hljs.APOS_STRING_MODE = { 684 | className: 'string', 685 | begin: '\'', end: '\'', 686 | illegal: '\\n', 687 | contains: [hljs.BACKSLASH_ESCAPE] 688 | }; 689 | hljs.QUOTE_STRING_MODE = { 690 | className: 'string', 691 | begin: '"', end: '"', 692 | illegal: '\\n', 693 | contains: [hljs.BACKSLASH_ESCAPE] 694 | }; 695 | hljs.PHRASAL_WORDS_MODE = { 696 | begin: /\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/ 697 | }; 698 | hljs.COMMENT = function (begin, end, inherits) { 699 | var mode = hljs.inherit( 700 | { 701 | className: 'comment', 702 | begin: begin, end: end, 703 | contains: [] 704 | }, 705 | inherits || {} 706 | ); 707 | mode.contains.push(hljs.PHRASAL_WORDS_MODE); 708 | mode.contains.push({ 709 | className: 'doctag', 710 | beginKeywords: "TODO FIXME NOTE BUG XXX", 711 | relevance: 0 712 | }); 713 | return mode; 714 | }; 715 | hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$'); 716 | hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/'); 717 | hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$'); 718 | hljs.NUMBER_MODE = { 719 | className: 'number', 720 | begin: hljs.NUMBER_RE, 721 | relevance: 0 722 | }; 723 | hljs.C_NUMBER_MODE = { 724 | className: 'number', 725 | begin: hljs.C_NUMBER_RE, 726 | relevance: 0 727 | }; 728 | hljs.BINARY_NUMBER_MODE = { 729 | className: 'number', 730 | begin: hljs.BINARY_NUMBER_RE, 731 | relevance: 0 732 | }; 733 | hljs.CSS_NUMBER_MODE = { 734 | className: 'number', 735 | begin: hljs.NUMBER_RE + '(' + 736 | '%|em|ex|ch|rem' + 737 | '|vw|vh|vmin|vmax' + 738 | '|cm|mm|in|pt|pc|px' + 739 | '|deg|grad|rad|turn' + 740 | '|s|ms' + 741 | '|Hz|kHz' + 742 | '|dpi|dpcm|dppx' + 743 | ')?', 744 | relevance: 0 745 | }; 746 | hljs.REGEXP_MODE = { 747 | className: 'regexp', 748 | begin: /\//, end: /\/[gimuy]*/, 749 | illegal: /\n/, 750 | contains: [ 751 | hljs.BACKSLASH_ESCAPE, 752 | { 753 | begin: /\[/, end: /\]/, 754 | relevance: 0, 755 | contains: [hljs.BACKSLASH_ESCAPE] 756 | } 757 | ] 758 | }; 759 | hljs.TITLE_MODE = { 760 | className: 'title', 761 | begin: hljs.IDENT_RE, 762 | relevance: 0 763 | }; 764 | hljs.UNDERSCORE_TITLE_MODE = { 765 | className: 'title', 766 | begin: hljs.UNDERSCORE_IDENT_RE, 767 | relevance: 0 768 | }; 769 | 770 | return hljs; 771 | })); 772 | -------------------------------------------------------------------------------- /extension/chrome/js/lib/languages/json.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: JSON 3 | Author: Ivan Sagalaev 4 | Category: common, protocols 5 | */ 6 | 7 | hljs.registerLanguage('json', function(hljs) { 8 | var LITERALS = {literal: 'true false null'}; 9 | var TYPES = [ 10 | hljs.QUOTE_STRING_MODE, 11 | hljs.C_NUMBER_MODE 12 | ]; 13 | var VALUE_CONTAINER = { 14 | className: 'value', 15 | end: ',', endsWithParent: true, excludeEnd: true, 16 | contains: TYPES, 17 | keywords: LITERALS 18 | }; 19 | var OBJECT = { 20 | begin: '{', end: '}', 21 | contains: [ 22 | { 23 | className: 'attribute', 24 | begin: '\\s*"', end: '"\\s*:\\s*', excludeBegin: true, excludeEnd: true, 25 | contains: [hljs.BACKSLASH_ESCAPE], 26 | illegal: '\\n', 27 | starts: VALUE_CONTAINER 28 | } 29 | ], 30 | illegal: '\\S' 31 | }; 32 | var ARRAY = { 33 | begin: '\\[', end: '\\]', 34 | contains: [hljs.inherit(VALUE_CONTAINER, {className: null})], // inherit is also a workaround for a bug that makes shared modes with endsWithParent compile only the ending of one of the parents 35 | illegal: '\\S' 36 | }; 37 | TYPES.splice(TYPES.length, 0, OBJECT, ARRAY); 38 | return { 39 | contains: TYPES, 40 | keywords: LITERALS, 41 | illegal: '\\S' 42 | }; 43 | }) 44 | -------------------------------------------------------------------------------- /extension/chrome/js/lib/languages/sql.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: SQL 3 | Contributors: Nikolay Lisienko , Heiko August , Travis Odom 4 | Category: common 5 | */ 6 | 7 | hljs.registerLanguage('sql', function(hljs) { 8 | var COMMENT_MODE = hljs.COMMENT('--', '$'); 9 | return { 10 | case_insensitive: true, 11 | illegal: /[<>]/, 12 | contains: [ 13 | { 14 | className: 'operator', 15 | beginKeywords: 16 | 'begin end start commit rollback savepoint lock alter create drop rename call '+ 17 | 'delete do handler insert load replace select truncate update set show pragma grant '+ 18 | 'merge describe use explain help declare prepare execute deallocate savepoint release '+ 19 | 'unlock purge reset change stop analyze cache flush optimize repair kill '+ 20 | 'install uninstall checksum restore check backup revoke', 21 | end: /;/, endsWithParent: true, 22 | keywords: { 23 | keyword: 24 | 'abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter ' + 25 | 'analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup ' + 26 | 'before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by ' + 27 | 'cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length ' + 28 | 'character_length charindex charset check checksum checksum_agg choose close coalesce ' + 29 | 'coercibility collate collation collationproperty column columns columns_updated commit compress concat ' + 30 | 'concat_ws concurrent connect connection connection_id consistent constraint constraints continue ' + 31 | 'contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist ' + 32 | 'curdate current current_date current_time current_timestamp current_user cursor curtime data database ' + 33 | 'databases datalength date_add date_format date_sub dateadd datediff datefromparts datename ' + 34 | 'datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear ' + 35 | 'deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt ' + 36 | 'des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct ' + 37 | 'distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec ' + 38 | 'engine engines eomonth errors escape escaped event eventdata events except exception exec execute ' + 39 | 'exists exp explain export_set extended external extract fast fetch field fields find_in_set ' + 40 | 'first first_value floor flush for force foreign format found found_rows from from_base64 ' + 41 | 'from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant ' + 42 | 'grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help ' + 43 | 'hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore ' + 44 | 'iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner ' + 45 | 'innodb input insert install instr intersect into is is_free_lock is_ipv4 ' + 46 | 'is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill ' + 47 | 'language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level ' + 48 | 'like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile ' + 49 | 'logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max ' + 50 | 'md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names ' + 51 | 'national natural nchar next no no_write_to_binlog not now nullif nvarchar oct ' + 52 | 'octet_length of old_password on only open optimize option optionally or ord order outer outfile output ' + 53 | 'pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add ' + 54 | 'period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges ' + 55 | 'procedure procedure_analyze processlist profile profiles public publishingservername purge quarter ' + 56 | 'query quick quote quotename radians rand read references regexp relative relaylog release ' + 57 | 'release_lock rename repair repeat replace replicate reset restore restrict return returns reverse ' + 58 | 'revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll ' + 59 | 'sec_to_time second section select serializable server session session_user set sha sha1 sha2 share ' + 60 | 'show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex ' + 61 | 'sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache ' + 62 | 'sql_small_result sql_variant_property sqlstate sqrt square start starting status std ' + 63 | 'stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff ' + 64 | 'subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset ' + 65 | 'system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time ' + 66 | 'time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour ' + 67 | 'timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation ' + 68 | 'trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress ' + 69 | 'uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade ' + 70 | 'upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short ' + 71 | 'validate_password_strength value values var var_pop var_samp variables variance varp ' + 72 | 'version view warnings week weekday weekofyear weight_string when whenever where with work write xml ' + 73 | 'xor year yearweek zon', 74 | literal: 75 | 'true false null', 76 | built_in: 77 | 'array bigint binary bit blob boolean char character date dec decimal float int integer interval number ' + 78 | 'numeric real serial smallint varchar varying int8 serial8 text' 79 | }, 80 | contains: [ 81 | { 82 | className: 'string', 83 | begin: '\'', end: '\'', 84 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '\'\''}] 85 | }, 86 | { 87 | className: 'string', 88 | begin: '"', end: '"', 89 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '""'}] 90 | }, 91 | { 92 | className: 'string', 93 | begin: '`', end: '`', 94 | contains: [hljs.BACKSLASH_ESCAPE] 95 | }, 96 | hljs.C_NUMBER_MODE, 97 | hljs.C_BLOCK_COMMENT_MODE, 98 | COMMENT_MODE 99 | ] 100 | }, 101 | hljs.C_BLOCK_COMMENT_MODE, 102 | COMMENT_MODE 103 | ] 104 | }; 105 | }) 106 | -------------------------------------------------------------------------------- /extension/chrome/js/lib/sql-formatter.min.js: -------------------------------------------------------------------------------- 1 | !function(e,E){"object"==typeof exports&&"object"==typeof module?module.exports=E():"function"==typeof define&&define.amd?define([],E):"object"==typeof exports?exports.sqlFormatter=E():e.sqlFormatter=E()}(this,function(){return function(e){function E(n){if(t[n])return t[n].exports;var r=t[n]={exports:{},id:n,loaded:!1};return e[n].call(r.exports,r,r.exports,E),r.loaded=!0,r.exports}var t={};return E.m=e,E.c=t,E.p="",E(0)}([function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(18),T=n(r),R=t(19),o=n(R),N=t(20),A=n(N),I=t(21),O=n(I);E["default"]={format:function(e,E){switch(E=E||{},E.language){case"db2":return new T["default"](E).format(e);case"n1ql":return new o["default"](E).format(e);case"pl/sql":return new A["default"](E).format(e);case"sql":case void 0:return new O["default"](E).format(e);default:throw Error("Unsupported SQL dialect: "+E.language)}}},e.exports=E["default"]},function(e,E){"use strict";E.__esModule=!0,E["default"]=function(e,E){if(!(e instanceof E))throw new TypeError("Cannot call a class as a function")}},function(e,E,t){var n=t(39),r="object"==typeof self&&self&&self.Object===Object&&self,T=n||r||Function("return this")();e.exports=T},function(e,E,t){function n(e,E){var t=T(e,E);return r(t)?t:void 0}var r=t(33),T=t(41);e.exports=n},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(66),o=n(R),N=t(7),A=n(N),I=t(15),O=n(I),i=t(16),S=n(i),u=t(17),L=n(u),C=function(){function e(E,t){(0,T["default"])(this,e),this.cfg=E||{},this.indentation=new O["default"](this.cfg.indent),this.inlineBlock=new S["default"],this.params=new L["default"](this.cfg.params),this.tokenizer=t,this.previousReservedWord={}}return e.prototype.format=function(e){var E=this.tokenizer.tokenize(e),t=this.getFormattedQueryFromTokens(E);return t.trim()},e.prototype.getFormattedQueryFromTokens=function(e){var E=this,t="";return e.forEach(function(n,r){n.type!==A["default"].WHITESPACE&&(n.type===A["default"].LINE_COMMENT?t=E.formatLineComment(n,t):n.type===A["default"].BLOCK_COMMENT?t=E.formatBlockComment(n,t):n.type===A["default"].RESERVED_TOPLEVEL?(t=E.formatToplevelReservedWord(n,t),E.previousReservedWord=n):n.type===A["default"].RESERVED_NEWLINE?(t=E.formatNewlineReservedWord(n,t),E.previousReservedWord=n):n.type===A["default"].RESERVED?(t=E.formatWithSpaces(n,t),E.previousReservedWord=n):t=n.type===A["default"].OPEN_PAREN?E.formatOpeningParentheses(e,r,t):n.type===A["default"].CLOSE_PAREN?E.formatClosingParentheses(n,t):n.type===A["default"].PLACEHOLDER?E.formatPlaceholder(n,t):","===n.value?E.formatComma(n,t):":"===n.value?E.formatWithSpaceAfter(n,t):"."===n.value||";"===n.value?E.formatWithoutSpaces(n,t):E.formatWithSpaces(n,t))}),t},e.prototype.formatLineComment=function(e,E){return this.addNewline(E+e.value)},e.prototype.formatBlockComment=function(e,E){return this.addNewline(this.addNewline(E)+this.indentComment(e.value))},e.prototype.indentComment=function(e){return e.replace(/\n/g,"\n"+this.indentation.getIndent())},e.prototype.formatToplevelReservedWord=function(e,E){return this.indentation.decreaseTopLevel(),E=this.addNewline(E),this.indentation.increaseToplevel(),E+=this.equalizeWhitespace(e.value),this.addNewline(E)},e.prototype.formatNewlineReservedWord=function(e,E){return this.addNewline(E)+this.equalizeWhitespace(e.value)+" "},e.prototype.equalizeWhitespace=function(e){return e.replace(/\s+/g," ")},e.prototype.formatOpeningParentheses=function(e,E,t){var n=e[E-1];return n&&n.type!==A["default"].WHITESPACE&&n.type!==A["default"].OPEN_PAREN&&(t=(0,o["default"])(t)),t+=e[E].value,this.inlineBlock.beginIfPossible(e,E),this.inlineBlock.isActive()||(this.indentation.increaseBlockLevel(),t=this.addNewline(t)),t},e.prototype.formatClosingParentheses=function(e,E){return this.inlineBlock.isActive()?(this.inlineBlock.end(),this.formatWithSpaceAfter(e,E)):(this.indentation.decreaseBlockLevel(),this.formatWithSpaces(e,this.addNewline(E)))},e.prototype.formatPlaceholder=function(e,E){return E+this.params.get(e)+" "},e.prototype.formatComma=function(e,E){return E=(0,o["default"])(E)+e.value+" ",this.inlineBlock.isActive()?E:/^LIMIT$/i.test(this.previousReservedWord.value)?E:this.addNewline(E)},e.prototype.formatWithSpaceAfter=function(e,E){return(0,o["default"])(E)+e.value+" "},e.prototype.formatWithoutSpaces=function(e,E){return(0,o["default"])(E)+e.value},e.prototype.formatWithSpaces=function(e,E){return E+e.value+" "},e.prototype.addNewline=function(e){return(0,o["default"])(e)+"\n"+this.indentation.getIndent()},e}();E["default"]=C,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(58),o=n(R),N=t(53),A=n(N),I=t(7),O=n(I),i=function(){function e(E){(0,T["default"])(this,e),this.WHITESPACE_REGEX=/^(\s+)/,this.NUMBER_REGEX=/^((-\s*)?[0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)\b/,this.OPERATOR_REGEX=/^(!=|<>|==|<=|>=|!<|!>|\|\||::|->>|->|~~\*|~~|!~~\*|!~~|~\*|!~\*|!~|.)/,this.BLOCK_COMMENT_REGEX=/^(\/\*[^]*?(?:\*\/|$))/,this.LINE_COMMENT_REGEX=this.createLineCommentRegex(E.lineCommentTypes),this.RESERVED_TOPLEVEL_REGEX=this.createReservedWordRegex(E.reservedToplevelWords),this.RESERVED_NEWLINE_REGEX=this.createReservedWordRegex(E.reservedNewlineWords),this.RESERVED_PLAIN_REGEX=this.createReservedWordRegex(E.reservedWords),this.WORD_REGEX=this.createWordRegex(E.specialWordChars),this.STRING_REGEX=this.createStringRegex(E.stringTypes),this.OPEN_PAREN_REGEX=this.createParenRegex(E.openParens),this.CLOSE_PAREN_REGEX=this.createParenRegex(E.closeParens),this.INDEXED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(E.indexedPlaceholderTypes,"[0-9]*"),this.IDENT_NAMED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(E.namedPlaceholderTypes,"[a-zA-Z0-9._$]+"),this.STRING_NAMED_PLACEHOLDER_REGEX=this.createPlaceholderRegex(E.namedPlaceholderTypes,this.createStringPattern(E.stringTypes))}return e.prototype.createLineCommentRegex=function(e){return RegExp("^((?:"+e.map(function(e){return(0,A["default"])(e)}).join("|")+").*?(?:\n|$))")},e.prototype.createReservedWordRegex=function(e){var E=e.join("|").replace(/ /g,"\\s+");return RegExp("^("+E+")\\b","i")},e.prototype.createWordRegex=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return RegExp("^([\\w"+e.join("")+"]+)")},e.prototype.createStringRegex=function(e){return RegExp("^("+this.createStringPattern(e)+")")},e.prototype.createStringPattern=function(e){var E={"``":"((`[^`]*($|`))+)","[]":"((\\[[^\\]]*($|\\]))(\\][^\\]]*($|\\]))*)",'""':'(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)',"''":"(('[^'\\\\]*(?:\\\\.[^'\\\\]*)*('|$))+)","N''":"((N'[^N'\\\\]*(?:\\\\.[^N'\\\\]*)*('|$))+)"};return e.map(function(e){return E[e]}).join("|")},e.prototype.createParenRegex=function(e){var E=this;return RegExp("^("+e.map(function(e){return E.escapeParen(e)}).join("|")+")","i")},e.prototype.escapeParen=function(e){return 1===e.length?(0,A["default"])(e):"\\b"+e+"\\b"},e.prototype.createPlaceholderRegex=function(e,E){if((0,o["default"])(e))return!1;var t=e.map(A["default"]).join("|");return RegExp("^((?:"+t+")(?:"+E+"))")},e.prototype.tokenize=function(e){for(var E=[],t=void 0;e.length;)t=this.getNextToken(e,t),e=e.substring(t.value.length),E.push(t);return E},e.prototype.getNextToken=function(e,E){return this.getWhitespaceToken(e)||this.getCommentToken(e)||this.getStringToken(e)||this.getOpenParenToken(e)||this.getCloseParenToken(e)||this.getPlaceholderToken(e)||this.getNumberToken(e)||this.getReservedWordToken(e,E)||this.getWordToken(e)||this.getOperatorToken(e)},e.prototype.getWhitespaceToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].WHITESPACE,regex:this.WHITESPACE_REGEX})},e.prototype.getCommentToken=function(e){return this.getLineCommentToken(e)||this.getBlockCommentToken(e)},e.prototype.getLineCommentToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].LINE_COMMENT,regex:this.LINE_COMMENT_REGEX})},e.prototype.getBlockCommentToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].BLOCK_COMMENT,regex:this.BLOCK_COMMENT_REGEX})},e.prototype.getStringToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].STRING,regex:this.STRING_REGEX})},e.prototype.getOpenParenToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].OPEN_PAREN,regex:this.OPEN_PAREN_REGEX})},e.prototype.getCloseParenToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].CLOSE_PAREN,regex:this.CLOSE_PAREN_REGEX})},e.prototype.getPlaceholderToken=function(e){return this.getIdentNamedPlaceholderToken(e)||this.getStringNamedPlaceholderToken(e)||this.getIndexedPlaceholderToken(e)},e.prototype.getIdentNamedPlaceholderToken=function(e){return this.getPlaceholderTokenWithKey({input:e,regex:this.IDENT_NAMED_PLACEHOLDER_REGEX,parseKey:function(e){return e.slice(1)}})},e.prototype.getStringNamedPlaceholderToken=function(e){var E=this;return this.getPlaceholderTokenWithKey({input:e,regex:this.STRING_NAMED_PLACEHOLDER_REGEX,parseKey:function(e){return E.getEscapedPlaceholderKey({key:e.slice(2,-1),quoteChar:e.slice(-1)})}})},e.prototype.getIndexedPlaceholderToken=function(e){return this.getPlaceholderTokenWithKey({input:e,regex:this.INDEXED_PLACEHOLDER_REGEX,parseKey:function(e){return e.slice(1)}})},e.prototype.getPlaceholderTokenWithKey=function(e){var E=e.input,t=e.regex,n=e.parseKey,r=this.getTokenOnFirstMatch({input:E,regex:t,type:O["default"].PLACEHOLDER});return r&&(r.key=n(r.value)),r},e.prototype.getEscapedPlaceholderKey=function(e){var E=e.key,t=e.quoteChar;return E.replace(RegExp((0,A["default"])("\\")+t,"g"),t)},e.prototype.getNumberToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].NUMBER,regex:this.NUMBER_REGEX})},e.prototype.getOperatorToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].OPERATOR,regex:this.OPERATOR_REGEX})},e.prototype.getReservedWordToken=function(e,E){if(!E||!E.value||"."!==E.value)return this.getToplevelReservedToken(e)||this.getNewlineReservedToken(e)||this.getPlainReservedToken(e)},e.prototype.getToplevelReservedToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].RESERVED_TOPLEVEL,regex:this.RESERVED_TOPLEVEL_REGEX})},e.prototype.getNewlineReservedToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].RESERVED_NEWLINE,regex:this.RESERVED_NEWLINE_REGEX})},e.prototype.getPlainReservedToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].RESERVED,regex:this.RESERVED_PLAIN_REGEX})},e.prototype.getWordToken=function(e){return this.getTokenOnFirstMatch({input:e,type:O["default"].WORD,regex:this.WORD_REGEX})},e.prototype.getTokenOnFirstMatch=function(e){var E=e.input,t=e.type,n=e.regex,r=E.match(n);if(r)return{type:t,value:r[1]}},e}();E["default"]=i,e.exports=E["default"]},function(e,E){function t(e){var E=typeof e;return null!=e&&("object"==E||"function"==E)}e.exports=t},function(e,E){"use strict";E.__esModule=!0,E["default"]={WHITESPACE:"whitespace",WORD:"word",STRING:"string",RESERVED:"reserved",RESERVED_TOPLEVEL:"reserved-toplevel",RESERVED_NEWLINE:"reserved-newline",OPERATOR:"operator",OPEN_PAREN:"open-paren",CLOSE_PAREN:"close-paren",LINE_COMMENT:"line-comment",BLOCK_COMMENT:"block-comment",NUMBER:"number",PLACEHOLDER:"placeholder"},e.exports=E["default"]},function(e,E,t){function n(e){return null!=e&&T(e.length)&&!r(e)}var r=t(12),T=t(59);e.exports=n},function(e,E,t){function n(e){return null==e?"":r(e)}var r=t(10);e.exports=n},function(e,E,t){function n(e){if("string"==typeof e)return e;if(T(e))return N?N.call(e):"";var E=e+"";return"0"==E&&1/e==-R?"-0":E}var r=t(26),T=t(14),R=1/0,o=r?r.prototype:void 0,N=o?o.toString:void 0;e.exports=n},function(e,E){function t(e){if(null!=e){try{return r.call(e)}catch(E){}try{return e+""}catch(E){}}return""}var n=Function.prototype,r=n.toString;e.exports=t},function(e,E,t){function n(e){var E=r(e)?N.call(e):"";return E==T||E==R}var r=t(6),T="[object Function]",R="[object GeneratorFunction]",o=Object.prototype,N=o.toString;e.exports=n},function(e,E){function t(e){return null!=e&&"object"==typeof e}e.exports=t},function(e,E,t){function n(e){return"symbol"==typeof e||r(e)&&o.call(e)==T}var r=t(13),T="[object Symbol]",R=Object.prototype,o=R.toString;e.exports=n},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(61),o=n(R),N=t(60),A=n(N),I="top-level",O="block-level",i=function(){function e(E){(0,T["default"])(this,e),this.indent=E||" ",this.indentTypes=[]}return e.prototype.getIndent=function(){return(0,o["default"])(this.indent,this.indentTypes.length)},e.prototype.increaseToplevel=function(){this.indentTypes.push(I)},e.prototype.increaseBlockLevel=function(){this.indentTypes.push(O)},e.prototype.decreaseTopLevel=function(){(0,A["default"])(this.indentTypes)===I&&this.indentTypes.pop()},e.prototype.decreaseBlockLevel=function(){for(;this.indentTypes.length>0;){var e=this.indentTypes.pop();if(e!==I)break}},e}();E["default"]=i,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(7),o=n(R),N=50,A=function(){function e(){(0,T["default"])(this,e),this.level=0}return e.prototype.beginIfPossible=function(e,E){0===this.level&&this.isInlineBlock(e,E)?this.level=1:this.level>0?this.level++:this.level=0},e.prototype.end=function(){this.level--},e.prototype.isActive=function(){return this.level>0},e.prototype.isInlineBlock=function(e,E){for(var t=0,n=0,r=E;e.length>r;r++){var T=e[r];if(t+=T.value.length,t>N)return!1;if(T.type===o["default"].OPEN_PAREN)n++;else if(T.type===o["default"].CLOSE_PAREN&&(n--,0===n))return!0;if(this.isForbiddenToken(T))return!1}return!1},e.prototype.isForbiddenToken=function(e){var E=e.type,t=e.value;return E===o["default"].RESERVED_TOPLEVEL||E===o["default"].RESERVED_NEWLINE||E===o["default"].COMMENT||E===o["default"].BLOCK_COMMENT||";"===t},e}();E["default"]=A,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=function(){function e(E){(0,T["default"])(this,e),this.params=E,this.index=0}return e.prototype.get=function(e){var E=e.key,t=e.value;return this.params?E?this.params[E]:this.params[this.index++]:t},e}();E["default"]=R,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(4),o=n(R),N=t(5),A=n(N),I=["ABS","ACTIVATE","ALIAS","ALL","ALLOCATE","ALLOW","ALTER","ANY","ARE","ARRAY","AS","ASC","ASENSITIVE","ASSOCIATE","ASUTIME","ASYMMETRIC","AT","ATOMIC","ATTRIBUTES","AUDIT","AUTHORIZATION","AUX","AUXILIARY","AVG","BEFORE","BEGIN","BETWEEN","BIGINT","BINARY","BLOB","BOOLEAN","BOTH","BUFFERPOOL","BY","CACHE","CALL","CALLED","CAPTURE","CARDINALITY","CASCADED","CASE","CAST","CCSID","CEIL","CEILING","CHAR","CHARACTER","CHARACTER_LENGTH","CHAR_LENGTH","CHECK","CLOB","CLONE","CLOSE","CLUSTER","COALESCE","COLLATE","COLLECT","COLLECTION","COLLID","COLUMN","COMMENT","COMMIT","CONCAT","CONDITION","CONNECT","CONNECTION","CONSTRAINT","CONTAINS","CONTINUE","CONVERT","CORR","CORRESPONDING","COUNT","COUNT_BIG","COVAR_POP","COVAR_SAMP","CREATE","CROSS","CUBE","CUME_DIST","CURRENT","CURRENT_DATE","CURRENT_DEFAULT_TRANSFORM_GROUP","CURRENT_LC_CTYPE","CURRENT_PATH","CURRENT_ROLE","CURRENT_SCHEMA","CURRENT_SERVER","CURRENT_TIME","CURRENT_TIMESTAMP","CURRENT_TIMEZONE","CURRENT_TRANSFORM_GROUP_FOR_TYPE","CURRENT_USER","CURSOR","CYCLE","DATA","DATABASE","DATAPARTITIONNAME","DATAPARTITIONNUM","DATE","DAY","DAYS","DB2GENERAL","DB2GENRL","DB2SQL","DBINFO","DBPARTITIONNAME","DBPARTITIONNUM","DEALLOCATE","DEC","DECIMAL","DECLARE","DEFAULT","DEFAULTS","DEFINITION","DELETE","DENSERANK","DENSE_RANK","DEREF","DESCRIBE","DESCRIPTOR","DETERMINISTIC","DIAGNOSTICS","DISABLE","DISALLOW","DISCONNECT","DISTINCT","DO","DOCUMENT","DOUBLE","DROP","DSSIZE","DYNAMIC","EACH","EDITPROC","ELEMENT","ELSE","ELSEIF","ENABLE","ENCODING","ENCRYPTION","END","END-EXEC","ENDING","ERASE","ESCAPE","EVERY","EXCEPTION","EXCLUDING","EXCLUSIVE","EXEC","EXECUTE","EXISTS","EXIT","EXP","EXPLAIN","EXTENDED","EXTERNAL","EXTRACT","FALSE","FENCED","FETCH","FIELDPROC","FILE","FILTER","FINAL","FIRST","FLOAT","FLOOR","FOR","FOREIGN","FREE","FULL","FUNCTION","FUSION","GENERAL","GENERATED","GET","GLOBAL","GOTO","GRANT","GRAPHIC","GROUP","GROUPING","HANDLER","HASH","HASHED_VALUE","HINT","HOLD","HOUR","HOURS","IDENTITY","IF","IMMEDIATE","IN","INCLUDING","INCLUSIVE","INCREMENT","INDEX","INDICATOR","INDICATORS","INF","INFINITY","INHERIT","INNER","INOUT","INSENSITIVE","INSERT","INT","INTEGER","INTEGRITY","INTERSECTION","INTERVAL","INTO","IS","ISOBID","ISOLATION","ITERATE","JAR","JAVA","KEEP","KEY","LABEL","LANGUAGE","LARGE","LATERAL","LC_CTYPE","LEADING","LEAVE","LEFT","LIKE","LINKTYPE","LN","LOCAL","LOCALDATE","LOCALE","LOCALTIME","LOCALTIMESTAMP","LOCATOR","LOCATORS","LOCK","LOCKMAX","LOCKSIZE","LONG","LOOP","LOWER","MAINTAINED","MATCH","MATERIALIZED","MAX","MAXVALUE","MEMBER","MERGE","METHOD","MICROSECOND","MICROSECONDS","MIN","MINUTE","MINUTES","MINVALUE","MOD","MODE","MODIFIES","MODULE","MONTH","MONTHS","MULTISET","NAN","NATIONAL","NATURAL","NCHAR","NCLOB","NEW","NEW_TABLE","NEXTVAL","NO","NOCACHE","NOCYCLE","NODENAME","NODENUMBER","NOMAXVALUE","NOMINVALUE","NONE","NOORDER","NORMALIZE","NORMALIZED","NOT","NULL","NULLIF","NULLS","NUMERIC","NUMPARTS","OBID","OCTET_LENGTH","OF","OFFSET","OLD","OLD_TABLE","ON","ONLY","OPEN","OPTIMIZATION","OPTIMIZE","OPTION","ORDER","OUT","OUTER","OVER","OVERLAPS","OVERLAY","OVERRIDING","PACKAGE","PADDED","PAGESIZE","PARAMETER","PART","PARTITION","PARTITIONED","PARTITIONING","PARTITIONS","PASSWORD","PATH","PERCENTILE_CONT","PERCENTILE_DISC","PERCENT_RANK","PIECESIZE","PLAN","POSITION","POWER","PRECISION","PREPARE","PREVVAL","PRIMARY","PRIQTY","PRIVILEGES","PROCEDURE","PROGRAM","PSID","PUBLIC","QUERY","QUERYNO","RANGE","RANK","READ","READS","REAL","RECOVERY","RECURSIVE","REF","REFERENCES","REFERENCING","REFRESH","REGR_AVGX","REGR_AVGY","REGR_COUNT","REGR_INTERCEPT","REGR_R2","REGR_SLOPE","REGR_SXX","REGR_SXY","REGR_SYY","RELEASE","RENAME","REPEAT","RESET","RESIGNAL","RESTART","RESTRICT","RESULT","RESULT_SET_LOCATOR","RETURN","RETURNS","REVOKE","RIGHT","ROLE","ROLLBACK","ROLLUP","ROUND_CEILING","ROUND_DOWN","ROUND_FLOOR","ROUND_HALF_DOWN","ROUND_HALF_EVEN","ROUND_HALF_UP","ROUND_UP","ROUTINE","ROW","ROWNUMBER","ROWS","ROWSET","ROW_NUMBER","RRN","RUN","SAVEPOINT","SCHEMA","SCOPE","SCRATCHPAD","SCROLL","SEARCH","SECOND","SECONDS","SECQTY","SECURITY","SENSITIVE","SEQUENCE","SESSION","SESSION_USER","SIGNAL","SIMILAR","SIMPLE","SMALLINT","SNAN","SOME","SOURCE","SPECIFIC","SPECIFICTYPE","SQL","SQLEXCEPTION","SQLID","SQLSTATE","SQLWARNING","SQRT","STACKED","STANDARD","START","STARTING","STATEMENT","STATIC","STATMENT","STAY","STDDEV_POP","STDDEV_SAMP","STOGROUP","STORES","STYLE","SUBMULTISET","SUBSTRING","SUM","SUMMARY","SYMMETRIC","SYNONYM","SYSFUN","SYSIBM","SYSPROC","SYSTEM","SYSTEM_USER","TABLE","TABLESAMPLE","TABLESPACE","THEN","TIME","TIMESTAMP","TIMEZONE_HOUR","TIMEZONE_MINUTE","TO","TRAILING","TRANSACTION","TRANSLATE","TRANSLATION","TREAT","TRIGGER","TRIM","TRUE","TRUNCATE","TYPE","UESCAPE","UNDO","UNIQUE","UNKNOWN","UNNEST","UNTIL","UPPER","USAGE","USER","USING","VALIDPROC","VALUE","VARCHAR","VARIABLE","VARIANT","VARYING","VAR_POP","VAR_SAMP","VCAT","VERSION","VIEW","VOLATILE","VOLUMES","WHEN","WHENEVER","WHILE","WIDTH_BUCKET","WINDOW","WITH","WITHIN","WITHOUT","WLM","WRITE","XMLELEMENT","XMLEXISTS","XMLNAMESPACES","YEAR","YEARS"],O=["ADD","AFTER","ALTER COLUMN","ALTER TABLE","DELETE FROM","EXCEPT","FETCH FIRST","FROM","GROUP BY","GO","HAVING","INSERT INTO","INTERSECT","LIMIT","ORDER BY","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","UNION ALL","UPDATE","VALUES","WHERE"],i=["AND","CROSS JOIN","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN"],S=void 0,u=function(){function e(E){(0,T["default"])(this,e),this.cfg=E}return e.prototype.format=function(e){return S||(S=new A["default"]({reservedWords:I,reservedToplevelWords:O,reservedNewlineWords:i,stringTypes:['""',"''","``","[]"],openParens:["("],closeParens:[")"],indexedPlaceholderTypes:["?"],namedPlaceholderTypes:[":"],lineCommentTypes:["--"],specialWordChars:["#","@"]})),new o["default"](this.cfg,S).format(e)},e}();E["default"]=u,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(4),o=n(R),N=t(5),A=n(N),I=["ALL","ALTER","ANALYZE","AND","ANY","ARRAY","AS","ASC","BEGIN","BETWEEN","BINARY","BOOLEAN","BREAK","BUCKET","BUILD","BY","CALL","CASE","CAST","CLUSTER","COLLATE","COLLECTION","COMMIT","CONNECT","CONTINUE","CORRELATE","COVER","CREATE","DATABASE","DATASET","DATASTORE","DECLARE","DECREMENT","DELETE","DERIVED","DESC","DESCRIBE","DISTINCT","DO","DROP","EACH","ELEMENT","ELSE","END","EVERY","EXCEPT","EXCLUDE","EXECUTE","EXISTS","EXPLAIN","FALSE","FETCH","FIRST","FLATTEN","FOR","FORCE","FROM","FUNCTION","GRANT","GROUP","GSI","HAVING","IF","IGNORE","ILIKE","IN","INCLUDE","INCREMENT","INDEX","INFER","INLINE","INNER","INSERT","INTERSECT","INTO","IS","JOIN","KEY","KEYS","KEYSPACE","KNOWN","LAST","LEFT","LET","LETTING","LIKE","LIMIT","LSM","MAP","MAPPING","MATCHED","MATERIALIZED","MERGE","MINUS","MISSING","NAMESPACE","NEST","NOT","NULL","NUMBER","OBJECT","OFFSET","ON","OPTION","OR","ORDER","OUTER","OVER","PARSE","PARTITION","PASSWORD","PATH","POOL","PREPARE","PRIMARY","PRIVATE","PRIVILEGE","PROCEDURE","PUBLIC","RAW","REALM","REDUCE","RENAME","RETURN","RETURNING","REVOKE","RIGHT","ROLE","ROLLBACK","SATISFIES","SCHEMA","SELECT","SELF","SEMI","SET","SHOW","SOME","START","STATISTICS","STRING","SYSTEM","THEN","TO","TRANSACTION","TRIGGER","TRUE","TRUNCATE","UNDER","UNION","UNIQUE","UNKNOWN","UNNEST","UNSET","UPDATE","UPSERT","USE","USER","USING","VALIDATE","VALUE","VALUED","VALUES","VIA","VIEW","WHEN","WHERE","WHILE","WITH","WITHIN","WORK","XOR"],O=["DELETE FROM","EXCEPT ALL","EXCEPT","EXPLAIN DELETE FROM","EXPLAIN UPDATE","EXPLAIN UPSERT","FROM","GROUP BY","HAVING","INFER","INSERT INTO","INTERSECT ALL","INTERSECT","LET","LIMIT","MERGE","NEST","ORDER BY","PREPARE","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","UNION ALL","UNION","UNNEST","UPDATE","UPSERT","USE KEYS","VALUES","WHERE"],i=["AND","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","XOR"],S=void 0,u=function(){function e(E){(0,T["default"])(this,e),this.cfg=E}return e.prototype.format=function(e){return S||(S=new A["default"]({reservedWords:I,reservedToplevelWords:O,reservedNewlineWords:i,stringTypes:['""',"''","``"],openParens:["(","[","{"],closeParens:[")","]","}"],namedPlaceholderTypes:["$"],lineCommentTypes:["#","--"]})),new o["default"](this.cfg,S).format(e)},e}();E["default"]=u,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(4),o=n(R),N=t(5),A=n(N),I=["A","ACCESSIBLE","AGENT","AGGREGATE","ALL","ALTER","ANY","ARRAY","AS","ASC","AT","ATTRIBUTE","AUTHID","AVG","BETWEEN","BFILE_BASE","BINARY_INTEGER","BINARY","BLOB_BASE","BLOCK","BODY","BOOLEAN","BOTH","BOUND","BULK","BY","BYTE","C","CALL","CALLING","CASCADE","CASE","CHAR_BASE","CHAR","CHARACTER","CHARSET","CHARSETFORM","CHARSETID","CHECK","CLOB_BASE","CLONE","CLOSE","CLUSTER","CLUSTERS","COALESCE","COLAUTH","COLLECT","COLUMNS","COMMENT","COMMIT","COMMITTED","COMPILED","COMPRESS","CONNECT","CONSTANT","CONSTRUCTOR","CONTEXT","CONTINUE","CONVERT","COUNT","CRASH","CREATE","CREDENTIAL","CURRENT","CURRVAL","CURSOR","CUSTOMDATUM","DANGLING","DATA","DATE_BASE","DATE","DAY","DECIMAL","DEFAULT","DEFINE","DELETE","DESC","DETERMINISTIC","DIRECTORY","DISTINCT","DO","DOUBLE","DROP","DURATION","ELEMENT","ELSIF","EMPTY","ESCAPE","EXCEPTIONS","EXCLUSIVE","EXECUTE","EXISTS","EXIT","EXTENDS","EXTERNAL","EXTRACT","FALSE","FETCH","FINAL","FIRST","FIXED","FLOAT","FOR","FORALL","FORCE","FROM","FUNCTION","GENERAL","GOTO","GRANT","GROUP","HASH","HEAP","HIDDEN","HOUR","IDENTIFIED","IF","IMMEDIATE","IN","INCLUDING","INDEX","INDEXES","INDICATOR","INDICES","INFINITE","INSTANTIABLE","INT","INTEGER","INTERFACE","INTERVAL","INTO","INVALIDATE","IS","ISOLATION","JAVA","LANGUAGE","LARGE","LEADING","LENGTH","LEVEL","LIBRARY","LIKE","LIKE2","LIKE4","LIKEC","LIMITED","LOCAL","LOCK","LONG","MAP","MAX","MAXLEN","MEMBER","MERGE","MIN","MINUS","MINUTE","MLSLABEL","MOD","MODE","MONTH","MULTISET","NAME","NAN","NATIONAL","NATIVE","NATURAL","NATURALN","NCHAR","NEW","NEXTVAL","NOCOMPRESS","NOCOPY","NOT","NOWAIT","NULL","NULLIF","NUMBER_BASE","NUMBER","OBJECT","OCICOLL","OCIDATE","OCIDATETIME","OCIDURATION","OCIINTERVAL","OCILOBLOCATOR","OCINUMBER","OCIRAW","OCIREF","OCIREFCURSOR","OCIROWID","OCISTRING","OCITYPE","OF","OLD","ON","ONLY","OPAQUE","OPEN","OPERATOR","OPTION","ORACLE","ORADATA","ORDER","ORGANIZATION","ORLANY","ORLVARY","OTHERS","OUT","OVERLAPS","OVERRIDING","PACKAGE","PARALLEL_ENABLE","PARAMETER","PARAMETERS","PARENT","PARTITION","PASCAL","PCTFREE","PIPE","PIPELINED","PLS_INTEGER","PLUGGABLE","POSITIVE","POSITIVEN","PRAGMA","PRECISION","PRIOR","PRIVATE","PROCEDURE","PUBLIC","RAISE","RANGE","RAW","READ","REAL","RECORD","REF","REFERENCE","RELEASE","RELIES_ON","REM","REMAINDER","RENAME","RESOURCE","RESULT_CACHE","RESULT","RETURN","RETURNING","REVERSE","REVOKE","ROLLBACK","ROW","ROWID","ROWNUM","ROWTYPE","SAMPLE","SAVE","SAVEPOINT","SB1","SB2","SB4","SECOND","SEGMENT","SELF","SEPARATE","SEQUENCE","SERIALIZABLE","SHARE","SHORT","SIZE_T","SIZE","SMALLINT","SOME","SPACE","SPARSE","SQL","SQLCODE","SQLDATA","SQLERRM","SQLNAME","SQLSTATE","STANDARD","START","STATIC","STDDEV","STORED","STRING","STRUCT","STYLE","SUBMULTISET","SUBPARTITION","SUBSTITUTABLE","SUBTYPE","SUCCESSFUL","SUM","SYNONYM","SYSDATE","TABAUTH","TABLE","TDO","THE","THEN","TIME","TIMESTAMP","TIMEZONE_ABBR","TIMEZONE_HOUR","TIMEZONE_MINUTE","TIMEZONE_REGION","TO","TRAILING","TRANSACTION","TRANSACTIONAL","TRIGGER","TRUE","TRUSTED","TYPE","UB1","UB2","UB4","UID","UNDER","UNIQUE","UNPLUG","UNSIGNED","UNTRUSTED","USE","USER","USING","VALIDATE","VALIST","VALUE","VARCHAR","VARCHAR2","VARIABLE","VARIANCE","VARRAY","VARYING","VIEW","VIEWS","VOID","WHENEVER","WHILE","WITH","WORK","WRAPPED","WRITE","YEAR","ZONE"],O=["ADD","ALTER COLUMN","ALTER TABLE","BEGIN","CONNECT BY","DECLARE","DELETE FROM","DELETE","END","EXCEPT","EXCEPTION","FETCH FIRST","FROM","GROUP BY","HAVING","INSERT INTO","INSERT","INTERSECT","LIMIT","LOOP","MODIFY","ORDER BY","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","START WITH","UNION ALL","UNION","UPDATE","VALUES","WHERE"],i=["AND","CROSS APPLY","CROSS JOIN","ELSE","END","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER APPLY","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","WHEN","XOR"],S=void 0,u=function(){function e(E){(0,T["default"])(this,e),this.cfg=E}return e.prototype.format=function(e){return S||(S=new A["default"]({reservedWords:I,reservedToplevelWords:O,reservedNewlineWords:i,stringTypes:['""',"N''","''","``"],openParens:["(","CASE"],closeParens:[")","END"],indexedPlaceholderTypes:["?"],namedPlaceholderTypes:[":"],lineCommentTypes:["--"],specialWordChars:["_","$","#",".","@"]})),new o["default"](this.cfg,S).format(e)},e}();E["default"]=u,e.exports=E["default"]},function(e,E,t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}E.__esModule=!0;var r=t(1),T=n(r),R=t(4),o=n(R),N=t(5),A=n(N),I=["ACCESSIBLE","ACTION","AGAINST","AGGREGATE","ALGORITHM","ALL","ALTER","ANALYSE","ANALYZE","AS","ASC","AUTOCOMMIT","AUTO_INCREMENT","BACKUP","BEGIN","BETWEEN","BINLOG","BOTH","CASCADE","CASE","CHANGE","CHANGED","CHARACTER SET","CHARSET","CHECK","CHECKSUM","COLLATE","COLLATION","COLUMN","COLUMNS","COMMENT","COMMIT","COMMITTED","COMPRESSED","CONCURRENT","CONSTRAINT","CONTAINS","CONVERT","CREATE","CROSS","CURRENT_TIMESTAMP","DATABASE","DATABASES","DAY","DAY_HOUR","DAY_MINUTE","DAY_SECOND","DEFAULT","DEFINER","DELAYED","DELETE","DESC","DESCRIBE","DETERMINISTIC","DISTINCT","DISTINCTROW","DIV","DO","DROP","DUMPFILE","DUPLICATE","DYNAMIC","ELSE","ENCLOSED","END","ENGINE","ENGINES","ENGINE_TYPE","ESCAPE","ESCAPED","EVENTS","EXEC","EXECUTE","EXISTS","EXPLAIN","EXTENDED","FAST","FETCH","FIELDS","FILE","FIRST","FIXED","FLUSH","FOR","FORCE","FOREIGN","FULL","FULLTEXT","FUNCTION","GLOBAL","GRANT","GRANTS","GROUP_CONCAT","HEAP","HIGH_PRIORITY","HOSTS","HOUR","HOUR_MINUTE","HOUR_SECOND","IDENTIFIED","IF","IFNULL","IGNORE","IN","INDEX","INDEXES","INFILE","INSERT","INSERT_ID","INSERT_METHOD","INTERVAL","INTO","INVOKER","IS","ISOLATION","KEY","KEYS","KILL","LAST_INSERT_ID","LEADING","LEVEL","LIKE","LINEAR","LINES","LOAD","LOCAL","LOCK","LOCKS","LOGS","LOW_PRIORITY","MARIA","MASTER","MASTER_CONNECT_RETRY","MASTER_HOST","MASTER_LOG_FILE","MATCH","MAX_CONNECTIONS_PER_HOUR","MAX_QUERIES_PER_HOUR","MAX_ROWS","MAX_UPDATES_PER_HOUR","MAX_USER_CONNECTIONS","MEDIUM","MERGE","MINUTE","MINUTE_SECOND","MIN_ROWS","MODE","MODIFY","MONTH","MRG_MYISAM","MYISAM","NAMES","NATURAL","NOT","NOW()","NULL","OFFSET","ON DELETE","ON UPDATE","ON","ONLY","OPEN","OPTIMIZE","OPTION","OPTIONALLY","OUTFILE","PACK_KEYS","PAGE","PARTIAL","PARTITION","PARTITIONS","PASSWORD","PRIMARY","PRIVILEGES","PROCEDURE","PROCESS","PROCESSLIST","PURGE","QUICK","RAID0","RAID_CHUNKS","RAID_CHUNKSIZE","RAID_TYPE","RANGE","READ","READ_ONLY","READ_WRITE","REFERENCES","REGEXP","RELOAD","RENAME","REPAIR","REPEATABLE","REPLACE","REPLICATION","RESET","RESTORE","RESTRICT","RETURN","RETURNS","REVOKE","RLIKE","ROLLBACK","ROW","ROWS","ROW_FORMAT","SECOND","SECURITY","SEPARATOR","SERIALIZABLE","SESSION","SHARE","SHOW","SHUTDOWN","SLAVE","SONAME","SOUNDS","SQL","SQL_AUTO_IS_NULL","SQL_BIG_RESULT","SQL_BIG_SELECTS","SQL_BIG_TABLES","SQL_BUFFER_RESULT","SQL_CACHE","SQL_CALC_FOUND_ROWS","SQL_LOG_BIN","SQL_LOG_OFF","SQL_LOG_UPDATE","SQL_LOW_PRIORITY_UPDATES","SQL_MAX_JOIN_SIZE","SQL_NO_CACHE","SQL_QUOTE_SHOW_CREATE","SQL_SAFE_UPDATES","SQL_SELECT_LIMIT","SQL_SLAVE_SKIP_COUNTER","SQL_SMALL_RESULT","SQL_WARNINGS","START","STARTING","STATUS","STOP","STORAGE","STRAIGHT_JOIN","STRING","STRIPED","SUPER","TABLE","TABLES","TEMPORARY","TERMINATED","THEN","TO","TRAILING","TRANSACTIONAL","TRUE","TRUNCATE","TYPE","TYPES","UNCOMMITTED","UNIQUE","UNLOCK","UNSIGNED","USAGE","USE","USING","VARIABLES","VIEW","WHEN","WITH","WORK","WRITE","YEAR_MONTH"],O=["ADD","AFTER","ALTER COLUMN","ALTER TABLE","DELETE FROM","EXCEPT","FETCH FIRST","FROM","GROUP BY","GO","HAVING","INSERT INTO","INSERT","INTERSECT","LIMIT","MODIFY","ORDER BY","SELECT","SET CURRENT SCHEMA","SET SCHEMA","SET","UNION ALL","UNION","UPDATE","VALUES","WHERE"],i=["AND","CROSS APPLY","CROSS JOIN","ELSE","INNER JOIN","JOIN","LEFT JOIN","LEFT OUTER JOIN","OR","OUTER APPLY","OUTER JOIN","RIGHT JOIN","RIGHT OUTER JOIN","WHEN","XOR"],S=void 0,u=function(){function e(E){(0,T["default"])(this,e),this.cfg=E}return e.prototype.format=function(e){return S||(S=new A["default"]({reservedWords:I,reservedToplevelWords:O,reservedNewlineWords:i,stringTypes:['""',"N''","''","``","[]"],openParens:["(","CASE"],closeParens:[")","END"],indexedPlaceholderTypes:["?"],namedPlaceholderTypes:["@",":"],lineCommentTypes:["#","--"]})),new o["default"](this.cfg,S).format(e)},e}();E["default"]=u,e.exports=E["default"]},function(e,E,t){var n=t(3),r=t(2),T=n(r,"DataView");e.exports=T},function(e,E,t){var n=t(3),r=t(2),T=n(r,"Map");e.exports=T},function(e,E,t){var n=t(3),r=t(2),T=n(r,"Promise");e.exports=T},function(e,E,t){var n=t(3),r=t(2),T=n(r,"Set");e.exports=T},function(e,E,t){var n=t(2),r=n.Symbol;e.exports=r},function(e,E,t){var n=t(3),r=t(2),T=n(r,"WeakMap");e.exports=T},function(e,E){function t(e){return e.split("")}e.exports=t},function(e,E){function t(e,E,t,n){for(var r=e.length,T=t+(n?1:-1);n?T--:++TE||E>n)return t;do E%2&&(t+=e),E=r(E/2),E&&(e+=e);while(E);return t}var n=9007199254740991,r=Math.floor;e.exports=t},function(e,E){function t(e,E,t){var n=-1,r=e.length;0>E&&(E=-E>r?0:r+E),t=t>r?r:t,0>t&&(t+=r),r=E>t?0:t-E>>>0,E>>>=0;for(var T=Array(r);++nt?r(e,E,t):e}var r=t(35);e.exports=n},function(e,E,t){function n(e,E){for(var t=e.length;t--&&r(E,e[t],0)>-1;);return t}var r=t(31);e.exports=n},function(e,E,t){var n=t(2),r=n["__core-js_shared__"];e.exports=r},function(e,E){(function(E){var t="object"==typeof E&&E&&E.Object===Object&&E;e.exports=t}).call(E,function(){return this}())},function(e,E,t){var n=t(22),r=t(23),T=t(24),R=t(25),o=t(27),N=t(30),A=t(11),I="[object Map]",O="[object Object]",i="[object Promise]",S="[object Set]",u="[object WeakMap]",L="[object DataView]",C=Object.prototype,s=C.toString,a=A(n),f=A(r),c=A(T),p=A(R),l=A(o),D=N;(n&&D(new n(new ArrayBuffer(1)))!=L||r&&D(new r)!=I||T&&D(T.resolve())!=i||R&&D(new R)!=S||o&&D(new o)!=u)&&(D=function(e){var E=s.call(e),t=E==O?e.constructor:void 0,n=t?A(t):void 0;if(n)switch(n){case a:return L;case f:return I;case c:return i;case p:return S;case l:return u}return E}),e.exports=D},function(e,E){function t(e,E){return null==e?void 0:e[E]}e.exports=t},function(e,E){function t(e){return N.test(e)}var n="\\ud800-\\udfff",r="\\u0300-\\u036f\\ufe20-\\ufe23",T="\\u20d0-\\u20f0",R="\\ufe0e\\ufe0f",o="\\u200d",N=RegExp("["+o+n+r+T+R+"]");e.exports=t},function(e,E){function t(e,E){return E=null==E?n:E,!!E&&("number"==typeof e||r.test(e))&&e>-1&&e%1==0&&E>e}var n=9007199254740991,r=/^(?:0|[1-9]\d*)$/;e.exports=t},function(e,E,t){function n(e,E,t){if(!o(t))return!1;var n=typeof E;return!!("number"==n?T(t)&&R(E,t.length):"string"==n&&E in t)&&r(t[E],e)}var r=t(52),T=t(8),R=t(43),o=t(6);e.exports=n},function(e,E,t){function n(e){return!!T&&T in e}var r=t(38),T=function(){var e=/[^.]+$/.exec(r&&r.keys&&r.keys.IE_PROTO||"");return e?"Symbol(src)_1."+e:""}();e.exports=n},function(e,E){function t(e){var E=e&&e.constructor,t="function"==typeof E&&E.prototype||n;return e===t}var n=Object.prototype;e.exports=t},function(e,E,t){var n=t(48),r=n(Object.keys,Object);e.exports=r},function(e,E){function t(e,E){return function(t){return e(E(t))}}e.exports=t},function(e,E){function t(e,E,t){for(var n=t-1,r=e.length;++n-1&&e%1==0&&n>=e}var n=9007199254740991;e.exports=t},function(e,E){function t(e){var E=e?e.length:0;return E?e[E-1]:void 0}e.exports=t},function(e,E,t){function n(e,E,t){return E=(t?T(e,E,t):void 0===E)?1:R(E),r(o(e),E)}var r=t(34),T=t(44),R=t(64),o=t(9);e.exports=n},function(e,E){function t(){return!1}e.exports=t},function(e,E,t){function n(e){if(!e)return 0===e?e:0;if(e=r(e),e===T||e===-T){var E=0>e?-1:1;return E*R}return e===e?e:0}var r=t(65),T=1/0,R=1.7976931348623157e308;e.exports=n},function(e,E,t){function n(e){var E=r(e),t=E%1;return E===E?t?E-t:E:0}var r=t(63);e.exports=n},function(e,E,t){function n(e){if("number"==typeof e)return e;if(T(e))return R;if(r(e)){var E="function"==typeof e.valueOf?e.valueOf():e;e=r(E)?E+"":E}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(o,"");var t=A.test(e);return t||I.test(e)?O(e.slice(2),t?2:8):N.test(e)?R:+e}var r=t(6),T=t(14),R=NaN,o=/^\s+|\s+$/g,N=/^[-+]0x[0-9a-f]+$/i,A=/^0b[01]+$/i,I=/^0o[0-7]+$/i,O=parseInt;e.exports=n},function(e,E,t){function n(e,E,t){if(e=N(e),e&&(t||void 0===E))return e.replace(A,"");if(!e||!(E=r(E)))return e;var n=o(e),I=R(n,o(E))+1;return T(n,0,I).join("")}var r=t(10),T=t(36),R=t(37),o=t(50),N=t(9),A=/\s+$/;e.exports=n},function(e,E){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children=[],e.webpackPolyfill=1),e}}])}); -------------------------------------------------------------------------------- /extension/chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Everbug", 3 | "icons": { 4 | "16": "img/icons/icon_16.png", 5 | "32": "img/icons/icon_32.png", 6 | "64": "img/icons/icon_64.png" 7 | }, 8 | "browser_action": { "name": "Everbug" }, 9 | "version": "1.24", 10 | "description": "Everbug - Debugger for Django projects", 11 | "devtools_page": "html/devtools.html", 12 | "background": { 13 | "scripts": ["js/ext/background.js"], 14 | "persistent": true 15 | }, 16 | "web_accessible_resources": [ "js/*", "js/lib/*", "js/languages/*", "html/*", "css/*", "img/*" ], 17 | "permissions": [ "tabs", "webRequest", "webRequestBlocking", "webNavigation", ""], 18 | "manifest_version": 2 19 | } 20 | 21 | -------------------------------------------------------------------------------- /extension/firefox/css/hljs.theme.css: -------------------------------------------------------------------------------- 1 | .hljs { 2 | display: block; 3 | overflow-x: auto; 4 | padding: .5em; 5 | background: #eaeef3; 6 | color: #00193a; 7 | } 8 | 9 | .hljs-keyword,.hljs-selector-tag,.hljs-title,.hljs-section,.hljs-doctag,.hljs-name,.hljs-strong { 10 | font-weight: 700; 11 | } 12 | 13 | .hljs-comment { 14 | color: #738191; 15 | } 16 | 17 | .hljs-string,.hljs-title,.hljs-section,.hljs-built_in,.hljs-literal,.hljs-type,.hljs-addition,.hljs-tag,.hljs-quote,.hljs-name,.hljs-selector-id,.hljs-selector-class { 18 | color: #0048ab; 19 | } 20 | 21 | .hljs-meta,.hljs-subst,.hljs-symbol,.hljs-regexp,.hljs-attribute,.hljs-deletion,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-bullet { 22 | color: #4c81c9; 23 | } 24 | 25 | .hljs-emphasis { 26 | font-style: italic; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /extension/firefox/css/plugin.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Ubuntu'; 3 | src: url(../fonts/Ubuntu.ttf); 4 | } 5 | 6 | @font-face { 7 | font-family:'UbuntuMono'; 8 | src:url(../fonts/UbuntuMono.ttf); 9 | } 10 | 11 | * { 12 | margin: 0; 13 | padding: 0; 14 | } 15 | 16 | html { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | background: #F5F5F5; 22 | font: 12px Ubuntu; 23 | color: #333; 24 | padding-top: 2px; 25 | overflow-y: auto; 26 | overflow-x: hidden; 27 | } 28 | 29 | a { 30 | color: #333; 31 | } 32 | 33 | #extension { 34 | width: 100%; 35 | min-height: 50px; 36 | padding: 0; 37 | margin: 0; 38 | } 39 | 40 | #tabs { 41 | user-select: none; 42 | -moz-user-select: none; 43 | float: left; 44 | margin: 0; 45 | padding: 0; 46 | height: 28px; 47 | width: 100%; 48 | list-style: none; 49 | border: 0; 50 | border-bottom: 1px solid #999; 51 | border-left: 0; 52 | background: #f5f5f5; 53 | } 54 | 55 | #tabs li { 56 | float: left; 57 | margin: 0; 58 | padding: 0; 59 | height: 27px; 60 | line-height: 27px; 61 | border: 1px solid #999; 62 | border-left: none; 63 | overflow: hidden; 64 | position: relative; 65 | background: #e0e0e0; 66 | } 67 | 68 | #tabs li a { 69 | text-decoration: none; 70 | display: block; 71 | padding: 0 20px; 72 | outline: none; 73 | } 74 | 75 | #tabs li:first-child { 76 | border-left: 0; 77 | } 78 | 79 | #tabs li:active,#tabs li:active { 80 | background: #F5F5F5; 81 | border-bottom: 1px solid #F5F5F5; 82 | } 83 | 84 | #tabs li a:hover { 85 | background: #fafafa; 86 | } 87 | 88 | #tabs .active,#tabs .active a:hover { 89 | background: #F5F5F5; 90 | border-bottom: 1px solid #F5F5F5; 91 | } 92 | 93 | #tabs .has_unread { 94 | background: #DDF2CE; 95 | } 96 | 97 | #panels { 98 | background: #F5F5F5; 99 | padding: 5px; 100 | height: 100%; 101 | } 102 | 103 | #panels .wrapper { 104 | margin-top: 30px; 105 | background: #FFF; 106 | border: solid 1px #aaa; 107 | border-bottom: 0; 108 | } 109 | 110 | .context-view { 111 | list-style: none; 112 | margin: 0; 113 | padding: 0; 114 | width: 100%; 115 | } 116 | 117 | .context-view li { 118 | margin: 1px; 119 | margin-bottom: 0; 120 | background: #FCFCFC; 121 | border-bottom: 1px solid #CCC; 122 | position: relative; 123 | padding: 0; 124 | padding-left: 5px; 125 | padding-right: 5px; 126 | } 127 | 128 | .context-view .item { 129 | margin: 0; 130 | padding: 0; 131 | width: 100%; 132 | height: 30px; 133 | user-select: none; 134 | -moz-user-select: none; 135 | display: inline-table; 136 | cursor: default; 137 | } 138 | 139 | .context-view .item span { 140 | line-height: 20px; 141 | display: inline-block; 142 | margin-left: 0; 143 | } 144 | 145 | .context-view .ext { 146 | margin: 0; 147 | margin-top: 3px; 148 | background: #d5d5d5; 149 | border-radius: 3px; 150 | font-size: 12px!important; 151 | height: 18px; 152 | line-height: 18px; 153 | padding: 1px 6px 2px 4px; 154 | } 155 | 156 | .context-view .ext_0 { 157 | background: #F2F2C4; 158 | border: 1px solid #CDCDA6; 159 | color: #8D8118; 160 | } 161 | 162 | .context-view .ext_1 { 163 | background: #DDF3FB; 164 | border: 1px solid #9FC9D7; 165 | color: #1E6CA8; 166 | } 167 | 168 | .context-view .ext_2 { 169 | background: #DDF2CE; 170 | border: 1px solid #C4D7B7; 171 | color: #449609; 172 | } 173 | 174 | .context-view .ext_3 { 175 | background: #E0E0E0; 176 | border: 1px solid #D3D3D3; 177 | color: #575757; 178 | } 179 | 180 | .context-view .name { 181 | color: gray; 182 | padding-left: 10px; 183 | } 184 | 185 | .context-view .value { 186 | padding-left: 5px; 187 | color: #555; 188 | } 189 | 190 | .context-view .expand { 191 | float: right; 192 | padding-right: 10px; 193 | height: 30px; 194 | width: 30px; 195 | } 196 | 197 | .context-view .content { 198 | width: 100%; 199 | background: #fff; 200 | border: 1px solid #CCC; 201 | margin-bottom: 5px; 202 | line-height: 20px; 203 | } 204 | 205 | .context-view .content .inner { 206 | padding: 5px; 207 | padding-left: 10px; 208 | background: #EAEEF3; 209 | color: #6f7e8b; 210 | white-space: pre; 211 | } 212 | 213 | .context-view .wrap_text { 214 | white-space: normal!important; 215 | } 216 | 217 | #tab_queries { 218 | overflow: hidden; 219 | } 220 | 221 | #tab_queries .info { 222 | float: right; 223 | margin-top: 8px; 224 | margin-right: 16px; 225 | color: #555; 226 | font-size: 12px; 227 | user-select: none; 228 | -moz-user-select: none; 229 | } 230 | 231 | #tab_queries .db-select { 232 | width: 500px; 233 | padding: 6px; 234 | padding-top: 3px; 235 | user-select: none; 236 | -moz-user-select: none; 237 | } 238 | 239 | #tab_queries .db label { 240 | user-select: none; 241 | color: #555; 242 | font-size: 12px; 243 | } 244 | 245 | #tab_queries .db { 246 | user-select: none; 247 | -moz-user-select: none; 248 | width: 100%; 249 | height: 30px; 250 | border-bottom: 1px solid #CCC; 251 | background: #FAFAFA; 252 | } 253 | 254 | #tab_queries .db select { 255 | -moz-appearance: none; 256 | background: url(../img/dropdown.png) left / 20px no-repeat #fff; 257 | padding-left: 20px; 258 | margin-left: 10px; 259 | min-width: 150px; 260 | text-align: right; 261 | height: 24px; 262 | border: 1px solid #9d9d9d; 263 | color: #444; 264 | } 265 | 266 | #tab_queries .db option { 267 | user-select: none; 268 | -moz-user-select: none; 269 | background: #FFF; 270 | text-align: right; 271 | } 272 | 273 | .queries { 274 | overflow: hidden; 275 | } 276 | 277 | .queries table { 278 | width: 100%; 279 | min-width: 500px; 280 | border-collapse: collapse; 281 | font-size: 12px; 282 | color: #6b6b6b; 283 | } 284 | 285 | .queries table tr { 286 | line-height: 24px; 287 | background: #fdfdfd; 288 | border-bottom: 1px solid #b6bbbf; 289 | } 290 | 291 | .queries thead tr { 292 | height: 24px; 293 | background: #e3e3e3; 294 | font-size: 12px; 295 | text-transform: uppercase; 296 | color: #727272; 297 | border: 0; 298 | border-bottom: 1px solid #CCC; 299 | user-select: none; 300 | -moz-user-select: none; 301 | } 302 | 303 | .queries td { 304 | box-sizing: border-box; 305 | padding-left: 10px; 306 | vertical-align: top; 307 | } 308 | 309 | .queries tbody td:nth-child(3) { 310 | color: #000; 311 | white-space: pre; 312 | } 313 | 314 | .profile-view { 315 | margin: 0; 316 | padding: 0; 317 | width: 100%; 318 | } 319 | 320 | .profile-view ul { 321 | margin: 0; 322 | padding: 0; 323 | list-style: none; 324 | } 325 | 326 | .profile-view li { 327 | padding: 0; 328 | margin: 1px; 329 | margin-bottom: 0; 330 | background: #FCFCFC; 331 | border-bottom: 1px solid #ccc; 332 | position: relative; 333 | height: auto; 334 | overflow: hidden; 335 | } 336 | 337 | .profile-view .name div { 338 | float: right; 339 | display: inline-block; 340 | } 341 | 342 | .profile-view li .name { 343 | cursor: pointer; 344 | height: 30px; 345 | line-height: 30px; 346 | user-select: none; 347 | -moz-user-select: none; 348 | overflow: hidden; 349 | } 350 | 351 | .profile-view li .content { 352 | height: 50px; 353 | display: inline-table; 354 | width: 100%; 355 | } 356 | 357 | .profile-view table { 358 | display: inline-table; 359 | color: #333; 360 | border-collapse: collapse; 361 | width: 100%; 362 | } 363 | 364 | .profile-view table thead { 365 | height: 24px; 366 | line-height: 24px; 367 | background: #e3e3e3; 368 | font-size: 13px; 369 | text-transform: uppercase; 370 | color: #727272; 371 | border: 0; 372 | border-top: 1px solid #CCC; 373 | border-bottom: 1px solid #CCC; 374 | user-select: none; 375 | -moz-user-select: none; 376 | } 377 | 378 | .profile-view table thead td { 379 | padding-left: 10px; 380 | } 381 | 382 | .profile-view table tbody { 383 | background: #fff; 384 | } 385 | 386 | .profile-view table tbody td { 387 | padding-left: 10px; 388 | line-height: 20px; 389 | background: #FDFDFD; 390 | color: #555; 391 | } 392 | 393 | .profile-view table tbody tr { 394 | border-bottom: 1px solid #dcdfe4; 395 | } 396 | 397 | .profile-view table tbody tr:last-child { 398 | border-bottom: 0; 399 | } 400 | 401 | .profile-view table tbody tr td:nth-last-child(1) { 402 | background: #EAEEF3; 403 | color: #6f7e8b; 404 | } 405 | 406 | .profile-view span { 407 | padding-left: 10px; 408 | } 409 | 410 | .profile-view .totals { 411 | color: #727272; 412 | } 413 | 414 | .profile-view .module { 415 | color: #9b9b9b; 416 | } 417 | 418 | .profile-view .func { 419 | margin-left: 4px; 420 | padding: 4px 4px 3px 4px; 421 | background: #e5e1f6; 422 | border: 1px solid #d9cce9; 423 | border-radius: 3px; 424 | color: #6a3a99; 425 | } 426 | 427 | .profile-view .expand { 428 | float: right; 429 | padding-right: 11px; 430 | height: 24px; 431 | width: 24px; 432 | background-size: 28%!important; 433 | } 434 | 435 | #tab_help .menu { 436 | width: 100%; 437 | font-size: 14px; 438 | border-bottom: 1px solid #a5a5a5; 439 | padding-bottom: 20px; 440 | padding-top: 10px; 441 | } 442 | 443 | #tab_help hr { 444 | border: 0; 445 | border-bottom: 1px solid #e3e3e3; 446 | margin-bottom: 5px; 447 | } 448 | 449 | #tab_help h2 { 450 | font-size: 22px; 451 | font-weight: 400!important; 452 | color: #4c81c9; 453 | background: url(../img/icons/icon_32.png) no-repeat top left; 454 | background-position: 10px 0; 455 | padding-top: 4px; 456 | padding-left: 55px; 457 | height: 40px; 458 | } 459 | 460 | #tab_help h3 { 461 | font-size: 18px; 462 | font-weight: 400!important; 463 | color: #7ca3d4; 464 | padding-left: 10px; 465 | } 466 | 467 | #tab_help p { 468 | padding-left: 10px; 469 | color: #6b6b6b; 470 | } 471 | 472 | .close { 473 | background: url(../img/up.png) top left no-repeat; 474 | background-position: 20px 8px; 475 | background-size: 30%; 476 | display: inline-block; 477 | } 478 | 479 | .open { 480 | background: url(../img/down.png) top left no-repeat; 481 | background-position: 20px 8px; 482 | background-size: 30%; 483 | display: inline-block; 484 | } 485 | 486 | .expandable { 487 | cursor: pointer!important; 488 | } 489 | 490 | -------------------------------------------------------------------------------- /extension/firefox/fonts/Ubuntu.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/fonts/Ubuntu.ttf -------------------------------------------------------------------------------- /extension/firefox/fonts/UbuntuMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/fonts/UbuntuMono.ttf -------------------------------------------------------------------------------- /extension/firefox/html/devtools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /extension/firefox/html/panel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
        22 | 23 | 29 | 30 |
        31 |
        32 | 33 |
        34 |
          35 |
          36 | 37 |
          38 |
          39 |
          40 |
          41 | 42 | 43 |
          44 |
          45 |
          46 |
          47 | 48 |
          49 |
          50 |
            51 |
            52 |
            53 | 54 |
            55 | 56 | 70 | 71 |
            72 | 73 |
            74 |
            75 | 76 | 77 |
            78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /extension/firefox/img/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/down.png -------------------------------------------------------------------------------- /extension/firefox/img/dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/dropdown.png -------------------------------------------------------------------------------- /extension/firefox/img/icons/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/icons/icon_16.png -------------------------------------------------------------------------------- /extension/firefox/img/icons/icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/icons/icon_32.png -------------------------------------------------------------------------------- /extension/firefox/img/icons/icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/icons/icon_64.png -------------------------------------------------------------------------------- /extension/firefox/img/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/extension/firefox/img/up.png -------------------------------------------------------------------------------- /extension/firefox/js/ext/background.js: -------------------------------------------------------------------------------- 1 | var connections = {}; 2 | 3 | function isTraced(headers) { 4 | for (var i = 0; i < headers.length; ++i) { 5 | if (headers[i].name === 'HTTP_HAS_TRACE') { 6 | return headers[i].value 7 | } 8 | } 9 | return 0 10 | } 11 | 12 | browser.runtime.onConnect.addListener(function(port){ 13 | var extensionListener = function(message, sender, sendResponse){ 14 | if (message.name === "init"){ 15 | connections[message.tab_id] = port; 16 | connections[message.tab_id].postMessage({ 17 | 'status': 'initiated', 18 | 'tab_id': message.tab_id 19 | }); 20 | return null 21 | } 22 | }; 23 | port.onMessage.addListener(extensionListener); 24 | port.onDisconnect.addListener(function(port){ 25 | port.onMessage.removeListener(extensionListener); 26 | var tabs = Object.keys(connections); 27 | for (var i = 0, len = tabs.length; i < len; i++){ 28 | if (connections[tabs[i]] === port){ 29 | delete connections[tabs[i]]; 30 | break 31 | } 32 | } 33 | }) 34 | }); 35 | 36 | browser.webRequest.onHeadersReceived.addListener(function callback(details) { 37 | if (details.tabId in connections) { 38 | if ((details.frameId >= 0) && ((details.type === 'main_frame') || (details.type === 'xmlhttprequest'))) { 39 | if (details.type === 'main_frame') { 40 | connections[details.tabId].postMessage({ 41 | status: 'clear', 42 | tab_id: details.tabId 43 | }) 44 | } 45 | var trace_id = isTraced(details.responseHeaders); 46 | if (trace_id >= 1 && trace_id !== 'undefined'){ 47 | connections[details.tabId].postMessage({ 48 | 'status': 'trace', 49 | 'tab_id': details.tabId, 50 | 'trace_id': trace_id, 51 | 'url': details.url 52 | }) 53 | } 54 | } 55 | } 56 | }, 57 | { 58 | urls: [''], 59 | types: ['main_frame', 'xmlhttprequest'] 60 | }, ['responseHeaders']); 61 | 62 | browser.webRequest.onBeforeSendHeaders.addListener(function(details){ 63 | if (details.frameId >= 0){ 64 | if (!('TRACE-ID' in details.requestHeaders)){ 65 | details.requestHeaders.push({ 66 | name: 'REQUEST-ID', 67 | value: details.requestId 68 | }) 69 | } 70 | } 71 | return {requestHeaders: details.requestHeaders} 72 | }, { urls: [""]}, ["blocking", "requestHeaders"]); 73 | 74 | browser.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 75 | if (tabId in connections){ 76 | switch (changeInfo.status){ 77 | case 'complete': 78 | connections[tabId].postMessage({ 79 | 'status': 'complete', 80 | 'tab_id': tabId 81 | }); 82 | break; 83 | case 'loading': 84 | connections[tabId].postMessage({ 85 | 'status': 'loading', 86 | 'tab_id': tabId 87 | }); 88 | break 89 | } 90 | } 91 | }) 92 | -------------------------------------------------------------------------------- /extension/firefox/js/ext/devtools.js: -------------------------------------------------------------------------------- 1 | var hwd = null; 2 | var port = null; 3 | var tab = browser.devtools.inspectedWindow.tabId; 4 | 5 | browser.devtools.panels.create("Everbug", "../img/icons/icon_32.png", "../html/panel.html", function(plugin){ 6 | plugin.onShown.addListener(function captureHandle(handleWindow){ 7 | hwd = handleWindow; 8 | port = browser.runtime.connect({name: 'everbug-devtool'}); 9 | port.postMessage({name: 'init', tab_id: tab}); 10 | port.onMessage.addListener(messageDispatcher) 11 | }) 12 | }); 13 | 14 | function getTrace(url, trace_id){ 15 | $.ajax({ 16 | type: "GET", 17 | url: url, 18 | dataType: "json", 19 | data: {'trace': !0}, 20 | beforeSend: function (xhr){ 21 | xhr.setRequestHeader("Accept", "application/json, text/plain, */*"); 22 | xhr.setRequestHeader("TRACE-ID", trace_id) 23 | }, 24 | success: function (data){ 25 | append(hwd, JSON.stringify(data)) 26 | } 27 | }) 28 | } 29 | 30 | function messageDispatcher(msg){ 31 | if (msg.tab_id === tab){ 32 | switch (msg.status){ 33 | case 'initiated': 34 | init(hwd); 35 | break; 36 | case 'clear': 37 | clear(hwd); 38 | break; 39 | case 'loading': 40 | break; 41 | case 'complete': 42 | break; 43 | case 'trace': 44 | append(hwd, getTrace(msg.url, msg.trace_id)); 45 | break 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /extension/firefox/js/ext/panel.js: -------------------------------------------------------------------------------- 1 | var queries_count = 0; 2 | var queries_time = 0; 3 | var current_alias = '__all__'; 4 | var aliases = [current_alias]; 5 | 6 | function isJSON(val) { 7 | if (typeof val !== 'string') 8 | val = JSON.stringify(val); 9 | try { 10 | JSON.parse(val); 11 | return !0 12 | } catch (e) { 13 | return !1 14 | } 15 | } 16 | 17 | function init(handle) { 18 | handle.$('#tabs li').hide(); 19 | handle.$('.tb_help').show().addClass('active'); 20 | handle.$(".panel").hide(); 21 | handle.$('#tab_help').show(); 22 | handle.$("ul#tabs li").click(function() { 23 | handle.$("ul#tabs li").removeClass("active"); 24 | $(this).addClass("active").removeClass('has_unread'); 25 | handle.$(".panel").hide(); 26 | var actTab = $(this).find("a").attr("href"); 27 | handle.$(actTab).show(); 28 | return !1 29 | }); 30 | clear(handle) 31 | } 32 | 33 | function clear(handle) { 34 | handle.$('#tabs li').hide(); 35 | handle.$('.tb_help').show(); 36 | queries_count = 0; 37 | queries_time = 0; 38 | aliases = ['__all__']; 39 | handle.$('.context-view').empty(); 40 | handle.$('#tab_queries .info').empty(); 41 | handle.$('#db_filter').empty().append($("").attr("value", '__all__').text('ALL')); 42 | handle.$('.queries').empty(); 43 | handle.$('.profile-view').empty() 44 | } 45 | 46 | function filterQueries(handle, alias) { 47 | var rows = handle.$('.queries > table > tbody > tr'); 48 | if (alias === '__all__') { 49 | rows.show() 50 | } else { 51 | rows.hide(); 52 | handle.$('.queries .' + alias).show() 53 | } 54 | } 55 | 56 | function appendContext(handle, data) { 57 | handle.$('.tb_context').addClass('has_unread'); 58 | var ul = handle.$('.context-view'); 59 | $.each(data, function(index, obj) { 60 | var name = obj[0], 61 | value = obj[1], 62 | cls = obj[2], 63 | ext = obj[3], 64 | cnt = obj[4]; 65 | var is_inline = !((ext === 1) || (ext === 2)); 66 | var item = $('
          • ').append($('
            ', { 67 | 'class': 'item' 68 | }).append($('', { 69 | 'class': 'ext' 70 | }).append(cls)).append($('', { 71 | 'class': 'name' 72 | }).append(name + ' = ')).append($('', { 73 | 'class': 'value' 74 | }))); 75 | if ((ext === 1) || (ext === 2)) { 76 | if (isJSON(value)) { 77 | value = JSON.stringify(value, null, '\t') 78 | } 79 | } 80 | item.find('.ext').addClass('ext_' + ext); 81 | if (is_inline !== !0) { 82 | item.find('.item').addClass('expandable').append($('').addClass('expand').addClass('open')); 83 | item.append($('
            ', { 84 | 'class': 'content' 85 | }).append($('
            ', { 86 | 'class': 'inner' 87 | }).append(value))); 88 | item.find('.value').text('[ items: ' + cnt + ' ]') 89 | } else { 90 | item.find('.value').text(value) 91 | } 92 | if (cls === 'str') { 93 | if (value.length < 50) { 94 | item.find('.value').empty().text(value); 95 | item.find('.content').remove(); 96 | item.find('.expand').remove(); 97 | item.find('.item').removeClass('expandable') 98 | } else { 99 | item.find('.value').empty().text('[ length: ' + value.length + ' ]'); 100 | item.find('.inner').addClass('wrap_text') 101 | } 102 | } 103 | if ((ext >= 1) && (ext <= 3) && (isJSON(value) === !0)) { 104 | item.find('.inner').addClass('json_code') 105 | } 106 | ul.append(item) 107 | }); 108 | hljs.initHighlightingOnLoad(); 109 | handle.$('.json_code').each(function(i, block) { 110 | hljs.highlightBlock(block) 111 | }); 112 | handle.$(".context-view .content").hide(); 113 | handle.$(".context-view .item").click(function() { 114 | var item = $(this).parent(); 115 | if (item.hasClass('active')) { 116 | item.removeClass('active'); 117 | item.find('.expand').removeClass('close').addClass('open'); 118 | item.find('.content').hide() 119 | } else { 120 | item.addClass('active'); 121 | item.find('.expand').removeClass('open').addClass('close'); 122 | item.find('.content').show() 123 | } 124 | return !1 125 | }) 126 | } 127 | 128 | function appendQueries(handle, data) { 129 | handle.$('.tb_queries').addClass('has_unread'); 130 | if (handle.$('.queries').text().length === 0) { 131 | var create_table = $('').append($('').append($('').append($('')); 132 | handle.$('.queries').append(create_table) 133 | } 134 | var filter = handle.$('#db_filter'); 135 | var table_body = handle.$('.queries table').find('tbody'); 136 | $.each(data, function(alias, queries) { 137 | if (!aliases.includes(alias)) { 138 | aliases.push(alias); 139 | filter.append($("").attr("value", alias).text(':: ' + alias)) 140 | } 141 | $.each(queries, function(index, query) { 142 | queries_time += parseFloat(query.time); 143 | queries_count += 1; 144 | var explains = ''; 145 | $.each(query.explain, function(index, expl) { 146 | explains = explains + expl + '\n' 147 | }); 148 | table_body.append($('', { 149 | 'class': alias 150 | }).append($('
            ').text('Time')).append($('').text('Explain')).append($('').text('Sql')))).append($('
            ').text(query.time)).append($('').text(explains)).append($('', { 151 | 'class': 'sql_code' 152 | }).text(query.sql))) 153 | }) 154 | }); 155 | hljs.initHighlightingOnLoad(); 156 | var info = handle.$('#tab_queries .info'); 157 | info.text('Total queries: ' + queries_count + ', total time: ' + queries_time + ' ms'); 158 | handle.$(".queries > table > tbody > tr").each(function() { 159 | var cell = $(this).find("td").eq(2); 160 | cell.text(sqlFormatter.format(cell.text(), { 161 | language: 'sql', 162 | indent: "\t" 163 | })) 164 | }); 165 | if (!aliases.includes(current_alias)) { 166 | current_alias = '__all__' 167 | } 168 | filter.val(current_alias); 169 | filterQueries(handle, current_alias); 170 | filter.click(function() { 171 | var sel = $(this).find('option:selected').val(); 172 | if (sel !== current_alias) { 173 | current_alias = sel 174 | } 175 | filterQueries(handle, current_alias); 176 | return !1 177 | }); 178 | handle.$('.sql_code').each(function(i, block) { 179 | hljs.highlightBlock(block) 180 | }) 181 | } 182 | 183 | function appendProfiles(handle, data) { 184 | handle.$('.tb_profile').addClass('has_unread'); 185 | if (handle.$('.profile-view').find('ul').text().length === 0) { 186 | handle.$('.profile-view').append('
              ') 187 | } 188 | var list = handle.$('.profile-view').find('ul'); 189 | $.each(data, function(i, profile) { 190 | var li = $('
            • ', { 191 | 'class': 'profile' 192 | }).append($('
              ', { 193 | 'class': 'name' 194 | }).append($('', { 195 | 'class': 'func' 196 | }).text('Method: ' + profile.method)).append($('', { 197 | 'class': 'module' 198 | }).text(profile.module)).append($('
              ').append($('', { 199 | 'class': 'totals' 200 | }).text('Total calls: ' + profile.total_calls + ', total time: ' + profile.total_time)).append($('', { 201 | 'class': 'expand close' 202 | })))).append($('
              ', { 203 | 'class': 'content' 204 | }).hide().append($('').append($('').append($('').append($('')))); 205 | var rows = li.find('tbody'); 206 | $.each(profile.lines, function(i, line) { 207 | rows.append($('').append($('
              ').text('ncalls')).append($('').text('tottime')).append($('').text('cumtime')).append($('').text('call')))).append($('
              ').text(line[0])).append($('').text(line[1])).append($('').text(line[2])).append($('').text(line[3]))) 208 | }); 209 | list.append(li) 210 | }); 211 | handle.$(".profile-view .name").unbind('click'); 212 | handle.$(".profile-view .name").click(function() { 213 | var item = $(this).parent(); 214 | if (item.hasClass('active')) { 215 | item.removeClass('active'); 216 | item.find('.expand').removeClass('close').addClass('open'); 217 | item.find('.content').hide() 218 | } else { 219 | item.addClass('active'); 220 | item.find('.expand').removeClass('open').addClass('close'); 221 | item.find('.content').show() 222 | } 223 | return !1 224 | }) 225 | } 226 | 227 | function append(handle, data) { 228 | if (data !== undefined && data !== null) { 229 | var trace = JSON.parse(data); 230 | if ('context' in trace) { 231 | appendContext(handle, trace.context); 232 | handle.$('.tb_context').show() 233 | } 234 | if ('queries' in trace) { 235 | appendQueries(handle, trace.queries); 236 | handle.$('.tb_queries').show() 237 | } 238 | if ('profiles' in trace) { 239 | appendProfiles(handle, trace.profiles); 240 | handle.$('.tb_profile').show() 241 | } 242 | } 243 | if (handle.$('#tabs > li:visible').length > 1) { 244 | if (handle.$("ul#tabs").find('li.active').text() === 'Help') { 245 | handle.$("ul#tabs").find('li:visible:first').click() 246 | } 247 | } 248 | handle.$("ul#tabs").find('li.active').removeClass('has_unread') 249 | } 250 | -------------------------------------------------------------------------------- /extension/firefox/js/lib/highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Syntax highlighting with language autodetection. 3 | https://highlightjs.org/ 4 | */ 5 | 6 | (function(factory) { 7 | 8 | // Setup highlight.js for different environments. First is Node.js or 9 | // CommonJS. 10 | if(typeof exports !== 'undefined') { 11 | factory(exports); 12 | } else { 13 | // Export hljs globally even when using AMD for cases when this script 14 | // is loaded with others that may still expect a global hljs. 15 | window.hljs = factory({}); 16 | 17 | // Finally register the global hljs with AMD. 18 | if(typeof define === 'function' && define.amd) { 19 | define([], function() { 20 | return window.hljs; 21 | }); 22 | } 23 | } 24 | 25 | }(function(hljs) { 26 | 27 | /* Utility functions */ 28 | 29 | function escape(value) { 30 | return value.replace(/&/gm, '&').replace(//gm, '>'); 31 | } 32 | 33 | function tag(node) { 34 | return node.nodeName.toLowerCase(); 35 | } 36 | 37 | function testRe(re, lexeme) { 38 | var match = re && re.exec(lexeme); 39 | return match && match.index == 0; 40 | } 41 | 42 | function isNotHighlighted(language) { 43 | return /no-?highlight|plain|text/.test(language); 44 | } 45 | 46 | function blockLanguage(block) { 47 | var i, language, length, 48 | classes = block.className + ' '; 49 | 50 | classes += block.parentNode ? block.parentNode.className : ''; 51 | classes = classes.split(/\s+/); 52 | 53 | for(i = 0, length = classes.length; i < length; i++) { 54 | language = classes[i].replace(/^lang(uage)?-/, ''); 55 | 56 | if(getLanguage(language) || isNotHighlighted(language)) { 57 | return language; 58 | } 59 | } 60 | } 61 | 62 | function inherit(parent, obj) { 63 | var result = {}, key; 64 | for (key in parent) 65 | result[key] = parent[key]; 66 | if (obj) 67 | for (key in obj) 68 | result[key] = obj[key]; 69 | return result; 70 | } 71 | 72 | /* Stream merging */ 73 | 74 | function nodeStream(node) { 75 | var result = []; 76 | (function _nodeStream(node, offset) { 77 | for (var child = node.firstChild; child; child = child.nextSibling) { 78 | if (child.nodeType == 3) 79 | offset += child.nodeValue.length; 80 | else if (child.nodeType == 1) { 81 | result.push({ 82 | event: 'start', 83 | offset: offset, 84 | node: child 85 | }); 86 | offset = _nodeStream(child, offset); 87 | // Prevent void elements from having an end tag that would actually 88 | // double them in the output. There are more void elements in HTML 89 | // but we list only those realistically expected in code display. 90 | if (!tag(child).match(/br|hr|img|input/)) { 91 | result.push({ 92 | event: 'stop', 93 | offset: offset, 94 | node: child 95 | }); 96 | } 97 | } 98 | } 99 | return offset; 100 | })(node, 0); 101 | return result; 102 | } 103 | 104 | function mergeStreams(original, highlighted, value) { 105 | var processed = 0; 106 | var result = ''; 107 | var nodeStack = []; 108 | 109 | function selectStream() { 110 | if (!original.length || !highlighted.length) { 111 | return original.length ? original : highlighted; 112 | } 113 | if (original[0].offset != highlighted[0].offset) { 114 | return (original[0].offset < highlighted[0].offset) ? original : highlighted; 115 | } 116 | 117 | /* 118 | To avoid starting the stream just before it should stop the order is 119 | ensured that original always starts first and closes last: 120 | 121 | if (event1 == 'start' && event2 == 'start') 122 | return original; 123 | if (event1 == 'start' && event2 == 'stop') 124 | return highlighted; 125 | if (event1 == 'stop' && event2 == 'start') 126 | return original; 127 | if (event1 == 'stop' && event2 == 'stop') 128 | return highlighted; 129 | 130 | ... which is collapsed to: 131 | */ 132 | return highlighted[0].event == 'start' ? original : highlighted; 133 | } 134 | 135 | function open(node) { 136 | function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"';} 137 | result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attr_str).join('') + '>'; 138 | } 139 | 140 | function close(node) { 141 | result += ''; 142 | } 143 | 144 | function render(event) { 145 | (event.event == 'start' ? open : close)(event.node); 146 | } 147 | 148 | while (original.length || highlighted.length) { 149 | var stream = selectStream(); 150 | result += escape(value.substr(processed, stream[0].offset - processed)); 151 | processed = stream[0].offset; 152 | if (stream == original) { 153 | /* 154 | On any opening or closing tag of the original markup we first close 155 | the entire highlighted node stack, then render the original tag along 156 | with all the following original tags at the same offset and then 157 | reopen all the tags on the highlighted stack. 158 | */ 159 | nodeStack.reverse().forEach(close); 160 | do { 161 | render(stream.splice(0, 1)[0]); 162 | stream = selectStream(); 163 | } while (stream == original && stream.length && stream[0].offset == processed); 164 | nodeStack.reverse().forEach(open); 165 | } else { 166 | if (stream[0].event == 'start') { 167 | nodeStack.push(stream[0].node); 168 | } else { 169 | nodeStack.pop(); 170 | } 171 | render(stream.splice(0, 1)[0]); 172 | } 173 | } 174 | return result + escape(value.substr(processed)); 175 | } 176 | 177 | /* Initialization */ 178 | 179 | function compileLanguage(language) { 180 | 181 | function reStr(re) { 182 | return (re && re.source) || re; 183 | } 184 | 185 | function langRe(value, global) { 186 | return new RegExp( 187 | reStr(value), 188 | 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '') 189 | ); 190 | } 191 | 192 | function compileMode(mode, parent) { 193 | if (mode.compiled) 194 | return; 195 | mode.compiled = true; 196 | 197 | mode.keywords = mode.keywords || mode.beginKeywords; 198 | if (mode.keywords) { 199 | var compiled_keywords = {}; 200 | 201 | var flatten = function(className, str) { 202 | if (language.case_insensitive) { 203 | str = str.toLowerCase(); 204 | } 205 | str.split(' ').forEach(function(kw) { 206 | var pair = kw.split('|'); 207 | compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; 208 | }); 209 | }; 210 | 211 | if (typeof mode.keywords == 'string') { // string 212 | flatten('keyword', mode.keywords); 213 | } else { 214 | Object.keys(mode.keywords).forEach(function (className) { 215 | flatten(className, mode.keywords[className]); 216 | }); 217 | } 218 | mode.keywords = compiled_keywords; 219 | } 220 | mode.lexemesRe = langRe(mode.lexemes || /\b\w+\b/, true); 221 | 222 | if (parent) { 223 | if (mode.beginKeywords) { 224 | mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b'; 225 | } 226 | if (!mode.begin) 227 | mode.begin = /\B|\b/; 228 | mode.beginRe = langRe(mode.begin); 229 | if (!mode.end && !mode.endsWithParent) 230 | mode.end = /\B|\b/; 231 | if (mode.end) 232 | mode.endRe = langRe(mode.end); 233 | mode.terminator_end = reStr(mode.end) || ''; 234 | if (mode.endsWithParent && parent.terminator_end) 235 | mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end; 236 | } 237 | if (mode.illegal) 238 | mode.illegalRe = langRe(mode.illegal); 239 | if (mode.relevance === undefined) 240 | mode.relevance = 1; 241 | if (!mode.contains) { 242 | mode.contains = []; 243 | } 244 | var expanded_contains = []; 245 | mode.contains.forEach(function(c) { 246 | if (c.variants) { 247 | c.variants.forEach(function(v) {expanded_contains.push(inherit(c, v));}); 248 | } else { 249 | expanded_contains.push(c == 'self' ? mode : c); 250 | } 251 | }); 252 | mode.contains = expanded_contains; 253 | mode.contains.forEach(function(c) {compileMode(c, mode);}); 254 | 255 | if (mode.starts) { 256 | compileMode(mode.starts, parent); 257 | } 258 | 259 | var terminators = 260 | mode.contains.map(function(c) { 261 | return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin; 262 | }) 263 | .concat([mode.terminator_end, mode.illegal]) 264 | .map(reStr) 265 | .filter(Boolean); 266 | mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(/*s*/) {return null;}}; 267 | } 268 | 269 | compileMode(language); 270 | } 271 | 272 | /* 273 | Core highlighting function. Accepts a language name, or an alias, and a 274 | string with the code to highlight. Returns an object with the following 275 | properties: 276 | 277 | - relevance (int) 278 | - value (an HTML string with highlighting markup) 279 | 280 | */ 281 | function highlight(name, value, ignore_illegals, continuation) { 282 | 283 | function subMode(lexeme, mode) { 284 | for (var i = 0; i < mode.contains.length; i++) { 285 | if (testRe(mode.contains[i].beginRe, lexeme)) { 286 | return mode.contains[i]; 287 | } 288 | } 289 | } 290 | 291 | function endOfMode(mode, lexeme) { 292 | if (testRe(mode.endRe, lexeme)) { 293 | while (mode.endsParent && mode.parent) { 294 | mode = mode.parent; 295 | } 296 | return mode; 297 | } 298 | if (mode.endsWithParent) { 299 | return endOfMode(mode.parent, lexeme); 300 | } 301 | } 302 | 303 | function isIllegal(lexeme, mode) { 304 | return !ignore_illegals && testRe(mode.illegalRe, lexeme); 305 | } 306 | 307 | function keywordMatch(mode, match) { 308 | var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; 309 | return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str]; 310 | } 311 | 312 | function buildSpan(classname, insideSpan, leaveOpen, noPrefix) { 313 | var classPrefix = noPrefix ? '' : options.classPrefix, 314 | openSpan = ''; 318 | 319 | return openSpan + insideSpan + closeSpan; 320 | } 321 | 322 | function processKeywords() { 323 | if (!top.keywords) 324 | return escape(mode_buffer); 325 | var result = ''; 326 | var last_index = 0; 327 | top.lexemesRe.lastIndex = 0; 328 | var match = top.lexemesRe.exec(mode_buffer); 329 | while (match) { 330 | result += escape(mode_buffer.substr(last_index, match.index - last_index)); 331 | var keyword_match = keywordMatch(top, match); 332 | if (keyword_match) { 333 | relevance += keyword_match[1]; 334 | result += buildSpan(keyword_match[0], escape(match[0])); 335 | } else { 336 | result += escape(match[0]); 337 | } 338 | last_index = top.lexemesRe.lastIndex; 339 | match = top.lexemesRe.exec(mode_buffer); 340 | } 341 | return result + escape(mode_buffer.substr(last_index)); 342 | } 343 | 344 | function processSubLanguage() { 345 | if (top.subLanguage && !languages[top.subLanguage]) { 346 | return escape(mode_buffer); 347 | } 348 | var result = top.subLanguage ? highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) : highlightAuto(mode_buffer); 349 | // Counting embedded language score towards the host language may be disabled 350 | // with zeroing the containing mode relevance. Usecase in point is Markdown that 351 | // allows XML everywhere and makes every XML snippet to have a much larger Markdown 352 | // score. 353 | if (top.relevance > 0) { 354 | relevance += result.relevance; 355 | } 356 | if (top.subLanguageMode == 'continuous') { 357 | continuations[top.subLanguage] = result.top; 358 | } 359 | return buildSpan(result.language, result.value, false, true); 360 | } 361 | 362 | function processBuffer() { 363 | return top.subLanguage !== undefined ? processSubLanguage() : processKeywords(); 364 | } 365 | 366 | function startNewMode(mode, lexeme) { 367 | var markup = mode.className? buildSpan(mode.className, '', true): ''; 368 | if (mode.returnBegin) { 369 | result += markup; 370 | mode_buffer = ''; 371 | } else if (mode.excludeBegin) { 372 | result += escape(lexeme) + markup; 373 | mode_buffer = ''; 374 | } else { 375 | result += markup; 376 | mode_buffer = lexeme; 377 | } 378 | top = Object.create(mode, {parent: {value: top}}); 379 | } 380 | 381 | function processLexeme(buffer, lexeme) { 382 | 383 | mode_buffer += buffer; 384 | if (lexeme === undefined) { 385 | result += processBuffer(); 386 | return 0; 387 | } 388 | 389 | var new_mode = subMode(lexeme, top); 390 | if (new_mode) { 391 | result += processBuffer(); 392 | startNewMode(new_mode, lexeme); 393 | return new_mode.returnBegin ? 0 : lexeme.length; 394 | } 395 | 396 | var end_mode = endOfMode(top, lexeme); 397 | if (end_mode) { 398 | var origin = top; 399 | if (!(origin.returnEnd || origin.excludeEnd)) { 400 | mode_buffer += lexeme; 401 | } 402 | result += processBuffer(); 403 | do { 404 | if (top.className) { 405 | result += ''; 406 | } 407 | relevance += top.relevance; 408 | top = top.parent; 409 | } while (top != end_mode.parent); 410 | if (origin.excludeEnd) { 411 | result += escape(lexeme); 412 | } 413 | mode_buffer = ''; 414 | if (end_mode.starts) { 415 | startNewMode(end_mode.starts, ''); 416 | } 417 | return origin.returnEnd ? 0 : lexeme.length; 418 | } 419 | 420 | if (isIllegal(lexeme, top)) 421 | throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '') + '"'); 422 | 423 | /* 424 | Parser should not reach this point as all types of lexemes should be caught 425 | earlier, but if it does due to some bug make sure it advances at least one 426 | character forward to prevent infinite looping. 427 | */ 428 | mode_buffer += lexeme; 429 | return lexeme.length || 1; 430 | } 431 | 432 | var language = getLanguage(name); 433 | if (!language) { 434 | throw new Error('Unknown language: "' + name + '"'); 435 | } 436 | 437 | compileLanguage(language); 438 | var top = continuation || language; 439 | var continuations = {}; // keep continuations for sub-languages 440 | var result = '', current; 441 | for(current = top; current != language; current = current.parent) { 442 | if (current.className) { 443 | result = buildSpan(current.className, '', true) + result; 444 | } 445 | } 446 | var mode_buffer = ''; 447 | var relevance = 0; 448 | try { 449 | var match, count, index = 0; 450 | while (true) { 451 | top.terminators.lastIndex = index; 452 | match = top.terminators.exec(value); 453 | if (!match) 454 | break; 455 | count = processLexeme(value.substr(index, match.index - index), match[0]); 456 | index = match.index + count; 457 | } 458 | processLexeme(value.substr(index)); 459 | for(current = top; current.parent; current = current.parent) { // close dangling modes 460 | if (current.className) { 461 | result += ''; 462 | } 463 | } 464 | return { 465 | relevance: relevance, 466 | value: result, 467 | language: name, 468 | top: top 469 | }; 470 | } catch (e) { 471 | if (e.message.indexOf('Illegal') != -1) { 472 | return { 473 | relevance: 0, 474 | value: escape(value) 475 | }; 476 | } else { 477 | throw e; 478 | } 479 | } 480 | } 481 | 482 | /* 483 | Highlighting with language detection. Accepts a string with the code to 484 | highlight. Returns an object with the following properties: 485 | 486 | - language (detected language) 487 | - relevance (int) 488 | - value (an HTML string with highlighting markup) 489 | - second_best (object with the same structure for second-best heuristically 490 | detected language, may be absent) 491 | 492 | */ 493 | function highlightAuto(text, languageSubset) { 494 | languageSubset = languageSubset || options.languages || Object.keys(languages); 495 | var result = { 496 | relevance: 0, 497 | value: escape(text) 498 | }; 499 | var second_best = result; 500 | languageSubset.forEach(function(name) { 501 | if (!getLanguage(name)) { 502 | return; 503 | } 504 | var current = highlight(name, text, false); 505 | current.language = name; 506 | if (current.relevance > second_best.relevance) { 507 | second_best = current; 508 | } 509 | if (current.relevance > result.relevance) { 510 | second_best = result; 511 | result = current; 512 | } 513 | }); 514 | if (second_best.language) { 515 | result.second_best = second_best; 516 | } 517 | return result; 518 | } 519 | 520 | /* 521 | Post-processing of the highlighted markup: 522 | 523 | - replace TABs with something more useful 524 | - replace real line-breaks with '
              ' for non-pre containers 525 | 526 | */ 527 | function fixMarkup(value) { 528 | if (options.tabReplace) { 529 | value = value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1 /*..., offset, s*/) { 530 | return p1.replace(/\t/g, options.tabReplace); 531 | }); 532 | } 533 | if (options.useBR) { 534 | value = value.replace(/\n/g, '
              '); 535 | } 536 | return value; 537 | } 538 | 539 | function buildClassName(prevClassName, currentLang, resultLang) { 540 | var language = currentLang ? aliases[currentLang] : resultLang, 541 | result = [prevClassName.trim()]; 542 | 543 | if (!prevClassName.match(/\bhljs\b/)) { 544 | result.push('hljs'); 545 | } 546 | 547 | if (prevClassName.indexOf(language) === -1) { 548 | result.push(language); 549 | } 550 | 551 | return result.join(' ').trim(); 552 | } 553 | 554 | /* 555 | Applies highlighting to a DOM node containing code. Accepts a DOM node and 556 | two optional parameters for fixMarkup. 557 | */ 558 | function highlightBlock(block) { 559 | var language = blockLanguage(block); 560 | if (isNotHighlighted(language)) 561 | return; 562 | 563 | var node; 564 | if (options.useBR) { 565 | node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 566 | node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(//g, '\n'); 567 | } else { 568 | node = block; 569 | } 570 | var text = node.textContent; 571 | var result = language ? highlight(language, text, true) : highlightAuto(text); 572 | 573 | var originalStream = nodeStream(node); 574 | if (originalStream.length) { 575 | var resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 576 | resultNode.innerHTML = result.value; 577 | result.value = mergeStreams(originalStream, nodeStream(resultNode), text); 578 | } 579 | 580 | if (options.lineNumbers) { 581 | var resultPre = document.createElement('pre'); 582 | resultPre.innerHTML = result.value; 583 | var linesPre = document.createElement('pre'); 584 | var lines = escape(text).replace(/^/gm, ''); 585 | linesPre.innerHTML = lines; 586 | result.value = mergeStreams(nodeStream(linesPre), nodeStream(resultPre), text); 587 | } 588 | 589 | result.value = fixMarkup(result.value); 590 | block.innerHTML = result.value; 591 | block.className = buildClassName(block.className, language, result.language); 592 | block.result = { 593 | language: result.language, 594 | re: result.relevance 595 | }; 596 | if (result.second_best) { 597 | block.second_best = { 598 | language: result.second_best.language, 599 | re: result.second_best.relevance 600 | }; 601 | } 602 | } 603 | 604 | var options = { 605 | classPrefix: 'hljs-', 606 | tabReplace: null, 607 | useBR: false, 608 | lineNumbers: false, 609 | languages: undefined 610 | }; 611 | 612 | /* 613 | Updates highlight.js global options with values passed in the form of an object 614 | */ 615 | function configure(user_options) { 616 | options = inherit(options, user_options); 617 | } 618 | 619 | /* 620 | Applies highlighting to all
              ..
              blocks on a page. 621 | */ 622 | function initHighlighting() { 623 | if (initHighlighting.called) 624 | return; 625 | initHighlighting.called = true; 626 | 627 | var blocks = document.querySelectorAll('pre code'); 628 | Array.prototype.forEach.call(blocks, highlightBlock); 629 | } 630 | 631 | /* 632 | Attaches highlighting to the page load event. 633 | */ 634 | function initHighlightingOnLoad() { 635 | addEventListener('DOMContentLoaded', initHighlighting, false); 636 | addEventListener('load', initHighlighting, false); 637 | } 638 | 639 | var languages = {}; 640 | var aliases = {}; 641 | 642 | function registerLanguage(name, language) { 643 | var lang = languages[name] = language(hljs); 644 | if (lang.aliases) { 645 | lang.aliases.forEach(function(alias) {aliases[alias] = name;}); 646 | } 647 | } 648 | 649 | function listLanguages() { 650 | return Object.keys(languages); 651 | } 652 | 653 | function getLanguage(name) { 654 | return languages[name] || languages[aliases[name]]; 655 | } 656 | 657 | /* Interface definition */ 658 | 659 | hljs.highlight = highlight; 660 | hljs.highlightAuto = highlightAuto; 661 | hljs.fixMarkup = fixMarkup; 662 | hljs.highlightBlock = highlightBlock; 663 | hljs.configure = configure; 664 | hljs.initHighlighting = initHighlighting; 665 | hljs.initHighlightingOnLoad = initHighlightingOnLoad; 666 | hljs.registerLanguage = registerLanguage; 667 | hljs.listLanguages = listLanguages; 668 | hljs.getLanguage = getLanguage; 669 | hljs.inherit = inherit; 670 | 671 | // Common regexps 672 | hljs.IDENT_RE = '[a-zA-Z]\\w*'; 673 | hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; 674 | hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; 675 | hljs.C_NUMBER_RE = '\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float 676 | hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... 677 | hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; 678 | 679 | // Common modes 680 | hljs.BACKSLASH_ESCAPE = { 681 | begin: '\\\\[\\s\\S]', relevance: 0 682 | }; 683 | hljs.APOS_STRING_MODE = { 684 | className: 'string', 685 | begin: '\'', end: '\'', 686 | illegal: '\\n', 687 | contains: [hljs.BACKSLASH_ESCAPE] 688 | }; 689 | hljs.QUOTE_STRING_MODE = { 690 | className: 'string', 691 | begin: '"', end: '"', 692 | illegal: '\\n', 693 | contains: [hljs.BACKSLASH_ESCAPE] 694 | }; 695 | hljs.PHRASAL_WORDS_MODE = { 696 | begin: /\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/ 697 | }; 698 | hljs.COMMENT = function (begin, end, inherits) { 699 | var mode = hljs.inherit( 700 | { 701 | className: 'comment', 702 | begin: begin, end: end, 703 | contains: [] 704 | }, 705 | inherits || {} 706 | ); 707 | mode.contains.push(hljs.PHRASAL_WORDS_MODE); 708 | mode.contains.push({ 709 | className: 'doctag', 710 | beginKeywords: "TODO FIXME NOTE BUG XXX", 711 | relevance: 0 712 | }); 713 | return mode; 714 | }; 715 | hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$'); 716 | hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/'); 717 | hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$'); 718 | hljs.NUMBER_MODE = { 719 | className: 'number', 720 | begin: hljs.NUMBER_RE, 721 | relevance: 0 722 | }; 723 | hljs.C_NUMBER_MODE = { 724 | className: 'number', 725 | begin: hljs.C_NUMBER_RE, 726 | relevance: 0 727 | }; 728 | hljs.BINARY_NUMBER_MODE = { 729 | className: 'number', 730 | begin: hljs.BINARY_NUMBER_RE, 731 | relevance: 0 732 | }; 733 | hljs.CSS_NUMBER_MODE = { 734 | className: 'number', 735 | begin: hljs.NUMBER_RE + '(' + 736 | '%|em|ex|ch|rem' + 737 | '|vw|vh|vmin|vmax' + 738 | '|cm|mm|in|pt|pc|px' + 739 | '|deg|grad|rad|turn' + 740 | '|s|ms' + 741 | '|Hz|kHz' + 742 | '|dpi|dpcm|dppx' + 743 | ')?', 744 | relevance: 0 745 | }; 746 | hljs.REGEXP_MODE = { 747 | className: 'regexp', 748 | begin: /\//, end: /\/[gimuy]*/, 749 | illegal: /\n/, 750 | contains: [ 751 | hljs.BACKSLASH_ESCAPE, 752 | { 753 | begin: /\[/, end: /\]/, 754 | relevance: 0, 755 | contains: [hljs.BACKSLASH_ESCAPE] 756 | } 757 | ] 758 | }; 759 | hljs.TITLE_MODE = { 760 | className: 'title', 761 | begin: hljs.IDENT_RE, 762 | relevance: 0 763 | }; 764 | hljs.UNDERSCORE_TITLE_MODE = { 765 | className: 'title', 766 | begin: hljs.UNDERSCORE_IDENT_RE, 767 | relevance: 0 768 | }; 769 | 770 | return hljs; 771 | })); 772 | -------------------------------------------------------------------------------- /extension/firefox/js/lib/languages/json.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: JSON 3 | Author: Ivan Sagalaev 4 | Category: common, protocols 5 | */ 6 | 7 | hljs.registerLanguage('json', function(hljs) { 8 | var LITERALS = {literal: 'true false null'}; 9 | var TYPES = [ 10 | hljs.QUOTE_STRING_MODE, 11 | hljs.C_NUMBER_MODE 12 | ]; 13 | var VALUE_CONTAINER = { 14 | className: 'value', 15 | end: ',', endsWithParent: true, excludeEnd: true, 16 | contains: TYPES, 17 | keywords: LITERALS 18 | }; 19 | var OBJECT = { 20 | begin: '{', end: '}', 21 | contains: [ 22 | { 23 | className: 'attribute', 24 | begin: '\\s*"', end: '"\\s*:\\s*', excludeBegin: true, excludeEnd: true, 25 | contains: [hljs.BACKSLASH_ESCAPE], 26 | illegal: '\\n', 27 | starts: VALUE_CONTAINER 28 | } 29 | ], 30 | illegal: '\\S' 31 | }; 32 | var ARRAY = { 33 | begin: '\\[', end: '\\]', 34 | contains: [hljs.inherit(VALUE_CONTAINER, {className: null})], // inherit is also a workaround for a bug that makes shared modes with endsWithParent compile only the ending of one of the parents 35 | illegal: '\\S' 36 | }; 37 | TYPES.splice(TYPES.length, 0, OBJECT, ARRAY); 38 | return { 39 | contains: TYPES, 40 | keywords: LITERALS, 41 | illegal: '\\S' 42 | }; 43 | }) 44 | -------------------------------------------------------------------------------- /extension/firefox/js/lib/languages/sql.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: SQL 3 | Contributors: Nikolay Lisienko , Heiko August , Travis Odom 4 | Category: common 5 | */ 6 | 7 | hljs.registerLanguage('sql', function(hljs) { 8 | var COMMENT_MODE = hljs.COMMENT('--', '$'); 9 | return { 10 | case_insensitive: true, 11 | illegal: /[<>]/, 12 | contains: [ 13 | { 14 | className: 'operator', 15 | beginKeywords: 16 | 'begin end start commit rollback savepoint lock alter create drop rename call '+ 17 | 'delete do handler insert load replace select truncate update set show pragma grant '+ 18 | 'merge describe use explain help declare prepare execute deallocate savepoint release '+ 19 | 'unlock purge reset change stop analyze cache flush optimize repair kill '+ 20 | 'install uninstall checksum restore check backup revoke', 21 | end: /;/, endsWithParent: true, 22 | keywords: { 23 | keyword: 24 | 'abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter ' + 25 | 'analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup ' + 26 | 'before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by ' + 27 | 'cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length ' + 28 | 'character_length charindex charset check checksum checksum_agg choose close coalesce ' + 29 | 'coercibility collate collation collationproperty column columns columns_updated commit compress concat ' + 30 | 'concat_ws concurrent connect connection connection_id consistent constraint constraints continue ' + 31 | 'contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist ' + 32 | 'curdate current current_date current_time current_timestamp current_user cursor curtime data database ' + 33 | 'databases datalength date_add date_format date_sub dateadd datediff datefromparts datename ' + 34 | 'datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear ' + 35 | 'deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt ' + 36 | 'des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct ' + 37 | 'distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec ' + 38 | 'engine engines eomonth errors escape escaped event eventdata events except exception exec execute ' + 39 | 'exists exp explain export_set extended external extract fast fetch field fields find_in_set ' + 40 | 'first first_value floor flush for force foreign format found found_rows from from_base64 ' + 41 | 'from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant ' + 42 | 'grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help ' + 43 | 'hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore ' + 44 | 'iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner ' + 45 | 'innodb input insert install instr intersect into is is_free_lock is_ipv4 ' + 46 | 'is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill ' + 47 | 'language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level ' + 48 | 'like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile ' + 49 | 'logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max ' + 50 | 'md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names ' + 51 | 'national natural nchar next no no_write_to_binlog not now nullif nvarchar oct ' + 52 | 'octet_length of old_password on only open optimize option optionally or ord order outer outfile output ' + 53 | 'pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add ' + 54 | 'period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges ' + 55 | 'procedure procedure_analyze processlist profile profiles public publishingservername purge quarter ' + 56 | 'query quick quote quotename radians rand read references regexp relative relaylog release ' + 57 | 'release_lock rename repair repeat replace replicate reset restore restrict return returns reverse ' + 58 | 'revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll ' + 59 | 'sec_to_time second section select serializable server session session_user set sha sha1 sha2 share ' + 60 | 'show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex ' + 61 | 'sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache ' + 62 | 'sql_small_result sql_variant_property sqlstate sqrt square start starting status std ' + 63 | 'stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff ' + 64 | 'subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset ' + 65 | 'system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time ' + 66 | 'time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour ' + 67 | 'timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation ' + 68 | 'trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress ' + 69 | 'uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade ' + 70 | 'upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short ' + 71 | 'validate_password_strength value values var var_pop var_samp variables variance varp ' + 72 | 'version view warnings week weekday weekofyear weight_string when whenever where with work write xml ' + 73 | 'xor year yearweek zon', 74 | literal: 75 | 'true false null', 76 | built_in: 77 | 'array bigint binary bit blob boolean char character date dec decimal float int integer interval number ' + 78 | 'numeric real serial smallint varchar varying int8 serial8 text' 79 | }, 80 | contains: [ 81 | { 82 | className: 'string', 83 | begin: '\'', end: '\'', 84 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '\'\''}] 85 | }, 86 | { 87 | className: 'string', 88 | begin: '"', end: '"', 89 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '""'}] 90 | }, 91 | { 92 | className: 'string', 93 | begin: '`', end: '`', 94 | contains: [hljs.BACKSLASH_ESCAPE] 95 | }, 96 | hljs.C_NUMBER_MODE, 97 | hljs.C_BLOCK_COMMENT_MODE, 98 | COMMENT_MODE 99 | ] 100 | }, 101 | hljs.C_BLOCK_COMMENT_MODE, 102 | COMMENT_MODE 103 | ] 104 | }; 105 | }) 106 | -------------------------------------------------------------------------------- /extension/firefox/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Everbug", 3 | "icons": { 4 | "16": "img/icons/icon_16.png", 5 | "32": "img/icons/icon_32.png", 6 | "64": "img/icons/icon_64.png" 7 | }, 8 | "browser_action": { 9 | "default_icon": "img/icons/icon_16.png", 10 | "default_title": "Everbug" 11 | }, 12 | "version": "1.24", 13 | "description": "Everbug - Debugger for Django projects", 14 | "devtools_page": "html/devtools.html", 15 | "background": { 16 | "scripts": ["js/ext/background.js"] 17 | }, 18 | "web_accessible_resources": [ "js/*", "js/lib/*", "js/languages/*", "html/*", "css/*", "img/*" ], 19 | "permissions": [ "tabs", "webRequest", "webRequestBlocking", "webNavigation", ""], 20 | "manifest_version": 2 21 | } 22 | 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from setuptools import find_packages 3 | from everbug import __version__ 4 | 5 | setup( 6 | name='everbug', 7 | version=__version__, 8 | description='Django debug extension', 9 | license='MIT', 10 | platform='any', 11 | long_description=open('README.rst').read(), 12 | classifiers=[ 13 | 'Development Status :: 5 - Production/Stable', 14 | 'Environment :: Web Environment', 15 | 'Framework :: Django', 16 | 'Framework :: Django :: 1.11', 17 | 'Framework :: Django :: 2.0', 18 | 'Intended Audience :: Developers', 19 | 'Operating System :: OS Independent', 20 | 'Programming Language :: Python', 21 | 'Programming Language :: Python :: 3', 22 | 'Programming Language :: Python :: 3.5', 23 | 'Programming Language :: Python :: 3.6', 24 | 'License :: OSI Approved :: MIT License', 25 | ], 26 | author='Igor Tolkachnikov', 27 | author_email='i.tolkachnikov@gmail.com', 28 | url='https://github.com/everhide/everbug', 29 | packages=['everbug'], 30 | include_package_data=True, 31 | zip_safe=False, 32 | ) 33 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/tests/__init__.py -------------------------------------------------------------------------------- /tests/db/alt_db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/tests/db/alt_db -------------------------------------------------------------------------------- /tests/db/def_db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/everhide/everbug/72da1372510a2116e45c23da934a40dca1f4dbd5/tests/db/def_db -------------------------------------------------------------------------------- /tests/runtests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from unittest import TestSuite, TextTestRunner, defaultTestLoader 4 | 5 | from django import setup 6 | 7 | 8 | TEST_MODULES = ( 9 | 'test_profile', 10 | 'test_pstats', 11 | 'test_manager', 12 | 'test_queries', 13 | 'test_context', 14 | 'test_middleware', 15 | 'test_serializer', 16 | ) 17 | 18 | 19 | def run(): 20 | suite = TestSuite() 21 | for test in TEST_MODULES: 22 | try: 23 | mod = __import__(test, globals(), locals(), ['suite']) 24 | suitefn = getattr(mod, 'suite') 25 | suite.addTest(suitefn()) 26 | except (ImportError, AttributeError): 27 | suite.addTest(defaultTestLoader.loadTestsFromName(test)) 28 | TextTestRunner().run(suite) 29 | 30 | 31 | if __name__ == '__main__': 32 | sys.path.append(os.path.abspath(os.curdir)) 33 | os.environ['DJANGO_SETTINGS_MODULE'] = 'stub.settings' 34 | setup() 35 | run() 36 | -------------------------------------------------------------------------------- /tests/stub/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | 4 | class TestForm(forms.Form): 5 | item = forms.CharField(max_length=30) 6 | -------------------------------------------------------------------------------- /tests/stub/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | index page of stub 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/stub/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class CustomEntity(models.Model): 5 | item = models.CharField(max_length=30) 6 | 7 | def __str__(self): 8 | return self.item 9 | 10 | class Meta: 11 | abstract = True 12 | managed = False 13 | 14 | 15 | class Entity(CustomEntity): 16 | class Meta: 17 | db_table = 'def_entity' 18 | 19 | 20 | class AltEntity(CustomEntity): 21 | class Meta: 22 | db_table = 'alt_entity' 23 | -------------------------------------------------------------------------------- /tests/stub/router.py: -------------------------------------------------------------------------------- 1 | from tests.stub.models import Entity 2 | 3 | 4 | class DBRouter: 5 | 6 | def db_for_read(self, model): 7 | if model == Entity: 8 | return 'default' 9 | else: 10 | return 'alternate' 11 | -------------------------------------------------------------------------------- /tests/stub/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 4 | DEBUG = True 5 | ROOT_URLCONF = 'stub.urls' 6 | ALLOWED_HOSTS = ['*'] 7 | 8 | SECRET_KEY = 'whoknows' 9 | LANGUAGE_CODE = 'en-us' 10 | TIME_ZONE = 'UTC' 11 | USE_I18N = True 12 | USE_L10N = True 13 | USE_TZ = True 14 | 15 | 16 | INSTALLED_APPS = [ 17 | 'django.contrib.admin', 18 | 'django.contrib.auth', 19 | 'django.contrib.contenttypes', 20 | 'django.contrib.sessions', 21 | 'django.contrib.messages', 22 | 'django.contrib.staticfiles', 23 | 'everbug', 24 | 'tests', 25 | ] 26 | 27 | MIDDLEWARE_CLASSES = [ 28 | 'everbug.middleware.Tracer' 29 | ] 30 | 31 | 32 | MIDDLEWARE = [ 33 | 'everbug.middleware.Tracer' 34 | ] 35 | 36 | 37 | TEMPLATES = [ 38 | { 39 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 40 | 'DIRS': [os.path.join(BASE_DIR, 'stub')], 41 | 'APP_DIRS': True, 42 | 'OPTIONS': { 43 | 'context_processors': [ 44 | 'django.template.context_processors.debug', 45 | 'django.template.context_processors.request', 46 | 'django.contrib.auth.context_processors.auth', 47 | 'django.contrib.messages.context_processors.messages', 48 | ], 49 | }, 50 | }, 51 | ] 52 | 53 | 54 | DATABASE_ROUTERS = ['stub.router.DBRouter'] 55 | 56 | 57 | DATABASES = { 58 | 'default': { 59 | 'ENGINE': 'django.db.backends.sqlite3', 60 | 'NAME': os.path.join(BASE_DIR, 'db', 'def_db'), 61 | }, 62 | 'alternate': { 63 | 'ENGINE': 'django.db.backends.sqlite3', 64 | 'NAME': os.path.join(BASE_DIR, 'db', 'alt_db'), 65 | }, 66 | 67 | } 68 | -------------------------------------------------------------------------------- /tests/stub/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from tests.stub.views import ( 4 | Context, 5 | ContextEmpty, 6 | context, 7 | context_empty, 8 | context_render, 9 | query_multiply, 10 | query_no, 11 | query_single 12 | ) 13 | 14 | 15 | urlpatterns = [ 16 | url(r'^context/$', context), 17 | url(r'^context_empty/$', context_empty), 18 | url(r'^context_render/$', context_render), 19 | url(r'^context_cbv/$', Context.as_view()), 20 | url(r'^context_cbv_empty/$', ContextEmpty.as_view()), 21 | url(r'^query_no/$', query_no), 22 | url(r'^query_single/$', query_single), 23 | url(r'^query_multiply/$', query_multiply), 24 | ] 25 | -------------------------------------------------------------------------------- /tests/stub/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.template.response import TemplateResponse 3 | from django.views.generic import TemplateView 4 | 5 | from tests.stub.models import AltEntity, Entity 6 | 7 | 8 | CONTEXT = {'yes': True} 9 | TEMPLATE = 'index.html' 10 | 11 | 12 | def context(request, *args, **kwargs): 13 | return TemplateResponse(request, TEMPLATE, CONTEXT) 14 | 15 | 16 | def context_render(request): 17 | return render(request, TEMPLATE, CONTEXT) 18 | 19 | 20 | def context_empty(request): 21 | return TemplateResponse(request, TEMPLATE, {}) 22 | 23 | 24 | class ContextEmpty(TemplateView): 25 | template_name = TEMPLATE 26 | 27 | 28 | class Context(TemplateView): 29 | template_name = TEMPLATE 30 | 31 | def get_context_data(self, **kwargs): 32 | return CONTEXT 33 | 34 | 35 | def query_single(request): 36 | list(Entity.objects.all()) 37 | return render(request, TEMPLATE) 38 | 39 | 40 | def query_multiply(request): 41 | list(Entity.objects.all()) 42 | list(AltEntity.objects.all()) 43 | return render(request, TEMPLATE) 44 | 45 | 46 | def query_no(request): 47 | return render(request, TEMPLATE) 48 | -------------------------------------------------------------------------------- /tests/test_context.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | from unittest.mock import Mock 3 | 4 | from everbug.utils.context import Ext, wrap_context 5 | 6 | from tests.stub.forms import TestForm 7 | from tests.stub.models import Entity as TestModel 8 | 9 | 10 | class TestBuiltins(TestCase): 11 | 12 | def test_instance(self): 13 | i = Mock() 14 | ref = ('i', i, 'Instance: %s' % i.__class__.__name__, Ext.CLASS, 0) 15 | self.assertEqual(wrap_context({'i': i}), [ref]) 16 | 17 | def test_class(self): 18 | ref = ('cls', Mock, 'Class: %s' % Mock.__name__, Ext.CLASS, 0) 19 | self.assertEqual(wrap_context({'cls': Mock}), [ref]) 20 | 21 | def test_int(self): 22 | ref = ('int', 1, 'int', Ext.SIMPLE, 0) 23 | self.assertEqual(wrap_context({'int': 1}), [ref]) 24 | 25 | def test_float(self): 26 | ref = ('float', 0.1, 'float', Ext.SIMPLE, 0) 27 | self.assertEqual(wrap_context({'float': 0.1}), [ref]) 28 | 29 | def test_complex(self): 30 | ref = ('complex', 1 + 1j, 'complex', Ext.SIMPLE, 0) 31 | self.assertEqual(wrap_context({'complex': 1 + 1j}), [ref]) 32 | 33 | def test_bool(self): 34 | ref = ('bool', True, 'bool', Ext.SIMPLE, 0) 35 | self.assertEqual(wrap_context({'bool': True}), [ref]) 36 | 37 | def test_bytes(self): 38 | ref = ('bytes', b'\x00', 'bytes', Ext.ITERABLE, 1) 39 | self.assertEqual(wrap_context({'bytes': bytes([0])}), [ref]) 40 | 41 | def test_bytearray(self): 42 | ref = ('bytearray', b'\x00\x01', 'bytearray', Ext.ITERABLE, 2) 43 | self.assertEqual(wrap_context({'bytearray': bytearray([0, 1])}), [ref]) 44 | 45 | def test_str(self): 46 | ref = ('str', 'foo', 'str', Ext.ITERABLE, 3) 47 | self.assertEqual(wrap_context({'str': 'foo'}), [ref]) 48 | 49 | def test_tuple(self): 50 | ref = ('tuple', (0, 1), 'tuple', Ext.ITERABLE, 2) 51 | self.assertEqual(wrap_context({'tuple': (0, 1)}), [ref]) 52 | 53 | def test_list(self): 54 | ref = ('list', [0, 1], 'list', Ext.ITERABLE, 2) 55 | self.assertEqual(wrap_context({'list': [0, 1]}), [ref]) 56 | 57 | def test_dict(self): 58 | ref = ('dict', {'var': None}, 'dict', Ext.ITERABLE, 1) 59 | self.assertEqual(wrap_context({'dict': {'var': None}}), [ref]) 60 | 61 | def test_set(self): 62 | ref = ('set', {0, 1}, 'set', Ext.ITERABLE, 2) 63 | self.assertEqual(wrap_context({'set': {0, 1}}), [ref]) 64 | 65 | def test_frozenset(self): 66 | ref = ('frozenset', frozenset([0, 1]), 'frozenset', Ext.ITERABLE, 2) 67 | self.assertEqual(wrap_context({'frozenset': frozenset([0, 1])}), [ref]) 68 | 69 | def test_form(self): 70 | form = TestForm() 71 | ref = ('form', form, 'Form: %s' % TestForm.__name__, Ext.DJANGO, 1) 72 | self.assertEqual(wrap_context({'form': form}), [ref]) 73 | 74 | def test_model(self): 75 | model = TestModel.objects.first() 76 | ref = ('model', model, 'Model: %s' % TestModel.__name__, Ext.DJANGO, 1) 77 | self.assertEqual(wrap_context({'model': model}), [ref]) 78 | 79 | def test_queryset(self): 80 | qs = TestModel.objects.all()[:2] 81 | ref = ('qs', qs, 'QuerySet: %s' % TestModel.__name__, Ext.DJANGO, 2) 82 | self.assertEqual(wrap_context({'qs': qs}), [ref]) 83 | -------------------------------------------------------------------------------- /tests/test_manager.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from everbug.utils.manager import ProfileManager 4 | 5 | 6 | class TestProfileManager(TestCase): 7 | 8 | @classmethod 9 | def setUp(cls): 10 | cls.manager = ProfileManager() 11 | 12 | def test_single_instance(self): 13 | self.assertEqual(id(self.manager), id(ProfileManager())) 14 | 15 | def test_append(self): 16 | self.manager.clear() 17 | self.manager.add('item') 18 | self.assertEqual(self.manager.profiles()[0], 'item') 19 | 20 | def test_count(self): 21 | self.manager.clear() 22 | for i in range(0, 10): 23 | self.manager.add('item_%s' % i) 24 | self.assertEqual(self.manager.count, 10) 25 | -------------------------------------------------------------------------------- /tests/test_middleware.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from django.test import Client, TestCase, override_settings 4 | 5 | from everbug.middleware import Header 6 | 7 | 8 | class TestTracer(TestCase): 9 | 10 | @classmethod 11 | def setUp(cls): 12 | # Disable notices for expected 404 status 13 | logging.disable(logging.ERROR) 14 | cls.client = Client() 15 | 16 | @classmethod 17 | def tearDownClass(cls): 18 | logging.disable(logging.NOTSET) 19 | 20 | def trace(self, url): 21 | """ 22 | Makes two requests: target and request of trace data for target request 23 | We expect REQUEST_ID in the headers of target request, so we generate 24 | it during the test randomly 25 | """ 26 | test_id = 'RID_%s' % id(self) 27 | self.client.get(url, **{Header.REQUEST: test_id}) 28 | return self.client.get(url, **{Header.TRACE: test_id}) 29 | 30 | def test_field_context_through_fbv(self): 31 | response = self.trace('/context/') 32 | self.assertIn('context', response.content.decode()) 33 | 34 | def test_field_context_through_cbv(self): 35 | response = self.trace('/context_cbv/') 36 | self.assertIn('context', response.content.decode()) 37 | 38 | def test_field_queries_with_single_db(self): 39 | response = self.trace('/query_single/') 40 | self.assertIn('queries', response.content.decode()) 41 | 42 | def test_field_queries_with_multiply_db(self): 43 | response = self.trace('/query_multiply/') 44 | self.assertIn('queries', response.content.decode()) 45 | 46 | def test_status_context_through_render(self): 47 | response = self.trace('/context_render/') 48 | self.assertEqual(response.status_code, 404) 49 | 50 | def test_status_context_fbv_empty(self): 51 | response = self.trace('/context_empty/') 52 | self.assertEqual(response.status_code, 404) 53 | 54 | def test_status_context_cbv_empty(self): 55 | response = self.trace('/context_empty_cbv/') 56 | self.assertEqual(response.status_code, 404) 57 | 58 | def test_status_queries_empty(self): 59 | response = self.trace('/query_no/') 60 | self.assertEqual(response.status_code, 404) 61 | 62 | def test_if_trace_data_exists(self): 63 | response = self.client.get('/context/', **{Header.REQUEST: 1}) 64 | self.assertEqual(response[Header.HAS_TRACE], '1') 65 | 66 | def test_if_trace_data_not_exists(self): 67 | response = self.client.get('/context_empty/', **{Header.REQUEST: 1}) 68 | self.assertEqual(response[Header.HAS_TRACE], '0') 69 | 70 | @override_settings(DEBUG=False) 71 | def test_headers_if_not_debug(self): 72 | response = self.client.get('/context/', **{Header.REQUEST: 1}) 73 | self.assertNotIn(Header.HAS_TRACE, response) 74 | -------------------------------------------------------------------------------- /tests/test_profile.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from unittest import TestCase 3 | 4 | from everbug.shortcuts import profile 5 | from everbug.utils.manager import ProfileManager 6 | 7 | 8 | class TestProfile(TestCase): 9 | 10 | @classmethod 11 | def setUp(cls): 12 | cls.manager = ProfileManager() 13 | 14 | @profile 15 | def target(self): 16 | import inspect 17 | return inspect.stack() 18 | 19 | @profile(short=False) 20 | def target_with_arg(self): 21 | import inspect 22 | return inspect.stack() 23 | 24 | def test_arg_default(self): 25 | self.manager.clear() 26 | self.target() 27 | self.assertEqual(len(self.manager.profiles()[0]['lines']), 20) 28 | 29 | def test_arg_custom(self): 30 | self.manager.clear() 31 | self.target_with_arg() 32 | self.assertGreater(len(self.manager.profiles()[0]['lines']), 20) 33 | 34 | def test_field_method(self): 35 | self.manager.clear() 36 | self.target() 37 | origin_name = self.target.__name__ 38 | profiled_name = self.manager.profiles()[0]['method'] 39 | self.assertEqual(origin_name, profiled_name) 40 | 41 | def test_field_module(self): 42 | self.manager.clear() 43 | self.target() 44 | origin_name = sys.modules[self.target.__module__].__file__ 45 | profiled_name = self.manager.profiles()[0]['module'] 46 | self.assertEqual(origin_name, profiled_name) 47 | -------------------------------------------------------------------------------- /tests/test_pstats.py: -------------------------------------------------------------------------------- 1 | from cProfile import Profile 2 | from unittest import TestCase 3 | 4 | from everbug.utils.pstats import StatsDict 5 | 6 | 7 | class TestStatsDictDump(TestCase): 8 | 9 | def func_with_many_calls(self): 10 | import inspect 11 | return inspect.stack() 12 | 13 | def inspect(self, method): 14 | profile = Profile() 15 | profile.enable() 16 | method() 17 | profile.disable() 18 | return StatsDict(profile).sort_stats('cumtime') 19 | 20 | def test_lines_default(self): 21 | stats = self.inspect(self.func_with_many_calls).dump() 22 | self.assertGreater(len(stats['lines']), 20) 23 | 24 | def test_lines_short(self): 25 | stats = self.inspect(self.func_with_many_calls).dump(short=True) 26 | self.assertEqual(len(stats['lines']), 20) 27 | 28 | def test_lines_all(self): 29 | stats = self.inspect(self.func_with_many_calls).dump(short=False) 30 | self.assertGreater(len(stats['lines']), 20) 31 | 32 | def test_fields(self): 33 | stats = self.inspect(self.func_with_many_calls).dump() 34 | self.assertCountEqual(['lines', 'total_calls', 'total_time'], stats) 35 | -------------------------------------------------------------------------------- /tests/test_queries.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from django.db import reset_queries 4 | 5 | from everbug.utils.queries import wrap_queries 6 | 7 | from tests.stub.models import AltEntity, Entity 8 | 9 | 10 | def run_queries(multi_db=False, multi_query=False): 11 | 12 | def run(db_model=None, multi=False): 13 | list(db_model.objects.all()) 14 | if multi: 15 | list(db_model.objects.all()[:5]) 16 | 17 | reset_queries() 18 | run(Entity, multi_query) 19 | if multi_db: 20 | run(AltEntity, multi_query) 21 | 22 | 23 | class TestQueries(TestCase): 24 | 25 | def test_without_queries(self): 26 | reset_queries() 27 | self.assertEqual(None, wrap_queries()) 28 | 29 | def test_alias_single_db(self): 30 | run_queries() 31 | self.assertCountEqual(['default'], wrap_queries()) 32 | 33 | def test_alias_multi_db(self): 34 | run_queries(multi_db=True) 35 | self.assertCountEqual(['default', 'alternate'], wrap_queries()) 36 | 37 | def test_fields_single_db(self): 38 | run_queries() 39 | query = wrap_queries()['default'][0] 40 | self.assertCountEqual(['time', 'explain', 'sql'], query) 41 | 42 | def test_fields_multi_db(self): 43 | run_queries(multi_db=True) 44 | db_queries = wrap_queries() 45 | for query in (db_queries['default'], db_queries['alternate']): 46 | self.assertCountEqual(['time', 'explain', 'sql'], query[0]) 47 | 48 | def test_fields_multiquery_single_db(self): 49 | run_queries(multi_query=True) 50 | queries = wrap_queries()['default'] 51 | for query in queries: 52 | self.assertCountEqual(['time', 'explain', 'sql'], query) 53 | 54 | def test_fields_multiquery_multi_db(self): 55 | run_queries(multi_db=True, multi_query=True) 56 | db_queries = wrap_queries() 57 | for queries in (db_queries['default'], db_queries['alternate']): 58 | for query in queries: 59 | self.assertCountEqual(['time', 'explain', 'sql'], query) 60 | -------------------------------------------------------------------------------- /tests/test_serializer.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | from unittest.mock import Mock 3 | 4 | from django.core.serializers import serialize 5 | from django.forms.models import model_to_dict 6 | 7 | from everbug.utils.serilalize import serial 8 | 9 | from tests.stub.forms import TestForm 10 | from tests.stub.models import Entity 11 | 12 | 13 | class TestSerial(TestCase): 14 | 15 | def test_as_is_int_float_bool_str(self): 16 | for item in (1, 0.1, True, 'string'): 17 | self.assertEqual(item, serial(item)) 18 | 19 | def test_iterables(self): 20 | for item in (frozenset([0]), {0}, (0,)): 21 | self.assertEqual([0], serial(item)) 22 | 23 | def test_dict(self): 24 | sample_dict = {'key': 'value'} 25 | self.assertEqual(sample_dict, serial(sample_dict)) 26 | 27 | def test_dict_nested(self): 28 | pattern = {'key': {'sub_key': [0, 1, 2]}} 29 | test_dict = {'key': {'sub_key': frozenset([0, 1, 2])}} 30 | self.assertEqual(pattern, serial(test_dict)) 31 | 32 | def test_list(self): 33 | sample_list = [0, 1, 2] 34 | self.assertEqual(sample_list, serial(sample_list)) 35 | 36 | def test_list_nested(self): 37 | pattern = [0, [1, [2, [3]]]] 38 | test_list = [0, (1, (2, frozenset({3})))] 39 | self.assertEqual(pattern, serial(test_list)) 40 | 41 | def test_form(self): 42 | form = TestForm() 43 | fields = form.fields 44 | pattern = {f: type(fields[f]).__name__ for f in fields} 45 | self.assertEqual(pattern, serial(form)) 46 | 47 | def test_queryset(self): 48 | items = Entity.objects.all() 49 | pattern = serialize('python', items) 50 | self.assertEqual(pattern, serial(items)) 51 | 52 | def test_model(self): 53 | item = Entity.objects.first() 54 | pattern = model_to_dict(item) 55 | self.assertEqual(pattern, serial(item)) 56 | 57 | def test_unknowns(self): 58 | self.assertEqual(str(Mock), serial(Mock)) 59 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = cov_clean, {py35}-{dj11, dj20}, {py36}-{dj11, dj20}, cov_stat, flake8 3 | skipsdist = {env:TOXBUILD:false} 4 | 5 | 6 | [testenv] 7 | usedevelop = True 8 | sitepackages = False 9 | deps = 10 | coverage 11 | dj11: Django==1.11 12 | dj20: Django==2.0.5 13 | commands = 14 | {env:TOXBUILD:python ./tests/runtests.py} 15 | coverage run -a ./tests/runtests.py 16 | 17 | [testenv:cov_clean] 18 | commands= 19 | coverage erase 20 | 21 | [testenv:cov_stat] 22 | commands= 23 | coverage report -m --omit="*/.tox*" 24 | 25 | [testenv:flake8] 26 | basepython = python3 27 | skip_install = true 28 | deps = 29 | flake8 30 | pep8-naming 31 | flake8-colors 32 | flake8-import-order>=0.9 33 | commands = 34 | flake8 everbug tests 35 | 36 | 37 | [flake8] 38 | exclude = /venv 39 | max-line-length = 79 40 | format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s 41 | ignore = F811 42 | --------------------------------------------------------------------------------