diff options
53 files changed, 2250 insertions, 1493 deletions
| diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..01f598b --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +# Make file to compress and join all JS files +all: compress_js compress_css + +compress_js: +	java -jar ~/bin/yuicompressor.jar debug_toolbar/media/debug_toolbar/js/jquery.js > debug_toolbar/media/debug_toolbar/js/toolbar.min.js +	java -jar ~/bin/yuicompressor.jar debug_toolbar/media/debug_toolbar/js/toolbar.js >> debug_toolbar/media/debug_toolbar/js/toolbar.min.js + +compress_css: +	java -jar ~/bin/yuicompressor.jar --type css debug_toolbar/media/debug_toolbar/css/toolbar.css > debug_toolbar/media/debug_toolbar/css/toolbar.min.css @@ -25,6 +25,8 @@ There is also one Django management command currently:  If you have ideas for other panels please let us know. +* Note: The Debug Toolbar only works on Django 1.1 and newer. +  Installation  ============ @@ -104,7 +106,7 @@ The debug toolbar has two settings that can be set in `settings.py`:     * `SHOW_TOOLBAR_CALLBACK`: If not set or set to None, the debug_toolbar       middleware will use its built-in show_toolbar method for determining whether       the toolbar should show or not.  The default checks are that DEBUG must be -     set to True and the IP of the request must be in INTERNAL_IPS.  You can +     set to True or the IP of the request must be in INTERNAL_IPS.  You can       provide your own method for displaying the toolbar which contains your       custom logic.  This method should return True or False. @@ -190,6 +192,13 @@ adding proper coverage (especially if it has a chance for a regression) in the t      python setup.py test + +3rd Party Panels +================ + +A list of 3rd party panels can be found on the Django Debug Toolbar Github wiki: +https://github.com/django-debug-toolbar/django-debug-toolbar/wiki/3rd-Party-Panels +  TODOs and BUGS  ==============  See: https://github.com/django-debug-toolbar/django-debug-toolbar/issues diff --git a/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.mo b/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.moBinary files differ new file mode 100644 index 0000000..0fa0a13 --- /dev/null +++ b/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.mo diff --git a/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.po b/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..80a1bd2 --- /dev/null +++ b/debug_toolbar/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,367 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Percy Pérez-Pinedo, 2009. +# +# +msgid "" +msgstr "" +"Project-Id-Version: Django Debug Toolbar 0.8.4\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-01-22 08:58+0000\n" +"PO-Revision-Date: 2011-01-22 08:58+0000\n" +"Last-Translator: Eduardo Cereto Carvalho <eduardocereto@gmail.com>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: panels/cache.py:92 +#, python-format +msgid "Cache: %.2fms" +msgstr "Cache: %.2fms" + +#: panels/cache.py:95 +msgid "Cache Usage" +msgstr "Uso do Cache" + +#: panels/headers.py:36 panels/headers.py:39 +msgid "HTTP Headers" +msgstr "Cabeçalhos HTTP" + +#: panels/logger.py:56 +msgid "Logging" +msgstr "Logs" + +#: panels/logger.py:63 +msgid "Log Messages" +msgstr "Mensagens de Log" + +#: panels/request_vars.py:13 panels/request_vars.py:16 +msgid "Request Vars" +msgstr "Variáveis do Request" + +#: panels/settings_vars.py:16 +msgid "Settings" +msgstr "Configurações" + +#: panels/settings_vars.py:19 +#, python-format +msgid "Settings from <code>%s</code>" +msgstr "Configurações de <code>%s</code>" + +#: panels/signals.py:39 panels/signals.py:42 +msgid "Signals" +msgstr "Sinais" + +#: panels/sql.py:146 +msgid "SQL" +msgstr "SQL" + +#: panels/sql.py:160 +msgid "SQL Queries" +msgstr "Queries SQL" + +#: panels/template.py:47 +msgid "Templates" +msgstr "Templates" + +#: panels/template.py:52 +#, python-format +msgid "Templates (%(num_templates)s rendered)" +msgstr "Templates (%(num_templates)s renderizados)" + +#: panels/timer.py:35 templates/debug_toolbar/panels/cache.html:39 +#: templates/debug_toolbar/panels/logger.html:7 +#: templates/debug_toolbar/panels/sql.html:5 +#: templates/debug_toolbar/panels/sql_explain.html:11 +#: templates/debug_toolbar/panels/sql_profile.html:12 +#: templates/debug_toolbar/panels/sql_select.html:11 +msgid "Time" +msgstr "Tempo" + +#: panels/timer.py:47 +msgid "Resource Usage" +msgstr "Uso de Recursos" + +#: panels/timer.py:78 +msgid "User CPU time" +msgstr "Tempo de CPU do usuário" + +#: panels/timer.py:79 +msgid "System CPU time" +msgstr "Tempo de CPU do sistema" + +#: panels/timer.py:80 +msgid "Total CPU time" +msgstr "Tempo de CPU total" + +#: panels/timer.py:81 +msgid "Elapsed time" +msgstr "Tempo decorrido" + +#: panels/timer.py:82 +msgid "Context switches" +msgstr "Alterações de contexto" + +#: panels/version.py:20 panels/version.py:29 +msgid "Versions" +msgstr "Versões" + +#: templates/debug_toolbar/base.html:23 +msgid "Hide Toolbar" +msgstr "Esconder Barra" + +#: templates/debug_toolbar/base.html:23 +msgid "Hide" +msgstr "Esconder" + +#: templates/debug_toolbar/base.html:48 +msgid "Show Toolbar" +msgstr "Mostrar Barra" + +#: templates/debug_toolbar/base.html:54 +msgid "Close" +msgstr "Fechar" + +#: templates/debug_toolbar/redirect.html:7 +#: templates/debug_toolbar/panels/logger.html:9 +msgid "Location" +msgstr "Localização" + +#: templates/debug_toolbar/redirect.html:9 +msgid "" +"The Django Debug Toolbar has intercepted a redirect to the above URL for " +"debug viewing purposes.  You can click the above link to continue with the " +"redirect as normal.  If you'd like to disable this feature, set the " +"<code>DEBUG_TOOLBAR_CONFIG</code> dictionary's key " +"<code>INTERCEPT_REDIRECTS</code> to <code>False</code>." +msgstr "" +"A Barra de Debug do Django interceptou um redirecionamento para a URL acima por " +"propósito de debug. Você pode clicar no link acima para continuar com o " +"redirecionamento normal. Se você gostaria de desabilitar essa funcionalidade, configure a " +"chave <code></code> do dicionário " +"<code>DEBUG_TOOLBAR_CONFIG</code> para <code>False</code>" + +#: templates/debug_toolbar/panels/cache.html:14 +msgid "Total Calls" +msgstr "Total de Chamadas" + +#: templates/debug_toolbar/panels/cache.html:16 +msgid "Total Time" +msgstr "Tempo Total" + +#: templates/debug_toolbar/panels/cache.html:18 +msgid "Hits" +msgstr "Hits" + +#: templates/debug_toolbar/panels/cache.html:20 +msgid "Misses" +msgstr "Misses" + +#: templates/debug_toolbar/panels/cache.html:35 +msgid "Breakdown" +msgstr "Breakdown" + +#: templates/debug_toolbar/panels/cache.html:40 +msgid "Type" +msgstr "Tipo" + +#: templates/debug_toolbar/panels/cache.html:41 +msgid "Parameters" +msgstr "Parâmetros" + +#: templates/debug_toolbar/panels/cache.html:42 +msgid "Function" +msgstr "Função" + +#: templates/debug_toolbar/panels/headers.html:5 +msgid "Key" +msgstr "Chave" + +#: templates/debug_toolbar/panels/headers.html:6 +#: templates/debug_toolbar/panels/request_vars.html:37 +#: templates/debug_toolbar/panels/request_vars.html:63 +#: templates/debug_toolbar/panels/request_vars.html:85 +#: templates/debug_toolbar/panels/request_vars.html:107 +#: templates/debug_toolbar/panels/settings_vars.html:6 +#: templates/debug_toolbar/panels/timer.html:10 +msgid "Value" +msgstr "Valor" + +#: templates/debug_toolbar/panels/logger.html:6 +msgid "Level" +msgstr "Nível" + +#: templates/debug_toolbar/panels/logger.html:8 +msgid "Message" +msgstr "Mensagem" + +#: templates/debug_toolbar/panels/logger.html:24 +msgid "No messages logged" +msgstr "Nenhuma mensagem logada" + +#: templates/debug_toolbar/panels/request_vars.html:3 +msgid "View information" +msgstr "Informações da View" + +#: templates/debug_toolbar/panels/request_vars.html:7 +msgid "View Function" +msgstr "Função View" + +#: templates/debug_toolbar/panels/request_vars.html:8 +msgid "args" +msgstr "args" + +#: templates/debug_toolbar/panels/request_vars.html:9 +msgid "kwargs" +msgstr "kwargs" + +#: templates/debug_toolbar/panels/request_vars.html:27 +msgid "COOKIES Variables" +msgstr "Variáveis do COOKIE" + +#: templates/debug_toolbar/panels/request_vars.html:36 +#: templates/debug_toolbar/panels/request_vars.html:62 +#: templates/debug_toolbar/panels/request_vars.html:84 +#: templates/debug_toolbar/panels/request_vars.html:106 +msgid "Variable" +msgstr "Variável" + +#: templates/debug_toolbar/panels/request_vars.html:50 +msgid "No COOKIE data" +msgstr "Não há dados de COOKIE" + +#: templates/debug_toolbar/panels/request_vars.html:53 +msgid "SESSION Variables" +msgstr "Variáveis de SESSION" + +#: templates/debug_toolbar/panels/request_vars.html:76 +msgid "No SESSION data" +msgstr "Não há dados de SESSION" + +#: templates/debug_toolbar/panels/request_vars.html:79 +msgid "GET Variables" +msgstr "Variáveis de GET" + +#: templates/debug_toolbar/panels/request_vars.html:98 +msgid "No GET data" +msgstr "Não há dados de GET" + +#: templates/debug_toolbar/panels/request_vars.html:101 +msgid "POST Variables" +msgstr "Variáveis de POST" + +#: templates/debug_toolbar/panels/request_vars.html:120 +msgid "No POST data" +msgstr "Não há dados de POST" + +#: templates/debug_toolbar/panels/settings_vars.html:5 +msgid "Setting" +msgstr "Configuração" + +#: templates/debug_toolbar/panels/signals.html:5 +msgid "Signal" +msgstr "Sinais" + +#: templates/debug_toolbar/panels/signals.html:6 +msgid "Providing Args" +msgstr "Argumentos Fornecidos" + +#: templates/debug_toolbar/panels/signals.html:7 +msgid "Receivers" +msgstr "Recebedores" + +#: templates/debug_toolbar/panels/sql.html:6 +msgid "Action" +msgstr "Ação" + +#: templates/debug_toolbar/panels/sql.html:7 +msgid "Stacktrace" +msgstr "Stacktrace" + +#: templates/debug_toolbar/panels/sql.html:8 +msgid "Query" +msgstr "Query" + +#: templates/debug_toolbar/panels/sql.html:38 +msgid "Line" +msgstr "Linha" + +#: templates/debug_toolbar/panels/sql.html:39 +msgid "Method" +msgstr "Método" + +#: templates/debug_toolbar/panels/sql.html:40 +msgid "File" +msgstr "Arquivo" + +#: templates/debug_toolbar/panels/sql_explain.html:3 +#: templates/debug_toolbar/panels/sql_profile.html:3 +#: templates/debug_toolbar/panels/sql_select.html:3 +#: templates/debug_toolbar/panels/template_source.html:3 +msgid "Back" +msgstr "Voltar" + +#: templates/debug_toolbar/panels/sql_explain.html:4 +msgid "SQL Explained" +msgstr "SQL Explicada" + +#: templates/debug_toolbar/panels/sql_explain.html:9 +#: templates/debug_toolbar/panels/sql_profile.html:10 +#: templates/debug_toolbar/panels/sql_select.html:9 +msgid "Executed SQL" +msgstr "SQL Executada" + +#: templates/debug_toolbar/panels/sql_profile.html:4 +msgid "SQL Profiled" +msgstr "Perfil da SQL" + +#: templates/debug_toolbar/panels/sql_profile.html:35 +msgid "Error" +msgstr "Erro" + +#: templates/debug_toolbar/panels/sql_select.html:4 +msgid "SQL Selected" +msgstr "SQL Selecionada" + +#: templates/debug_toolbar/panels/sql_select.html:34 +msgid "Empty set" +msgstr "Conjunto vazio" + +#: templates/debug_toolbar/panels/template_source.html:4 +msgid "Template Source" +msgstr "Origem do Template" + +#: templates/debug_toolbar/panels/templates.html:2 +msgid "Template path" +msgstr "Caminho do Template" + +#: templates/debug_toolbar/panels/templates.html:13 +msgid "Template" +msgstr "Template" + +#: templates/debug_toolbar/panels/templates.html:21 +#: templates/debug_toolbar/panels/templates.html:37 +msgid "Toggle Context" +msgstr "Mostrar/Esconder Contexto" + +#: templates/debug_toolbar/panels/templates.html:28 +#: templates/debug_toolbar/panels/templates.html:43 +msgid "None" +msgstr "Nenhum" + +#: templates/debug_toolbar/panels/templates.html:31 +msgid "Context processor" +msgstr "Processador do Contexto" + +#: templates/debug_toolbar/panels/timer.html:9 +msgid "Resource" +msgstr "Recurso" + +#: templates/debug_toolbar/panels/versions.html:6 +msgid "Package" +msgstr "Pacote" + +#: templates/debug_toolbar/panels/versions.html:7 +msgid "Version" +msgstr "Versão" diff --git a/debug_toolbar/management/commands/debugsqlshell.py b/debug_toolbar/management/commands/debugsqlshell.py index 6bb16de..8878d25 100644 --- a/debug_toolbar/management/commands/debugsqlshell.py +++ b/debug_toolbar/management/commands/debugsqlshell.py @@ -2,8 +2,8 @@ import os  from optparse import make_option  from datetime import datetime -from django.core.management.base import NoArgsCommand  from django.db.backends import util +from django.core.management.commands.shell import Command  from debug_toolbar.utils import sqlparse @@ -21,61 +21,3 @@ class PrintQueryWrapper(util.CursorDebugWrapper):              print  util.CursorDebugWrapper = PrintQueryWrapper - -# The rest is copy/paste from django/core/management/commands/shell.py - -class Command(NoArgsCommand): -    option_list = NoArgsCommand.option_list + ( -        make_option('--plain', action='store_true', dest='plain', -            help='Tells Django to use plain Python, not IPython.'), -    ) -    help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available." - -    requires_model_validation = False - -    def handle_noargs(self, **options): -        # XXX: (Temporary) workaround for ticket #1796: force early loading of all -        # models from installed apps. -        from django.db.models.loading import get_models -        loaded_models = get_models() - -        use_plain = options.get('plain', False) - -        try: -            if use_plain: -                # Don't bother loading IPython, because the user wants plain Python. -                raise ImportError -            import IPython -            # Explicitly pass an empty list as arguments, because otherwise IPython -            # would use sys.argv from this script. -            shell = IPython.Shell.IPShell(argv=[]) -            shell.mainloop() -        except ImportError: -            import code -            # Set up a dictionary to serve as the environment for the shell, so -            # that tab completion works on objects that are imported at runtime. -            # See ticket 5082. -            imported_objects = {} -            try: # Try activating rlcompleter, because it's handy. -                import readline -            except ImportError: -                pass -            else: -                # We don't have to wrap the following import in a 'try', because -                # we already know 'readline' was imported successfully. -                import rlcompleter -                readline.set_completer(rlcompleter.Completer(imported_objects).complete) -                readline.parse_and_bind("tab:complete") - -            # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system -            # conventions and get $PYTHONSTARTUP first then import user. -            if not use_plain: -                pythonrc = os.environ.get("PYTHONSTARTUP") -                if pythonrc and os.path.isfile(pythonrc): -                    try: -                        execfile(pythonrc) -                    except NameError: -                        pass -                # This will import .pythonrc.py as a side-effect -                import user -            code.interact(local=imported_objects) diff --git a/debug_toolbar/media/debug_toolbar/Makefile b/debug_toolbar/media/debug_toolbar/Makefile deleted file mode 100644 index 95f91bb..0000000 --- a/debug_toolbar/media/debug_toolbar/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# Make file to compress and join all JS files -all: compress_js compress_css - -compress_js: -	java -jar ~/bin/yuicompressor.jar js/jquery.js > js/toolbar.min.js -	java -jar ~/bin/yuicompressor.jar js/toolbar.js >> js/toolbar.min.js - -compress_css: -	java -jar ~/bin/yuicompressor.jar --type css css/toolbar.css > css/toolbar.min.css diff --git a/debug_toolbar/media/debug_toolbar/css/toolbar.css b/debug_toolbar/media/debug_toolbar/css/toolbar.css index 820617f..4770ade 100644 --- a/debug_toolbar/media/debug_toolbar/css/toolbar.css +++ b/debug_toolbar/media/debug_toolbar/css/toolbar.css @@ -369,19 +369,17 @@  	position:relative;  } -#djDebug .djDebugCollapse { -    display: inline-block; -    background: #ddd; -    background: url(data:image/gif;base64,R0lGODlhBgAKAJEDAJGRkdra2qysrP///yH5BAEAAAMALAAAAAAGAAoAAAIPnI+JIRImABBQ0sGc2qoAADs=) 0 3px repeat-x; -    width: 18px; -    text-indent: -10000em; +#djDebug .djDebugCollapsed { +    display: none; +    text-decoration: none; +    color: #333;  } -#djDebug .djSelected .djDebugCollapse { -    background: inherit; -    text-indent: 0; -    width: auto; -    display: inline; + +#djDebug .djDebugUncollapsed { +    color: #333; +    text-decoration: none;  } +  #djDebug .djUnselected {      display: none;  } @@ -547,8 +545,13 @@  #djDebug .djSQLDetailsDiv {      margin-top:0.8em;  } -#djDebug .djSQLDetailsDiv pre { -    color: #777; +#djDebug pre { +	white-space: pre-wrap;       /* CSS-3                  */ +	white-space: -moz-pre-wrap;  /* Mozilla, since 1999    */ +	white-space: -pre-wrap;      /* Opera 4-6              */ +	white-space: -o-pre-wrap;    /* Opera 7                */ +	word-wrap: break-word;       /* Internet Explorer 5.5+ */ +    color: #555;      border:1px solid #ccc;      border-collapse:collapse;      background-color:#fff; diff --git a/debug_toolbar/media/debug_toolbar/css/toolbar.min.css b/debug_toolbar/media/debug_toolbar/css/toolbar.min.css index 5088442..aa30728 100644 --- a/debug_toolbar/media/debug_toolbar/css/toolbar.min.css +++ b/debug_toolbar/media/debug_toolbar/css/toolbar.min.css @@ -1 +1 @@ -.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.clearfix{display:inline-block;}/* Hides from IE-mac \*/ .clearfix{display:block;}* html .clearfix{height:1%;}/* end hide from IE-mac */ #djDebug{color:#000;background:#FFF;}#djDebug,#djDebug div,#djDebug span,#djDebug applet,#djDebug object,#djDebug iframe,#djDebug h1,#djDebug h2,#djDebug h3,#djDebug h4,#djDebug h5,#djDebug h6,#djDebug p,#djDebug blockquote,#djDebug pre,#djDebug a,#djDebug abbr,#djDebug acronym,#djDebug address,#djDebug big,#djDebug cite,#djDebug code,#djDebug del,#djDebug dfn,#djDebug em,#djDebug font,#djDebug img,#djDebug ins,#djDebug kbd,#djDebug q,#djDebug s,#djDebug samp,#djDebug small,#djDebug strike,#djDebug strong,#djDebug sub,#djDebug sup,#djDebug tt,#djDebug var,#djDebug b,#djDebug u,#djDebug i,#djDebug center,#djDebug dl,#djDebug dt,#djDebug dd,#djDebug ol,#djDebug ul,#djDebug li,#djDebug fieldset,#djDebug form,#djDebug label,#djDebug legend,#djDebug table,#djDebug caption,#djDebug tbody,#djDebug tfoot,#djDebug thead,#djDebug tr,#djDebug th,#djDebug td{margin:0;padding:0;border:0;outline:0;font-size:12px;line-height:1.5em;color:#000;vertical-align:baseline;background:transparent;font-family:sans-serif;text-align:left;}#djDebug #djDebugToolbar{background:#111;width:200px;z-index:100000000;position:fixed;top:0;bottom:0;right:0;opacity:.9;}#djDebug #djDebugToolbar small{color:#999;}#djDebug #djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebug #djDebugToolbar li{border-bottom:1px solid #222;color:#fff;display:block;font-weight:bold;float:none;margin:0;padding:0;position:relative;width:auto;}#djDebug #djDebugToolbar li>a,#djDebug #djDebugToolbar li>div.contentless{font-weight:normal;font-style:normal;text-decoration:none;display:block;font-size:16px;padding:10px 10px 5px 25px;color:#fff;}#djDebug #djDebugToolbar li a:hover{color:#111;background-color:#ffc;}#djDebug #djDebugToolbar li.active{background-image:url(../img/indicator.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgFJREFUeNqUlE1LAmEQx11fesNeDLt08hZ4KcgvIF7EgxcR9CT4IQwErx47WhFBdvPgwUNQeOiogiLRQSQUQaKD6Vpba7ar20izMe4+bjTwY5/Zl//OMzPPcCaTaRUwAxbTjynAdAHq84XGARuADQXN+MGEIJG1QmCaOZVK7WKUdmCdYMf7K/hDKwagwjRLPp9/cLvdzUKh8Ab+GgosExGz5hvFSJAbDAYKmFSpVM4DgUABX57l6wsYAR/AO64/MQUyyauiE1SdTqdTC4fDZ61W6x0FRUAAXvEqElGJCP5qzG3H5XIdFovFdCgUOgB3B3AC28AmyekSKSDH3LL2piRJcjabvU4kEnfg8sAL0Me1GulYE+ViQdWq1ep9NBrN9vv9J3B7KPyKOf3EtNAe1VVwzjwez36pVDoKBoMu3KpNs13dlg0FZ+ZwOJx+v3+PHATO6H2r0UOe54fJZPIil8vVSLtMjE7LQsFGo/EYiUSuut3uM/aimjPJSFQnCE0+hVNzE4/Hb1FoyOjBCasHdYKiKPLpdPo0k8k0GY1NKyvTyjIFe71eLRaLHZfLZYFx9AS8jhgR6gXb7faJ1+u9FATBglWU8cMxRjki0RmOMmu9Xo/4fL4y9pmVzEMZBcakGPJfw3YWzRY2rA19dWLLBMNCaAXXNHNPIVFO/zOtZ/YtwADKQgq0l7HbRAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:left center;background-color:#333;padding-left:10px;}#djDebug #djDebugToolbar li.active a:hover{color:#b36a60;background-color:transparent;}#djDebug #djDebugToolbar li small{font-size:12px;color:#999;font-style:normal;text-decoration:none;font-variant:small-caps;}#djDebug #djDebugToolbarHandle{position:fixed;background:#fff;border:1px solid #111;top:30px;right:0;z-index:100000000;opacity:.75;}#djDebug a#djShowToolBarButton{display:block;height:75px;width:30px;border-right:none;border-bottom:4px solid #fff;border-top:4px solid #fff;border-left:4px solid #fff;color:#fff;font-size:10px;font-weight:bold;text-decoration:none;text-align:center;text-indent:-999999px;background:#000 url(../img/djdt_vertical.png) no-repeat left center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAABLCAYAAAACnsWZAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAATCSURBVGiB7ZlvSBtnHMe/sckZY5aMw06r7aTLjGOwTKOMEWYs7M2EaaUdjG6+GDoQ9mIyupUxGIONwVZfDHwxg2E4igym24s5sFB0oDRq1yi1G0RijTjhjJBI86fR/LvbC+nFs7ncXR7jMsgXDp67e57vffI8v/s9z3NRAeBQxCr7rwGkVAIkVQmQVCVAUpUASVX0gGqxGxaLBTabDVqtFn6/H5OTk4jFYifJxovLdgwNDXGH1dDQkLVeoY+iH+KiBxSNwaOy2+0wmUyKzH0+H7xer2Koo5IVg/loZGSkuGOwtraW2KOggHt7e8QesmMwEomAZVlF5uvr64qBjko2YEtLC9bW1ogfqFRFn2b+v4CpVIovsyyrOP6OSyrksS8uKysDTdNQq9XY3d1FIpEoAFpGshJma2sr53A4OI/Hw7EsK0jIDMNw4+PjXFdXVyEWDLkr6PV6bmJiQvbs4XK5uJqampMBpCiKW1hYUDzF+Xw+zmAwFB5wcHBQMdxjDQ8PHwug6EtC0zS2trag0+kE16enp7G4uAiv14tUKgWz2Qyr1YrOzk6oVCq+XjweR11dHYLBYDZ7RcpK3tvbK+iRcDjMdXR0iP5Sm83GMQwjaNPX11e4IR4dHRU8bGBgQNKsp6dH0MbpdBYO0OVyCR5mNBolzTQaDZdOp/k2c3NzxICiMwlN03x5e3sboVBIrCqvZDIJhmH4c6PRKNlGSqKrGYqi+HJFRQX6+/tlGWq12qxlEmXt2pWVlbxTzGMtLS0VbogjkQjxLw+Hw8QeooA7OzvE5n6/n9hDNAbdbrfibeZRLS8vE7UH8lxunaSKfkUte9MEAAa6EhrqVNZ7HAc8DETBpo935a1oiJ1zH6O5rUH0fmI/iQ2PH1Nji/jpuxlwHHn0KOpBKVFaDRqbz6Gx+RysdjOudn9P7FmwGGy/+DLa3rQQ++QNmEykEA3t8UcsGn+izhvvvEIEBxAM8c2xO/iy74bgWu35KjhmPkLt+SoAwFnTaTI6HPMQMxsBLM1mvgdqdVSO2vKkqAdvXL+FuzOrYFkOd/9YzVqHfsbAlze95NNlnht3FQx0JU6pyxDejSGZyHyFOGs6DWu7GVVnjLh3+wGWZ8m+sMoGfLG1Ht3vvwZruxn1jdWCDVJgO4R7tx9gauwO5iZXiIAUA+r05fhi9D28/pZVluH9+XV8ctmBoJ98qQVIAGooNUZmr+KlV59TZMpsBHCl6Ss8Cu+T8uV+iz/4+qJiOOAg3Xz47eW8oQ5LtAcNdCWmtr55IlX8Oe3BX4sb2PTuIJ1Ko95cjResz6Kt0yKIy0Q8hY66awgFHxEBiqaZC91NArhYZB+fvu3E/M2/s9a32Ey4/ks/qs4c7OSocjUudDfhtx9cRICiQ9zc9rzgfPjzSVE44ODlGLr2q+BaPuFxVKKA9eZqwfnvP85Lmt362Q2WzURMfWN1jtryJApooCv5cmA7hGhI+j+PVDKNAPOQP9cbKwjxcsSghsrcKq/Q4FK/XZYhpdVk2h0q5ytRwFg0k8OeelqHzxzvKjbPtgRTKtEhjkXIzQuaqIM75FNV0C/9wUlKokPscW8SLzhXl/8hag+UNu7kKgGSqgRIqhIgqUqApCp6wH8B9cAOKo9Os8wAAAAASUVORK5CYII=);opacity:.5;}#djDebug a#djShowToolBarButton:hover{background-color:#111;padding-right:6px;border-top-color:#FFE761;border-left-color:#FFE761;border-bottom-color:#FFE761;opacity:1.0;}#djDebug code{display:block;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;white-space:pre;overflow:auto;}#djDebug tr.djDebugOdd{background-color:#f5f5f5;}#djDebug .panelContent{display:none;position:fixed;margin:0;top:0;right:200px;bottom:0;left:0;background-color:#eee;color:#666;z-index:100000000;}#djDebug .panelContent>div{border-bottom:1px solid #ddd;}#djDebug .djDebugPanelTitle{position:absolute;background-color:#ffc;color:#666;padding-left:20px;top:0;right:0;left:0;height:50px;}#djDebug .djDebugPanelTitle code{display:inline;font-size:inherit;}#djDebug .djDebugPanelContent{position:absolute;top:50px;right:0;bottom:0;left:0;height:auto;padding:5px 0 0 20px;}#djDebug .djDebugPanelContent .scroll{height:100%;overflow:auto;display:block;padding:0 10px 0 0;}#djDebug h3{font-size:24px;font-weight:normal;line-height:50px;}#djDebug h4{font-size:20px;font-weight:bold;margin-top:.8em;}#djDebug .panelContent table{border:1px solid #ccc;border-collapse:collapse;width:100%;background-color:#fff;display:block;margin-top:.8em;overflow:auto;}#djDebug .panelContent tbody td,#djDebug .panelContent tbody th{vertical-align:top;padding:2px 3px;}#djDebug .panelContent thead th{padding:1px 6px 1px 3px;text-align:left;font-weight:bold;font-size:14px;}#djDebug .panelContent tbody th{width:12em;text-align:right;color:#666;padding-right:.5em;}#djDebug .djTemplateHideContextDiv{background-color:#fff;}#djDebug .panelContent .djDebugClose{text-indent:-9999999px;display:block;position:absolute;top:4px;right:15px;height:40px;width:40px;background:url(../img/close.png) no-repeat center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA7dJREFUeNqsWM1PE0EU3+7ShdJKoTRA8UYgIUKM3rmaEI0euXsw0YMHIZEbxBijEiIHLkb/A44SDYlXzkYPGBM+ri1NWz7aUmhp6+9tps10mLfdfrzkl2535r39zc77mvUdHh4abUoUCAD3xP/fQAFItWJkYmLC+e1p8eGPgQcC08ycf8BPgW2vhr0SeQa8AWIe5k4LvATiwCrwtZmS2WT8IfAL+OKRhCoxoftH2GqLyBLwHbhvdC53ha2lVrfmE/DKzbLP5yubplnt7e310f+rq6tqpVLxVatVy0VtHbgNLHohsupGIhQKFQG7v79f+8CLiwsjl8sVAZsxQbYTwFrDwpTwpaj4ptPu6+vLDw4OBkHA014QobOzs3yhUAgyUx4BP2rhq/rIe53GwMBAeXx83DMJEpobi8WCpMtMWeOc9TkwoyMRjUattrMedBkyM+KZN4isqDMDgUCuExIyGbKlGVpRiSzo8kQ4HA4ZXRLGVuzo6GhBJjKviw6dT5TLZSOTyRinp6cGQrV+n67hnEY6nTaur6+1PkM2NWTm5fCd0xDRhh89CKHpXCMijLGxMef6+PjYiRSSUqlUv6/arOlKMlcjQlV0qsGDTZPehpYIxurXRCSRSFByq5NQ56hvhWwj8cm2p7A9UdKYVBX8fn+F2+tIJGIgmzaQkUnYtm0MDw+zvsLYniQiEc2q/WxxwmqRHxrISA9xxiyLDzTGdsRsJwJoK3QPo3vctnhpAzLqTexhiVOg6JAdU5bLy0vHZ+Ro8mg7Q0QO1LvwenZZJycnN3yCIPsMRRYnjO0DU/SY+wprW7fiWmjKJMgnUIcafEaeoxZCJWJI9lH4UjV2u6pSPp/XJR9jaGiIKrERDAbrjllzYOQJZ4zm6ISxuSsntB3gqTyazWZtMowa0aBFb4HegC6aRkZG2C2hLSObmqEdOcVvUdJUZyBlZ7tVa1ASdEUvjW3ZUqvvO82e3kqlUuVOSZANvBFd0fugawM2VKclOT8/tzohQ7pkgzn/rHNdvLbLJkPxeDzHRRIXIaTDkCB57XacoJPZW8bZQpSskslk0Y0QjdEcmstsB8myegrsYbqmENfJU3dOpZyOEwjdCqLIWUyxWKygVzHFccJ2eVkbar/qdq5ZFC3/R5dUb6EBsqQmyEtLuawj0eykRwpPgL0uRO+esLXW7tmX9nEWeAEk2yCQFLqzzb4MeK3Zn4FRsapNEXqGy2eJTTF3VOh27bOE/Ia2pQ81YeCO+P+XknGrH2pq8l+AAQDv/n2Gmq99BgAAAABJRU5ErkJggg==);}#djDebug .panelContent .djDebugClose:hover{background-image:url(../img/close_hover.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABCVJREFUeNqsWG1IU1EYfjfd0i1bTc2WFTW3tG2aFWlEf4KkMIrCvhH6U9DnjxTyV0ZEXxIVGBH1JyKIPiBK8kf1syCKwu8M3VQsK7OV6ba2udZ7bmd6d+85827zhYftnnPe5z73nvc95z1X5XQ6IUHLQqQjiul1E8KHGIqHxGw2C7+pcd58E6KMooAzphPxnKJBKbFSIfsRpxAmBWMLKI4iviBOIm5O5qSepL8c8R5xQ6EIqZmobzPlSkhINeIpYhkkb0WUqzreqbmEOBaTOjQGf/0+CHz7Klxqc+aAehrGbkrM2b6IyEVUKRFyMpYI38dW8HS0gc/5kdmfnpcPepsD0vMLeRSEm6ivEzeqJOlLsuIJyzs40Au/Xr+CP64uRXORZraCoXQ1aHMX8YZsRDRG0lcqpA1hl3p4mt+C+/nThILDWLYR9EtXsrraEY6IEHGwHmCJGG16k7AIYsTX0/KO1WWn95QJqZWODHxyws8XjUmnjPtZg8DFsFqpkB2sdWL4zWuYKuNwmVwu1w6xkA2s7GAFpnaGAcxbd8H8snJQa7QTUZ+aCrlr10NexR5Iy8yW+REuwsmwDeL0XSOLjfYW5pNZtldC9orS/4FoK4LWa5cgHP4L9n1HILNoudCuM82F1qsXgcXJSOs1ESFkF7WKe8JBfxifQMVMY8/o+P+Z+TYoPFwNoYAfMh3FE2udz8d8CPJWCLdKM03MbcXpySJTY5EtmsNuFW+uex4/gJFe14SYxUuiRHi/fIaue7f5CzKb20KEGKWtYx4Pl2jM54WW+joY6euR9Xm/DkDT5bMQHB3h+7O5jepEMiAUDDBvRtpCfn9CWUWEuGUbkF7PdSDZQQLTaC+S9Rks+VB4qCoqmxRyu4mQbmlrisEY5hEtLN8ynh2RmBjt74sK4LyK3VwhHO5uNa0xoxYMEtVk02KZbk7uxB400C/ERPOVc1EBrMsxcTdCScYQ68L9ZiiyjryUprC+wM5c0PoaH4EmIwMCv4eh6+6t8VghAWzdtVdYzHoaHjKFEE6GvRTvvmSZvScd8f3hHfjT2z0lS3zaQgtkb6tkde3EN3I/kjX3ET9kwVdSOmV7jaF0Fav5BxEh3X3PyPaVBVaYta48aRGkJtHOt7C6zrPKgMvSoCU2vbhEIEpGBKcw6qQ1LLNmrWaVioRIk2kUtvK4SsWSVaCdl8cbcjxW8UxOZqcRJ2TThITZCO+HZvB2dsQsnnUFNtAtWRpLZ430FKjinH0VHSdCXg8EhwaFS03WbEjR6Sc7TkRCoErp2beKlvwX+EtkKqRkGATEYTXSY4SSkx5x2Eyr7WStnXLVJXr2JfPoQBxEDCYgYJD6Oib7MqC0DLiOyKFPVU9TD2J8lqinY3Oo75R9lhC/oQbRhxoSIDZ63UGK9Xg/1ETsnwADAJrrTk7nZiozAAAAAElFTkSuQmCC);}#djDebug .panelContent .djDebugClose.djDebugBack{background-image:url(../img/back.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA7FJREFUeNrMWM1PE0EU3+7S7bZdKSFNSIFgJJAgINE7VxOi0SP/gYkePAiJ3CDGGJUQOXAx+h9wlGhIvHI2fgQ08mEkkjZNIZR2+7Httr63zMoyOzPdthx8yS+bnZn3m9/OvDcfG9jd3ZVatDggDLhO3j8DioBMMySDg4P2s6PJzu8AbhKMcNr8AHwkWPNL7FfIPcATQMJH2xGCh4AkYAHwtpGT3KD+FuAT4I1PEbQliO8XwtWSkFnAe8ANqX2bIFyzzU7NK8AjEXMgELBkWa6HQqEAvpfL5XqtVgvU63VF4LYE6APM+BGyIBKh67oJUCORCLPDQqEg5fN5E6ByKJA7BVg892FU+mJWvGN5a5pmdHV1RUGAr7lAQdls1igWi1FOk9uAD0760jHynOXR2dlp9fb2+haBhm0TiUQUfTlNFnnBeh8wxhIRj8eVllc98OWIGSN9eoTM0y3D4XC+HRFuMcjFqJqnhUyz1olYLKa730uVCrMjXrmIy1ln9vb2pt1CpljZQcdE1ihIW/sHHrayWbHLq1ZNGDPIyaiacguZZAhhph+K+fpr39Ppqcg/wtHhcE46QnAXHT4XwbJssjJECwbtp1EqS99AjNNpSD0r//77wH7yRgW5qeJhmJ44ChmiHYLBIHOMY9GINDrQ9y8uHDEoEMs7FNl+x5HhieFwD6GQbs8GJMtBbtCBmIkrA3anOD0YH2ci+21RWJ4vldibG5u7W5b+E8O95oguhM0LP1PhBauTOfj1Tnxg+c+DpD0aOFq6pjE75HAfoZAdunGlUpH9iLh6uc9+nsaFt5xlHO4dmZwxtynVKm5avIUrqoWkaxAnTmdOnGC5SARyIjdVvA0bX8ZRt0E7GYZhNgpWb0b1c0UIODfcC9o6XZvL5VTYwrnp6zaMEyd9eYZcyMmoWncLWQUcemIim82xFjTeQiey4+Nj1qZ3CNOySu++zxhzeimTyVjtpiZywIiwNr0XrGPAMh20aCcnJ0o7YtAXOTj3nyXeKZ55ykaiZDKZZ2WS6KiIPhwRaI9F1wm8mT3lBJueSqWkdDptigRhHbbBtpzpQJujb4EdnFOTzjvJ4+kcYF8nFEWpqapqf4xpmjXLsmRynVAFg7VMn1dF95oZcuR/yWPDDqvVKsIp8nOknGOJaHTTQ4e7gM0L2NM2Cddiq3dfnMdxwANAugUBaeI73ujPgN9jwGtAD/mqFZJ6kuC3xApp20N8L+y3hHuE1lw/amKAUfK+hYtxsz9qHPsrwACHs5P9Qys/0AAAAABJRU5ErkJggg==);}#djDebug .panelContent .djDebugClose.djDebugBack:hover{background-image:url(../img/back_hover.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA6hJREFUeNrMWF1Ik1EYPtt0pkuGa/aDJTY3nNvSfkglvEwQpa7CbrosKAghBedNikKgEgVe1m03SVeJXmSXBmIozpxpuiUS/eicSc75m73vx/nGt7Nzvm8/BR14+Pjec85znp297znv++kCgQBJs1kBuYDz9H0KEAWEUiGx2WzSMyvFxa8B6iicgjFzgBGKwWSJdUnuyB1AF+BUisK/AToBz7V2RK9B1ACYBDxLQwShc3Cuj3IJm5qQVsAQ4ALJvFVQrlbRAJGPPAE8UKU+2Ce/d6Jk98d36dV44iTR54DvGlTd7jGgCNCSjJBONRHR+Q8kMjtDooF5bn9uaRkxuTwkt+yciAK5UX2fmrNiVLzmzd77ukR+jr0j28GFpP6LIzYHMVdfIcais6IhjYBh2VlZITMANzsj4ntPwiNDaTmHpa6RmCov87r8AA8vau7yRGxOjactAhvOjUxP8LrcdM0EIR3syN0vAbL+djjjkAm/GZS4OK2DFdLEOyc2xsfi/3frcb4/COxqXPI5EwwGm5RC6nnRwTpmgdNNKpq9iZFiLZTsWXkmoRDkQk5Oq1cKqU3wDf80lxDFXGzvTlhUFqm2OwLOWlkI3qIOZc/h3s4hL0y3QyvSM7+4hFxq74otGg2txuyVzW3SU7QryM2YHfD3WFGIPeHQ3AjreETrc34y3d8b8wtZDApE+/5WRHrHnRGJEXDbUYiFte5HIsLtRTGTPR3Sovj3oH8oRaIotB8t5h9kAm6LnvwnDe+acILRJPZ+ZeTgr5f9A+2u2/el3cDd2lz+zF+Qzx1GIYus1WC2oEPptET4+vukp+wXrJ3XBNyLeppjxoWILjtHh5eW6OD6tbxEJno6Y4vJfoJ2NRHIidyMeQHum5DsI6PsJJPTremsvIgSiVDhHFXevnjMvmRHrL56QbaXFuN2hLeQyB43psROCm/c4nXdhB0ZkHdkALDGjjBXVXMPNNFBp9bM1TU88xqKYG/fR+woY7GDFFxtyDg0MScxnrHzunpEGdon9rj/h4kR1j/logKrlZcqIlH2MYt0laeUKlbVEOPpUtGQNq0CqxvwUDR766OPbM3NqibPeU4XySuvVNPplZNnUc6aUjlxACG8Rx01GyLHgKmBQbOKfaosJ7Rq3xaa8vcK6WBBQ75ZQgrNy5YRyVR6OOE6zbYzbX7K1ZdOyUloNe8B3AOspCFghc71aH0Z0KX4feSvf5bQctZkP9Sgg7jo+ywm6+l+qPkjwADNS26fFM/O1QAAAABJRU5ErkJggg==);}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dt{margin-top:.75em;}#djDebug .panelContent dd{margin-left:10px;}#djDebug a.toggleTemplate{padding:4px;background-color:#bbb;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.toggleTemplate:hover{padding:4px;background-color:#444;color:#ffe761;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.djTemplateShowContext,#djDebug a.djTemplateShowContext span.toggleArrow{color:#999;}#djDebug a.djTemplateShowContext:hover,#djDebug a.djTemplateShowContext:hover span.toggleArrow{color:#000;cursor:pointer;}#djDebug .djDebugSqlWrap{position:relative;}#djDebug .djDebugCollapse{display:inline-block;background:#ddd;background:url(data:image/gif;base64,R0lGODlhBgAKAJEDAJGRkdra2qysrP///yH5BAEAAAMALAAAAAAGAAoAAAIPnI+JIRImABBQ0sGc2qoAADs=) 0 3px repeat-x;width:18px;text-indent:-10000em;}#djDebug .djSelected .djDebugCollapse{background:inherit;text-indent:0;width:auto;display:inline;}#djDebug .djUnselected{display:none;}#djDebug tr.djHiddenByDefault{display:none;}#djDebug tr.djSelected{display:table-row;}#djDebug .djDebugSql{z-index:100000002;}#djDebug .djSQLDetailsDiv tbody th{text-align:left;}#djDebug .djSqlExplain td{white-space:pre;}#djDebug span.djDebugLineChart{background-color:#777;height:3px;position:absolute;bottom:0;top:0;left:0;display:block;z-index:1000000001;}#djDebug span.djDebugLineChartWarning{background-color:#900;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#000;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#000;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#000;font-weight:bold;}#djDebug .highlight .s{color:#333;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#000;font-weight:bold;}#djDebug .highlight .na{color:#333;}#djDebug .highlight .nt{color:#000;font-weight:bold;}#djDebug .highlight .nv{color:#333;}#djDebug .highlight .s2{color:#333;}#djDebug .highlight .cp{color:#333;}#djDebug .timeline{width:30%;}#djDebug .djDebugTimeline{position:relative;height:100%;min-height:100%;}#djDebug div.djDebugLineChart{position:absolute;left:0;right:0;top:0;bottom:0;vertical-align:middle;}#djDebug div.djDebugLineChart strong{text-indent:-10000em;display:block;font-weight:normal;vertical-align:middle;background-color:#ccc;}#djDebug div.djDebugLineChartWarning strong{background-color:#900;}#djDebug .djDebugInTransaction div.djDebugLineChart strong{background-color:#d3ff82;}#djDebug .djDebugStartTransaction div.djDebugLineChart strong{border-left:1px solid #94b24d;}#djDebug .djDebugEndTransaction div.djDebugLineChart strong{border-right:1px solid #94b24d;}#djDebug .djDebugHover div.djDebugLineChart strong{background-color:#000;}#djDebug .djDebugInTransaction.djDebugHover div.djDebugLineChart strong{background-color:#94b24d;}#djDebug .panelContent ul.stats{position:relative;}#djDebug .panelContent ul.stats li{width:30%;float:left;}#djDebug .panelContent ul.stats li strong.label{display:block;}#djDebug .panelContent ul.stats li span.color{height:12px;width:3px;display:inline-block;}#djDebug .panelContent ul.stats li span.info{display:block;padding-left:5px;}#djDebug .panelcontent thead th{white-space:nowrap;}#djDebug .djDebugRowWarning .time{color:red;}#djdebug .panelcontent table .toggle{width:14px;padding-top:3px;}#djdebug .panelcontent table .actions{min-width:70px;}#djdebug .panelcontent table .color{width:3px;}#djdebug .panelcontent table .color span{width:3px;height:12px;overflow:hidden;padding:0;}#djDebug .djToggleSwitch{text-decoration:none;border:1px solid #999;height:12px;width:12px;line-height:12px;text-align:center;color:#777;display:inline-block;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF',endColorstr='#DCDCDC');background:-webkit-gradient(linear,left top,left bottom,from(#FFF),to(#DCDCDC));background:-moz-linear-gradient(center top,#FFF 0,#DCDCDC 100%) repeat scroll 0 0 transparent;}#djDebug .djNoToggleSwitch{height:14px;width:14px;display:inline-block;}#djDebug .djSQLDetailsDiv{margin-top:.8em;}#djDebug .djSQLDetailsDiv pre{color:#777;border:1px solid #ccc;border-collapse:collapse;background-color:#fff;display:block;overflow:auto;padding:2px 3px;margin-bottom:3px;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;}#djDebug .stack span{color:#000;font-weight:bold;}#djDebug .stack span.path{color:#777;font-weight:normal;}#djDebug .stack span.code{font-weight:normal;}@media print{#djDebug{display:none;}}
\ No newline at end of file +.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.clearfix{display:inline-block;}/* Hides from IE-mac \*/ .clearfix{display:block;}* html .clearfix{height:1%;}/* end hide from IE-mac */ #djDebug{color:#000;background:#FFF;}#djDebug,#djDebug div,#djDebug span,#djDebug applet,#djDebug object,#djDebug iframe,#djDebug h1,#djDebug h2,#djDebug h3,#djDebug h4,#djDebug h5,#djDebug h6,#djDebug p,#djDebug blockquote,#djDebug pre,#djDebug a,#djDebug abbr,#djDebug acronym,#djDebug address,#djDebug big,#djDebug cite,#djDebug code,#djDebug del,#djDebug dfn,#djDebug em,#djDebug font,#djDebug img,#djDebug ins,#djDebug kbd,#djDebug q,#djDebug s,#djDebug samp,#djDebug small,#djDebug strike,#djDebug strong,#djDebug sub,#djDebug sup,#djDebug tt,#djDebug var,#djDebug b,#djDebug u,#djDebug i,#djDebug center,#djDebug dl,#djDebug dt,#djDebug dd,#djDebug ol,#djDebug ul,#djDebug li,#djDebug fieldset,#djDebug form,#djDebug label,#djDebug legend,#djDebug table,#djDebug caption,#djDebug tbody,#djDebug tfoot,#djDebug thead,#djDebug tr,#djDebug th,#djDebug td{margin:0;padding:0;border:0;outline:0;font-size:12px;line-height:1.5em;color:#000;vertical-align:baseline;background:transparent;font-family:sans-serif;text-align:left;}#djDebug #djDebugToolbar{background:#111;width:200px;z-index:100000000;position:fixed;top:0;bottom:0;right:0;opacity:.9;}#djDebug #djDebugToolbar small{color:#999;}#djDebug #djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebug #djDebugToolbar li{border-bottom:1px solid #222;color:#fff;display:block;font-weight:bold;float:none;margin:0;padding:0;position:relative;width:auto;}#djDebug #djDebugToolbar li>a,#djDebug #djDebugToolbar li>div.contentless{font-weight:normal;font-style:normal;text-decoration:none;display:block;font-size:16px;padding:10px 10px 5px 25px;color:#fff;}#djDebug #djDebugToolbar li a:hover{color:#111;background-color:#ffc;}#djDebug #djDebugToolbar li.active{background-image:url(../img/indicator.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgFJREFUeNqUlE1LAmEQx11fesNeDLt08hZ4KcgvIF7EgxcR9CT4IQwErx47WhFBdvPgwUNQeOiogiLRQSQUQaKD6Vpba7ar20izMe4+bjTwY5/Zl//OMzPPcCaTaRUwAxbTjynAdAHq84XGARuADQXN+MGEIJG1QmCaOZVK7WKUdmCdYMf7K/hDKwagwjRLPp9/cLvdzUKh8Ab+GgosExGz5hvFSJAbDAYKmFSpVM4DgUABX57l6wsYAR/AO64/MQUyyauiE1SdTqdTC4fDZ61W6x0FRUAAXvEqElGJCP5qzG3H5XIdFovFdCgUOgB3B3AC28AmyekSKSDH3LL2piRJcjabvU4kEnfg8sAL0Me1GulYE+ViQdWq1ep9NBrN9vv9J3B7KPyKOf3EtNAe1VVwzjwez36pVDoKBoMu3KpNs13dlg0FZ+ZwOJx+v3+PHATO6H2r0UOe54fJZPIil8vVSLtMjE7LQsFGo/EYiUSuut3uM/aimjPJSFQnCE0+hVNzE4/Hb1FoyOjBCasHdYKiKPLpdPo0k8k0GY1NKyvTyjIFe71eLRaLHZfLZYFx9AS8jhgR6gXb7faJ1+u9FATBglWU8cMxRjki0RmOMmu9Xo/4fL4y9pmVzEMZBcakGPJfw3YWzRY2rA19dWLLBMNCaAXXNHNPIVFO/zOtZ/YtwADKQgq0l7HbRAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:left center;background-color:#333;padding-left:10px;}#djDebug #djDebugToolbar li.active a:hover{color:#b36a60;background-color:transparent;}#djDebug #djDebugToolbar li small{font-size:12px;color:#999;font-style:normal;text-decoration:none;font-variant:small-caps;}#djDebug #djDebugToolbarHandle{position:fixed;background:#fff;border:1px solid #111;top:30px;right:0;z-index:100000000;opacity:.75;}#djDebug a#djShowToolBarButton{display:block;height:75px;width:30px;border-right:none;border-bottom:4px solid #fff;border-top:4px solid #fff;border-left:4px solid #fff;color:#fff;font-size:10px;font-weight:bold;text-decoration:none;text-align:center;text-indent:-999999px;background:#000 url(../img/djdt_vertical.png) no-repeat left center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAABLCAYAAAACnsWZAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAATCSURBVGiB7ZlvSBtnHMe/sckZY5aMw06r7aTLjGOwTKOMEWYs7M2EaaUdjG6+GDoQ9mIyupUxGIONwVZfDHwxg2E4igym24s5sFB0oDRq1yi1G0RijTjhjJBI86fR/LvbC+nFs7ncXR7jMsgXDp67e57vffI8v/s9z3NRAeBQxCr7rwGkVAIkVQmQVCVAUpUASVX0gGqxGxaLBTabDVqtFn6/H5OTk4jFYifJxovLdgwNDXGH1dDQkLVeoY+iH+KiBxSNwaOy2+0wmUyKzH0+H7xer2Koo5IVg/loZGSkuGOwtraW2KOggHt7e8QesmMwEomAZVlF5uvr64qBjko2YEtLC9bW1ogfqFRFn2b+v4CpVIovsyyrOP6OSyrksS8uKysDTdNQq9XY3d1FIpEoAFpGshJma2sr53A4OI/Hw7EsK0jIDMNw4+PjXFdXVyEWDLkr6PV6bmJiQvbs4XK5uJqampMBpCiKW1hYUDzF+Xw+zmAwFB5wcHBQMdxjDQ8PHwug6EtC0zS2trag0+kE16enp7G4uAiv14tUKgWz2Qyr1YrOzk6oVCq+XjweR11dHYLBYDZ7RcpK3tvbK+iRcDjMdXR0iP5Sm83GMQwjaNPX11e4IR4dHRU8bGBgQNKsp6dH0MbpdBYO0OVyCR5mNBolzTQaDZdOp/k2c3NzxICiMwlN03x5e3sboVBIrCqvZDIJhmH4c6PRKNlGSqKrGYqi+HJFRQX6+/tlGWq12qxlEmXt2pWVlbxTzGMtLS0VbogjkQjxLw+Hw8QeooA7OzvE5n6/n9hDNAbdbrfibeZRLS8vE7UH8lxunaSKfkUte9MEAAa6EhrqVNZ7HAc8DETBpo935a1oiJ1zH6O5rUH0fmI/iQ2PH1Nji/jpuxlwHHn0KOpBKVFaDRqbz6Gx+RysdjOudn9P7FmwGGy/+DLa3rQQ++QNmEykEA3t8UcsGn+izhvvvEIEBxAM8c2xO/iy74bgWu35KjhmPkLt+SoAwFnTaTI6HPMQMxsBLM1mvgdqdVSO2vKkqAdvXL+FuzOrYFkOd/9YzVqHfsbAlze95NNlnht3FQx0JU6pyxDejSGZyHyFOGs6DWu7GVVnjLh3+wGWZ8m+sMoGfLG1Ht3vvwZruxn1jdWCDVJgO4R7tx9gauwO5iZXiIAUA+r05fhi9D28/pZVluH9+XV8ctmBoJ98qQVIAGooNUZmr+KlV59TZMpsBHCl6Ss8Cu+T8uV+iz/4+qJiOOAg3Xz47eW8oQ5LtAcNdCWmtr55IlX8Oe3BX4sb2PTuIJ1Ko95cjResz6Kt0yKIy0Q8hY66awgFHxEBiqaZC91NArhYZB+fvu3E/M2/s9a32Ey4/ks/qs4c7OSocjUudDfhtx9cRICiQ9zc9rzgfPjzSVE44ODlGLr2q+BaPuFxVKKA9eZqwfnvP85Lmt362Q2WzURMfWN1jtryJApooCv5cmA7hGhI+j+PVDKNAPOQP9cbKwjxcsSghsrcKq/Q4FK/XZYhpdVk2h0q5ytRwFg0k8OeelqHzxzvKjbPtgRTKtEhjkXIzQuaqIM75FNV0C/9wUlKokPscW8SLzhXl/8hag+UNu7kKgGSqgRIqhIgqUqApCp6wH8B9cAOKo9Os8wAAAAASUVORK5CYII=);opacity:.5;}#djDebug a#djShowToolBarButton:hover{background-color:#111;padding-right:6px;border-top-color:#FFE761;border-left-color:#FFE761;border-bottom-color:#FFE761;opacity:1.0;}#djDebug code{display:block;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;white-space:pre;overflow:auto;}#djDebug tr.djDebugOdd{background-color:#f5f5f5;}#djDebug .panelContent{display:none;position:fixed;margin:0;top:0;right:200px;bottom:0;left:0;background-color:#eee;color:#666;z-index:100000000;}#djDebug .panelContent>div{border-bottom:1px solid #ddd;}#djDebug .djDebugPanelTitle{position:absolute;background-color:#ffc;color:#666;padding-left:20px;top:0;right:0;left:0;height:50px;}#djDebug .djDebugPanelTitle code{display:inline;font-size:inherit;}#djDebug .djDebugPanelContent{position:absolute;top:50px;right:0;bottom:0;left:0;height:auto;padding:5px 0 0 20px;}#djDebug .djDebugPanelContent .scroll{height:100%;overflow:auto;display:block;padding:0 10px 0 0;}#djDebug h3{font-size:24px;font-weight:normal;line-height:50px;}#djDebug h4{font-size:20px;font-weight:bold;margin-top:.8em;}#djDebug .panelContent table{border:1px solid #ccc;border-collapse:collapse;width:100%;background-color:#fff;display:block;margin-top:.8em;overflow:auto;}#djDebug .panelContent tbody td,#djDebug .panelContent tbody th{vertical-align:top;padding:2px 3px;}#djDebug .panelContent thead th{padding:1px 6px 1px 3px;text-align:left;font-weight:bold;font-size:14px;}#djDebug .panelContent tbody th{width:12em;text-align:right;color:#666;padding-right:.5em;}#djDebug .djTemplateHideContextDiv{background-color:#fff;}#djDebug .panelContent .djDebugClose{text-indent:-9999999px;display:block;position:absolute;top:4px;right:15px;height:40px;width:40px;background:url(../img/close.png) no-repeat center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA7dJREFUeNqsWM1PE0EU3+7ShdJKoTRA8UYgIUKM3rmaEI0euXsw0YMHIZEbxBijEiIHLkb/A44SDYlXzkYPGBM+ri1NWz7aUmhp6+9tps10mLfdfrzkl2535r39zc77mvUdHh4abUoUCAD3xP/fQAFItWJkYmLC+e1p8eGPgQcC08ycf8BPgW2vhr0SeQa8AWIe5k4LvATiwCrwtZmS2WT8IfAL+OKRhCoxoftH2GqLyBLwHbhvdC53ha2lVrfmE/DKzbLP5yubplnt7e310f+rq6tqpVLxVatVy0VtHbgNLHohsupGIhQKFQG7v79f+8CLiwsjl8sVAZsxQbYTwFrDwpTwpaj4ptPu6+vLDw4OBkHA014QobOzs3yhUAgyUx4BP2rhq/rIe53GwMBAeXx83DMJEpobi8WCpMtMWeOc9TkwoyMRjUattrMedBkyM+KZN4isqDMDgUCuExIyGbKlGVpRiSzo8kQ4HA4ZXRLGVuzo6GhBJjKviw6dT5TLZSOTyRinp6cGQrV+n67hnEY6nTaur6+1PkM2NWTm5fCd0xDRhh89CKHpXCMijLGxMef6+PjYiRSSUqlUv6/arOlKMlcjQlV0qsGDTZPehpYIxurXRCSRSFByq5NQ56hvhWwj8cm2p7A9UdKYVBX8fn+F2+tIJGIgmzaQkUnYtm0MDw+zvsLYniQiEc2q/WxxwmqRHxrISA9xxiyLDzTGdsRsJwJoK3QPo3vctnhpAzLqTexhiVOg6JAdU5bLy0vHZ+Ro8mg7Q0QO1LvwenZZJycnN3yCIPsMRRYnjO0DU/SY+wprW7fiWmjKJMgnUIcafEaeoxZCJWJI9lH4UjV2u6pSPp/XJR9jaGiIKrERDAbrjllzYOQJZ4zm6ISxuSsntB3gqTyazWZtMowa0aBFb4HegC6aRkZG2C2hLSObmqEdOcVvUdJUZyBlZ7tVa1ASdEUvjW3ZUqvvO82e3kqlUuVOSZANvBFd0fugawM2VKclOT8/tzohQ7pkgzn/rHNdvLbLJkPxeDzHRRIXIaTDkCB57XacoJPZW8bZQpSskslk0Y0QjdEcmstsB8myegrsYbqmENfJU3dOpZyOEwjdCqLIWUyxWKygVzHFccJ2eVkbar/qdq5ZFC3/R5dUb6EBsqQmyEtLuawj0eykRwpPgL0uRO+esLXW7tmX9nEWeAEk2yCQFLqzzb4MeK3Zn4FRsapNEXqGy2eJTTF3VOh27bOE/Ia2pQ81YeCO+P+XknGrH2pq8l+AAQDv/n2Gmq99BgAAAABJRU5ErkJggg==);}#djDebug .panelContent .djDebugClose:hover{background-image:url(../img/close_hover.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABCVJREFUeNqsWG1IU1EYfjfd0i1bTc2WFTW3tG2aFWlEf4KkMIrCvhH6U9DnjxTyV0ZEXxIVGBH1JyKIPiBK8kf1syCKwu8M3VQsK7OV6ba2udZ7bmd6d+85827zhYftnnPe5z73nvc95z1X5XQ6IUHLQqQjiul1E8KHGIqHxGw2C7+pcd58E6KMooAzphPxnKJBKbFSIfsRpxAmBWMLKI4iviBOIm5O5qSepL8c8R5xQ6EIqZmobzPlSkhINeIpYhkkb0WUqzreqbmEOBaTOjQGf/0+CHz7Klxqc+aAehrGbkrM2b6IyEVUKRFyMpYI38dW8HS0gc/5kdmfnpcPepsD0vMLeRSEm6ivEzeqJOlLsuIJyzs40Au/Xr+CP64uRXORZraCoXQ1aHMX8YZsRDRG0lcqpA1hl3p4mt+C+/nThILDWLYR9EtXsrraEY6IEHGwHmCJGG16k7AIYsTX0/KO1WWn95QJqZWODHxyws8XjUmnjPtZg8DFsFqpkB2sdWL4zWuYKuNwmVwu1w6xkA2s7GAFpnaGAcxbd8H8snJQa7QTUZ+aCrlr10NexR5Iy8yW+REuwsmwDeL0XSOLjfYW5pNZtldC9orS/4FoK4LWa5cgHP4L9n1HILNoudCuM82F1qsXgcXJSOs1ESFkF7WKe8JBfxifQMVMY8/o+P+Z+TYoPFwNoYAfMh3FE2udz8d8CPJWCLdKM03MbcXpySJTY5EtmsNuFW+uex4/gJFe14SYxUuiRHi/fIaue7f5CzKb20KEGKWtYx4Pl2jM54WW+joY6euR9Xm/DkDT5bMQHB3h+7O5jepEMiAUDDBvRtpCfn9CWUWEuGUbkF7PdSDZQQLTaC+S9Rks+VB4qCoqmxRyu4mQbmlrisEY5hEtLN8ynh2RmBjt74sK4LyK3VwhHO5uNa0xoxYMEtVk02KZbk7uxB400C/ERPOVc1EBrMsxcTdCScYQ68L9ZiiyjryUprC+wM5c0PoaH4EmIwMCv4eh6+6t8VghAWzdtVdYzHoaHjKFEE6GvRTvvmSZvScd8f3hHfjT2z0lS3zaQgtkb6tkde3EN3I/kjX3ET9kwVdSOmV7jaF0Fav5BxEh3X3PyPaVBVaYta48aRGkJtHOt7C6zrPKgMvSoCU2vbhEIEpGBKcw6qQ1LLNmrWaVioRIk2kUtvK4SsWSVaCdl8cbcjxW8UxOZqcRJ2TThITZCO+HZvB2dsQsnnUFNtAtWRpLZ430FKjinH0VHSdCXg8EhwaFS03WbEjR6Sc7TkRCoErp2beKlvwX+EtkKqRkGATEYTXSY4SSkx5x2Eyr7WStnXLVJXr2JfPoQBxEDCYgYJD6Oib7MqC0DLiOyKFPVU9TD2J8lqinY3Oo75R9lhC/oQbRhxoSIDZ63UGK9Xg/1ETsnwADAJrrTk7nZiozAAAAAElFTkSuQmCC);}#djDebug .panelContent .djDebugClose.djDebugBack{background-image:url(../img/back.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA7FJREFUeNrMWM1PE0EU3+7S7bZdKSFNSIFgJJAgINE7VxOi0SP/gYkePAiJ3CDGGJUQOXAx+h9wlGhIvHI2fgQ08mEkkjZNIZR2+7Httr63zMoyOzPdthx8yS+bnZn3m9/OvDcfG9jd3ZVatDggDLhO3j8DioBMMySDg4P2s6PJzu8AbhKMcNr8AHwkWPNL7FfIPcATQMJH2xGCh4AkYAHwtpGT3KD+FuAT4I1PEbQliO8XwtWSkFnAe8ANqX2bIFyzzU7NK8AjEXMgELBkWa6HQqEAvpfL5XqtVgvU63VF4LYE6APM+BGyIBKh67oJUCORCLPDQqEg5fN5E6ByKJA7BVg892FU+mJWvGN5a5pmdHV1RUGAr7lAQdls1igWi1FOk9uAD0760jHynOXR2dlp9fb2+haBhm0TiUQUfTlNFnnBeh8wxhIRj8eVllc98OWIGSN9eoTM0y3D4XC+HRFuMcjFqJqnhUyz1olYLKa730uVCrMjXrmIy1ln9vb2pt1CpljZQcdE1ihIW/sHHrayWbHLq1ZNGDPIyaiacguZZAhhph+K+fpr39Ppqcg/wtHhcE46QnAXHT4XwbJssjJECwbtp1EqS99AjNNpSD0r//77wH7yRgW5qeJhmJ44ChmiHYLBIHOMY9GINDrQ9y8uHDEoEMs7FNl+x5HhieFwD6GQbs8GJMtBbtCBmIkrA3anOD0YH2ci+21RWJ4vldibG5u7W5b+E8O95oguhM0LP1PhBauTOfj1Tnxg+c+DpD0aOFq6pjE75HAfoZAdunGlUpH9iLh6uc9+nsaFt5xlHO4dmZwxtynVKm5avIUrqoWkaxAnTmdOnGC5SARyIjdVvA0bX8ZRt0E7GYZhNgpWb0b1c0UIODfcC9o6XZvL5VTYwrnp6zaMEyd9eYZcyMmoWncLWQUcemIim82xFjTeQiey4+Nj1qZ3CNOySu++zxhzeimTyVjtpiZywIiwNr0XrGPAMh20aCcnJ0o7YtAXOTj3nyXeKZ55ykaiZDKZZ2WS6KiIPhwRaI9F1wm8mT3lBJueSqWkdDptigRhHbbBtpzpQJujb4EdnFOTzjvJ4+kcYF8nFEWpqapqf4xpmjXLsmRynVAFg7VMn1dF95oZcuR/yWPDDqvVKsIp8nOknGOJaHTTQ4e7gM0L2NM2Cddiq3dfnMdxwANAugUBaeI73ujPgN9jwGtAD/mqFZJ6kuC3xApp20N8L+y3hHuE1lw/amKAUfK+hYtxsz9qHPsrwACHs5P9Qys/0AAAAABJRU5ErkJggg==);}#djDebug .panelContent .djDebugClose.djDebugBack:hover{background-image:url(../img/back_hover.png);background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA6hJREFUeNrMWF1Ik1EYPtt0pkuGa/aDJTY3nNvSfkglvEwQpa7CbrosKAghBedNikKgEgVe1m03SVeJXmSXBmIozpxpuiUS/eicSc75m73vx/nGt7Nzvm8/BR14+Pjec85znp297znv++kCgQBJs1kBuYDz9H0KEAWEUiGx2WzSMyvFxa8B6iicgjFzgBGKwWSJdUnuyB1AF+BUisK/AToBz7V2RK9B1ACYBDxLQwShc3Cuj3IJm5qQVsAQ4ALJvFVQrlbRAJGPPAE8UKU+2Ce/d6Jk98d36dV44iTR54DvGlTd7jGgCNCSjJBONRHR+Q8kMjtDooF5bn9uaRkxuTwkt+yciAK5UX2fmrNiVLzmzd77ukR+jr0j28GFpP6LIzYHMVdfIcais6IhjYBh2VlZITMANzsj4ntPwiNDaTmHpa6RmCov87r8AA8vau7yRGxOjactAhvOjUxP8LrcdM0EIR3syN0vAbL+djjjkAm/GZS4OK2DFdLEOyc2xsfi/3frcb4/COxqXPI5EwwGm5RC6nnRwTpmgdNNKpq9iZFiLZTsWXkmoRDkQk5Oq1cKqU3wDf80lxDFXGzvTlhUFqm2OwLOWlkI3qIOZc/h3s4hL0y3QyvSM7+4hFxq74otGg2txuyVzW3SU7QryM2YHfD3WFGIPeHQ3AjreETrc34y3d8b8wtZDApE+/5WRHrHnRGJEXDbUYiFte5HIsLtRTGTPR3Sovj3oH8oRaIotB8t5h9kAm6LnvwnDe+acILRJPZ+ZeTgr5f9A+2u2/el3cDd2lz+zF+Qzx1GIYus1WC2oEPptET4+vukp+wXrJ3XBNyLeppjxoWILjtHh5eW6OD6tbxEJno6Y4vJfoJ2NRHIidyMeQHum5DsI6PsJJPTremsvIgSiVDhHFXevnjMvmRHrL56QbaXFuN2hLeQyB43psROCm/c4nXdhB0ZkHdkALDGjjBXVXMPNNFBp9bM1TU88xqKYG/fR+woY7GDFFxtyDg0MScxnrHzunpEGdon9rj/h4kR1j/logKrlZcqIlH2MYt0laeUKlbVEOPpUtGQNq0CqxvwUDR766OPbM3NqibPeU4XySuvVNPplZNnUc6aUjlxACG8Rx01GyLHgKmBQbOKfaosJ7Rq3xaa8vcK6WBBQ75ZQgrNy5YRyVR6OOE6zbYzbX7K1ZdOyUloNe8B3AOspCFghc71aH0Z0KX4feSvf5bQctZkP9Sgg7jo+ywm6+l+qPkjwADNS26fFM/O1QAAAABJRU5ErkJggg==);}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dt{margin-top:.75em;}#djDebug .panelContent dd{margin-left:10px;}#djDebug a.toggleTemplate{padding:4px;background-color:#bbb;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.toggleTemplate:hover{padding:4px;background-color:#444;color:#ffe761;-moz-border-radius:3px;-webkit-border-radius:3px;}#djDebug a.djTemplateShowContext,#djDebug a.djTemplateShowContext span.toggleArrow{color:#999;}#djDebug a.djTemplateShowContext:hover,#djDebug a.djTemplateShowContext:hover span.toggleArrow{color:#000;cursor:pointer;}#djDebug .djDebugSqlWrap{position:relative;}#djDebug .djDebugCollapsed{display:none;text-decoration:none;color:#333;}#djDebug .djDebugUncollapsed{color:#333;text-decoration:none;}#djDebug .djUnselected{display:none;}#djDebug tr.djHiddenByDefault{display:none;}#djDebug tr.djSelected{display:table-row;}#djDebug .djDebugSql{z-index:100000002;}#djDebug .djSQLDetailsDiv tbody th{text-align:left;}#djDebug .djSqlExplain td{white-space:pre;}#djDebug span.djDebugLineChart{background-color:#777;height:3px;position:absolute;bottom:0;top:0;left:0;display:block;z-index:1000000001;}#djDebug span.djDebugLineChartWarning{background-color:#900;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#000;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#000;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#000;font-weight:bold;}#djDebug .highlight .s{color:#333;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#000;font-weight:bold;}#djDebug .highlight .na{color:#333;}#djDebug .highlight .nt{color:#000;font-weight:bold;}#djDebug .highlight .nv{color:#333;}#djDebug .highlight .s2{color:#333;}#djDebug .highlight .cp{color:#333;}#djDebug .timeline{width:30%;}#djDebug .djDebugTimeline{position:relative;height:100%;min-height:100%;}#djDebug div.djDebugLineChart{position:absolute;left:0;right:0;top:0;bottom:0;vertical-align:middle;}#djDebug div.djDebugLineChart strong{text-indent:-10000em;display:block;font-weight:normal;vertical-align:middle;background-color:#ccc;}#djDebug div.djDebugLineChartWarning strong{background-color:#900;}#djDebug .djDebugInTransaction div.djDebugLineChart strong{background-color:#d3ff82;}#djDebug .djDebugStartTransaction div.djDebugLineChart strong{border-left:1px solid #94b24d;}#djDebug .djDebugEndTransaction div.djDebugLineChart strong{border-right:1px solid #94b24d;}#djDebug .djDebugHover div.djDebugLineChart strong{background-color:#000;}#djDebug .djDebugInTransaction.djDebugHover div.djDebugLineChart strong{background-color:#94b24d;}#djDebug .panelContent ul.stats{position:relative;}#djDebug .panelContent ul.stats li{width:30%;float:left;}#djDebug .panelContent ul.stats li strong.label{display:block;}#djDebug .panelContent ul.stats li span.color{height:12px;width:3px;display:inline-block;}#djDebug .panelContent ul.stats li span.info{display:block;padding-left:5px;}#djDebug .panelcontent thead th{white-space:nowrap;}#djDebug .djDebugRowWarning .time{color:red;}#djdebug .panelcontent table .toggle{width:14px;padding-top:3px;}#djdebug .panelcontent table .actions{min-width:70px;}#djdebug .panelcontent table .color{width:3px;}#djdebug .panelcontent table .color span{width:3px;height:12px;overflow:hidden;padding:0;}#djDebug .djToggleSwitch{text-decoration:none;border:1px solid #999;height:12px;width:12px;line-height:12px;text-align:center;color:#777;display:inline-block;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF',endColorstr='#DCDCDC');background:-webkit-gradient(linear,left top,left bottom,from(#FFF),to(#DCDCDC));background:-moz-linear-gradient(center top,#FFF 0,#DCDCDC 100%) repeat scroll 0 0 transparent;}#djDebug .djNoToggleSwitch{height:14px;width:14px;display:inline-block;}#djDebug .djSQLDetailsDiv{margin-top:.8em;}#djDebug pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;color:#555;border:1px solid #ccc;border-collapse:collapse;background-color:#fff;display:block;overflow:auto;padding:2px 3px;margin-bottom:3px;font-family:Consolas,Monaco,"Bitstream Vera Sans Mono","Lucida Console",monospace;}#djDebug .stack span{color:#000;font-weight:bold;}#djDebug .stack span.path{color:#777;font-weight:normal;}#djDebug .stack span.code{font-weight:normal;}@media print{#djDebug{display:none;}}
\ No newline at end of file diff --git a/debug_toolbar/media/debug_toolbar/js/toolbar.js b/debug_toolbar/media/debug_toolbar/js/toolbar.js index c763fd2..3d66769 100644 --- a/debug_toolbar/media/debug_toolbar/js/toolbar.js +++ b/debug_toolbar/media/debug_toolbar/js/toolbar.js @@ -51,6 +51,11 @@ window.djdt = (function(window, document, jQuery) {  				djdt.toggle_content($(this).parent().next());  				return false;  			}); +            $('#djDebug a.djDebugToggle').click(function(e) { +                e.preventDefault(); +                $(this).parent().find('.djDebugCollapsed').toggle(); +                $(this).parent().find('.djDebugUncollapsed').toggle() +            });  			$('#djDebug a.djToggleSwitch').click(function(e) {  				e.preventDefault();  				var btn = $(this); @@ -60,6 +65,8 @@ window.djdt = (function(window, document, jQuery) {  					return;  				} +                btn.parents('.djDebugPanelContent').find('#sqlMain_' + id).find('.djDebugCollapsed').toggle(open_me); +                btn.parents('.djDebugPanelContent').find('#sqlMain_' + id).find('.djDebugUncollapsed').toggle(!open_me);  				$(this).parents('.djDebugPanelContent').find('.djToggleDetails_' + id).each(function(){  					var $this = $(this);  					if (open_me) { @@ -198,4 +205,4 @@ window.djdt = (function(window, document, jQuery) {  		djdt.init();  	});  	return djdt; -}(window, document, jQuery.noConflict())); +}(window, document, jQuery.noConflict(true))); diff --git a/debug_toolbar/media/debug_toolbar/js/toolbar.min.js b/debug_toolbar/media/debug_toolbar/js/toolbar.min.js index b72b0b5..4f843e2 100644 --- a/debug_toolbar/media/debug_toolbar/js/toolbar.min.js +++ b/debug_toolbar/media/debug_toolbar/js/toolbar.min.js @@ -20,4 +20,4 @@   *  Released under the MIT, BSD, and GPL Licenses.   *  More information: http://sizzlejs.com/   */ -}(function(){var a5=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,a6=0,a8=Object.prototype.toString,a0=false,aZ=true;[0,0].sort(function(){aZ=false;return 0});var aW=function(bh,bc,bk,bl){bk=bk||[];var bn=bc=bc||aa;if(bc.nodeType!==1&&bc.nodeType!==9){return[]}if(!bh||typeof bh!=="string"){return bk}var bi=[],be,bp,bs,bd,bg=true,bf=aX(bc),bm=bh;while((a5.exec(""),be=a5.exec(bm))!==null){bm=be[3];bi.push(be[1]);if(be[2]){bd=be[3];break}}if(bi.length>1&&a1.exec(bh)){if(bi.length===2&&a2.relative[bi[0]]){bp=a9(bi[0]+bi[1],bc)}else{bp=a2.relative[bi[0]]?[bc]:aW(bi.shift(),bc);while(bi.length){bh=bi.shift();if(a2.relative[bh]){bh+=bi.shift()}bp=a9(bh,bp)}}}else{if(!bl&&bi.length>1&&bc.nodeType===9&&!bf&&a2.match.ID.test(bi[0])&&!a2.match.ID.test(bi[bi.length-1])){var bo=aW.find(bi.shift(),bc,bf);bc=bo.expr?aW.filter(bo.expr,bo.set)[0]:bo.set[0]}if(bc){var bo=bl?{expr:bi.pop(),set:a4(bl)}:aW.find(bi.pop(),bi.length===1&&(bi[0]==="~"||bi[0]==="+")&&bc.parentNode?bc.parentNode:bc,bf);bp=bo.expr?aW.filter(bo.expr,bo.set):bo.set;if(bi.length>0){bs=a4(bp)}else{bg=false}while(bi.length){var br=bi.pop(),bq=br;if(!a2.relative[br]){br=""}else{bq=bi.pop()}if(bq==null){bq=bc}a2.relative[br](bs,bq,bf)}}else{bs=bi=[]}}if(!bs){bs=bp}if(!bs){aW.error(br||bh)}if(a8.call(bs)==="[object Array]"){if(!bg){bk.push.apply(bk,bs)}else{if(bc&&bc.nodeType===1){for(var bj=0;bs[bj]!=null;bj++){if(bs[bj]&&(bs[bj]===true||bs[bj].nodeType===1&&a3(bc,bs[bj]))){bk.push(bp[bj])}}}else{for(var bj=0;bs[bj]!=null;bj++){if(bs[bj]&&bs[bj].nodeType===1){bk.push(bp[bj])}}}}}else{a4(bs,bk)}if(bd){aW(bd,bn,bk,bl);aW.uniqueSort(bk)}return bk};aW.uniqueSort=function(bd){if(a7){a0=aZ;bd.sort(a7);if(a0){for(var bc=1;bc<bd.length;bc++){if(bd[bc]===bd[bc-1]){bd.splice(bc--,1)}}}}return bd};aW.matches=function(bc,bd){return aW(bc,null,null,bd)};aW.find=function(bj,bc,bk){var bi,bg;if(!bj){return[]}for(var bf=0,be=a2.order.length;bf<be;bf++){var bh=a2.order[bf],bg;if((bg=a2.leftMatch[bh].exec(bj))){var bd=bg[1];bg.splice(1,1);if(bd.substr(bd.length-1)!=="\\"){bg[1]=(bg[1]||"").replace(/\\/g,"");bi=a2.find[bh](bg,bc,bk);if(bi!=null){bj=bj.replace(a2.match[bh],"");break}}}}if(!bi){bi=bc.getElementsByTagName("*")}return{set:bi,expr:bj}};aW.filter=function(bn,bm,bq,bg){var be=bn,bs=[],bk=bm,bi,bc,bj=bm&&bm[0]&&aX(bm[0]);while(bn&&bm.length){for(var bl in a2.filter){if((bi=a2.leftMatch[bl].exec(bn))!=null&&bi[2]){var bd=a2.filter[bl],br,bp,bf=bi[1];bc=false;bi.splice(1,1);if(bf.substr(bf.length-1)==="\\"){continue}if(bk===bs){bs=[]}if(a2.preFilter[bl]){bi=a2.preFilter[bl](bi,bk,bq,bs,bg,bj);if(!bi){bc=br=true}else{if(bi===true){continue}}}if(bi){for(var bh=0;(bp=bk[bh])!=null;bh++){if(bp){br=bd(bp,bi,bh,bk);var bo=bg^!!br;if(bq&&br!=null){if(bo){bc=true}else{bk[bh]=false}}else{if(bo){bs.push(bp);bc=true}}}}}if(br!==B){if(!bq){bk=bs}bn=bn.replace(a2.match[bl],"");if(!bc){return[]}break}}}if(bn===be){if(bc==null){aW.error(bn)}else{break}}be=bn}return bk};aW.error=function(bc){throw"Syntax error, unrecognized expression: "+bc};var a2=aW.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(bc){return bc.getAttribute("href")}},relative:{"+":function(bi,bd){var bf=typeof bd==="string",bh=bf&&!/\W/.test(bd),bj=bf&&!bh;if(bh){bd=bd.toLowerCase()}for(var be=0,bc=bi.length,bg;be<bc;be++){if((bg=bi[be])){while((bg=bg.previousSibling)&&bg.nodeType!==1){}bi[be]=bj||bg&&bg.nodeName.toLowerCase()===bd?bg||false:bg===bd}}if(bj){aW.filter(bd,bi,true)}},">":function(bi,bd){var bg=typeof bd==="string";if(bg&&!/\W/.test(bd)){bd=bd.toLowerCase();for(var be=0,bc=bi.length;be<bc;be++){var bh=bi[be];if(bh){var bf=bh.parentNode;bi[be]=bf.nodeName.toLowerCase()===bd?bf:false}}}else{for(var be=0,bc=bi.length;be<bc;be++){var bh=bi[be];if(bh){bi[be]=bg?bh.parentNode:bh.parentNode===bd}}if(bg){aW.filter(bd,bi,true)}}},"":function(bf,bd,bh){var be=a6++,bc=ba;if(typeof bd==="string"&&!/\W/.test(bd)){var bg=bd=bd.toLowerCase();bc=aU}bc("parentNode",bd,be,bf,bg,bh)},"~":function(bf,bd,bh){var be=a6++,bc=ba;if(typeof bd==="string"&&!/\W/.test(bd)){var bg=bd=bd.toLowerCase();bc=aU}bc("previousSibling",bd,be,bf,bg,bh)}},find:{ID:function(bd,be,bf){if(typeof be.getElementById!=="undefined"&&!bf){var bc=be.getElementById(bd[1]);return bc?[bc]:[]}},NAME:function(be,bh){if(typeof bh.getElementsByName!=="undefined"){var bd=[],bg=bh.getElementsByName(be[1]);for(var bf=0,bc=bg.length;bf<bc;bf++){if(bg[bf].getAttribute("name")===be[1]){bd.push(bg[bf])}}return bd.length===0?null:bd}},TAG:function(bc,bd){return bd.getElementsByTagName(bc[1])}},preFilter:{CLASS:function(bf,bd,be,bc,bi,bj){bf=" "+bf[1].replace(/\\/g,"")+" ";if(bj){return bf}for(var bg=0,bh;(bh=bd[bg])!=null;bg++){if(bh){if(bi^(bh.className&&(" "+bh.className+" ").replace(/[\t\n]/g," ").indexOf(bf)>=0)){if(!be){bc.push(bh)}}else{if(be){bd[bg]=false}}}}return false},ID:function(bc){return bc[1].replace(/\\/g,"")},TAG:function(bd,bc){return bd[1].toLowerCase()},CHILD:function(bc){if(bc[1]==="nth"){var bd=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(bc[2]==="even"&&"2n"||bc[2]==="odd"&&"2n+1"||!/\D/.test(bc[2])&&"0n+"+bc[2]||bc[2]);bc[2]=(bd[1]+(bd[2]||1))-0;bc[3]=bd[3]-0}bc[0]=a6++;return bc},ATTR:function(bg,bd,be,bc,bh,bi){var bf=bg[1].replace(/\\/g,"");if(!bi&&a2.attrMap[bf]){bg[1]=a2.attrMap[bf]}if(bg[2]==="~="){bg[4]=" "+bg[4]+" "}return bg},PSEUDO:function(bg,bd,be,bc,bh){if(bg[1]==="not"){if((a5.exec(bg[3])||"").length>1||/^\w/.test(bg[3])){bg[3]=aW(bg[3],null,null,bd)}else{var bf=aW.filter(bg[3],bd,be,true^bh);if(!be){bc.push.apply(bc,bf)}return false}}else{if(a2.match.POS.test(bg[0])||a2.match.CHILD.test(bg[0])){return true}}return bg},POS:function(bc){bc.unshift(true);return bc}},filters:{enabled:function(bc){return bc.disabled===false&&bc.type!=="hidden"},disabled:function(bc){return bc.disabled===true},checked:function(bc){return bc.checked===true},selected:function(bc){bc.parentNode.selectedIndex;return bc.selected===true},parent:function(bc){return !!bc.firstChild},empty:function(bc){return !bc.firstChild},has:function(be,bd,bc){return !!aW(bc[3],be).length},header:function(bc){return/h\d/i.test(bc.nodeName)},text:function(bc){return"text"===bc.type},radio:function(bc){return"radio"===bc.type},checkbox:function(bc){return"checkbox"===bc.type},file:function(bc){return"file"===bc.type},password:function(bc){return"password"===bc.type},submit:function(bc){return"submit"===bc.type},image:function(bc){return"image"===bc.type},reset:function(bc){return"reset"===bc.type},button:function(bc){return"button"===bc.type||bc.nodeName.toLowerCase()==="button"},input:function(bc){return/input|select|textarea|button/i.test(bc.nodeName)}},setFilters:{first:function(bd,bc){return bc===0},last:function(be,bd,bc,bf){return bd===bf.length-1},even:function(bd,bc){return bc%2===0},odd:function(bd,bc){return bc%2===1},lt:function(be,bd,bc){return bd<bc[3]-0},gt:function(be,bd,bc){return bd>bc[3]-0},nth:function(be,bd,bc){return bc[3]-0===bd},eq:function(be,bd,bc){return bc[3]-0===bd}},filter:{PSEUDO:function(bi,be,bf,bj){var bd=be[1],bg=a2.filters[bd];if(bg){return bg(bi,bf,be,bj)}else{if(bd==="contains"){return(bi.textContent||bi.innerText||aV([bi])||"").indexOf(be[3])>=0}else{if(bd==="not"){var bh=be[3];for(var bf=0,bc=bh.length;bf<bc;bf++){if(bh[bf]===bi){return false}}return true}else{aW.error("Syntax error, unrecognized expression: "+bd)}}}},CHILD:function(bc,bf){var bi=bf[1],bd=bc;switch(bi){case"only":case"first":while((bd=bd.previousSibling)){if(bd.nodeType===1){return false}}if(bi==="first"){return true}bd=bc;case"last":while((bd=bd.nextSibling)){if(bd.nodeType===1){return false}}return true;case"nth":var be=bf[2],bl=bf[3];if(be===1&&bl===0){return true}var bh=bf[0],bk=bc.parentNode;if(bk&&(bk.sizcache!==bh||!bc.nodeIndex)){var bg=0;for(bd=bk.firstChild;bd;bd=bd.nextSibling){if(bd.nodeType===1){bd.nodeIndex=++bg}}bk.sizcache=bh}var bj=bc.nodeIndex-bl;if(be===0){return bj===0}else{return(bj%be===0&&bj/be>=0)}}},ID:function(bd,bc){return bd.nodeType===1&&bd.getAttribute("id")===bc},TAG:function(bd,bc){return(bc==="*"&&bd.nodeType===1)||bd.nodeName.toLowerCase()===bc},CLASS:function(bd,bc){return(" "+(bd.className||bd.getAttribute("class"))+" ").indexOf(bc)>-1},ATTR:function(bh,bf){var be=bf[1],bc=a2.attrHandle[be]?a2.attrHandle[be](bh):bh[be]!=null?bh[be]:bh.getAttribute(be),bi=bc+"",bg=bf[2],bd=bf[4];return bc==null?bg==="!=":bg==="="?bi===bd:bg==="*="?bi.indexOf(bd)>=0:bg==="~="?(" "+bi+" ").indexOf(bd)>=0:!bd?bi&&bc!==false:bg==="!="?bi!==bd:bg==="^="?bi.indexOf(bd)===0:bg==="$="?bi.substr(bi.length-bd.length)===bd:bg==="|="?bi===bd||bi.substr(0,bd.length+1)===bd+"-":false},POS:function(bg,bd,be,bh){var bc=bd[2],bf=a2.setFilters[bc];if(bf){return bf(bg,be,bd,bh)}}}};var a1=a2.match.POS;for(var aY in a2.match){a2.match[aY]=new RegExp(a2.match[aY].source+/(?![^\[]*\])(?![^\(]*\))/.source);a2.leftMatch[aY]=new RegExp(/(^(?:.|\r|\n)*?)/.source+a2.match[aY].source.replace(/\\(\d+)/g,function(bd,bc){return"\\"+(bc-0+1)}))}var a4=function(bd,bc){bd=Array.prototype.slice.call(bd,0);if(bc){bc.push.apply(bc,bd);return bc}return bd};try{Array.prototype.slice.call(aa.documentElement.childNodes,0)}catch(bb){a4=function(bg,bf){var bd=bf||[];if(a8.call(bg)==="[object Array]"){Array.prototype.push.apply(bd,bg)}else{if(typeof bg.length==="number"){for(var be=0,bc=bg.length;be<bc;be++){bd.push(bg[be])}}else{for(var be=0;bg[be];be++){bd.push(bg[be])}}}return bd}}var a7;if(aa.documentElement.compareDocumentPosition){a7=function(bd,bc){if(!bd.compareDocumentPosition||!bc.compareDocumentPosition){if(bd==bc){a0=true}return bd.compareDocumentPosition?-1:1}var be=bd.compareDocumentPosition(bc)&4?-1:bd===bc?0:1;if(be===0){a0=true}return be}}else{if("sourceIndex" in aa.documentElement){a7=function(bd,bc){if(!bd.sourceIndex||!bc.sourceIndex){if(bd==bc){a0=true}return bd.sourceIndex?-1:1}var be=bd.sourceIndex-bc.sourceIndex;if(be===0){a0=true}return be}}else{if(aa.createRange){a7=function(bf,bd){if(!bf.ownerDocument||!bd.ownerDocument){if(bf==bd){a0=true}return bf.ownerDocument?-1:1}var be=bf.ownerDocument.createRange(),bc=bd.ownerDocument.createRange();be.setStart(bf,0);be.setEnd(bf,0);bc.setStart(bd,0);bc.setEnd(bd,0);var bg=be.compareBoundaryPoints(Range.START_TO_END,bc);if(bg===0){a0=true}return bg}}}}function aV(bc){var bd="",bf;for(var be=0;bc[be];be++){bf=bc[be];if(bf.nodeType===3||bf.nodeType===4){bd+=bf.nodeValue}else{if(bf.nodeType!==8){bd+=aV(bf.childNodes)}}}return bd}(function(){var bd=aa.createElement("div"),be="script"+(new Date).getTime();bd.innerHTML="<a name='"+be+"'/>";var bc=aa.documentElement;bc.insertBefore(bd,bc.firstChild);if(aa.getElementById(be)){a2.find.ID=function(bg,bh,bi){if(typeof bh.getElementById!=="undefined"&&!bi){var bf=bh.getElementById(bg[1]);return bf?bf.id===bg[1]||typeof bf.getAttributeNode!=="undefined"&&bf.getAttributeNode("id").nodeValue===bg[1]?[bf]:B:[]}};a2.filter.ID=function(bh,bf){var bg=typeof bh.getAttributeNode!=="undefined"&&bh.getAttributeNode("id");return bh.nodeType===1&&bg&&bg.nodeValue===bf}}bc.removeChild(bd);bc=bd=null})();(function(){var bc=aa.createElement("div");bc.appendChild(aa.createComment(""));if(bc.getElementsByTagName("*").length>0){a2.find.TAG=function(bd,bh){var bg=bh.getElementsByTagName(bd[1]);if(bd[1]==="*"){var bf=[];for(var be=0;bg[be];be++){if(bg[be].nodeType===1){bf.push(bg[be])}}bg=bf}return bg}}bc.innerHTML="<a href='#'></a>";if(bc.firstChild&&typeof bc.firstChild.getAttribute!=="undefined"&&bc.firstChild.getAttribute("href")!=="#"){a2.attrHandle.href=function(bd){return bd.getAttribute("href",2)}}bc=null})();if(aa.querySelectorAll){(function(){var bc=aW,be=aa.createElement("div");be.innerHTML="<p class='TEST'></p>";if(be.querySelectorAll&&be.querySelectorAll(".TEST").length===0){return}aW=function(bi,bh,bf,bg){bh=bh||aa;if(!bg&&bh.nodeType===9&&!aX(bh)){try{return a4(bh.querySelectorAll(bi),bf)}catch(bj){}}return bc(bi,bh,bf,bg)};for(var bd in bc){aW[bd]=bc[bd]}be=null})()}(function(){var bc=aa.createElement("div");bc.innerHTML="<div class='test e'></div><div class='test'></div>";if(!bc.getElementsByClassName||bc.getElementsByClassName("e").length===0){return}bc.lastChild.className="e";if(bc.getElementsByClassName("e").length===1){return}a2.order.splice(1,0,"CLASS");a2.find.CLASS=function(bd,be,bf){if(typeof be.getElementsByClassName!=="undefined"&&!bf){return be.getElementsByClassName(bd[1])}};bc=null})();function aU(bd,bi,bh,bl,bj,bk){for(var bf=0,be=bl.length;bf<be;bf++){var bc=bl[bf];if(bc){bc=bc[bd];var bg=false;while(bc){if(bc.sizcache===bh){bg=bl[bc.sizset];break}if(bc.nodeType===1&&!bk){bc.sizcache=bh;bc.sizset=bf}if(bc.nodeName.toLowerCase()===bi){bg=bc;break}bc=bc[bd]}bl[bf]=bg}}}function ba(bd,bi,bh,bl,bj,bk){for(var bf=0,be=bl.length;bf<be;bf++){var bc=bl[bf];if(bc){bc=bc[bd];var bg=false;while(bc){if(bc.sizcache===bh){bg=bl[bc.sizset];break}if(bc.nodeType===1){if(!bk){bc.sizcache=bh;bc.sizset=bf}if(typeof bi!=="string"){if(bc===bi){bg=true;break}}else{if(aW.filter(bi,[bc]).length>0){bg=bc;break}}}bc=bc[bd]}bl[bf]=bg}}}var a3=aa.compareDocumentPosition?function(bd,bc){return bd.compareDocumentPosition(bc)&16}:function(bd,bc){return bd!==bc&&(bd.contains?bd.contains(bc):true)};var aX=function(bc){var bd=(bc?bc.ownerDocument||bc:0).documentElement;return bd?bd.nodeName!=="HTML":false};var a9=function(bc,bj){var bf=[],bg="",bh,be=bj.nodeType?[bj]:bj;while((bh=a2.match.PSEUDO.exec(bc))){bg+=bh[0];bc=bc.replace(a2.match.PSEUDO,"")}bc=a2.relative[bc]?bc+"*":bc;for(var bi=0,bd=be.length;bi<bd;bi++){aW(bc,be[bi],bf)}return aW.filter(bg,bf)};a.find=aW;a.expr=aW.selectors;a.expr[":"]=a.expr.filters;a.unique=aW.uniqueSort;a.getText=aV;a.isXMLDoc=aX;a.contains=a3;return;aI.Sizzle=aW})();var M=/Until$/,X=/^(?:parents|prevUntil|prevAll)/,aH=/,/,D=Array.prototype.slice;var ag=function(aX,aW,aU){if(a.isFunction(aW)){return a.grep(aX,function(aZ,aY){return !!aW.call(aZ,aY,aZ)===aU})}else{if(aW.nodeType){return a.grep(aX,function(aZ,aY){return(aZ===aW)===aU})}else{if(typeof aW==="string"){var aV=a.grep(aX,function(aY){return aY.nodeType===1});if(aS.test(aW)){return a.filter(aW,aV,!aU)}else{aW=a.filter(aW,aV)}}}}return a.grep(aX,function(aZ,aY){return(a.inArray(aZ,aW)>=0)===aU})};a.fn.extend({find:function(aU){var aW=this.pushStack("","find",aU),aZ=0;for(var aX=0,aV=this.length;aX<aV;aX++){aZ=aW.length;a.find(aU,this[aX],aW);if(aX>0){for(var a0=aZ;a0<aW.length;a0++){for(var aY=0;aY<aZ;aY++){if(aW[aY]===aW[a0]){aW.splice(a0--,1);break}}}}}return aW},has:function(aV){var aU=a(aV);return this.filter(function(){for(var aX=0,aW=aU.length;aX<aW;aX++){if(a.contains(this,aU[aX])){return true}}})},not:function(aU){return this.pushStack(ag(this,aU,false),"not",aU)},filter:function(aU){return this.pushStack(ag(this,aU,true),"filter",aU)},is:function(aU){return !!aU&&a.filter(aU,this).length>0},closest:function(a3,aU){if(a.isArray(a3)){var a0=[],a2=this[0],aZ,aY={},aW;if(a2&&a3.length){for(var aX=0,aV=a3.length;aX<aV;aX++){aW=a3[aX];if(!aY[aW]){aY[aW]=a.expr.match.POS.test(aW)?a(aW,aU||this.context):aW}}while(a2&&a2.ownerDocument&&a2!==aU){for(aW in aY){aZ=aY[aW];if(aZ.jquery?aZ.index(a2)>-1:a(a2).is(aZ)){a0.push({selector:aW,elem:a2});delete aY[aW]}}a2=a2.parentNode}}return a0}var a1=a.expr.match.POS.test(a3)?a(a3,aU||this.context):null;return this.map(function(a4,a5){while(a5&&a5.ownerDocument&&a5!==aU){if(a1?a1.index(a5)>-1:a(a5).is(a3)){return a5}a5=a5.parentNode}return null})},index:function(aU){if(!aU||typeof aU==="string"){return a.inArray(this[0],aU?a(aU):this.parent().children())}return a.inArray(aU.jquery?aU[0]:aU,this)},add:function(aU,aV){var aX=typeof aU==="string"?a(aU,aV||this.context):a.makeArray(aU),aW=a.merge(this.get(),aX);return this.pushStack(x(aX[0])||x(aW[0])?aW:a.unique(aW))},andSelf:function(){return this.add(this.prevObject)}});function x(aU){return !aU||!aU.parentNode||aU.parentNode.nodeType===11}a.each({parent:function(aV){var aU=aV.parentNode;return aU&&aU.nodeType!==11?aU:null},parents:function(aU){return a.dir(aU,"parentNode")},parentsUntil:function(aV,aU,aW){return a.dir(aV,"parentNode",aW)},next:function(aU){return a.nth(aU,2,"nextSibling")},prev:function(aU){return a.nth(aU,2,"previousSibling")},nextAll:function(aU){return a.dir(aU,"nextSibling")},prevAll:function(aU){return a.dir(aU,"previousSibling")},nextUntil:function(aV,aU,aW){return a.dir(aV,"nextSibling",aW)},prevUntil:function(aV,aU,aW){return a.dir(aV,"previousSibling",aW)},siblings:function(aU){return a.sibling(aU.parentNode.firstChild,aU)},children:function(aU){return a.sibling(aU.firstChild)},contents:function(aU){return a.nodeName(aU,"iframe")?aU.contentDocument||aU.contentWindow.document:a.makeArray(aU.childNodes)}},function(aU,aV){a.fn[aU]=function(aY,aW){var aX=a.map(this,aV,aY);if(!M.test(aU)){aW=aY}if(aW&&typeof aW==="string"){aX=a.filter(aW,aX)}aX=this.length>1?a.unique(aX):aX;if((this.length>1||aH.test(aW))&&X.test(aU)){aX=aX.reverse()}return this.pushStack(aX,aU,D.call(arguments).join(","))}});a.extend({filter:function(aW,aU,aV){if(aV){aW=":not("+aW+")"}return a.find.matches(aW,aU)},dir:function(aW,aV,aY){var aU=[],aX=aW[aV];while(aX&&aX.nodeType!==9&&(aY===B||aX.nodeType!==1||!a(aX).is(aY))){if(aX.nodeType===1){aU.push(aX)}aX=aX[aV]}return aU},nth:function(aY,aU,aW,aX){aU=aU||1;var aV=0;for(;aY;aY=aY[aW]){if(aY.nodeType===1&&++aV===aU){break}}return aY},sibling:function(aW,aV){var aU=[];for(;aW;aW=aW.nextSibling){if(aW.nodeType===1&&aW!==aV){aU.push(aW)}}return aU}});var S=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,F=/(<([\w:]+)[^>]*?)\/>/g,aj=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,c=/<([\w:]+)/,t=/<tbody/i,J=/<|&\w+;/,l=/checked\s*(?:[^=]|=\s*.checked.)/i,p=function(aV,aW,aU){return aj.test(aU)?aV:aW+"></"+aU+">"},ab={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};ab.optgroup=ab.option;ab.tbody=ab.tfoot=ab.colgroup=ab.caption=ab.thead;ab.th=ab.td;if(!a.support.htmlSerialize){ab._default=[1,"div<div>","</div>"]}a.fn.extend({text:function(aU){if(a.isFunction(aU)){return this.each(function(aW){var aV=a(this);aV.text(aU.call(this,aW,aV.text()))})}if(typeof aU!=="object"&&aU!==B){return this.empty().append((this[0]&&this[0].ownerDocument||aa).createTextNode(aU))}return a.getText(this)},wrapAll:function(aU){if(a.isFunction(aU)){return this.each(function(aW){a(this).wrapAll(aU.call(this,aW))})}if(this[0]){var aV=a(aU,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){aV.insertBefore(this[0])}aV.map(function(){var aW=this;while(aW.firstChild&&aW.firstChild.nodeType===1){aW=aW.firstChild}return aW}).append(this)}return this},wrapInner:function(aU){if(a.isFunction(aU)){return this.each(function(aV){a(this).wrapInner(aU.call(this,aV))})}return this.each(function(){var aV=a(this),aW=aV.contents();if(aW.length){aW.wrapAll(aU)}else{aV.append(aU)}})},wrap:function(aU){return this.each(function(){a(this).wrapAll(aU)})},unwrap:function(){return this.parent().each(function(){if(!a.nodeName(this,"body")){a(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(aU){if(this.nodeType===1){this.appendChild(aU)}})},prepend:function(){return this.domManip(arguments,true,function(aU){if(this.nodeType===1){this.insertBefore(aU,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(aV){this.parentNode.insertBefore(aV,this)})}else{if(arguments.length){var aU=a(arguments[0]);aU.push.apply(aU,this.toArray());return this.pushStack(aU,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(aV){this.parentNode.insertBefore(aV,this.nextSibling)})}else{if(arguments.length){var aU=this.pushStack(this,"after",arguments);aU.push.apply(aU,a(arguments[0]).toArray());return aU}}},clone:function(aV){var aU=this.map(function(){if(!a.support.noCloneEvent&&!a.isXMLDoc(this)){var aX=this.outerHTML,aW=this.ownerDocument;if(!aX){var aY=aW.createElement("div");aY.appendChild(this.cloneNode(true));aX=aY.innerHTML}return a.clean([aX.replace(S,"").replace(Y,"")],aW)[0]}else{return this.cloneNode(true)}});if(aV===true){q(this,aU);q(this.find("*"),aU.find("*"))}return aU},html:function(aW){if(aW===B){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(S,""):null}else{if(typeof aW==="string"&&!/<script/i.test(aW)&&(a.support.leadingWhitespace||!Y.test(aW))&&!ab[(c.exec(aW)||["",""])[1].toLowerCase()]){aW=aW.replace(F,p);try{for(var aV=0,aU=this.length;aV<aU;aV++){if(this[aV].nodeType===1){a.cleanData(this[aV].getElementsByTagName("*"));this[aV].innerHTML=aW}}}catch(aX){this.empty().append(aW)}}else{if(a.isFunction(aW)){this.each(function(a0){var aZ=a(this),aY=aZ.html();aZ.empty().append(function(){return aW.call(this,a0,aY)})})}else{this.empty().append(aW)}}}return this},replaceWith:function(aU){if(this[0]&&this[0].parentNode){if(!a.isFunction(aU)){aU=a(aU).detach()}else{return this.each(function(aX){var aW=a(this),aV=aW.html();aW.replaceWith(aU.call(this,aX,aV))})}return this.each(function(){var aW=this.nextSibling,aV=this.parentNode;a(this).remove();if(aW){a(aW).before(aU)}else{a(aV).append(aU)}})}else{return this.pushStack(a(a.isFunction(aU)?aU():aU),"replaceWith",aU)}},detach:function(aU){return this.remove(aU,true)},domManip:function(aZ,a3,a2){var aW,aY,a1=aZ[0],aV=[];if(!a.support.checkClone&&arguments.length===3&&typeof a1==="string"&&l.test(a1)){return this.each(function(){a(this).domManip(aZ,a3,a2,true)})}if(a.isFunction(a1)){return this.each(function(a5){var a4=a(this);aZ[0]=a1.call(this,a5,a3?a4.html():B);a4.domManip(aZ,a3,a2)})}if(this[0]){if(aZ[0]&&aZ[0].parentNode&&aZ[0].parentNode.nodeType===11){aW={fragment:aZ[0].parentNode}}else{aW=H(aZ,this,aV)}aY=aW.fragment.firstChild;if(aY){a3=a3&&a.nodeName(aY,"tr");for(var aX=0,aU=this.length;aX<aU;aX++){a2.call(a3?a0(this[aX],aY):this[aX],aW.cacheable||this.length>1||aX>0?aW.fragment.cloneNode(true):aW.fragment)}}if(aV){a.each(aV,aR)}}return this;function a0(a4,a5){return a.nodeName(a4,"table")?(a4.getElementsByTagName("tbody")[0]||a4.appendChild(a4.ownerDocument.createElement("tbody"))):a4}}});function q(aW,aU){var aV=0;aU.each(function(){if(this.nodeName!==(aW[aV]&&aW[aV].nodeName)){return}var a1=a.data(aW[aV++]),a0=a.data(this,a1),aX=a1&&a1.events;if(aX){delete a0.handle;a0.events={};for(var aZ in aX){for(var aY in aX[aZ]){a.event.add(this,aZ,aX[aZ][aY],aX[aZ][aY].data)}}}})}function H(aZ,aX,aV){var aY,aU,aW,a0;if(aZ.length===1&&typeof aZ[0]==="string"&&aZ[0].length<512&&aZ[0].indexOf("<option")<0&&(a.support.checkClone||!l.test(aZ[0]))){aU=true;aW=a.fragments[aZ[0]];if(aW){if(aW!==1){aY=aW}}}if(!aY){a0=(aX&&aX[0]?aX[0].ownerDocument||aX[0]:aa);aY=a0.createDocumentFragment();a.clean(aZ,a0,aY,aV)}if(aU){a.fragments[aZ[0]]=aW?aY:1}return{fragment:aY,cacheable:aU}}a.fragments={};a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(aU,aV){a.fn[aU]=function(aW){var aZ=[],a1=a(aW);for(var a0=0,aX=a1.length;a0<aX;a0++){var aY=(a0>0?this.clone(true):this).get();a.fn[aV].apply(a(a1[a0]),aY);aZ=aZ.concat(aY)}return this.pushStack(aZ,aU,a1.selector)}});a.each({remove:function(aU,aV){if(!aU||a.filter(aU,[this]).length){if(!aV&&this.nodeType===1){a.cleanData(this.getElementsByTagName("*"));a.cleanData([this])}if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){if(this.nodeType===1){a.cleanData(this.getElementsByTagName("*"))}while(this.firstChild){this.removeChild(this.firstChild)}}},function(aU,aV){a.fn[aU]=function(){return this.each(aV,arguments)}});a.extend({clean:function(aV,aZ,aX,aU){aZ=aZ||aa;if(typeof aZ.createElement==="undefined"){aZ=aZ.ownerDocument||aZ[0]&&aZ[0].ownerDocument||aa}var aW=[];a.each(aV,function(a6,a3){if(typeof a3==="number"){a3+=""}if(!a3){return}if(typeof a3==="string"&&!J.test(a3)){a3=aZ.createTextNode(a3)}else{if(typeof a3==="string"){a3=a3.replace(F,p);var a8=(c.exec(a3)||["",""])[1].toLowerCase(),a2=ab[a8]||ab._default,a5=a2[0],a0=aZ.createElement("div");a0.innerHTML=a2[1]+a3+a2[2];while(a5--){a0=a0.lastChild}if(!a.support.tbody){var a1=t.test(a3),a7=a8==="table"&&!a1?a0.firstChild&&a0.firstChild.childNodes:a2[1]==="<table>"&&!a1?a0.childNodes:[];for(var a4=a7.length-1;a4>=0;--a4){if(a.nodeName(a7[a4],"tbody")&&!a7[a4].childNodes.length){a7[a4].parentNode.removeChild(a7[a4])}}}if(!a.support.leadingWhitespace&&Y.test(a3)){a0.insertBefore(aZ.createTextNode(Y.exec(a3)[0]),a0.firstChild)}a3=a.makeArray(a0.childNodes)}}if(a3.nodeType){aW.push(a3)}else{aW=a.merge(aW,a3)}});if(aX){for(var aY=0;aW[aY];aY++){if(aU&&a.nodeName(aW[aY],"script")&&(!aW[aY].type||aW[aY].type.toLowerCase()==="text/javascript")){aU.push(aW[aY].parentNode?aW[aY].parentNode.removeChild(aW[aY]):aW[aY])}else{if(aW[aY].nodeType===1){aW.splice.apply(aW,[aY+1,0].concat(a.makeArray(aW[aY].getElementsByTagName("script"))))}aX.appendChild(aW[aY])}}}return aW},cleanData:function(aU){for(var aV=0,aW,aX;(aW=aU[aV])!=null;aV++){a.event.remove(aW);a.removeData(aW)}}});var ap=/z-?index|font-?weight|opacity|zoom|line-?height/i,T=/alpha\([^)]*\)/,Z=/opacity=([^)]*)/,af=/float/i,aw=/-([a-z])/ig,v=/([A-Z])/g,aK=/^-?\d+(?:px)?$/i,aQ=/^-?\d/,aG={position:"absolute",visibility:"hidden",display:"block"},V=["Left","Right"],aA=["Top","Bottom"],ai=aa.defaultView&&aa.defaultView.getComputedStyle,aJ=a.support.cssFloat?"cssFloat":"styleFloat",k=function(aU,aV){return aV.toUpperCase()};a.fn.css=function(aU,aV){return al(this,aU,aV,true,function(aX,aW,aY){if(aY===B){return a.curCSS(aX,aW)}if(typeof aY==="number"&&!ap.test(aW)){aY+="px"}a.style(aX,aW,aY)})};a.extend({style:function(aY,aV,aZ){if(!aY||aY.nodeType===3||aY.nodeType===8){return B}if((aV==="width"||aV==="height")&&parseFloat(aZ)<0){aZ=B}var aX=aY.style||aY,a0=aZ!==B;if(!a.support.opacity&&aV==="opacity"){if(a0){aX.zoom=1;var aU=parseInt(aZ,10)+""==="NaN"?"":"alpha(opacity="+aZ*100+")";var aW=aX.filter||a.curCSS(aY,"filter")||"";aX.filter=T.test(aW)?aW.replace(T,aU):aU}return aX.filter&&aX.filter.indexOf("opacity=")>=0?(parseFloat(Z.exec(aX.filter)[1])/100)+"":""}if(af.test(aV)){aV=aJ}aV=aV.replace(aw,k);if(a0){aX[aV]=aZ}return aX[aV]},css:function(aX,aV,aZ,aU){if(aV==="width"||aV==="height"){var a1,aW=aG,a0=aV==="width"?V:aA;function aY(){a1=aV==="width"?aX.offsetWidth:aX.offsetHeight;if(aU==="border"){return}a.each(a0,function(){if(!aU){a1-=parseFloat(a.curCSS(aX,"padding"+this,true))||0}if(aU==="margin"){a1+=parseFloat(a.curCSS(aX,"margin"+this,true))||0}else{a1-=parseFloat(a.curCSS(aX,"border"+this+"Width",true))||0}})}if(aX.offsetWidth!==0){aY()}else{a.swap(aX,aW,aY)}return Math.max(0,Math.round(a1))}return a.curCSS(aX,aV,aZ)},curCSS:function(a0,aV,aW){var a3,aU=a0.style,aX;if(!a.support.opacity&&aV==="opacity"&&a0.currentStyle){a3=Z.test(a0.currentStyle.filter||"")?(parseFloat(RegExp.$1)/100)+"":"";return a3===""?"1":a3}if(af.test(aV)){aV=aJ}if(!aW&&aU&&aU[aV]){a3=aU[aV]}else{if(ai){if(af.test(aV)){aV="float"}aV=aV.replace(v,"-$1").toLowerCase();var a2=a0.ownerDocument.defaultView;if(!a2){return null}var a4=a2.getComputedStyle(a0,null);if(a4){a3=a4.getPropertyValue(aV)}if(aV==="opacity"&&a3===""){a3="1"}}else{if(a0.currentStyle){var aZ=aV.replace(aw,k);a3=a0.currentStyle[aV]||a0.currentStyle[aZ];if(!aK.test(a3)&&aQ.test(a3)){var aY=aU.left,a1=a0.runtimeStyle.left;a0.runtimeStyle.left=a0.currentStyle.left;aU.left=aZ==="fontSize"?"1em":(a3||0);a3=aU.pixelLeft+"px";aU.left=aY;a0.runtimeStyle.left=a1}}}}return a3},swap:function(aX,aW,aY){var aU={};for(var aV in aW){aU[aV]=aX.style[aV];aX.style[aV]=aW[aV]}aY.call(aX);for(var aV in aW){aX.style[aV]=aU[aV]}}});if(a.expr&&a.expr.filters){a.expr.filters.hidden=function(aX){var aV=aX.offsetWidth,aU=aX.offsetHeight,aW=aX.nodeName.toLowerCase()==="tr";return aV===0&&aU===0&&!aW?true:aV>0&&aU>0&&!aW?false:a.curCSS(aX,"display")==="none"};a.expr.filters.visible=function(aU){return !a.expr.filters.hidden(aU)}}var ae=aL(),aF=/<script(.|\s)*?\/script>/gi,o=/select|textarea/i,ay=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,r=/=\?(&|$)/,C=/\?/,aT=/(\?|&)_=.*?(&|$)/,A=/^(\w+:)?\/\/([^\/?#]+)/,h=/%20/g;a.fn.extend({_load:a.fn.load,load:function(aW,aZ,a0){if(typeof aW!=="string"){return this._load(aW)}else{if(!this.length){return this}}var aY=aW.indexOf(" ");if(aY>=0){var aU=aW.slice(aY,aW.length);aW=aW.slice(0,aY)}var aX="GET";if(aZ){if(a.isFunction(aZ)){a0=aZ;aZ=null}else{if(typeof aZ==="object"){aZ=a.param(aZ,a.ajaxSettings.traditional);aX="POST"}}}var aV=this;a.ajax({url:aW,type:aX,dataType:"html",data:aZ,complete:function(a2,a1){if(a1==="success"||a1==="notmodified"){aV.html(aU?a("<div />").append(a2.responseText.replace(aF,"")).find(aU):a2.responseText)}if(a0){aV.each(a0,[a2.responseText,a1,a2])}}});return this},serialize:function(){return a.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?a.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||o.test(this.nodeName)||ay.test(this.type))}).map(function(aU,aV){var aW=a(this).val();return aW==null?null:a.isArray(aW)?a.map(aW,function(aY,aX){return{name:aV.name,value:aY}}):{name:aV.name,value:aW}}).get()}});a.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(aU,aV){a.fn[aV]=function(aW){return this.bind(aV,aW)}});a.extend({get:function(aU,aW,aX,aV){if(a.isFunction(aW)){aV=aV||aX;aX=aW;aW=null}return a.ajax({type:"GET",url:aU,data:aW,success:aX,dataType:aV})},getScript:function(aU,aV){return a.get(aU,null,aV,"script")},getJSON:function(aU,aV,aW){return a.get(aU,aV,aW,"json")},post:function(aU,aW,aX,aV){if(a.isFunction(aW)){aV=aV||aX;aX=aW;aW={}}return a.ajax({type:"POST",url:aU,data:aW,success:aX,dataType:aV})},ajaxSetup:function(aU){a.extend(a.ajaxSettings,aU)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:aI.XMLHttpRequest&&(aI.location.protocol!=="file:"||!aI.ActiveXObject)?function(){return new aI.XMLHttpRequest()}:function(){try{return new aI.ActiveXObject("Microsoft.XMLHTTP")}catch(aU){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a9){var a4=a.extend(true,{},a.ajaxSettings,a9);var be,a8,bd,bf=a9&&a9.context||a4,aW=a4.type.toUpperCase();if(a4.data&&a4.processData&&typeof a4.data!=="string"){a4.data=a.param(a4.data,a4.traditional)}if(a4.dataType==="jsonp"){if(aW==="GET"){if(!r.test(a4.url)){a4.url+=(C.test(a4.url)?"&":"?")+(a4.jsonp||"callback")+"=?"}}else{if(!a4.data||!r.test(a4.data)){a4.data=(a4.data?a4.data+"&":"")+(a4.jsonp||"callback")+"=?"}}a4.dataType="json"}if(a4.dataType==="json"&&(a4.data&&r.test(a4.data)||r.test(a4.url))){be=a4.jsonpCallback||("jsonp"+ae++);if(a4.data){a4.data=(a4.data+"").replace(r,"="+be+"$1")}a4.url=a4.url.replace(r,"="+be+"$1");a4.dataType="script";aI[be]=aI[be]||function(bg){bd=bg;aZ();a2();aI[be]=B;try{delete aI[be]}catch(bh){}if(aX){aX.removeChild(bb)}}}if(a4.dataType==="script"&&a4.cache===null){a4.cache=false}if(a4.cache===false&&aW==="GET"){var aU=aL();var bc=a4.url.replace(aT,"$1_="+aU+"$2");a4.url=bc+((bc===a4.url)?(C.test(a4.url)?"&":"?")+"_="+aU:"")}if(a4.data&&aW==="GET"){a4.url+=(C.test(a4.url)?"&":"?")+a4.data}if(a4.global&&!a.active++){a.event.trigger("ajaxStart")}var a7=A.exec(a4.url),aY=a7&&(a7[1]&&a7[1]!==location.protocol||a7[2]!==location.host);if(a4.dataType==="script"&&aW==="GET"&&aY){var aX=aa.getElementsByTagName("head")[0]||aa.documentElement;var bb=aa.createElement("script");bb.src=a4.url;if(a4.scriptCharset){bb.charset=a4.scriptCharset}if(!be){var a6=false;bb.onload=bb.onreadystatechange=function(){if(!a6&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){a6=true;aZ();a2();bb.onload=bb.onreadystatechange=null;if(aX&&bb.parentNode){aX.removeChild(bb)}}}}aX.insertBefore(bb,aX.firstChild);return B}var a1=false;var a0=a4.xhr();if(!a0){return}if(a4.username){a0.open(aW,a4.url,a4.async,a4.username,a4.password)}else{a0.open(aW,a4.url,a4.async)}try{if(a4.data||a9&&a9.contentType){a0.setRequestHeader("Content-Type",a4.contentType)}if(a4.ifModified){if(a.lastModified[a4.url]){a0.setRequestHeader("If-Modified-Since",a.lastModified[a4.url])}if(a.etag[a4.url]){a0.setRequestHeader("If-None-Match",a.etag[a4.url])}}if(!aY){a0.setRequestHeader("X-Requested-With","XMLHttpRequest")}a0.setRequestHeader("Accept",a4.dataType&&a4.accepts[a4.dataType]?a4.accepts[a4.dataType]+", */*":a4.accepts._default)}catch(ba){}if(a4.beforeSend&&a4.beforeSend.call(bf,a0,a4)===false){if(a4.global&&!--a.active){a.event.trigger("ajaxStop")}a0.abort();return false}if(a4.global){a5("ajaxSend",[a0,a4])}var a3=a0.onreadystatechange=function(bg){if(!a0||a0.readyState===0||bg==="abort"){if(!a1){a2()}a1=true;if(a0){a0.onreadystatechange=a.noop}}else{if(!a1&&a0&&(a0.readyState===4||bg==="timeout")){a1=true;a0.onreadystatechange=a.noop;a8=bg==="timeout"?"timeout":!a.httpSuccess(a0)?"error":a4.ifModified&&a.httpNotModified(a0,a4.url)?"notmodified":"success";var bi;if(a8==="success"){try{bd=a.httpData(a0,a4.dataType,a4)}catch(bh){a8="parsererror";bi=bh}}if(a8==="success"||a8==="notmodified"){if(!be){aZ()}}else{a.handleError(a4,a0,a8,bi)}a2();if(bg==="timeout"){a0.abort()}if(a4.async){a0=null}}}};try{var aV=a0.abort;a0.abort=function(){if(a0){aV.call(a0)}a3("abort")}}catch(ba){}if(a4.async&&a4.timeout>0){setTimeout(function(){if(a0&&!a1){a3("timeout")}},a4.timeout)}try{a0.send(aW==="POST"||aW==="PUT"||aW==="DELETE"?a4.data:null)}catch(ba){a.handleError(a4,a0,null,ba);a2()}if(!a4.async){a3()}function aZ(){if(a4.success){a4.success.call(bf,bd,a8,a0)}if(a4.global){a5("ajaxSuccess",[a0,a4])}}function a2(){if(a4.complete){a4.complete.call(bf,a0,a8)}if(a4.global){a5("ajaxComplete",[a0,a4])}if(a4.global&&!--a.active){a.event.trigger("ajaxStop")}}function a5(bh,bg){(a4.context?a(a4.context):a.event).trigger(bh,bg)}return a0},handleError:function(aV,aX,aU,aW){if(aV.error){aV.error.call(aV.context||aV,aX,aU,aW)}if(aV.global){(aV.context?a(aV.context):a.event).trigger("ajaxError",[aX,aV,aW])}},active:0,httpSuccess:function(aV){try{return !aV.status&&location.protocol==="file:"||(aV.status>=200&&aV.status<300)||aV.status===304||aV.status===1223||aV.status===0}catch(aU){}return false},httpNotModified:function(aX,aU){var aW=aX.getResponseHeader("Last-Modified"),aV=aX.getResponseHeader("Etag");if(aW){a.lastModified[aU]=aW}if(aV){a.etag[aU]=aV}return aX.status===304||aX.status===0},httpData:function(aZ,aX,aW){var aV=aZ.getResponseHeader("content-type")||"",aU=aX==="xml"||!aX&&aV.indexOf("xml")>=0,aY=aU?aZ.responseXML:aZ.responseText;if(aU&&aY.documentElement.nodeName==="parsererror"){a.error("parsererror")}if(aW&&aW.dataFilter){aY=aW.dataFilter(aY,aX)}if(typeof aY==="string"){if(aX==="json"||!aX&&aV.indexOf("json")>=0){aY=a.parseJSON(aY)}else{if(aX==="script"||!aX&&aV.indexOf("javascript")>=0){a.globalEval(aY)}}}return aY},param:function(aU,aX){var aV=[];if(aX===B){aX=a.ajaxSettings.traditional}if(a.isArray(aU)||aU.jquery){a.each(aU,function(){aZ(this.name,this.value)})}else{for(var aY in aU){aW(aY,aU[aY])}}return aV.join("&").replace(h,"+");function aW(a0,a1){if(a.isArray(a1)){a.each(a1,function(a3,a2){if(aX){aZ(a0,a2)}else{aW(a0+"["+(typeof a2==="object"||a.isArray(a2)?a3:"")+"]",a2)}})}else{if(!aX&&a1!=null&&typeof a1==="object"){a.each(a1,function(a3,a2){aW(a0+"["+a3+"]",a2)})}else{aZ(a0,a1)}}}function aZ(a0,a1){a1=a.isFunction(a1)?a1():a1;aV[aV.length]=encodeURIComponent(a0)+"="+encodeURIComponent(a1)}}});var E={},ad=/toggle|show|hide/,ar=/^([+-]=)?([\d+-.]+)(.*)$/,aB,ah=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];a.fn.extend({show:function(aV,a3){if(aV||aV===0){return this.animate(az("show",3),aV,a3)}else{for(var a0=0,aX=this.length;a0<aX;a0++){var aU=a.data(this[a0],"olddisplay");this[a0].style.display=aU||"";if(a.css(this[a0],"display")==="none"){var a2=this[a0].nodeName,a1;if(E[a2]){a1=E[a2]}else{var aW=a("<"+a2+" />").appendTo("body");a1=aW.css("display");if(a1==="none"){a1="block"}aW.remove();E[a2]=a1}a.data(this[a0],"olddisplay",a1)}}for(var aZ=0,aY=this.length;aZ<aY;aZ++){this[aZ].style.display=a.data(this[aZ],"olddisplay")||""}return this}},hide:function(aZ,a0){if(aZ||aZ===0){return this.animate(az("hide",3),aZ,a0)}else{for(var aY=0,aV=this.length;aY<aV;aY++){var aU=a.data(this[aY],"olddisplay");if(!aU&&aU!=="none"){a.data(this[aY],"olddisplay",a.css(this[aY],"display"))}}for(var aX=0,aW=this.length;aX<aW;aX++){this[aX].style.display="none"}return this}},_toggle:a.fn.toggle,toggle:function(aW,aV){var aU=typeof aW==="boolean";if(a.isFunction(aW)&&a.isFunction(aV)){this._toggle.apply(this,arguments)}else{if(aW==null||aU){this.each(function(){var aX=aU?aW:a(this).is(":hidden");a(this)[aX?"show":"hide"]()})}else{this.animate(az("toggle",3),aW,aV)}}return this},fadeTo:function(aU,aW,aV){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:aW},aU,aV)},animate:function(aY,aV,aX,aW){var aU=a.speed(aV,aX,aW);if(a.isEmptyObject(aY)){return this.each(aU.complete)}return this[aU.queue===false?"each":"queue"](function(){var a1=a.extend({},aU),a3,a2=this.nodeType===1&&a(this).is(":hidden"),aZ=this;for(a3 in aY){var a0=a3.replace(aw,k);if(a3!==a0){aY[a0]=aY[a3];delete aY[a3];a3=a0}if(aY[a3]==="hide"&&a2||aY[a3]==="show"&&!a2){return a1.complete.call(this)}if((a3==="height"||a3==="width")&&this.style){a1.display=a.css(this,"display");a1.overflow=this.style.overflow}if(a.isArray(aY[a3])){(a1.specialEasing=a1.specialEasing||{})[a3]=aY[a3][1];aY[a3]=aY[a3][0]}}if(a1.overflow!=null){this.style.overflow="hidden"}a1.curAnim=a.extend({},aY);a.each(aY,function(a5,a9){var a8=new a.fx(aZ,a1,a5);if(ad.test(a9)){a8[a9==="toggle"?a2?"show":"hide":a9](aY)}else{var a7=ar.exec(a9),ba=a8.cur(true)||0;if(a7){var a4=parseFloat(a7[2]),a6=a7[3]||"px";if(a6!=="px"){aZ.style[a5]=(a4||1)+a6;ba=((a4||1)/a8.cur(true))*ba;aZ.style[a5]=ba+a6}if(a7[1]){a4=((a7[1]==="-="?-1:1)*a4)+ba}a8.custom(ba,a4,a6)}else{a8.custom(ba,a9,"")}}});return true})},stop:function(aV,aU){var aW=a.timers;if(aV){this.queue([])}this.each(function(){for(var aX=aW.length-1;aX>=0;aX--){if(aW[aX].elem===this){if(aU){aW[aX](true)}aW.splice(aX,1)}}});if(!aU){this.dequeue()}return this}});a.each({slideDown:az("show",1),slideUp:az("hide",1),slideToggle:az("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(aU,aV){a.fn[aU]=function(aW,aX){return this.animate(aV,aW,aX)}});a.extend({speed:function(aW,aX,aV){var aU=aW&&typeof aW==="object"?aW:{complete:aV||!aV&&aX||a.isFunction(aW)&&aW,duration:aW,easing:aV&&aX||aX&&!a.isFunction(aX)&&aX};aU.duration=a.fx.off?0:typeof aU.duration==="number"?aU.duration:a.fx.speeds[aU.duration]||a.fx.speeds._default;aU.old=aU.complete;aU.complete=function(){if(aU.queue!==false){a(this).dequeue()}if(a.isFunction(aU.old)){aU.old.call(this)}};return aU},easing:{linear:function(aW,aX,aU,aV){return aU+aV*aW},swing:function(aW,aX,aU,aV){return((-Math.cos(aW*Math.PI)/2)+0.5)*aV+aU}},timers:[],fx:function(aV,aU,aW){this.options=aU;this.elem=aV;this.prop=aW;if(!aU.orig){aU.orig={}}}});a.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(a.fx.step[this.prop]||a.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(aV){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var aU=parseFloat(a.css(this.elem,this.prop,aV));return aU&&aU>-10000?aU:parseFloat(a.curCSS(this.elem,this.prop))||0},custom:function(aY,aX,aW){this.startTime=aL();this.start=aY;this.end=aX;this.unit=aW||this.unit||"px";this.now=this.start;this.pos=this.state=0;var aU=this;function aV(aZ){return aU.step(aZ)}aV.elem=this.elem;if(aV()&&a.timers.push(aV)&&!aB){aB=setInterval(a.fx.tick,13)}},show:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());a(this.elem).show()},hide:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(aX){var a2=aL(),aY=true;if(aX||a2>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var aZ in this.options.curAnim){if(this.options.curAnim[aZ]!==true){aY=false}}if(aY){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;var aW=a.data(this.elem,"olddisplay");this.elem.style.display=aW?aW:this.options.display;if(a.css(this.elem,"display")==="none"){this.elem.style.display="block"}}if(this.options.hide){a(this.elem).hide()}if(this.options.hide||this.options.show){for(var aU in this.options.curAnim){a.style(this.elem,aU,this.options.orig[aU])}}this.options.complete.call(this.elem)}return false}else{var aV=a2-this.startTime;this.state=aV/this.options.duration;var a0=this.options.specialEasing&&this.options.specialEasing[this.prop];var a1=this.options.easing||(a.easing.swing?"swing":"linear");this.pos=a.easing[a0||a1](this.state,aV,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};a.extend(a.fx,{tick:function(){var aV=a.timers;for(var aU=0;aU<aV.length;aU++){if(!aV[aU]()){aV.splice(aU--,1)}}if(!aV.length){a.fx.stop()}},stop:function(){clearInterval(aB);aB=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(aU){a.style(aU.elem,"opacity",aU.now)},_default:function(aU){if(aU.elem.style&&aU.elem.style[aU.prop]!=null){aU.elem.style[aU.prop]=(aU.prop==="width"||aU.prop==="height"?Math.max(0,aU.now):aU.now)+aU.unit}else{aU.elem[aU.prop]=aU.now}}}});if(a.expr&&a.expr.filters){a.expr.filters.animated=function(aU){return a.grep(a.timers,function(aV){return aU===aV.elem}).length}}function az(aV,aU){var aW={};a.each(ah.concat.apply([],ah.slice(0,aU)),function(){aW[this]=aV});return aW}if("getBoundingClientRect" in aa.documentElement){a.fn.offset=function(a3){var aW=this[0];if(a3){return this.each(function(a4){a.offset.setOffset(this,a3,a4)})}if(!aW||!aW.ownerDocument){return null}if(aW===aW.ownerDocument.body){return a.offset.bodyOffset(aW)}var aY=aW.getBoundingClientRect(),a2=aW.ownerDocument,aZ=a2.body,aU=a2.documentElement,aX=aU.clientTop||aZ.clientTop||0,a0=aU.clientLeft||aZ.clientLeft||0,a1=aY.top+(self.pageYOffset||a.support.boxModel&&aU.scrollTop||aZ.scrollTop)-aX,aV=aY.left+(self.pageXOffset||a.support.boxModel&&aU.scrollLeft||aZ.scrollLeft)-a0;return{top:a1,left:aV}}}else{a.fn.offset=function(a5){var aZ=this[0];if(a5){return this.each(function(a6){a.offset.setOffset(this,a5,a6)})}if(!aZ||!aZ.ownerDocument){return null}if(aZ===aZ.ownerDocument.body){return a.offset.bodyOffset(aZ)}a.offset.initialize();var aW=aZ.offsetParent,aV=aZ,a4=aZ.ownerDocument,a2,aX=a4.documentElement,a0=a4.body,a1=a4.defaultView,aU=a1?a1.getComputedStyle(aZ,null):aZ.currentStyle,a3=aZ.offsetTop,aY=aZ.offsetLeft;while((aZ=aZ.parentNode)&&aZ!==a0&&aZ!==aX){if(a.offset.supportsFixedPosition&&aU.position==="fixed"){break}a2=a1?a1.getComputedStyle(aZ,null):aZ.currentStyle;a3-=aZ.scrollTop;aY-=aZ.scrollLeft;if(aZ===aW){a3+=aZ.offsetTop;aY+=aZ.offsetLeft;if(a.offset.doesNotAddBorder&&!(a.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(aZ.nodeName))){a3+=parseFloat(a2.borderTopWidth)||0;aY+=parseFloat(a2.borderLeftWidth)||0}aV=aW,aW=aZ.offsetParent}if(a.offset.subtractsBorderForOverflowNotVisible&&a2.overflow!=="visible"){a3+=parseFloat(a2.borderTopWidth)||0;aY+=parseFloat(a2.borderLeftWidth)||0}aU=a2}if(aU.position==="relative"||aU.position==="static"){a3+=a0.offsetTop;aY+=a0.offsetLeft}if(a.offset.supportsFixedPosition&&aU.position==="fixed"){a3+=Math.max(aX.scrollTop,a0.scrollTop);aY+=Math.max(aX.scrollLeft,a0.scrollLeft)}return{top:a3,left:aY}}}a.offset={initialize:function(){var aU=aa.body,aV=aa.createElement("div"),aY,a0,aZ,a1,aW=parseFloat(a.curCSS(aU,"marginTop",true))||0,aX="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.extend(aV.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});aV.innerHTML=aX;aU.insertBefore(aV,aU.firstChild);aY=aV.firstChild;a0=aY.firstChild;a1=aY.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(a0.offsetTop!==5);this.doesAddBorderForTableAndCells=(a1.offsetTop===5);a0.style.position="fixed",a0.style.top="20px";this.supportsFixedPosition=(a0.offsetTop===20||a0.offsetTop===15);a0.style.position=a0.style.top="";aY.style.overflow="hidden",aY.style.position="relative";this.subtractsBorderForOverflowNotVisible=(a0.offsetTop===-5);this.doesNotIncludeMarginInBodyOffset=(aU.offsetTop!==aW);aU.removeChild(aV);aU=aV=aY=a0=aZ=a1=null;a.offset.initialize=a.noop},bodyOffset:function(aU){var aW=aU.offsetTop,aV=aU.offsetLeft;a.offset.initialize();if(a.offset.doesNotIncludeMarginInBodyOffset){aW+=parseFloat(a.curCSS(aU,"marginTop",true))||0;aV+=parseFloat(a.curCSS(aU,"marginLeft",true))||0}return{top:aW,left:aV}},setOffset:function(aZ,aV,aW){if(/static/.test(a.curCSS(aZ,"position"))){aZ.style.position="relative"}var aY=a(aZ),a1=aY.offset(),aU=parseInt(a.curCSS(aZ,"top",true),10)||0,a0=parseInt(a.curCSS(aZ,"left",true),10)||0;if(a.isFunction(aV)){aV=aV.call(aZ,aW,a1)}var aX={top:(aV.top-a1.top)+aU,left:(aV.left-a1.left)+a0};if("using" in aV){aV.using.call(aZ,aX)}else{aY.css(aX)}}};a.fn.extend({position:function(){if(!this[0]){return null}var aW=this[0],aV=this.offsetParent(),aX=this.offset(),aU=/^body|html$/i.test(aV[0].nodeName)?{top:0,left:0}:aV.offset();aX.top-=parseFloat(a.curCSS(aW,"marginTop",true))||0;aX.left-=parseFloat(a.curCSS(aW,"marginLeft",true))||0;aU.top+=parseFloat(a.curCSS(aV[0],"borderTopWidth",true))||0;aU.left+=parseFloat(a.curCSS(aV[0],"borderLeftWidth",true))||0;return{top:aX.top-aU.top,left:aX.left-aU.left}},offsetParent:function(){return this.map(function(){var aU=this.offsetParent||aa.body;while(aU&&(!/^body|html$/i.test(aU.nodeName)&&a.css(aU,"position")==="static")){aU=aU.offsetParent}return aU})}});a.each(["Left","Top"],function(aV,aU){var aW="scroll"+aU;a.fn[aW]=function(aZ){var aX=this[0],aY;if(!aX){return null}if(aZ!==B){return this.each(function(){aY=ak(this);if(aY){aY.scrollTo(!aV?aZ:a(aY).scrollLeft(),aV?aZ:a(aY).scrollTop())}else{this[aW]=aZ}})}else{aY=ak(aX);return aY?("pageXOffset" in aY)?aY[aV?"pageYOffset":"pageXOffset"]:a.support.boxModel&&aY.document.documentElement[aW]||aY.document.body[aW]:aX[aW]}}});function ak(aU){return("scrollTo" in aU&&aU.document)?aU:aU.nodeType===9?aU.defaultView||aU.parentWindow:false}a.each(["Height","Width"],function(aV,aU){var aW=aU.toLowerCase();a.fn["inner"+aU]=function(){return this[0]?a.css(this[0],aW,false,"padding"):null};a.fn["outer"+aU]=function(aX){return this[0]?a.css(this[0],aW,false,aX?"margin":"border"):null};a.fn[aW]=function(aX){var aY=this[0];if(!aY){return aX==null?null:this}if(a.isFunction(aX)){return this.each(function(a0){var aZ=a(this);aZ[aW](aX.call(this,a0,aZ[aW]()))})}return("scrollTo" in aY&&aY.document)?aY.document.compatMode==="CSS1Compat"&&aY.document.documentElement["client"+aU]||aY.document.body["client"+aU]:(aY.nodeType===9)?Math.max(aY.documentElement["client"+aU],aY.body["scroll"+aU],aY.documentElement["scroll"+aU],aY.body["offset"+aU],aY.documentElement["offset"+aU]):aX===B?a.css(aY,aW):this.css(aW,typeof aX==="string"?aX:aX+"px")}});aI.jQuery=aI.$=a})(window);window.djdt=(function(b,a,e){e.cookie=function(h,p,s){if(typeof p!="undefined"){s=s||{};if(p===null){p="";s.expires=-1}var l="";if(s.expires&&(typeof s.expires=="number"||s.expires.toUTCString)){var m;if(typeof s.expires=="number"){m=new Date();m.setTime(m.getTime()+(s.expires*24*60*60*1000))}else{m=s.expires}l="; expires="+m.toUTCString()}var r=s.path?"; path="+(s.path):"";var n=s.domain?"; domain="+(s.domain):"";var g=s.secure?"; secure":"";a.cookie=[h,"=",encodeURIComponent(p),l,r,n,g].join("")}else{var k=null;if(a.cookie&&a.cookie!=""){var q=a.cookie.split(";");for(var o=0;o<q.length;o++){var j=c.trim(q[o]);if(j.substring(0,h.length+1)==(h+"=")){k=decodeURIComponent(j.substring(h.length+1));break}}}return k}};var c=e;var f="djdt";var d={jQuery:e,events:{ready:[]},isReady:false,init:function(){c("#djDebug").show();var i=null;c("#djDebugPanelList li a").click(function(){if(!this.className){return false}i=c("#djDebug #"+this.className);if(i.is(":visible")){c(a).trigger("close.djDebug");c(this).parent().removeClass("active")}else{c(".panelContent").hide();i.show();c("#djDebugToolbar li").removeClass("active");c(this).parent().addClass("active")}return false});c("#djDebug a.djDebugClose").click(function(){c(a).trigger("close.djDebug");c("#djDebugToolbar li").removeClass("active");return false});c("#djDebug a.remoteCall").click(function(){c("#djDebugWindow").load(this.href,function(k,j,m){if(j=="error"){var l='<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+m.status+": "+m.statusText+"</h3></div>";c("#djDebugWindow").html(l)}c("#djDebugWindow a.djDebugBack").click(function(){c(this).parent().parent().hide();return false})});c("#djDebugWindow").show();return false});c("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){d.toggle_arrow(c(this).children(".toggleArrow"));d.toggle_content(c(this).parent().next());return false});c("#djDebug a.djToggleSwitch").click(function(l){l.preventDefault();var j=c(this);var m=j.attr("data-toggle-id");var k=j.text()==j.attr("data-toggle-open");if(m==""||!m){return}c(this).parents(".djDebugPanelContent").find(".djToggleDetails_"+m).each(function(){var n=c(this);if(k){n.addClass("djSelected");n.removeClass("djUnselected");j.text(j.attr("data-toggle-close"));n.find(".djToggleSwitch").text(j.text())}else{n.removeClass("djSelected");n.addClass("djUnselected");j.text(j.attr("data-toggle-open"));n.find(".djToggleSwitch").text(j.text())}});return});function g(j){id=j.attr("id");return c('.djDebugProfileRow[id^="'+id+'_"]')}function h(j){subcalls=g(j);depth=parseInt(j.attr("depth"))+1;return subcalls.filter("[depth="+depth+"]")}c(".djDebugProfileRow .djDebugProfileToggle").click(function(){row=c(this).closest(".djDebugProfileRow");subcalls=g(row);if(subcalls.css("display")=="none"){h(row).show()}else{subcalls.hide()}});c("#djHideToolBarButton").click(function(){d.hide_toolbar(true);return false});c("#djShowToolBarButton").click(function(){d.show_toolbar();return false});c(a).bind("close.djDebug",function(){if(c("#djDebugWindow").is(":visible")){c("#djDebugWindow").hide();return}if(c(".panelContent").is(":visible")){c(".panelContent").hide();return}if(c("#djDebugToolbar").is(":visible")){d.hide_toolbar(true);return}});if(c.cookie(f)){d.hide_toolbar(false)}else{d.show_toolbar(false)}c("#djDebug .djDebugHoverable").hover(function(){c(this).addClass("djDebugHover")},function(){c(this).removeClass("djDebugHover")});d.isReady=true;c.each(d.events.ready,function(j,k){k(d)})},toggle_content:function(g){if(g.is(":visible")){g.hide()}else{g.show()}},close:function(){c(a).trigger("close.djDebug");return false},hide_toolbar:function(g){c("#djDebugWindow").hide();c(".panelContent").hide();c("#djDebugToolbar li").removeClass("active");c("#djDebugToolbar").hide("fast");c("#djDebugToolbarHandle").show();c(a).unbind("keydown.djDebug");if(g){c.cookie(f,"hide",{path:"/",expires:10})}},show_toolbar:function(g){c(a).bind("keydown.djDebug",function(h){if(h.keyCode==27){d.close()}});c("#djDebugToolbarHandle").hide();if(g){c("#djDebugToolbar").show("fast")}else{c("#djDebugToolbar").show()}c.cookie(f,null,{path:"/",expires:-1})},toggle_arrow:function(h){var g=String.fromCharCode(9654);var i=String.fromCharCode(9660);h.html(h.html()==g?i:g)},ready:function(g){if(d.isReady){g(d)}else{d.events.ready.push(g)}}};c(a).ready(function(){d.init()});return d}(window,document,jQuery.noConflict()));
\ No newline at end of file +}(function(){var a5=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,a6=0,a8=Object.prototype.toString,a0=false,aZ=true;[0,0].sort(function(){aZ=false;return 0});var aW=function(bh,bc,bk,bl){bk=bk||[];var bn=bc=bc||aa;if(bc.nodeType!==1&&bc.nodeType!==9){return[]}if(!bh||typeof bh!=="string"){return bk}var bi=[],be,bp,bs,bd,bg=true,bf=aX(bc),bm=bh;while((a5.exec(""),be=a5.exec(bm))!==null){bm=be[3];bi.push(be[1]);if(be[2]){bd=be[3];break}}if(bi.length>1&&a1.exec(bh)){if(bi.length===2&&a2.relative[bi[0]]){bp=a9(bi[0]+bi[1],bc)}else{bp=a2.relative[bi[0]]?[bc]:aW(bi.shift(),bc);while(bi.length){bh=bi.shift();if(a2.relative[bh]){bh+=bi.shift()}bp=a9(bh,bp)}}}else{if(!bl&&bi.length>1&&bc.nodeType===9&&!bf&&a2.match.ID.test(bi[0])&&!a2.match.ID.test(bi[bi.length-1])){var bo=aW.find(bi.shift(),bc,bf);bc=bo.expr?aW.filter(bo.expr,bo.set)[0]:bo.set[0]}if(bc){var bo=bl?{expr:bi.pop(),set:a4(bl)}:aW.find(bi.pop(),bi.length===1&&(bi[0]==="~"||bi[0]==="+")&&bc.parentNode?bc.parentNode:bc,bf);bp=bo.expr?aW.filter(bo.expr,bo.set):bo.set;if(bi.length>0){bs=a4(bp)}else{bg=false}while(bi.length){var br=bi.pop(),bq=br;if(!a2.relative[br]){br=""}else{bq=bi.pop()}if(bq==null){bq=bc}a2.relative[br](bs,bq,bf)}}else{bs=bi=[]}}if(!bs){bs=bp}if(!bs){aW.error(br||bh)}if(a8.call(bs)==="[object Array]"){if(!bg){bk.push.apply(bk,bs)}else{if(bc&&bc.nodeType===1){for(var bj=0;bs[bj]!=null;bj++){if(bs[bj]&&(bs[bj]===true||bs[bj].nodeType===1&&a3(bc,bs[bj]))){bk.push(bp[bj])}}}else{for(var bj=0;bs[bj]!=null;bj++){if(bs[bj]&&bs[bj].nodeType===1){bk.push(bp[bj])}}}}}else{a4(bs,bk)}if(bd){aW(bd,bn,bk,bl);aW.uniqueSort(bk)}return bk};aW.uniqueSort=function(bd){if(a7){a0=aZ;bd.sort(a7);if(a0){for(var bc=1;bc<bd.length;bc++){if(bd[bc]===bd[bc-1]){bd.splice(bc--,1)}}}}return bd};aW.matches=function(bc,bd){return aW(bc,null,null,bd)};aW.find=function(bj,bc,bk){var bi,bg;if(!bj){return[]}for(var bf=0,be=a2.order.length;bf<be;bf++){var bh=a2.order[bf],bg;if((bg=a2.leftMatch[bh].exec(bj))){var bd=bg[1];bg.splice(1,1);if(bd.substr(bd.length-1)!=="\\"){bg[1]=(bg[1]||"").replace(/\\/g,"");bi=a2.find[bh](bg,bc,bk);if(bi!=null){bj=bj.replace(a2.match[bh],"");break}}}}if(!bi){bi=bc.getElementsByTagName("*")}return{set:bi,expr:bj}};aW.filter=function(bn,bm,bq,bg){var be=bn,bs=[],bk=bm,bi,bc,bj=bm&&bm[0]&&aX(bm[0]);while(bn&&bm.length){for(var bl in a2.filter){if((bi=a2.leftMatch[bl].exec(bn))!=null&&bi[2]){var bd=a2.filter[bl],br,bp,bf=bi[1];bc=false;bi.splice(1,1);if(bf.substr(bf.length-1)==="\\"){continue}if(bk===bs){bs=[]}if(a2.preFilter[bl]){bi=a2.preFilter[bl](bi,bk,bq,bs,bg,bj);if(!bi){bc=br=true}else{if(bi===true){continue}}}if(bi){for(var bh=0;(bp=bk[bh])!=null;bh++){if(bp){br=bd(bp,bi,bh,bk);var bo=bg^!!br;if(bq&&br!=null){if(bo){bc=true}else{bk[bh]=false}}else{if(bo){bs.push(bp);bc=true}}}}}if(br!==B){if(!bq){bk=bs}bn=bn.replace(a2.match[bl],"");if(!bc){return[]}break}}}if(bn===be){if(bc==null){aW.error(bn)}else{break}}be=bn}return bk};aW.error=function(bc){throw"Syntax error, unrecognized expression: "+bc};var a2=aW.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(bc){return bc.getAttribute("href")}},relative:{"+":function(bi,bd){var bf=typeof bd==="string",bh=bf&&!/\W/.test(bd),bj=bf&&!bh;if(bh){bd=bd.toLowerCase()}for(var be=0,bc=bi.length,bg;be<bc;be++){if((bg=bi[be])){while((bg=bg.previousSibling)&&bg.nodeType!==1){}bi[be]=bj||bg&&bg.nodeName.toLowerCase()===bd?bg||false:bg===bd}}if(bj){aW.filter(bd,bi,true)}},">":function(bi,bd){var bg=typeof bd==="string";if(bg&&!/\W/.test(bd)){bd=bd.toLowerCase();for(var be=0,bc=bi.length;be<bc;be++){var bh=bi[be];if(bh){var bf=bh.parentNode;bi[be]=bf.nodeName.toLowerCase()===bd?bf:false}}}else{for(var be=0,bc=bi.length;be<bc;be++){var bh=bi[be];if(bh){bi[be]=bg?bh.parentNode:bh.parentNode===bd}}if(bg){aW.filter(bd,bi,true)}}},"":function(bf,bd,bh){var be=a6++,bc=ba;if(typeof bd==="string"&&!/\W/.test(bd)){var bg=bd=bd.toLowerCase();bc=aU}bc("parentNode",bd,be,bf,bg,bh)},"~":function(bf,bd,bh){var be=a6++,bc=ba;if(typeof bd==="string"&&!/\W/.test(bd)){var bg=bd=bd.toLowerCase();bc=aU}bc("previousSibling",bd,be,bf,bg,bh)}},find:{ID:function(bd,be,bf){if(typeof be.getElementById!=="undefined"&&!bf){var bc=be.getElementById(bd[1]);return bc?[bc]:[]}},NAME:function(be,bh){if(typeof bh.getElementsByName!=="undefined"){var bd=[],bg=bh.getElementsByName(be[1]);for(var bf=0,bc=bg.length;bf<bc;bf++){if(bg[bf].getAttribute("name")===be[1]){bd.push(bg[bf])}}return bd.length===0?null:bd}},TAG:function(bc,bd){return bd.getElementsByTagName(bc[1])}},preFilter:{CLASS:function(bf,bd,be,bc,bi,bj){bf=" "+bf[1].replace(/\\/g,"")+" ";if(bj){return bf}for(var bg=0,bh;(bh=bd[bg])!=null;bg++){if(bh){if(bi^(bh.className&&(" "+bh.className+" ").replace(/[\t\n]/g," ").indexOf(bf)>=0)){if(!be){bc.push(bh)}}else{if(be){bd[bg]=false}}}}return false},ID:function(bc){return bc[1].replace(/\\/g,"")},TAG:function(bd,bc){return bd[1].toLowerCase()},CHILD:function(bc){if(bc[1]==="nth"){var bd=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(bc[2]==="even"&&"2n"||bc[2]==="odd"&&"2n+1"||!/\D/.test(bc[2])&&"0n+"+bc[2]||bc[2]);bc[2]=(bd[1]+(bd[2]||1))-0;bc[3]=bd[3]-0}bc[0]=a6++;return bc},ATTR:function(bg,bd,be,bc,bh,bi){var bf=bg[1].replace(/\\/g,"");if(!bi&&a2.attrMap[bf]){bg[1]=a2.attrMap[bf]}if(bg[2]==="~="){bg[4]=" "+bg[4]+" "}return bg},PSEUDO:function(bg,bd,be,bc,bh){if(bg[1]==="not"){if((a5.exec(bg[3])||"").length>1||/^\w/.test(bg[3])){bg[3]=aW(bg[3],null,null,bd)}else{var bf=aW.filter(bg[3],bd,be,true^bh);if(!be){bc.push.apply(bc,bf)}return false}}else{if(a2.match.POS.test(bg[0])||a2.match.CHILD.test(bg[0])){return true}}return bg},POS:function(bc){bc.unshift(true);return bc}},filters:{enabled:function(bc){return bc.disabled===false&&bc.type!=="hidden"},disabled:function(bc){return bc.disabled===true},checked:function(bc){return bc.checked===true},selected:function(bc){bc.parentNode.selectedIndex;return bc.selected===true},parent:function(bc){return !!bc.firstChild},empty:function(bc){return !bc.firstChild},has:function(be,bd,bc){return !!aW(bc[3],be).length},header:function(bc){return/h\d/i.test(bc.nodeName)},text:function(bc){return"text"===bc.type},radio:function(bc){return"radio"===bc.type},checkbox:function(bc){return"checkbox"===bc.type},file:function(bc){return"file"===bc.type},password:function(bc){return"password"===bc.type},submit:function(bc){return"submit"===bc.type},image:function(bc){return"image"===bc.type},reset:function(bc){return"reset"===bc.type},button:function(bc){return"button"===bc.type||bc.nodeName.toLowerCase()==="button"},input:function(bc){return/input|select|textarea|button/i.test(bc.nodeName)}},setFilters:{first:function(bd,bc){return bc===0},last:function(be,bd,bc,bf){return bd===bf.length-1},even:function(bd,bc){return bc%2===0},odd:function(bd,bc){return bc%2===1},lt:function(be,bd,bc){return bd<bc[3]-0},gt:function(be,bd,bc){return bd>bc[3]-0},nth:function(be,bd,bc){return bc[3]-0===bd},eq:function(be,bd,bc){return bc[3]-0===bd}},filter:{PSEUDO:function(bi,be,bf,bj){var bd=be[1],bg=a2.filters[bd];if(bg){return bg(bi,bf,be,bj)}else{if(bd==="contains"){return(bi.textContent||bi.innerText||aV([bi])||"").indexOf(be[3])>=0}else{if(bd==="not"){var bh=be[3];for(var bf=0,bc=bh.length;bf<bc;bf++){if(bh[bf]===bi){return false}}return true}else{aW.error("Syntax error, unrecognized expression: "+bd)}}}},CHILD:function(bc,bf){var bi=bf[1],bd=bc;switch(bi){case"only":case"first":while((bd=bd.previousSibling)){if(bd.nodeType===1){return false}}if(bi==="first"){return true}bd=bc;case"last":while((bd=bd.nextSibling)){if(bd.nodeType===1){return false}}return true;case"nth":var be=bf[2],bl=bf[3];if(be===1&&bl===0){return true}var bh=bf[0],bk=bc.parentNode;if(bk&&(bk.sizcache!==bh||!bc.nodeIndex)){var bg=0;for(bd=bk.firstChild;bd;bd=bd.nextSibling){if(bd.nodeType===1){bd.nodeIndex=++bg}}bk.sizcache=bh}var bj=bc.nodeIndex-bl;if(be===0){return bj===0}else{return(bj%be===0&&bj/be>=0)}}},ID:function(bd,bc){return bd.nodeType===1&&bd.getAttribute("id")===bc},TAG:function(bd,bc){return(bc==="*"&&bd.nodeType===1)||bd.nodeName.toLowerCase()===bc},CLASS:function(bd,bc){return(" "+(bd.className||bd.getAttribute("class"))+" ").indexOf(bc)>-1},ATTR:function(bh,bf){var be=bf[1],bc=a2.attrHandle[be]?a2.attrHandle[be](bh):bh[be]!=null?bh[be]:bh.getAttribute(be),bi=bc+"",bg=bf[2],bd=bf[4];return bc==null?bg==="!=":bg==="="?bi===bd:bg==="*="?bi.indexOf(bd)>=0:bg==="~="?(" "+bi+" ").indexOf(bd)>=0:!bd?bi&&bc!==false:bg==="!="?bi!==bd:bg==="^="?bi.indexOf(bd)===0:bg==="$="?bi.substr(bi.length-bd.length)===bd:bg==="|="?bi===bd||bi.substr(0,bd.length+1)===bd+"-":false},POS:function(bg,bd,be,bh){var bc=bd[2],bf=a2.setFilters[bc];if(bf){return bf(bg,be,bd,bh)}}}};var a1=a2.match.POS;for(var aY in a2.match){a2.match[aY]=new RegExp(a2.match[aY].source+/(?![^\[]*\])(?![^\(]*\))/.source);a2.leftMatch[aY]=new RegExp(/(^(?:.|\r|\n)*?)/.source+a2.match[aY].source.replace(/\\(\d+)/g,function(bd,bc){return"\\"+(bc-0+1)}))}var a4=function(bd,bc){bd=Array.prototype.slice.call(bd,0);if(bc){bc.push.apply(bc,bd);return bc}return bd};try{Array.prototype.slice.call(aa.documentElement.childNodes,0)}catch(bb){a4=function(bg,bf){var bd=bf||[];if(a8.call(bg)==="[object Array]"){Array.prototype.push.apply(bd,bg)}else{if(typeof bg.length==="number"){for(var be=0,bc=bg.length;be<bc;be++){bd.push(bg[be])}}else{for(var be=0;bg[be];be++){bd.push(bg[be])}}}return bd}}var a7;if(aa.documentElement.compareDocumentPosition){a7=function(bd,bc){if(!bd.compareDocumentPosition||!bc.compareDocumentPosition){if(bd==bc){a0=true}return bd.compareDocumentPosition?-1:1}var be=bd.compareDocumentPosition(bc)&4?-1:bd===bc?0:1;if(be===0){a0=true}return be}}else{if("sourceIndex" in aa.documentElement){a7=function(bd,bc){if(!bd.sourceIndex||!bc.sourceIndex){if(bd==bc){a0=true}return bd.sourceIndex?-1:1}var be=bd.sourceIndex-bc.sourceIndex;if(be===0){a0=true}return be}}else{if(aa.createRange){a7=function(bf,bd){if(!bf.ownerDocument||!bd.ownerDocument){if(bf==bd){a0=true}return bf.ownerDocument?-1:1}var be=bf.ownerDocument.createRange(),bc=bd.ownerDocument.createRange();be.setStart(bf,0);be.setEnd(bf,0);bc.setStart(bd,0);bc.setEnd(bd,0);var bg=be.compareBoundaryPoints(Range.START_TO_END,bc);if(bg===0){a0=true}return bg}}}}function aV(bc){var bd="",bf;for(var be=0;bc[be];be++){bf=bc[be];if(bf.nodeType===3||bf.nodeType===4){bd+=bf.nodeValue}else{if(bf.nodeType!==8){bd+=aV(bf.childNodes)}}}return bd}(function(){var bd=aa.createElement("div"),be="script"+(new Date).getTime();bd.innerHTML="<a name='"+be+"'/>";var bc=aa.documentElement;bc.insertBefore(bd,bc.firstChild);if(aa.getElementById(be)){a2.find.ID=function(bg,bh,bi){if(typeof bh.getElementById!=="undefined"&&!bi){var bf=bh.getElementById(bg[1]);return bf?bf.id===bg[1]||typeof bf.getAttributeNode!=="undefined"&&bf.getAttributeNode("id").nodeValue===bg[1]?[bf]:B:[]}};a2.filter.ID=function(bh,bf){var bg=typeof bh.getAttributeNode!=="undefined"&&bh.getAttributeNode("id");return bh.nodeType===1&&bg&&bg.nodeValue===bf}}bc.removeChild(bd);bc=bd=null})();(function(){var bc=aa.createElement("div");bc.appendChild(aa.createComment(""));if(bc.getElementsByTagName("*").length>0){a2.find.TAG=function(bd,bh){var bg=bh.getElementsByTagName(bd[1]);if(bd[1]==="*"){var bf=[];for(var be=0;bg[be];be++){if(bg[be].nodeType===1){bf.push(bg[be])}}bg=bf}return bg}}bc.innerHTML="<a href='#'></a>";if(bc.firstChild&&typeof bc.firstChild.getAttribute!=="undefined"&&bc.firstChild.getAttribute("href")!=="#"){a2.attrHandle.href=function(bd){return bd.getAttribute("href",2)}}bc=null})();if(aa.querySelectorAll){(function(){var bc=aW,be=aa.createElement("div");be.innerHTML="<p class='TEST'></p>";if(be.querySelectorAll&&be.querySelectorAll(".TEST").length===0){return}aW=function(bi,bh,bf,bg){bh=bh||aa;if(!bg&&bh.nodeType===9&&!aX(bh)){try{return a4(bh.querySelectorAll(bi),bf)}catch(bj){}}return bc(bi,bh,bf,bg)};for(var bd in bc){aW[bd]=bc[bd]}be=null})()}(function(){var bc=aa.createElement("div");bc.innerHTML="<div class='test e'></div><div class='test'></div>";if(!bc.getElementsByClassName||bc.getElementsByClassName("e").length===0){return}bc.lastChild.className="e";if(bc.getElementsByClassName("e").length===1){return}a2.order.splice(1,0,"CLASS");a2.find.CLASS=function(bd,be,bf){if(typeof be.getElementsByClassName!=="undefined"&&!bf){return be.getElementsByClassName(bd[1])}};bc=null})();function aU(bd,bi,bh,bl,bj,bk){for(var bf=0,be=bl.length;bf<be;bf++){var bc=bl[bf];if(bc){bc=bc[bd];var bg=false;while(bc){if(bc.sizcache===bh){bg=bl[bc.sizset];break}if(bc.nodeType===1&&!bk){bc.sizcache=bh;bc.sizset=bf}if(bc.nodeName.toLowerCase()===bi){bg=bc;break}bc=bc[bd]}bl[bf]=bg}}}function ba(bd,bi,bh,bl,bj,bk){for(var bf=0,be=bl.length;bf<be;bf++){var bc=bl[bf];if(bc){bc=bc[bd];var bg=false;while(bc){if(bc.sizcache===bh){bg=bl[bc.sizset];break}if(bc.nodeType===1){if(!bk){bc.sizcache=bh;bc.sizset=bf}if(typeof bi!=="string"){if(bc===bi){bg=true;break}}else{if(aW.filter(bi,[bc]).length>0){bg=bc;break}}}bc=bc[bd]}bl[bf]=bg}}}var a3=aa.compareDocumentPosition?function(bd,bc){return bd.compareDocumentPosition(bc)&16}:function(bd,bc){return bd!==bc&&(bd.contains?bd.contains(bc):true)};var aX=function(bc){var bd=(bc?bc.ownerDocument||bc:0).documentElement;return bd?bd.nodeName!=="HTML":false};var a9=function(bc,bj){var bf=[],bg="",bh,be=bj.nodeType?[bj]:bj;while((bh=a2.match.PSEUDO.exec(bc))){bg+=bh[0];bc=bc.replace(a2.match.PSEUDO,"")}bc=a2.relative[bc]?bc+"*":bc;for(var bi=0,bd=be.length;bi<bd;bi++){aW(bc,be[bi],bf)}return aW.filter(bg,bf)};a.find=aW;a.expr=aW.selectors;a.expr[":"]=a.expr.filters;a.unique=aW.uniqueSort;a.getText=aV;a.isXMLDoc=aX;a.contains=a3;return;aI.Sizzle=aW})();var M=/Until$/,X=/^(?:parents|prevUntil|prevAll)/,aH=/,/,D=Array.prototype.slice;var ag=function(aX,aW,aU){if(a.isFunction(aW)){return a.grep(aX,function(aZ,aY){return !!aW.call(aZ,aY,aZ)===aU})}else{if(aW.nodeType){return a.grep(aX,function(aZ,aY){return(aZ===aW)===aU})}else{if(typeof aW==="string"){var aV=a.grep(aX,function(aY){return aY.nodeType===1});if(aS.test(aW)){return a.filter(aW,aV,!aU)}else{aW=a.filter(aW,aV)}}}}return a.grep(aX,function(aZ,aY){return(a.inArray(aZ,aW)>=0)===aU})};a.fn.extend({find:function(aU){var aW=this.pushStack("","find",aU),aZ=0;for(var aX=0,aV=this.length;aX<aV;aX++){aZ=aW.length;a.find(aU,this[aX],aW);if(aX>0){for(var a0=aZ;a0<aW.length;a0++){for(var aY=0;aY<aZ;aY++){if(aW[aY]===aW[a0]){aW.splice(a0--,1);break}}}}}return aW},has:function(aV){var aU=a(aV);return this.filter(function(){for(var aX=0,aW=aU.length;aX<aW;aX++){if(a.contains(this,aU[aX])){return true}}})},not:function(aU){return this.pushStack(ag(this,aU,false),"not",aU)},filter:function(aU){return this.pushStack(ag(this,aU,true),"filter",aU)},is:function(aU){return !!aU&&a.filter(aU,this).length>0},closest:function(a3,aU){if(a.isArray(a3)){var a0=[],a2=this[0],aZ,aY={},aW;if(a2&&a3.length){for(var aX=0,aV=a3.length;aX<aV;aX++){aW=a3[aX];if(!aY[aW]){aY[aW]=a.expr.match.POS.test(aW)?a(aW,aU||this.context):aW}}while(a2&&a2.ownerDocument&&a2!==aU){for(aW in aY){aZ=aY[aW];if(aZ.jquery?aZ.index(a2)>-1:a(a2).is(aZ)){a0.push({selector:aW,elem:a2});delete aY[aW]}}a2=a2.parentNode}}return a0}var a1=a.expr.match.POS.test(a3)?a(a3,aU||this.context):null;return this.map(function(a4,a5){while(a5&&a5.ownerDocument&&a5!==aU){if(a1?a1.index(a5)>-1:a(a5).is(a3)){return a5}a5=a5.parentNode}return null})},index:function(aU){if(!aU||typeof aU==="string"){return a.inArray(this[0],aU?a(aU):this.parent().children())}return a.inArray(aU.jquery?aU[0]:aU,this)},add:function(aU,aV){var aX=typeof aU==="string"?a(aU,aV||this.context):a.makeArray(aU),aW=a.merge(this.get(),aX);return this.pushStack(x(aX[0])||x(aW[0])?aW:a.unique(aW))},andSelf:function(){return this.add(this.prevObject)}});function x(aU){return !aU||!aU.parentNode||aU.parentNode.nodeType===11}a.each({parent:function(aV){var aU=aV.parentNode;return aU&&aU.nodeType!==11?aU:null},parents:function(aU){return a.dir(aU,"parentNode")},parentsUntil:function(aV,aU,aW){return a.dir(aV,"parentNode",aW)},next:function(aU){return a.nth(aU,2,"nextSibling")},prev:function(aU){return a.nth(aU,2,"previousSibling")},nextAll:function(aU){return a.dir(aU,"nextSibling")},prevAll:function(aU){return a.dir(aU,"previousSibling")},nextUntil:function(aV,aU,aW){return a.dir(aV,"nextSibling",aW)},prevUntil:function(aV,aU,aW){return a.dir(aV,"previousSibling",aW)},siblings:function(aU){return a.sibling(aU.parentNode.firstChild,aU)},children:function(aU){return a.sibling(aU.firstChild)},contents:function(aU){return a.nodeName(aU,"iframe")?aU.contentDocument||aU.contentWindow.document:a.makeArray(aU.childNodes)}},function(aU,aV){a.fn[aU]=function(aY,aW){var aX=a.map(this,aV,aY);if(!M.test(aU)){aW=aY}if(aW&&typeof aW==="string"){aX=a.filter(aW,aX)}aX=this.length>1?a.unique(aX):aX;if((this.length>1||aH.test(aW))&&X.test(aU)){aX=aX.reverse()}return this.pushStack(aX,aU,D.call(arguments).join(","))}});a.extend({filter:function(aW,aU,aV){if(aV){aW=":not("+aW+")"}return a.find.matches(aW,aU)},dir:function(aW,aV,aY){var aU=[],aX=aW[aV];while(aX&&aX.nodeType!==9&&(aY===B||aX.nodeType!==1||!a(aX).is(aY))){if(aX.nodeType===1){aU.push(aX)}aX=aX[aV]}return aU},nth:function(aY,aU,aW,aX){aU=aU||1;var aV=0;for(;aY;aY=aY[aW]){if(aY.nodeType===1&&++aV===aU){break}}return aY},sibling:function(aW,aV){var aU=[];for(;aW;aW=aW.nextSibling){if(aW.nodeType===1&&aW!==aV){aU.push(aW)}}return aU}});var S=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,F=/(<([\w:]+)[^>]*?)\/>/g,aj=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,c=/<([\w:]+)/,t=/<tbody/i,J=/<|&\w+;/,l=/checked\s*(?:[^=]|=\s*.checked.)/i,p=function(aV,aW,aU){return aj.test(aU)?aV:aW+"></"+aU+">"},ab={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};ab.optgroup=ab.option;ab.tbody=ab.tfoot=ab.colgroup=ab.caption=ab.thead;ab.th=ab.td;if(!a.support.htmlSerialize){ab._default=[1,"div<div>","</div>"]}a.fn.extend({text:function(aU){if(a.isFunction(aU)){return this.each(function(aW){var aV=a(this);aV.text(aU.call(this,aW,aV.text()))})}if(typeof aU!=="object"&&aU!==B){return this.empty().append((this[0]&&this[0].ownerDocument||aa).createTextNode(aU))}return a.getText(this)},wrapAll:function(aU){if(a.isFunction(aU)){return this.each(function(aW){a(this).wrapAll(aU.call(this,aW))})}if(this[0]){var aV=a(aU,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){aV.insertBefore(this[0])}aV.map(function(){var aW=this;while(aW.firstChild&&aW.firstChild.nodeType===1){aW=aW.firstChild}return aW}).append(this)}return this},wrapInner:function(aU){if(a.isFunction(aU)){return this.each(function(aV){a(this).wrapInner(aU.call(this,aV))})}return this.each(function(){var aV=a(this),aW=aV.contents();if(aW.length){aW.wrapAll(aU)}else{aV.append(aU)}})},wrap:function(aU){return this.each(function(){a(this).wrapAll(aU)})},unwrap:function(){return this.parent().each(function(){if(!a.nodeName(this,"body")){a(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(aU){if(this.nodeType===1){this.appendChild(aU)}})},prepend:function(){return this.domManip(arguments,true,function(aU){if(this.nodeType===1){this.insertBefore(aU,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(aV){this.parentNode.insertBefore(aV,this)})}else{if(arguments.length){var aU=a(arguments[0]);aU.push.apply(aU,this.toArray());return this.pushStack(aU,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(aV){this.parentNode.insertBefore(aV,this.nextSibling)})}else{if(arguments.length){var aU=this.pushStack(this,"after",arguments);aU.push.apply(aU,a(arguments[0]).toArray());return aU}}},clone:function(aV){var aU=this.map(function(){if(!a.support.noCloneEvent&&!a.isXMLDoc(this)){var aX=this.outerHTML,aW=this.ownerDocument;if(!aX){var aY=aW.createElement("div");aY.appendChild(this.cloneNode(true));aX=aY.innerHTML}return a.clean([aX.replace(S,"").replace(Y,"")],aW)[0]}else{return this.cloneNode(true)}});if(aV===true){q(this,aU);q(this.find("*"),aU.find("*"))}return aU},html:function(aW){if(aW===B){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(S,""):null}else{if(typeof aW==="string"&&!/<script/i.test(aW)&&(a.support.leadingWhitespace||!Y.test(aW))&&!ab[(c.exec(aW)||["",""])[1].toLowerCase()]){aW=aW.replace(F,p);try{for(var aV=0,aU=this.length;aV<aU;aV++){if(this[aV].nodeType===1){a.cleanData(this[aV].getElementsByTagName("*"));this[aV].innerHTML=aW}}}catch(aX){this.empty().append(aW)}}else{if(a.isFunction(aW)){this.each(function(a0){var aZ=a(this),aY=aZ.html();aZ.empty().append(function(){return aW.call(this,a0,aY)})})}else{this.empty().append(aW)}}}return this},replaceWith:function(aU){if(this[0]&&this[0].parentNode){if(!a.isFunction(aU)){aU=a(aU).detach()}else{return this.each(function(aX){var aW=a(this),aV=aW.html();aW.replaceWith(aU.call(this,aX,aV))})}return this.each(function(){var aW=this.nextSibling,aV=this.parentNode;a(this).remove();if(aW){a(aW).before(aU)}else{a(aV).append(aU)}})}else{return this.pushStack(a(a.isFunction(aU)?aU():aU),"replaceWith",aU)}},detach:function(aU){return this.remove(aU,true)},domManip:function(aZ,a3,a2){var aW,aY,a1=aZ[0],aV=[];if(!a.support.checkClone&&arguments.length===3&&typeof a1==="string"&&l.test(a1)){return this.each(function(){a(this).domManip(aZ,a3,a2,true)})}if(a.isFunction(a1)){return this.each(function(a5){var a4=a(this);aZ[0]=a1.call(this,a5,a3?a4.html():B);a4.domManip(aZ,a3,a2)})}if(this[0]){if(aZ[0]&&aZ[0].parentNode&&aZ[0].parentNode.nodeType===11){aW={fragment:aZ[0].parentNode}}else{aW=H(aZ,this,aV)}aY=aW.fragment.firstChild;if(aY){a3=a3&&a.nodeName(aY,"tr");for(var aX=0,aU=this.length;aX<aU;aX++){a2.call(a3?a0(this[aX],aY):this[aX],aW.cacheable||this.length>1||aX>0?aW.fragment.cloneNode(true):aW.fragment)}}if(aV){a.each(aV,aR)}}return this;function a0(a4,a5){return a.nodeName(a4,"table")?(a4.getElementsByTagName("tbody")[0]||a4.appendChild(a4.ownerDocument.createElement("tbody"))):a4}}});function q(aW,aU){var aV=0;aU.each(function(){if(this.nodeName!==(aW[aV]&&aW[aV].nodeName)){return}var a1=a.data(aW[aV++]),a0=a.data(this,a1),aX=a1&&a1.events;if(aX){delete a0.handle;a0.events={};for(var aZ in aX){for(var aY in aX[aZ]){a.event.add(this,aZ,aX[aZ][aY],aX[aZ][aY].data)}}}})}function H(aZ,aX,aV){var aY,aU,aW,a0;if(aZ.length===1&&typeof aZ[0]==="string"&&aZ[0].length<512&&aZ[0].indexOf("<option")<0&&(a.support.checkClone||!l.test(aZ[0]))){aU=true;aW=a.fragments[aZ[0]];if(aW){if(aW!==1){aY=aW}}}if(!aY){a0=(aX&&aX[0]?aX[0].ownerDocument||aX[0]:aa);aY=a0.createDocumentFragment();a.clean(aZ,a0,aY,aV)}if(aU){a.fragments[aZ[0]]=aW?aY:1}return{fragment:aY,cacheable:aU}}a.fragments={};a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(aU,aV){a.fn[aU]=function(aW){var aZ=[],a1=a(aW);for(var a0=0,aX=a1.length;a0<aX;a0++){var aY=(a0>0?this.clone(true):this).get();a.fn[aV].apply(a(a1[a0]),aY);aZ=aZ.concat(aY)}return this.pushStack(aZ,aU,a1.selector)}});a.each({remove:function(aU,aV){if(!aU||a.filter(aU,[this]).length){if(!aV&&this.nodeType===1){a.cleanData(this.getElementsByTagName("*"));a.cleanData([this])}if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){if(this.nodeType===1){a.cleanData(this.getElementsByTagName("*"))}while(this.firstChild){this.removeChild(this.firstChild)}}},function(aU,aV){a.fn[aU]=function(){return this.each(aV,arguments)}});a.extend({clean:function(aV,aZ,aX,aU){aZ=aZ||aa;if(typeof aZ.createElement==="undefined"){aZ=aZ.ownerDocument||aZ[0]&&aZ[0].ownerDocument||aa}var aW=[];a.each(aV,function(a6,a3){if(typeof a3==="number"){a3+=""}if(!a3){return}if(typeof a3==="string"&&!J.test(a3)){a3=aZ.createTextNode(a3)}else{if(typeof a3==="string"){a3=a3.replace(F,p);var a8=(c.exec(a3)||["",""])[1].toLowerCase(),a2=ab[a8]||ab._default,a5=a2[0],a0=aZ.createElement("div");a0.innerHTML=a2[1]+a3+a2[2];while(a5--){a0=a0.lastChild}if(!a.support.tbody){var a1=t.test(a3),a7=a8==="table"&&!a1?a0.firstChild&&a0.firstChild.childNodes:a2[1]==="<table>"&&!a1?a0.childNodes:[];for(var a4=a7.length-1;a4>=0;--a4){if(a.nodeName(a7[a4],"tbody")&&!a7[a4].childNodes.length){a7[a4].parentNode.removeChild(a7[a4])}}}if(!a.support.leadingWhitespace&&Y.test(a3)){a0.insertBefore(aZ.createTextNode(Y.exec(a3)[0]),a0.firstChild)}a3=a.makeArray(a0.childNodes)}}if(a3.nodeType){aW.push(a3)}else{aW=a.merge(aW,a3)}});if(aX){for(var aY=0;aW[aY];aY++){if(aU&&a.nodeName(aW[aY],"script")&&(!aW[aY].type||aW[aY].type.toLowerCase()==="text/javascript")){aU.push(aW[aY].parentNode?aW[aY].parentNode.removeChild(aW[aY]):aW[aY])}else{if(aW[aY].nodeType===1){aW.splice.apply(aW,[aY+1,0].concat(a.makeArray(aW[aY].getElementsByTagName("script"))))}aX.appendChild(aW[aY])}}}return aW},cleanData:function(aU){for(var aV=0,aW,aX;(aW=aU[aV])!=null;aV++){a.event.remove(aW);a.removeData(aW)}}});var ap=/z-?index|font-?weight|opacity|zoom|line-?height/i,T=/alpha\([^)]*\)/,Z=/opacity=([^)]*)/,af=/float/i,aw=/-([a-z])/ig,v=/([A-Z])/g,aK=/^-?\d+(?:px)?$/i,aQ=/^-?\d/,aG={position:"absolute",visibility:"hidden",display:"block"},V=["Left","Right"],aA=["Top","Bottom"],ai=aa.defaultView&&aa.defaultView.getComputedStyle,aJ=a.support.cssFloat?"cssFloat":"styleFloat",k=function(aU,aV){return aV.toUpperCase()};a.fn.css=function(aU,aV){return al(this,aU,aV,true,function(aX,aW,aY){if(aY===B){return a.curCSS(aX,aW)}if(typeof aY==="number"&&!ap.test(aW)){aY+="px"}a.style(aX,aW,aY)})};a.extend({style:function(aY,aV,aZ){if(!aY||aY.nodeType===3||aY.nodeType===8){return B}if((aV==="width"||aV==="height")&&parseFloat(aZ)<0){aZ=B}var aX=aY.style||aY,a0=aZ!==B;if(!a.support.opacity&&aV==="opacity"){if(a0){aX.zoom=1;var aU=parseInt(aZ,10)+""==="NaN"?"":"alpha(opacity="+aZ*100+")";var aW=aX.filter||a.curCSS(aY,"filter")||"";aX.filter=T.test(aW)?aW.replace(T,aU):aU}return aX.filter&&aX.filter.indexOf("opacity=")>=0?(parseFloat(Z.exec(aX.filter)[1])/100)+"":""}if(af.test(aV)){aV=aJ}aV=aV.replace(aw,k);if(a0){aX[aV]=aZ}return aX[aV]},css:function(aX,aV,aZ,aU){if(aV==="width"||aV==="height"){var a1,aW=aG,a0=aV==="width"?V:aA;function aY(){a1=aV==="width"?aX.offsetWidth:aX.offsetHeight;if(aU==="border"){return}a.each(a0,function(){if(!aU){a1-=parseFloat(a.curCSS(aX,"padding"+this,true))||0}if(aU==="margin"){a1+=parseFloat(a.curCSS(aX,"margin"+this,true))||0}else{a1-=parseFloat(a.curCSS(aX,"border"+this+"Width",true))||0}})}if(aX.offsetWidth!==0){aY()}else{a.swap(aX,aW,aY)}return Math.max(0,Math.round(a1))}return a.curCSS(aX,aV,aZ)},curCSS:function(a0,aV,aW){var a3,aU=a0.style,aX;if(!a.support.opacity&&aV==="opacity"&&a0.currentStyle){a3=Z.test(a0.currentStyle.filter||"")?(parseFloat(RegExp.$1)/100)+"":"";return a3===""?"1":a3}if(af.test(aV)){aV=aJ}if(!aW&&aU&&aU[aV]){a3=aU[aV]}else{if(ai){if(af.test(aV)){aV="float"}aV=aV.replace(v,"-$1").toLowerCase();var a2=a0.ownerDocument.defaultView;if(!a2){return null}var a4=a2.getComputedStyle(a0,null);if(a4){a3=a4.getPropertyValue(aV)}if(aV==="opacity"&&a3===""){a3="1"}}else{if(a0.currentStyle){var aZ=aV.replace(aw,k);a3=a0.currentStyle[aV]||a0.currentStyle[aZ];if(!aK.test(a3)&&aQ.test(a3)){var aY=aU.left,a1=a0.runtimeStyle.left;a0.runtimeStyle.left=a0.currentStyle.left;aU.left=aZ==="fontSize"?"1em":(a3||0);a3=aU.pixelLeft+"px";aU.left=aY;a0.runtimeStyle.left=a1}}}}return a3},swap:function(aX,aW,aY){var aU={};for(var aV in aW){aU[aV]=aX.style[aV];aX.style[aV]=aW[aV]}aY.call(aX);for(var aV in aW){aX.style[aV]=aU[aV]}}});if(a.expr&&a.expr.filters){a.expr.filters.hidden=function(aX){var aV=aX.offsetWidth,aU=aX.offsetHeight,aW=aX.nodeName.toLowerCase()==="tr";return aV===0&&aU===0&&!aW?true:aV>0&&aU>0&&!aW?false:a.curCSS(aX,"display")==="none"};a.expr.filters.visible=function(aU){return !a.expr.filters.hidden(aU)}}var ae=aL(),aF=/<script(.|\s)*?\/script>/gi,o=/select|textarea/i,ay=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,r=/=\?(&|$)/,C=/\?/,aT=/(\?|&)_=.*?(&|$)/,A=/^(\w+:)?\/\/([^\/?#]+)/,h=/%20/g;a.fn.extend({_load:a.fn.load,load:function(aW,aZ,a0){if(typeof aW!=="string"){return this._load(aW)}else{if(!this.length){return this}}var aY=aW.indexOf(" ");if(aY>=0){var aU=aW.slice(aY,aW.length);aW=aW.slice(0,aY)}var aX="GET";if(aZ){if(a.isFunction(aZ)){a0=aZ;aZ=null}else{if(typeof aZ==="object"){aZ=a.param(aZ,a.ajaxSettings.traditional);aX="POST"}}}var aV=this;a.ajax({url:aW,type:aX,dataType:"html",data:aZ,complete:function(a2,a1){if(a1==="success"||a1==="notmodified"){aV.html(aU?a("<div />").append(a2.responseText.replace(aF,"")).find(aU):a2.responseText)}if(a0){aV.each(a0,[a2.responseText,a1,a2])}}});return this},serialize:function(){return a.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?a.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||o.test(this.nodeName)||ay.test(this.type))}).map(function(aU,aV){var aW=a(this).val();return aW==null?null:a.isArray(aW)?a.map(aW,function(aY,aX){return{name:aV.name,value:aY}}):{name:aV.name,value:aW}}).get()}});a.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(aU,aV){a.fn[aV]=function(aW){return this.bind(aV,aW)}});a.extend({get:function(aU,aW,aX,aV){if(a.isFunction(aW)){aV=aV||aX;aX=aW;aW=null}return a.ajax({type:"GET",url:aU,data:aW,success:aX,dataType:aV})},getScript:function(aU,aV){return a.get(aU,null,aV,"script")},getJSON:function(aU,aV,aW){return a.get(aU,aV,aW,"json")},post:function(aU,aW,aX,aV){if(a.isFunction(aW)){aV=aV||aX;aX=aW;aW={}}return a.ajax({type:"POST",url:aU,data:aW,success:aX,dataType:aV})},ajaxSetup:function(aU){a.extend(a.ajaxSettings,aU)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:aI.XMLHttpRequest&&(aI.location.protocol!=="file:"||!aI.ActiveXObject)?function(){return new aI.XMLHttpRequest()}:function(){try{return new aI.ActiveXObject("Microsoft.XMLHTTP")}catch(aU){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a9){var a4=a.extend(true,{},a.ajaxSettings,a9);var be,a8,bd,bf=a9&&a9.context||a4,aW=a4.type.toUpperCase();if(a4.data&&a4.processData&&typeof a4.data!=="string"){a4.data=a.param(a4.data,a4.traditional)}if(a4.dataType==="jsonp"){if(aW==="GET"){if(!r.test(a4.url)){a4.url+=(C.test(a4.url)?"&":"?")+(a4.jsonp||"callback")+"=?"}}else{if(!a4.data||!r.test(a4.data)){a4.data=(a4.data?a4.data+"&":"")+(a4.jsonp||"callback")+"=?"}}a4.dataType="json"}if(a4.dataType==="json"&&(a4.data&&r.test(a4.data)||r.test(a4.url))){be=a4.jsonpCallback||("jsonp"+ae++);if(a4.data){a4.data=(a4.data+"").replace(r,"="+be+"$1")}a4.url=a4.url.replace(r,"="+be+"$1");a4.dataType="script";aI[be]=aI[be]||function(bg){bd=bg;aZ();a2();aI[be]=B;try{delete aI[be]}catch(bh){}if(aX){aX.removeChild(bb)}}}if(a4.dataType==="script"&&a4.cache===null){a4.cache=false}if(a4.cache===false&&aW==="GET"){var aU=aL();var bc=a4.url.replace(aT,"$1_="+aU+"$2");a4.url=bc+((bc===a4.url)?(C.test(a4.url)?"&":"?")+"_="+aU:"")}if(a4.data&&aW==="GET"){a4.url+=(C.test(a4.url)?"&":"?")+a4.data}if(a4.global&&!a.active++){a.event.trigger("ajaxStart")}var a7=A.exec(a4.url),aY=a7&&(a7[1]&&a7[1]!==location.protocol||a7[2]!==location.host);if(a4.dataType==="script"&&aW==="GET"&&aY){var aX=aa.getElementsByTagName("head")[0]||aa.documentElement;var bb=aa.createElement("script");bb.src=a4.url;if(a4.scriptCharset){bb.charset=a4.scriptCharset}if(!be){var a6=false;bb.onload=bb.onreadystatechange=function(){if(!a6&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){a6=true;aZ();a2();bb.onload=bb.onreadystatechange=null;if(aX&&bb.parentNode){aX.removeChild(bb)}}}}aX.insertBefore(bb,aX.firstChild);return B}var a1=false;var a0=a4.xhr();if(!a0){return}if(a4.username){a0.open(aW,a4.url,a4.async,a4.username,a4.password)}else{a0.open(aW,a4.url,a4.async)}try{if(a4.data||a9&&a9.contentType){a0.setRequestHeader("Content-Type",a4.contentType)}if(a4.ifModified){if(a.lastModified[a4.url]){a0.setRequestHeader("If-Modified-Since",a.lastModified[a4.url])}if(a.etag[a4.url]){a0.setRequestHeader("If-None-Match",a.etag[a4.url])}}if(!aY){a0.setRequestHeader("X-Requested-With","XMLHttpRequest")}a0.setRequestHeader("Accept",a4.dataType&&a4.accepts[a4.dataType]?a4.accepts[a4.dataType]+", */*":a4.accepts._default)}catch(ba){}if(a4.beforeSend&&a4.beforeSend.call(bf,a0,a4)===false){if(a4.global&&!--a.active){a.event.trigger("ajaxStop")}a0.abort();return false}if(a4.global){a5("ajaxSend",[a0,a4])}var a3=a0.onreadystatechange=function(bg){if(!a0||a0.readyState===0||bg==="abort"){if(!a1){a2()}a1=true;if(a0){a0.onreadystatechange=a.noop}}else{if(!a1&&a0&&(a0.readyState===4||bg==="timeout")){a1=true;a0.onreadystatechange=a.noop;a8=bg==="timeout"?"timeout":!a.httpSuccess(a0)?"error":a4.ifModified&&a.httpNotModified(a0,a4.url)?"notmodified":"success";var bi;if(a8==="success"){try{bd=a.httpData(a0,a4.dataType,a4)}catch(bh){a8="parsererror";bi=bh}}if(a8==="success"||a8==="notmodified"){if(!be){aZ()}}else{a.handleError(a4,a0,a8,bi)}a2();if(bg==="timeout"){a0.abort()}if(a4.async){a0=null}}}};try{var aV=a0.abort;a0.abort=function(){if(a0){aV.call(a0)}a3("abort")}}catch(ba){}if(a4.async&&a4.timeout>0){setTimeout(function(){if(a0&&!a1){a3("timeout")}},a4.timeout)}try{a0.send(aW==="POST"||aW==="PUT"||aW==="DELETE"?a4.data:null)}catch(ba){a.handleError(a4,a0,null,ba);a2()}if(!a4.async){a3()}function aZ(){if(a4.success){a4.success.call(bf,bd,a8,a0)}if(a4.global){a5("ajaxSuccess",[a0,a4])}}function a2(){if(a4.complete){a4.complete.call(bf,a0,a8)}if(a4.global){a5("ajaxComplete",[a0,a4])}if(a4.global&&!--a.active){a.event.trigger("ajaxStop")}}function a5(bh,bg){(a4.context?a(a4.context):a.event).trigger(bh,bg)}return a0},handleError:function(aV,aX,aU,aW){if(aV.error){aV.error.call(aV.context||aV,aX,aU,aW)}if(aV.global){(aV.context?a(aV.context):a.event).trigger("ajaxError",[aX,aV,aW])}},active:0,httpSuccess:function(aV){try{return !aV.status&&location.protocol==="file:"||(aV.status>=200&&aV.status<300)||aV.status===304||aV.status===1223||aV.status===0}catch(aU){}return false},httpNotModified:function(aX,aU){var aW=aX.getResponseHeader("Last-Modified"),aV=aX.getResponseHeader("Etag");if(aW){a.lastModified[aU]=aW}if(aV){a.etag[aU]=aV}return aX.status===304||aX.status===0},httpData:function(aZ,aX,aW){var aV=aZ.getResponseHeader("content-type")||"",aU=aX==="xml"||!aX&&aV.indexOf("xml")>=0,aY=aU?aZ.responseXML:aZ.responseText;if(aU&&aY.documentElement.nodeName==="parsererror"){a.error("parsererror")}if(aW&&aW.dataFilter){aY=aW.dataFilter(aY,aX)}if(typeof aY==="string"){if(aX==="json"||!aX&&aV.indexOf("json")>=0){aY=a.parseJSON(aY)}else{if(aX==="script"||!aX&&aV.indexOf("javascript")>=0){a.globalEval(aY)}}}return aY},param:function(aU,aX){var aV=[];if(aX===B){aX=a.ajaxSettings.traditional}if(a.isArray(aU)||aU.jquery){a.each(aU,function(){aZ(this.name,this.value)})}else{for(var aY in aU){aW(aY,aU[aY])}}return aV.join("&").replace(h,"+");function aW(a0,a1){if(a.isArray(a1)){a.each(a1,function(a3,a2){if(aX){aZ(a0,a2)}else{aW(a0+"["+(typeof a2==="object"||a.isArray(a2)?a3:"")+"]",a2)}})}else{if(!aX&&a1!=null&&typeof a1==="object"){a.each(a1,function(a3,a2){aW(a0+"["+a3+"]",a2)})}else{aZ(a0,a1)}}}function aZ(a0,a1){a1=a.isFunction(a1)?a1():a1;aV[aV.length]=encodeURIComponent(a0)+"="+encodeURIComponent(a1)}}});var E={},ad=/toggle|show|hide/,ar=/^([+-]=)?([\d+-.]+)(.*)$/,aB,ah=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];a.fn.extend({show:function(aV,a3){if(aV||aV===0){return this.animate(az("show",3),aV,a3)}else{for(var a0=0,aX=this.length;a0<aX;a0++){var aU=a.data(this[a0],"olddisplay");this[a0].style.display=aU||"";if(a.css(this[a0],"display")==="none"){var a2=this[a0].nodeName,a1;if(E[a2]){a1=E[a2]}else{var aW=a("<"+a2+" />").appendTo("body");a1=aW.css("display");if(a1==="none"){a1="block"}aW.remove();E[a2]=a1}a.data(this[a0],"olddisplay",a1)}}for(var aZ=0,aY=this.length;aZ<aY;aZ++){this[aZ].style.display=a.data(this[aZ],"olddisplay")||""}return this}},hide:function(aZ,a0){if(aZ||aZ===0){return this.animate(az("hide",3),aZ,a0)}else{for(var aY=0,aV=this.length;aY<aV;aY++){var aU=a.data(this[aY],"olddisplay");if(!aU&&aU!=="none"){a.data(this[aY],"olddisplay",a.css(this[aY],"display"))}}for(var aX=0,aW=this.length;aX<aW;aX++){this[aX].style.display="none"}return this}},_toggle:a.fn.toggle,toggle:function(aW,aV){var aU=typeof aW==="boolean";if(a.isFunction(aW)&&a.isFunction(aV)){this._toggle.apply(this,arguments)}else{if(aW==null||aU){this.each(function(){var aX=aU?aW:a(this).is(":hidden");a(this)[aX?"show":"hide"]()})}else{this.animate(az("toggle",3),aW,aV)}}return this},fadeTo:function(aU,aW,aV){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:aW},aU,aV)},animate:function(aY,aV,aX,aW){var aU=a.speed(aV,aX,aW);if(a.isEmptyObject(aY)){return this.each(aU.complete)}return this[aU.queue===false?"each":"queue"](function(){var a1=a.extend({},aU),a3,a2=this.nodeType===1&&a(this).is(":hidden"),aZ=this;for(a3 in aY){var a0=a3.replace(aw,k);if(a3!==a0){aY[a0]=aY[a3];delete aY[a3];a3=a0}if(aY[a3]==="hide"&&a2||aY[a3]==="show"&&!a2){return a1.complete.call(this)}if((a3==="height"||a3==="width")&&this.style){a1.display=a.css(this,"display");a1.overflow=this.style.overflow}if(a.isArray(aY[a3])){(a1.specialEasing=a1.specialEasing||{})[a3]=aY[a3][1];aY[a3]=aY[a3][0]}}if(a1.overflow!=null){this.style.overflow="hidden"}a1.curAnim=a.extend({},aY);a.each(aY,function(a5,a9){var a8=new a.fx(aZ,a1,a5);if(ad.test(a9)){a8[a9==="toggle"?a2?"show":"hide":a9](aY)}else{var a7=ar.exec(a9),ba=a8.cur(true)||0;if(a7){var a4=parseFloat(a7[2]),a6=a7[3]||"px";if(a6!=="px"){aZ.style[a5]=(a4||1)+a6;ba=((a4||1)/a8.cur(true))*ba;aZ.style[a5]=ba+a6}if(a7[1]){a4=((a7[1]==="-="?-1:1)*a4)+ba}a8.custom(ba,a4,a6)}else{a8.custom(ba,a9,"")}}});return true})},stop:function(aV,aU){var aW=a.timers;if(aV){this.queue([])}this.each(function(){for(var aX=aW.length-1;aX>=0;aX--){if(aW[aX].elem===this){if(aU){aW[aX](true)}aW.splice(aX,1)}}});if(!aU){this.dequeue()}return this}});a.each({slideDown:az("show",1),slideUp:az("hide",1),slideToggle:az("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(aU,aV){a.fn[aU]=function(aW,aX){return this.animate(aV,aW,aX)}});a.extend({speed:function(aW,aX,aV){var aU=aW&&typeof aW==="object"?aW:{complete:aV||!aV&&aX||a.isFunction(aW)&&aW,duration:aW,easing:aV&&aX||aX&&!a.isFunction(aX)&&aX};aU.duration=a.fx.off?0:typeof aU.duration==="number"?aU.duration:a.fx.speeds[aU.duration]||a.fx.speeds._default;aU.old=aU.complete;aU.complete=function(){if(aU.queue!==false){a(this).dequeue()}if(a.isFunction(aU.old)){aU.old.call(this)}};return aU},easing:{linear:function(aW,aX,aU,aV){return aU+aV*aW},swing:function(aW,aX,aU,aV){return((-Math.cos(aW*Math.PI)/2)+0.5)*aV+aU}},timers:[],fx:function(aV,aU,aW){this.options=aU;this.elem=aV;this.prop=aW;if(!aU.orig){aU.orig={}}}});a.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(a.fx.step[this.prop]||a.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(aV){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var aU=parseFloat(a.css(this.elem,this.prop,aV));return aU&&aU>-10000?aU:parseFloat(a.curCSS(this.elem,this.prop))||0},custom:function(aY,aX,aW){this.startTime=aL();this.start=aY;this.end=aX;this.unit=aW||this.unit||"px";this.now=this.start;this.pos=this.state=0;var aU=this;function aV(aZ){return aU.step(aZ)}aV.elem=this.elem;if(aV()&&a.timers.push(aV)&&!aB){aB=setInterval(a.fx.tick,13)}},show:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());a(this.elem).show()},hide:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(aX){var a2=aL(),aY=true;if(aX||a2>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var aZ in this.options.curAnim){if(this.options.curAnim[aZ]!==true){aY=false}}if(aY){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;var aW=a.data(this.elem,"olddisplay");this.elem.style.display=aW?aW:this.options.display;if(a.css(this.elem,"display")==="none"){this.elem.style.display="block"}}if(this.options.hide){a(this.elem).hide()}if(this.options.hide||this.options.show){for(var aU in this.options.curAnim){a.style(this.elem,aU,this.options.orig[aU])}}this.options.complete.call(this.elem)}return false}else{var aV=a2-this.startTime;this.state=aV/this.options.duration;var a0=this.options.specialEasing&&this.options.specialEasing[this.prop];var a1=this.options.easing||(a.easing.swing?"swing":"linear");this.pos=a.easing[a0||a1](this.state,aV,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};a.extend(a.fx,{tick:function(){var aV=a.timers;for(var aU=0;aU<aV.length;aU++){if(!aV[aU]()){aV.splice(aU--,1)}}if(!aV.length){a.fx.stop()}},stop:function(){clearInterval(aB);aB=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(aU){a.style(aU.elem,"opacity",aU.now)},_default:function(aU){if(aU.elem.style&&aU.elem.style[aU.prop]!=null){aU.elem.style[aU.prop]=(aU.prop==="width"||aU.prop==="height"?Math.max(0,aU.now):aU.now)+aU.unit}else{aU.elem[aU.prop]=aU.now}}}});if(a.expr&&a.expr.filters){a.expr.filters.animated=function(aU){return a.grep(a.timers,function(aV){return aU===aV.elem}).length}}function az(aV,aU){var aW={};a.each(ah.concat.apply([],ah.slice(0,aU)),function(){aW[this]=aV});return aW}if("getBoundingClientRect" in aa.documentElement){a.fn.offset=function(a3){var aW=this[0];if(a3){return this.each(function(a4){a.offset.setOffset(this,a3,a4)})}if(!aW||!aW.ownerDocument){return null}if(aW===aW.ownerDocument.body){return a.offset.bodyOffset(aW)}var aY=aW.getBoundingClientRect(),a2=aW.ownerDocument,aZ=a2.body,aU=a2.documentElement,aX=aU.clientTop||aZ.clientTop||0,a0=aU.clientLeft||aZ.clientLeft||0,a1=aY.top+(self.pageYOffset||a.support.boxModel&&aU.scrollTop||aZ.scrollTop)-aX,aV=aY.left+(self.pageXOffset||a.support.boxModel&&aU.scrollLeft||aZ.scrollLeft)-a0;return{top:a1,left:aV}}}else{a.fn.offset=function(a5){var aZ=this[0];if(a5){return this.each(function(a6){a.offset.setOffset(this,a5,a6)})}if(!aZ||!aZ.ownerDocument){return null}if(aZ===aZ.ownerDocument.body){return a.offset.bodyOffset(aZ)}a.offset.initialize();var aW=aZ.offsetParent,aV=aZ,a4=aZ.ownerDocument,a2,aX=a4.documentElement,a0=a4.body,a1=a4.defaultView,aU=a1?a1.getComputedStyle(aZ,null):aZ.currentStyle,a3=aZ.offsetTop,aY=aZ.offsetLeft;while((aZ=aZ.parentNode)&&aZ!==a0&&aZ!==aX){if(a.offset.supportsFixedPosition&&aU.position==="fixed"){break}a2=a1?a1.getComputedStyle(aZ,null):aZ.currentStyle;a3-=aZ.scrollTop;aY-=aZ.scrollLeft;if(aZ===aW){a3+=aZ.offsetTop;aY+=aZ.offsetLeft;if(a.offset.doesNotAddBorder&&!(a.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(aZ.nodeName))){a3+=parseFloat(a2.borderTopWidth)||0;aY+=parseFloat(a2.borderLeftWidth)||0}aV=aW,aW=aZ.offsetParent}if(a.offset.subtractsBorderForOverflowNotVisible&&a2.overflow!=="visible"){a3+=parseFloat(a2.borderTopWidth)||0;aY+=parseFloat(a2.borderLeftWidth)||0}aU=a2}if(aU.position==="relative"||aU.position==="static"){a3+=a0.offsetTop;aY+=a0.offsetLeft}if(a.offset.supportsFixedPosition&&aU.position==="fixed"){a3+=Math.max(aX.scrollTop,a0.scrollTop);aY+=Math.max(aX.scrollLeft,a0.scrollLeft)}return{top:a3,left:aY}}}a.offset={initialize:function(){var aU=aa.body,aV=aa.createElement("div"),aY,a0,aZ,a1,aW=parseFloat(a.curCSS(aU,"marginTop",true))||0,aX="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.extend(aV.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});aV.innerHTML=aX;aU.insertBefore(aV,aU.firstChild);aY=aV.firstChild;a0=aY.firstChild;a1=aY.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(a0.offsetTop!==5);this.doesAddBorderForTableAndCells=(a1.offsetTop===5);a0.style.position="fixed",a0.style.top="20px";this.supportsFixedPosition=(a0.offsetTop===20||a0.offsetTop===15);a0.style.position=a0.style.top="";aY.style.overflow="hidden",aY.style.position="relative";this.subtractsBorderForOverflowNotVisible=(a0.offsetTop===-5);this.doesNotIncludeMarginInBodyOffset=(aU.offsetTop!==aW);aU.removeChild(aV);aU=aV=aY=a0=aZ=a1=null;a.offset.initialize=a.noop},bodyOffset:function(aU){var aW=aU.offsetTop,aV=aU.offsetLeft;a.offset.initialize();if(a.offset.doesNotIncludeMarginInBodyOffset){aW+=parseFloat(a.curCSS(aU,"marginTop",true))||0;aV+=parseFloat(a.curCSS(aU,"marginLeft",true))||0}return{top:aW,left:aV}},setOffset:function(aZ,aV,aW){if(/static/.test(a.curCSS(aZ,"position"))){aZ.style.position="relative"}var aY=a(aZ),a1=aY.offset(),aU=parseInt(a.curCSS(aZ,"top",true),10)||0,a0=parseInt(a.curCSS(aZ,"left",true),10)||0;if(a.isFunction(aV)){aV=aV.call(aZ,aW,a1)}var aX={top:(aV.top-a1.top)+aU,left:(aV.left-a1.left)+a0};if("using" in aV){aV.using.call(aZ,aX)}else{aY.css(aX)}}};a.fn.extend({position:function(){if(!this[0]){return null}var aW=this[0],aV=this.offsetParent(),aX=this.offset(),aU=/^body|html$/i.test(aV[0].nodeName)?{top:0,left:0}:aV.offset();aX.top-=parseFloat(a.curCSS(aW,"marginTop",true))||0;aX.left-=parseFloat(a.curCSS(aW,"marginLeft",true))||0;aU.top+=parseFloat(a.curCSS(aV[0],"borderTopWidth",true))||0;aU.left+=parseFloat(a.curCSS(aV[0],"borderLeftWidth",true))||0;return{top:aX.top-aU.top,left:aX.left-aU.left}},offsetParent:function(){return this.map(function(){var aU=this.offsetParent||aa.body;while(aU&&(!/^body|html$/i.test(aU.nodeName)&&a.css(aU,"position")==="static")){aU=aU.offsetParent}return aU})}});a.each(["Left","Top"],function(aV,aU){var aW="scroll"+aU;a.fn[aW]=function(aZ){var aX=this[0],aY;if(!aX){return null}if(aZ!==B){return this.each(function(){aY=ak(this);if(aY){aY.scrollTo(!aV?aZ:a(aY).scrollLeft(),aV?aZ:a(aY).scrollTop())}else{this[aW]=aZ}})}else{aY=ak(aX);return aY?("pageXOffset" in aY)?aY[aV?"pageYOffset":"pageXOffset"]:a.support.boxModel&&aY.document.documentElement[aW]||aY.document.body[aW]:aX[aW]}}});function ak(aU){return("scrollTo" in aU&&aU.document)?aU:aU.nodeType===9?aU.defaultView||aU.parentWindow:false}a.each(["Height","Width"],function(aV,aU){var aW=aU.toLowerCase();a.fn["inner"+aU]=function(){return this[0]?a.css(this[0],aW,false,"padding"):null};a.fn["outer"+aU]=function(aX){return this[0]?a.css(this[0],aW,false,aX?"margin":"border"):null};a.fn[aW]=function(aX){var aY=this[0];if(!aY){return aX==null?null:this}if(a.isFunction(aX)){return this.each(function(a0){var aZ=a(this);aZ[aW](aX.call(this,a0,aZ[aW]()))})}return("scrollTo" in aY&&aY.document)?aY.document.compatMode==="CSS1Compat"&&aY.document.documentElement["client"+aU]||aY.document.body["client"+aU]:(aY.nodeType===9)?Math.max(aY.documentElement["client"+aU],aY.body["scroll"+aU],aY.documentElement["scroll"+aU],aY.body["offset"+aU],aY.documentElement["offset"+aU]):aX===B?a.css(aY,aW):this.css(aW,typeof aX==="string"?aX:aX+"px")}});aI.jQuery=aI.$=a})(window);window.djdt=(function(b,a,e){e.cookie=function(h,p,s){if(typeof p!="undefined"){s=s||{};if(p===null){p="";s.expires=-1}var l="";if(s.expires&&(typeof s.expires=="number"||s.expires.toUTCString)){var m;if(typeof s.expires=="number"){m=new Date();m.setTime(m.getTime()+(s.expires*24*60*60*1000))}else{m=s.expires}l="; expires="+m.toUTCString()}var r=s.path?"; path="+(s.path):"";var n=s.domain?"; domain="+(s.domain):"";var g=s.secure?"; secure":"";a.cookie=[h,"=",encodeURIComponent(p),l,r,n,g].join("")}else{var k=null;if(a.cookie&&a.cookie!=""){var q=a.cookie.split(";");for(var o=0;o<q.length;o++){var j=c.trim(q[o]);if(j.substring(0,h.length+1)==(h+"=")){k=decodeURIComponent(j.substring(h.length+1));break}}}return k}};var c=e;var f="djdt";var d={jQuery:e,events:{ready:[]},isReady:false,init:function(){c("#djDebug").show();var i=null;c("#djDebugPanelList li a").click(function(){if(!this.className){return false}i=c("#djDebug #"+this.className);if(i.is(":visible")){c(a).trigger("close.djDebug");c(this).parent().removeClass("active")}else{c(".panelContent").hide();i.show();c("#djDebugToolbar li").removeClass("active");c(this).parent().addClass("active")}return false});c("#djDebug a.djDebugClose").click(function(){c(a).trigger("close.djDebug");c("#djDebugToolbar li").removeClass("active");return false});c("#djDebug a.remoteCall").click(function(){c("#djDebugWindow").load(this.href,function(k,j,m){if(j=="error"){var l='<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+m.status+": "+m.statusText+"</h3></div>";c("#djDebugWindow").html(l)}c("#djDebugWindow a.djDebugBack").click(function(){c(this).parent().parent().hide();return false})});c("#djDebugWindow").show();return false});c("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){d.toggle_arrow(c(this).children(".toggleArrow"));d.toggle_content(c(this).parent().next());return false});c("#djDebug a.djDebugToggle").click(function(j){j.preventDefault();c(this).parent().find(".djDebugCollapsed").toggle();c(this).parent().find(".djDebugUncollapsed").toggle()});c("#djDebug a.djToggleSwitch").click(function(l){l.preventDefault();var j=c(this);var m=j.attr("data-toggle-id");var k=j.text()==j.attr("data-toggle-open");if(m==""||!m){return}j.parents(".djDebugPanelContent").find("#sqlMain_"+m).find(".djDebugCollapsed").toggle(k);j.parents(".djDebugPanelContent").find("#sqlMain_"+m).find(".djDebugUncollapsed").toggle(!k);c(this).parents(".djDebugPanelContent").find(".djToggleDetails_"+m).each(function(){var n=c(this);if(k){n.addClass("djSelected");n.removeClass("djUnselected");j.text(j.attr("data-toggle-close"));n.find(".djToggleSwitch").text(j.text())}else{n.removeClass("djSelected");n.addClass("djUnselected");j.text(j.attr("data-toggle-open"));n.find(".djToggleSwitch").text(j.text())}});return});function g(j){id=j.attr("id");return c('.djDebugProfileRow[id^="'+id+'_"]')}function h(j){subcalls=g(j);depth=parseInt(j.attr("depth"))+1;return subcalls.filter("[depth="+depth+"]")}c(".djDebugProfileRow .djDebugProfileToggle").click(function(){row=c(this).closest(".djDebugProfileRow");subcalls=g(row);if(subcalls.css("display")=="none"){h(row).show()}else{subcalls.hide()}});c("#djHideToolBarButton").click(function(){d.hide_toolbar(true);return false});c("#djShowToolBarButton").click(function(){d.show_toolbar();return false});c(a).bind("close.djDebug",function(){if(c("#djDebugWindow").is(":visible")){c("#djDebugWindow").hide();return}if(c(".panelContent").is(":visible")){c(".panelContent").hide();return}if(c("#djDebugToolbar").is(":visible")){d.hide_toolbar(true);return}});if(c.cookie(f)){d.hide_toolbar(false)}else{d.show_toolbar(false)}c("#djDebug .djDebugHoverable").hover(function(){c(this).addClass("djDebugHover")},function(){c(this).removeClass("djDebugHover")});d.isReady=true;c.each(d.events.ready,function(j,k){k(d)})},toggle_content:function(g){if(g.is(":visible")){g.hide()}else{g.show()}},close:function(){c(a).trigger("close.djDebug");return false},hide_toolbar:function(g){c("#djDebugWindow").hide();c(".panelContent").hide();c("#djDebugToolbar li").removeClass("active");c("#djDebugToolbar").hide("fast");c("#djDebugToolbarHandle").show();c(a).unbind("keydown.djDebug");if(g){c.cookie(f,"hide",{path:"/",expires:10})}},show_toolbar:function(g){c(a).bind("keydown.djDebug",function(h){if(h.keyCode==27){d.close()}});c("#djDebugToolbarHandle").hide();if(g){c("#djDebugToolbar").show("fast")}else{c("#djDebugToolbar").show()}c.cookie(f,null,{path:"/",expires:-1})},toggle_arrow:function(h){var g=String.fromCharCode(9654);var i=String.fromCharCode(9660);h.html(h.html()==g?i:g)},ready:function(g){if(d.isReady){g(d)}else{d.events.ready.push(g)}}};c(a).ready(function(){d.init()});return d}(window,document,jQuery.noConflict(true)));
\ No newline at end of file diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py index de4ae9c..f49a29f 100644 --- a/debug_toolbar/middleware.py +++ b/debug_toolbar/middleware.py @@ -1,13 +1,15 @@  """  Debug Toolbar middleware  """ +import imp  import thread  from django.conf import settings +from django.conf.urls.defaults import include, patterns  from django.http import HttpResponseRedirect  from django.shortcuts import render_to_response  from django.utils.encoding import smart_unicode -from django.conf.urls.defaults import include, patterns +from django.utils.importlib import import_module  import debug_toolbar.urls  from debug_toolbar.toolbar.loader import DebugToolbar @@ -32,13 +34,13 @@ class DebugToolbarMiddleware(object):      on outgoing response.      """      debug_toolbars = {} -     +      @classmethod      def get_current(cls):          return cls.debug_toolbars.get(thread.get_ident())      def __init__(self): -        self.override_url = True +        self._urlconfs = {}          # Set method to use to decide to show toolbar          self.show_toolbar = self._show_toolbar # default @@ -57,32 +59,39 @@ class DebugToolbarMiddleware(object):                  self.tag = u'</' + tag + u'>'      def _show_toolbar(self, request): +        if getattr(settings, 'TEST', False): +            return False +          x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', None)          if x_forwarded_for:              remote_addr = x_forwarded_for.split(',')[0].strip()          else:              remote_addr = request.META.get('REMOTE_ADDR', None) -        if not remote_addr in settings.INTERNAL_IPS \ -            or (request.is_ajax() and \ -                not debug_toolbar.urls._PREFIX in request.path) \ -                    or not (settings.DEBUG or getattr(settings, 'TEST', False)): -            return False -        return True + +        # if not internal ip, and not DEBUG +        return remote_addr in settings.INTERNAL_IPS and bool(settings.DEBUG)      def process_request(self, request):          __traceback_hide__ = True          if self.show_toolbar(request): -            if self.override_url: -                original_urlconf = __import__(getattr(request, 'urlconf', settings.ROOT_URLCONF), {}, {}, ['*']) -                debug_toolbar.urls.urlpatterns += patterns('', -                    ('', include(original_urlconf)), -                ) -                if hasattr(original_urlconf, 'handler404'): -                    debug_toolbar.urls.handler404 = original_urlconf.handler404 -                if hasattr(original_urlconf, 'handler500'): -                    debug_toolbar.urls.handler500 = original_urlconf.handler500 -                self.override_url = False -            request.urlconf = 'debug_toolbar.urls' + +            urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) +            if isinstance(urlconf, basestring): +                urlconf = import_module(getattr(request, 'urlconf', settings.ROOT_URLCONF)) + +            if urlconf not in self._urlconfs: +                new_urlconf = imp.new_module('urlconf') +                new_urlconf.urlpatterns = debug_toolbar.urls.urlpatterns + \ +                        urlconf.urlpatterns + +                if hasattr(urlconf, 'handler404'): +                    new_urlconf.handler404 = urlconf.handler404 +                if hasattr(urlconf, 'handler500'): +                    new_urlconf.handler500 = urlconf.handler500 + +                self._urlconfs[urlconf] = new_urlconf + +            request.urlconf = self._urlconfs[urlconf]              toolbar = DebugToolbar(request)              for panel in toolbar.panels: @@ -119,7 +128,7 @@ class DebugToolbarMiddleware(object):              for panel in toolbar.panels:                  panel.process_response(request, response)              response.content = replace_insensitive( -                smart_unicode(response.content),  +                smart_unicode(response.content),                  self.tag,                  smart_unicode(toolbar.render_toolbar() + self.tag))              if response.get('Content-Length', None): diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py index fa2e4b6..b4f11fb 100644 --- a/debug_toolbar/panels/__init__.py +++ b/debug_toolbar/panels/__init__.py @@ -1,48 +1,67 @@ -"""Base DebugPanel class""" +from django.template.defaultfilters import slugify +from django.template.loader import render_to_string +from debug_toolbar.middleware import DebugToolbarMiddleware +  class DebugPanel(object):      """      Base class for debug panels.      """ -    # name = Base +    # name = 'Base' +    # template = 'debug_toolbar/panels/base.html'      has_content = False # If content returns something, set to true in subclass - +          # We'll maintain a local context instance so we can expose our template      # context variables to panels which need them:      context = {} - +          # Panel methods      def __init__(self, context={}):          self.context.update(context) - +        self.slug = slugify(self.name) +          def dom_id(self):          return 'djDebug%sPanel' % (self.name.replace(' ', '')) - +          def nav_title(self):          """Title showing in toolbar"""          raise NotImplementedError - +          def nav_subtitle(self):          """Subtitle showing until title in toolbar"""          return '' - +          def title(self):          """Title showing in panel"""          raise NotImplementedError - +          def url(self):          raise NotImplementedError - +          def content(self): -        raise NotImplementedError - +        if self.has_content: +            context = self.context.copy() +            context.update(self.get_stats()) +            return render_to_string(self.template, context) +     +    def record_stats(self, stats): +        toolbar = DebugToolbarMiddleware.get_current() +        panel_stats = toolbar.stats.get(self.slug) +        if panel_stats: +            panel_stats.update(stats) +        else: +            toolbar.stats[self.slug] = stats +     +    def get_stats(self): +        toolbar = DebugToolbarMiddleware.get_current() +        return toolbar.stats.get(self.slug, {}) +          # Standard middleware methods      def process_request(self, request):          pass - +          def process_view(self, request, view_func, view_args, view_kwargs):          pass - +          def process_response(self, request, response):          pass - diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py index 5617ec2..620be86 100644 --- a/debug_toolbar/panels/cache.py +++ b/debug_toolbar/panels/cache.py @@ -3,7 +3,6 @@ import inspect  from django.core import cache  from django.core.cache.backends.base import BaseCache -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  from debug_toolbar.panels import DebugPanel @@ -12,7 +11,7 @@ class CacheStatTracker(BaseCache):      def __init__(self, cache):          self.cache = cache          self.reset() - +          def reset(self):          self.calls = []          self.hits = 0 @@ -22,11 +21,11 @@ class CacheStatTracker(BaseCache):          self.get_many = 0          self.deletes = 0          self.total_time = 0 - +          def _get_func_info(self):          stack = inspect.stack()[2]          return (stack[1], stack[2], stack[3], stack[4]) - +          def get(self, key, default=None):          t = time.time()          value = self.cache.get(key, default) @@ -39,7 +38,7 @@ class CacheStatTracker(BaseCache):          self.gets += 1          self.calls.append((this_time, 'get', (key,), self._get_func_info()))          return value - +          def set(self, key, value, timeout=None):          t = time.time()          self.cache.set(key, value, timeout) @@ -47,7 +46,7 @@ class CacheStatTracker(BaseCache):          self.total_time += this_time * 1000          self.sets += 1          self.calls.append((this_time, 'set', (key, value, timeout), self._get_func_info())) - +          def delete(self, key):          t = time.time()          self.cache.delete(key) @@ -55,7 +54,7 @@ class CacheStatTracker(BaseCache):          self.total_time += this_time * 1000          self.deletes += 1          self.calls.append((this_time, 'delete', (key,), self._get_func_info())) - +          def get_many(self, keys):          t = time.time()          results = self.cache.get_many(keys) @@ -74,10 +73,11 @@ class CacheDebugPanel(DebugPanel):      Panel that displays the cache statistics.      """      name = 'Cache' +    template = 'debug_toolbar/panels/cache.html'      has_content = True - +          def __init__(self, *args, **kwargs): -        super(self.__class__, self).__init__(*args, **kwargs) +        super(CacheDebugPanel, self).__init__(*args, **kwargs)          # This is hackish but to prevent threading issues is somewhat needed          if isinstance(cache.cache, CacheStatTracker):              cache.cache.reset() @@ -85,21 +85,19 @@ class CacheDebugPanel(DebugPanel):          else:              self.cache = CacheStatTracker(cache.cache)              cache.cache = self.cache - +          def nav_title(self):          return _('Cache: %.2fms') % self.cache.total_time - +          def title(self):          return _('Cache Usage') - +          def url(self):          return '' - -    def content(self): -        context = self.context.copy() -        context.update({ +     +    def process_response(self, request, response): +        self.record_stats({              'cache_calls': len(self.cache.calls),              'cache_time': self.cache.total_time,              'cache': self.cache,          }) -        return render_to_string('debug_toolbar/panels/cache.html', context) diff --git a/debug_toolbar/panels/headers.py b/debug_toolbar/panels/headers.py index 1e929f6..181e88d 100644 --- a/debug_toolbar/panels/headers.py +++ b/debug_toolbar/panels/headers.py @@ -1,12 +1,13 @@ -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  from debug_toolbar.panels import DebugPanel +  class HeaderDebugPanel(DebugPanel):      """      A panel to display HTTP headers.      """      name = 'Header' +    template = 'debug_toolbar/panels/headers.html'      has_content = True      # List of headers we want to display      header_filter = ( @@ -31,24 +32,22 @@ class HeaderDebugPanel(DebugPanel):          'SERVER_PROTOCOL',          'SERVER_SOFTWARE',      ) - +          def nav_title(self):          return _('HTTP Headers') - +          def title(self):          return _('HTTP Headers') - +          def url(self):          return '' - +          def process_request(self, request):          self.headers = dict(              [(k, request.META[k]) for k in self.header_filter if k in request.META]          ) - -    def content(self): -        context = self.context.copy() -        context.update({ +     +    def process_response(self, request, response): +        self.record_stats({              'headers': self.headers          }) -        return render_to_string('debug_toolbar/panels/headers.html', context) diff --git a/debug_toolbar/panels/logger.py b/debug_toolbar/panels/logger.py index 5e82a13..55ae9bd 100644 --- a/debug_toolbar/panels/logger.py +++ b/debug_toolbar/panels/logger.py @@ -4,7 +4,6 @@ try:      import threading  except ImportError:      threading = None -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  from debug_toolbar.panels import DebugPanel @@ -15,15 +14,15 @@ class LogCollector(object):              raise NotImplementedError("threading module is not available, \                  the logging panel cannot be used without it")          self.records = {} # a dictionary that maps threads to log records - +          def add_record(self, record, thread=None):          # Avoid logging SQL queries since they are already in the SQL panel          # TODO: Make this check whether SQL panel is enabled          if record.get('channel', '') == 'django.db.backends':              return - +                  self.get_records(thread).append(record) - +          def get_records(self, thread=None):          """          Returns a list of records for the provided thread, of if none is provided, @@ -34,7 +33,7 @@ class LogCollector(object):          if thread not in self.records:              self.records[thread] = []          return self.records[thread] - +          def clear_records(self, thread=None):          if thread is None:              thread = threading.currentThread() @@ -46,7 +45,7 @@ class ThreadTrackingHandler(logging.Handler):      def __init__(self, collector):          logging.Handler.__init__(self)          self.collector = collector - +          def emit(self, record):          record = {              'message': record.getMessage(), @@ -76,7 +75,7 @@ if logbook_supported:          def __init__(self, collector):              logbook.handlers.Handler.__init__(self, bubble=True)              self.collector = collector - +                  def emit(self, record):              record = {                  'message': record.message, @@ -87,40 +86,37 @@ if logbook_supported:                  'channel': record.channel,              }              self.collector.add_record(record) - - +     +          logbook_handler = LogbookThreadTrackingHandler(collector)      logbook_handler.push_application()        # register with logbook  class LoggingPanel(DebugPanel):      name = 'Logging' +    template = 'debug_toolbar/panels/logger.html'      has_content = True - +          def process_request(self, request):          collector.clear_records() - +     +    def process_response(self, request, response): +        records = self.get_and_delete() +        self.record_stats({'records': records}) +          def get_and_delete(self):          records = collector.get_records()          collector.clear_records()          return records - +          def nav_title(self):          return _("Logging") - +          def nav_subtitle(self):          # FIXME l10n: use ngettext          return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's') - +          def title(self):          return _('Log Messages') - +          def url(self):          return '' - -    def content(self): -        records = self.get_and_delete() -        context = self.context.copy() -        context.update({'records': records}) - -        return render_to_string('debug_toolbar/panels/logger.html', context) - diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py index 95a1a4d..8913621 100644 --- a/debug_toolbar/panels/profiling.py +++ b/debug_toolbar/panels/profiling.py @@ -1,13 +1,22 @@  from __future__ import division -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  from django.utils.safestring import mark_safe  from debug_toolbar.panels import DebugPanel +try: +    from line_profiler import LineProfiler, show_func +    DJ_PROFILE_USE_LINE_PROFILER = True +except ImportError: +    DJ_PROFILE_USE_LINE_PROFILER = False + + +from cStringIO import StringIO  import cProfile  from pstats import Stats  from colorsys import hsv_to_rgb +import os +  class DjangoDebugToolbarStats(Stats):      __root = None @@ -19,16 +28,11 @@ class DjangoDebugToolbarStats(Stats):                      self.__root = func                      break          return self.__root -     -    def print_call_tree_node(self, function, depth, max_depth, cum_filter=0.1): -        self.print_line(function, depth=depth) -        if depth < max_depth: -            for called in self.all_callees[function].keys(): -                if self.stats[called][3] >= cum_filter: -                    self.print_call_tree_node(called, depth+1, max_depth, cum_filter=cum_filter) +  class FunctionCall(object): -    def __init__(self, statobj, func, depth=0, stats=None, id=0, parent_ids=[], hsv=(0,0.5,1)): +    def __init__(self, statobj, func, depth=0, stats=None, +                 id=0, parent_ids=[], hsv=(0,0.5,1)):          self.statobj = statobj          self.func = func          if stats: @@ -39,6 +43,7 @@ class FunctionCall(object):          self.id = id          self.parent_ids = parent_ids          self.hsv = hsv +        self._line_stats_text = None      def parent_classes(self):          return self.parent_classes @@ -60,9 +65,9 @@ class FunctionCall(object):              file_name, line_num, method = self.func              idx = file_name.find('/site-packages/')              if idx > -1: -                file_name=file_name[idx+14:] +                file_name = file_name[idx+14:] -            file_path, file_name = file_name.rsplit('/', 1) +            file_path, file_name = file_name.rsplit(os.sep, 1)              return mark_safe('<span class="path">{0}/</span><span class="file">{1}</span> in <span class="func">{3}</span>(<span class="lineno">{2}</span>)'.format(                  file_path, @@ -73,7 +78,7 @@ class FunctionCall(object):      def subfuncs(self):          i=0 -        h,s,v = self.hsv +        h, s, v = self.hsv          count = len(self.statobj.all_callees[self.func])          for func, stats in self.statobj.all_callees[self.func].iteritems():              i += 1 @@ -83,8 +88,8 @@ class FunctionCall(object):              else:                  s1 = s*(stats[3]/self.stats[3])              yield FunctionCall(self.statobj, -                               func,  -                               self.depth+1,  +                               func, +                               self.depth+1,                                 stats=stats,                                 id=str(self.id) + '_' + str(i),                                 parent_ids=self.parent_ids + [self.id], @@ -102,69 +107,97 @@ class FunctionCall(object):      def tottime_per_call(self):          cc, nc, tt, ct = self.stats - +                  if nc == 0:              return 0 - +                  return tt/nc      def cumtime_per_call(self):          cc, nc, tt, ct = self.stats - +                  if cc == 0:              return 0 - +                  return ct/cc - +          def indent(self):          return 16 * self.depth +     +    def line_stats_text(self): +        if self._line_stats_text is None and DJ_PROFILE_USE_LINE_PROFILER: +            lstats = self.statobj.line_stats +            if self.func in lstats.timings: +                out = StringIO() +                fn, lineno, name = self.func +                show_func(fn, lineno, name, lstats.timings[self.func], lstats.unit, stream=out) +                self._line_stats_text = out.getvalue() +            else: +                self._line_stats_text = False +        return self._line_stats_text  class ProfilingDebugPanel(DebugPanel):      """      Panel that displays the Django version.      """      name = 'Profiling' +    template = 'debug_toolbar/panels/profiling.html'      has_content = True - +          def nav_title(self):          return _('Profiling') - +          def url(self):          return ''      def title(self):          return _('Profiling') - +     +    def _unwrap_closure_and_profile(self, func): +        if not hasattr(func, 'func_code'): +            return +        self.line_profiler.add_function(func) +        if func.func_closure: +            for cell in func.func_closure: +                if hasattr(cell.cell_contents, 'func_code'): +                    self._unwrap_closure_and_profile(cell.cell_contents) +          def process_view(self, request, view_func, view_args, view_kwargs):          __traceback_hide__ = True          self.profiler = cProfile.Profile()          args = (request,) + view_args -        return self.profiler.runcall(view_func, *args, **view_kwargs) - -    def process_response(self, request, response): -        self.profiler.create_stats() -        self.stats = DjangoDebugToolbarStats(self.profiler) -        return response - +        if DJ_PROFILE_USE_LINE_PROFILER: +            self.line_profiler = LineProfiler() +            self._unwrap_closure_and_profile(view_func) +            self.line_profiler.enable_by_count() +            out = self.profiler.runcall(view_func, *args, **view_kwargs) +            self.line_profiler.disable_by_count() +        else: +            self.line_profiler = None +            out = self.profiler.runcall(view_func, *args, **view_kwargs) +        return out +          def add_node(self, func_list, func, max_depth, cum_time=0.1):          func_list.append(func)          func.has_subfuncs = False          if func.depth < max_depth:              for subfunc in func.subfuncs(): -                if subfunc.stats[3] >= cum_time: +                if (subfunc.stats[3] >= cum_time or +                   (hasattr(self.stats, 'line_stats') and +                   (subfunc.func in self.stats.line_stats.timings))):                      func.has_subfuncs = True                      self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) -    def content(self): -         +    def process_response(self, request, response): +        self.profiler.create_stats() +        self.stats = DjangoDebugToolbarStats(self.profiler) +        if DJ_PROFILE_USE_LINE_PROFILER: +            self.stats.line_stats = self.line_profiler.get_stats()          self.stats.calc_callees() +                  root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0)          func_list = []          self.add_node(func_list, root, 10, root.stats[3]/8) -        context = self.context.copy() -        context.update({ -            'func_list': func_list, -        }) - -        return render_to_string('debug_toolbar/panels/profiling.html', context) +         +        self.stats_record({'func_list': func_list}) diff --git a/debug_toolbar/panels/request_vars.py b/debug_toolbar/panels/request_vars.py index 632068e..ee9cdc5 100644 --- a/debug_toolbar/panels/request_vars.py +++ b/debug_toolbar/panels/request_vars.py @@ -1,52 +1,59 @@ -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _ +  from debug_toolbar.panels import DebugPanel +from debug_toolbar.utils import get_name_from_obj  class RequestVarsDebugPanel(DebugPanel):      """      A panel to display request variables (POST/GET, session, cookies).      """      name = 'RequestVars' +    template = 'debug_toolbar/panels/request_vars.html'      has_content = True - +     +    def __init__(self, *args, **kwargs): +        DebugPanel.__init__(self, *args, **kwargs) +        self.view_func = None +        self.view_args = None +        self.view_kwargs = None +          def nav_title(self):          return _('Request Vars') - +          def title(self):          return _('Request Vars') - +          def url(self):          return '' - +          def process_request(self, request):          self.request = request - +          def process_view(self, request, view_func, view_args, view_kwargs):          self.view_func = view_func          self.view_args = view_args          self.view_kwargs = view_kwargs - -    def content(self): -        context = self.context.copy() - -        if hasattr(self.view_func, '__name__'): -            view_name = self.view_func.__name__ -        elif hasattr(self.view_func, '__class__'): -            view_name = self.view_func.__class__.__name__ -        else: -            view_name = '<unknown>' - -        context.update({ +     +    def process_response(self, request, response): +        self.record_stats({              'get': [(k, self.request.GET.getlist(k)) for k in self.request.GET],              'post': [(k, self.request.POST.getlist(k)) for k in self.request.POST],              'cookies': [(k, self.request.COOKIES.get(k)) for k in self.request.COOKIES], -            'view_func': '%s.%s' % (self.view_func.__module__, view_name), -            'view_args': self.view_args, -            'view_kwargs': self.view_kwargs          }) +         +        if hasattr(self, 'view_func'): +            if self.view_func is not None: +                name = get_name_from_obj(self.view_func) +            else: +                name = '<no view>' +             +            self.record_stats({ +                'view_func': name, +                'view_args': self.view_args, +                'view_kwargs': self.view_kwargs +            }) +                  if hasattr(self.request, 'session'): -            context.update({ +            self.record_stats({                  'session': [(k, self.request.session.get(k)) for k in self.request.session.iterkeys()]              }) - -        return render_to_string('debug_toolbar/panels/request_vars.html', context) diff --git a/debug_toolbar/panels/settings_vars.py b/debug_toolbar/panels/settings_vars.py index ebb4464..e154dda 100644 --- a/debug_toolbar/panels/settings_vars.py +++ b/debug_toolbar/panels/settings_vars.py @@ -1,5 +1,4 @@  from django.conf import settings -from django.template.loader import render_to_string  from django.views.debug import get_safe_settings  from django.utils.translation import ugettext_lazy as _  from debug_toolbar.panels import DebugPanel @@ -10,20 +9,19 @@ class SettingsVarsDebugPanel(DebugPanel):      A panel to display all variables in django.conf.settings      """      name = 'SettingsVars' +    template = 'debug_toolbar/panels/settings_vars.html'      has_content = True - +          def nav_title(self):          return _('Settings') - +          def title(self):          return _('Settings from <code>%s</code>') % settings.SETTINGS_MODULE - +          def url(self):          return '' - -    def content(self): -        context = self.context.copy() -        context.update({ +     +    def process_response(self, request, response): +        self.record_stats({              'settings': get_safe_settings(),          }) -        return render_to_string('debug_toolbar/panels/settings_vars.html', context) diff --git a/debug_toolbar/panels/signals.py b/debug_toolbar/panels/signals.py index dbd3725..205b3c5 100644 --- a/debug_toolbar/panels/signals.py +++ b/debug_toolbar/panels/signals.py @@ -6,7 +6,6 @@ from django.core.signals import request_started, request_finished, \  from django.db.models.signals import class_prepared, pre_init, post_init, \      pre_save, post_save, pre_delete, post_delete, post_syncdb  from django.dispatch.dispatcher import WEAKREF_TYPES -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  try: @@ -18,8 +17,9 @@ from debug_toolbar.panels import DebugPanel  class SignalDebugPanel(DebugPanel):      name = "Signals" +    template = 'debug_toolbar/panels/signals.html'      has_content = True - +          SIGNALS = {          'request_started': request_started,          'request_finished': request_finished, @@ -34,16 +34,16 @@ class SignalDebugPanel(DebugPanel):          'post_delete': post_delete,          'post_syncdb': post_syncdb,      } - +          def nav_title(self):          return _("Signals") - +          def title(self):          return _("Signals") - +          def url(self):          return '' - +          def signals(self):          signals = self.SIGNALS.copy()          if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'): @@ -57,8 +57,8 @@ class SignalDebugPanel(DebugPanel):              signals[parts[-1]] = getattr(sys.modules[path], parts[-1])          return signals      signals = property(signals) - -    def content(self): +     +    def process_response(self, request, response):          signals = []          keys = self.signals.keys()          keys.sort() @@ -80,8 +80,5 @@ class SignalDebugPanel(DebugPanel):                      text = "function %s" % receiver.__name__                  receivers.append(text)              signals.append((name, signal, receivers)) - -        context = self.context.copy() -        context.update({'signals': signals}) - -        return render_to_string('debug_toolbar/panels/signals.html', context) +         +        self.record_stats({'signals': signals}) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index c6b5996..b27e6c0 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -2,7 +2,6 @@ import re  import uuid  from django.db.backends import BaseDatabaseWrapper -from django.template.loader import render_to_string  from django.utils.html import escape  from django.utils.safestring import mark_safe  from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __ @@ -14,11 +13,12 @@ from debug_toolbar.utils import sqlparse  from debug_toolbar.utils.tracking.db import CursorWrapper  from debug_toolbar.utils.tracking import replace_call +  # Inject our tracking cursor  @replace_call(BaseDatabaseWrapper.cursor)  def cursor(func, self):      result = func(self) - +          djdt = DebugToolbarMiddleware.get_current()      if not djdt:          return result @@ -26,6 +26,7 @@ def cursor(func, self):      return CursorWrapper(result, self, logger=logger) +  def get_isolation_level_display(engine, level):      if engine == 'psycopg2':          import psycopg2.extensions @@ -41,6 +42,7 @@ def get_isolation_level_display(engine, level):      return choices.get(level) +  def get_transaction_status_display(engine, level):      if engine == 'psycopg2':          import psycopg2.extensions @@ -56,16 +58,18 @@ def get_transaction_status_display(engine, level):      return choices.get(level) +  class SQLDebugPanel(DebugPanel):      """      Panel that displays information about the SQL queries run while processing      the request.      """      name = 'SQL' +    template = 'debug_toolbar/panels/sql.html'      has_content = True - +          def __init__(self, *args, **kwargs): -        super(self.__class__, self).__init__(*args, **kwargs) +        super(SQLDebugPanel, self).__init__(*args, **kwargs)          self._offset = dict((k, len(connections[k].queries)) for k in connections)          self._sql_time = 0          self._num_queries = 0 @@ -78,20 +82,20 @@ class SQLDebugPanel(DebugPanel):          conn = connections[alias].connection          if not conn:              return None - +                  engine = conn.__class__.__module__.split('.', 1)[0]          if engine == 'psycopg2':              cur_status = conn.get_transaction_status()          else:              raise ValueError(engine) - +                  last_status = self._transaction_status.get(alias)          self._transaction_status[alias] = cur_status - +                  if not cur_status:              # No available state              return None - +                  if cur_status != last_status:              if cur_status:                  self._transaction_ids[alias] = uuid.uuid4().hex @@ -112,10 +116,10 @@ class SQLDebugPanel(DebugPanel):              self._databases[alias]['num_queries'] += 1          self._sql_time += kwargs['duration']          self._num_queries += 1 - +          def nav_title(self):          return _('SQL') - +          def nav_subtitle(self):          # TODO l10n: use ngettext          return "%d %s in %.2fms" % ( @@ -123,18 +127,18 @@ class SQLDebugPanel(DebugPanel):              (self._num_queries == 1) and 'query' or 'queries',              self._sql_time          ) - +          def title(self):          count = len(self._databases)          return __('SQL Queries from %(count)d connection', 'SQL Queries from %(count)d connections', count) % dict(              count=count,          ) - +          def url(self):          return '' - -    def content(self): +     +    def process_response(self, request, response):          if self._queries:              width_ratio_tally = 0              colors = [ @@ -157,7 +161,7 @@ class SQLDebugPanel(DebugPanel):                          nn = 0                      rgb[nn] = nc                  db['rgb_color'] = rgb -         +                          trans_ids = {}              trans_id = None              i = 0 @@ -183,30 +187,34 @@ class SQLDebugPanel(DebugPanel):                  query['rgb_color'] = self._databases[alias]['rgb_color']                  try:                      query['width_ratio'] = (query['duration'] / self._sql_time) * 100 +                    query['width_ratio_relative'] =  100.0 * query['width_ratio'] / (100.0 - width_ratio_tally)                  except ZeroDivisionError:                      query['width_ratio'] = 0 +                    query['width_ratio_relative'] = 0                  query['start_offset'] = width_ratio_tally                  query['end_offset'] = query['width_ratio'] + query['start_offset']                  width_ratio_tally += query['width_ratio'] -             +                                  stacktrace = []                  for frame in query['stacktrace']:                      params = map(escape, frame[0].rsplit('/', 1) + list(frame[1:])) -                    stacktrace.append('<span class="path">{0}/</span><span class="file">{1}</span> in <span class="func">{3}</span>(<span class="lineno">{2}</span>)\n  <span class="code">{4}</span>'.format(*params)) +                    try: +                        stacktrace.append(u'<span class="path">{0}/</span><span class="file">{1}</span> in <span class="func">{3}</span>(<span class="lineno">{2}</span>)\n  <span class="code">{4}</span>'.format(*params)) +                    except IndexError: +                        # This frame doesn't have the expected format, so skip it and move on to the next one +                        continue                  query['stacktrace'] = mark_safe('\n'.join(stacktrace))                  i += 1 - +                          if trans_id:                  self._queries[i-1][1]['ends_trans'] = True -        context = self.context.copy() -        context.update({ +        self.record_stats({              'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']),              'queries': [q for a, q in self._queries],              'sql_time': self._sql_time,          }) -        return render_to_string('debug_toolbar/panels/sql.html', context)  class BoldKeywordFilter(sqlparse.filters.Filter):      """sqlparse filter to bold SQL keywords""" @@ -220,8 +228,11 @@ class BoldKeywordFilter(sqlparse.filters.Filter):              if is_keyword:                  yield sqlparse.tokens.Text, '</strong>' +  def swap_fields(sql): -    return re.sub('SELECT</strong> (.*) <strong>FROM', 'SELECT</strong> <span class="djDebugCollapse">\g<1></span> <strong>FROM', sql) +    return re.sub('SELECT</strong> (.*) <strong>FROM', 'SELECT</strong> <a class="djDebugUncollapsed djDebugToggle" href="#">•••</a> ' + +        '<a class="djDebugCollapsed djDebugToggle" href="#">\g<1></a> <strong>FROM', sql) +  def reformat_sql(sql):      stack = sqlparse.engine.FilterStack() diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index 44b8b3e..5c20fcd 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -4,10 +4,11 @@ from pprint import pformat  from django import http  from django.conf import settings  from django.template.context import get_standard_processors -from django.template.loader import render_to_string  from django.test.signals import template_rendered  from django.utils.translation import ugettext_lazy as _ +from django.db.models.query import QuerySet  from debug_toolbar.panels import DebugPanel +from debug_toolbar.utils.tracking.db import recording, SQLQueryTriggered  # Code taken and adapted from Simon Willison and Django Snippets:  # http://www.djangosnippets.org/snippets/766/ @@ -27,6 +28,7 @@ else:          Template.original_render = Template._render          Template._render = instrumented_test_render +  # MONSTER monkey-patch  old_template_init = Template.__init__  def new_template_init(self, template_string, origin=None, name='<Unknown Template>'): @@ -34,36 +36,76 @@ def new_template_init(self, template_string, origin=None, name='<Unknown Templat      self.origin = origin  Template.__init__ = new_template_init +  class TemplateDebugPanel(DebugPanel):      """      A panel that lists all templates used during processing of a response.      """      name = 'Template' +    template = 'debug_toolbar/panels/templates.html'      has_content = True - +          def __init__(self, *args, **kwargs): -        super(self.__class__, self).__init__(*args, **kwargs) +        super(TemplateDebugPanel, self).__init__(*args, **kwargs)          self.templates = []          template_rendered.connect(self._store_template_info) - +          def _store_template_info(self, sender, **kwargs): +        context_data = kwargs['context'] +         +        context_list = [] +        for context_layer in context_data.dicts: +            temp_layer = {} +            if hasattr(context_layer, 'items'): +                for key, value in context_layer.items(): +                    # Replace any request elements - they have a large +                    # unicode representation and the request data is +                    # already made available from the Request Vars panel. +                    if isinstance(value, http.HttpRequest): +                        temp_layer[key] = '<<request>>' +                    # Replace the debugging sql_queries element. The SQL +                    # data is already made available from the SQL panel. +                    elif key == 'sql_queries' and isinstance(value, list): +                        temp_layer[key] = '<<sql_queries>>' +                    # Replace LANGUAGES, which is available in i18n context processor +                    elif key == 'LANGUAGES' and isinstance(value, tuple): +                        temp_layer[key] = '<<languages>>' +                    # QuerySet would trigger the database: user can run the query from SQL Panel +                    elif isinstance(value, QuerySet): +                        model_name = "%s.%s" % (value.model._meta.app_label, value.model.__name__) +                        temp_layer[key] = '<<queryset of %s>>' % model_name +                    else: +                        try: +                            recording(False) +                            pformat(value)  # this MAY trigger a db query +                        except SQLQueryTriggered: +                            temp_layer[key] = '<<triggers database query>>' +                        else: +                            temp_layer[key] = value +                        finally: +                            recording(True) +            try: +                context_list.append(pformat(temp_layer)) +            except UnicodeEncodeError: +                pass +        kwargs['context'] = context_list          self.templates.append(kwargs) - +          def nav_title(self):          return _('Templates') - +          def title(self):          num_templates = len([t for t in self.templates              if not (t['template'].name and t['template'].name.startswith('debug_toolbar/'))])          return _('Templates (%(num_templates)s rendered)') % {'num_templates': num_templates} - +          def url(self):          return '' - +          def process_request(self, request):          self.request = request - -    def content(self): +     +    def process_response(self, request, response):          context_processors = dict(              [                  ("%s.%s" % (k.__module__, k.__name__), @@ -78,6 +120,8 @@ class TemplateDebugPanel(DebugPanel):              # Skip templates that we are generating through the debug toolbar.              if template.name and template.name.startswith('debug_toolbar/'):                  continue +            if not hasattr(template, 'origin'): +                continue              if template.origin and template.origin.name:                  template.origin_name = template.origin.name              else: @@ -85,36 +129,12 @@ class TemplateDebugPanel(DebugPanel):              info['template'] = template              # Clean up context for better readability              if getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('SHOW_TEMPLATE_CONTEXT', True): -                context_data = template_data.get('context', None) - -                context_list = [] -                for context_layer in context_data.dicts: -                    if hasattr(context_layer, 'items'): -                        for key, value in context_layer.items(): -                            # Replace any request elements - they have a large -                            # unicode representation and the request data is -                            # already made available from the Request Vars panel. -                            if isinstance(value, http.HttpRequest): -                                context_layer[key] = '<<request>>' -                            # Replace the debugging sql_queries element. The SQL -                            # data is already made available from the SQL panel. -                            elif key == 'sql_queries' and isinstance(value, list): -                                context_layer[key] = '<<sql_queries>>' -                            # Replace LANGUAGES, which is available in i18n context processor -                            elif key == 'LANGUAGES' and isinstance(value, tuple): -                                context_layer[key] = '<<languages>>' -                    try: -                        context_list.append(pformat(context_layer)) -                    except UnicodeEncodeError: -                        pass +                context_list = template_data.get('context', [])                  info['context'] = '\n'.join(context_list)              template_context.append(info) - -        context = self.context.copy() -        context.update({ +         +        self.record_stats({              'templates': template_context,              'template_dirs': [normpath(x) for x in settings.TEMPLATE_DIRS],              'context_processors': context_processors,          }) - -        return render_to_string('debug_toolbar/panels/templates.html', context) diff --git a/debug_toolbar/panels/timer.py b/debug_toolbar/panels/timer.py index d866166..7c0febf 100644 --- a/debug_toolbar/panels/timer.py +++ b/debug_toolbar/panels/timer.py @@ -7,11 +7,13 @@ from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _  from debug_toolbar.panels import DebugPanel +  class TimerDebugPanel(DebugPanel):      """      Panel that displays the time a response took in milliseconds.      """      name = 'Timer' +    template = 'debug_toolbar/panels/timer.html'      try: # if resource module not available, don't show content panel          resource      except NameError: @@ -20,47 +22,23 @@ class TimerDebugPanel(DebugPanel):      else:          has_content = True          has_resource = True - +          def process_request(self, request):          self._start_time = time.time()          if self.has_resource:              self._start_rusage = resource.getrusage(resource.RUSAGE_SELF) - +          def process_response(self, request, response): -        self.total_time = (time.time() - self._start_time) * 1000 +        total_time = (time.time() - self._start_time) * 1000          if self.has_resource:              self._end_rusage = resource.getrusage(resource.RUSAGE_SELF) - -    def nav_title(self): -        return _('Time') - -    def nav_subtitle(self): -        # TODO l10n -        if self.has_resource: -            utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime -            stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime -            return 'CPU: %0.2fms (%0.2fms)' % ((utime + stime) * 1000.0, self.total_time) -        else: -            return 'TOTAL: %0.2fms' % (self.total_time) - -    def title(self): -        return _('Resource Usage') - -    def url(self): -        return '' - -    def _elapsed_ru(self, name): -        return getattr(self._end_rusage, name) - getattr(self._start_rusage, name) - -    def content(self): - +                  utime = 1000 * self._elapsed_ru('ru_utime')          stime = 1000 * self._elapsed_ru('ru_stime')          vcsw = self._elapsed_ru('ru_nvcsw')          ivcsw = self._elapsed_ru('ru_nivcsw')          minflt = self._elapsed_ru('ru_minflt')          majflt = self._elapsed_ru('ru_majflt') -  # these are documented as not meaningful under Linux.  If you're running BSD  # feel free to enable them, and add any others that I hadn't gotten to before  # I noticed that I was getting nothing but zeroes and that the docs agreed. :-( @@ -72,22 +50,63 @@ class TimerDebugPanel(DebugPanel):  #        srss = self._end_rusage.ru_ixrss  #        urss = self._end_rusage.ru_idrss  #        usrss = self._end_rusage.ru_isrss - +         +        self.record_stats({ +            'total_time': total_time, +            'utime': utime, +            'stime': stime, +            'vcsw': vcsw, +            'ivcsw': ivcsw, +            'minflt': minflt, +            'majflt': majflt, +#            'blkin': blkin, +#            'blkout': blkout, +#            'swap': swap, +#            'rss': rss, +#            'urss': urss, +#            'srss': srss, +#            'usrss': usrss, +        }) +     +    def nav_title(self): +        return _('Time') +     +    def nav_subtitle(self): +        stats = self.get_stats() +         +        # TODO l10n +        if self.has_resource: +            utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime +            stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime +            return 'CPU: %0.2fms (%0.2fms)' % ((utime + stime) * 1000.0, stats['total_time']) +        else: +            return 'TOTAL: %0.2fms' % (stats['total_time']) +     +    def title(self): +        return _('Resource Usage') +     +    def url(self): +        return '' +     +    def _elapsed_ru(self, name): +        return getattr(self._end_rusage, name) - getattr(self._start_rusage, name) +     +    def content(self): +        stats = self.get_stats() +                  # TODO l10n on values          rows = ( -            (_('User CPU time'), '%0.3f msec' % utime), -            (_('System CPU time'), '%0.3f msec' % stime), -            (_('Total CPU time'), '%0.3f msec' % (utime + stime)), -            (_('Elapsed time'), '%0.3f msec' % self.total_time), -            (_('Context switches'), '%d voluntary, %d involuntary' % (vcsw, ivcsw)), -#            ('Memory use', '%d max RSS, %d shared, %d unshared' % (rss, srss, urss + usrss)), -#            ('Page faults', '%d no i/o, %d requiring i/o' % (minflt, majflt)), -#            ('Disk operations', '%d in, %d out, %d swapout' % (blkin, blkout, swap)), +            (_('User CPU time'), '%0.3f msec' % stats['utime']), +            (_('System CPU time'), '%0.3f msec' % stats['stime']), +            (_('Total CPU time'), '%0.3f msec' % (stats['utime'] + stats['stime'])), +            (_('Elapsed time'), '%0.3f msec' % stats['total_time']), +            (_('Context switches'), '%d voluntary, %d involuntary' % (stats['vcsw'], stats['ivcsw'])), +#            ('Memory use', '%d max RSS, %d shared, %d unshared' % (stats['rss'], stats.['srss'], +#                                                                   stats['urss'] + stats['usrss'])), +#            ('Page faults', '%d no i/o, %d requiring i/o' % (stats['minflt'], stats['majflt'])), +#            ('Disk operations', '%d in, %d out, %d swapout' % (stats['blkin'], stats['blkout'], stats['swap'])),          ) - +                  context = self.context.copy() -        context.update({ -            'rows': rows, -        }) - -        return render_to_string('debug_toolbar/panels/timer.html', context) +        context.update({'rows': rows,}) +        return render_to_string(self.template, context) diff --git a/debug_toolbar/panels/version.py b/debug_toolbar/panels/version.py index f0d8fbc..4e58971 100644 --- a/debug_toolbar/panels/version.py +++ b/debug_toolbar/panels/version.py @@ -2,10 +2,8 @@ import sys  import django  from django.conf import settings -from django.template.loader import render_to_string  from django.utils.translation import ugettext_lazy as _ -import debug_toolbar  from debug_toolbar.panels import DebugPanel @@ -14,21 +12,22 @@ class VersionDebugPanel(DebugPanel):      Panel that displays the Django version.      """      name = 'Version' +    template = 'debug_toolbar/panels/versions.html'      has_content = True - +          def nav_title(self):          return _('Versions') - +          def nav_subtitle(self):          return 'Django %s' % django.get_version() - +          def url(self):          return ''      def title(self):          return _('Versions') - -    def content(self): +     +    def process_response(self, request, response):          versions = {}          versions['Python'] = '%d.%d.%d' % sys.version_info[:3]          for app in settings.INSTALLED_APPS + ['django']: @@ -50,11 +49,8 @@ class VersionDebugPanel(DebugPanel):              if isinstance(version, (list, tuple)):                  version = '.'.join(str(o) for o in version)              versions[name] = version - -        context = self.context.copy() -        context.update({ +         +        self.record_stats({              'versions': versions,              'paths': sys.path,          }) - -        return render_to_string('debug_toolbar/panels/versions.html', context) diff --git a/debug_toolbar/templates/debug_toolbar/panels/profiling.html b/debug_toolbar/templates/debug_toolbar/panels/profiling.html index ebc91cc..f2d43de 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/profiling.html +++ b/debug_toolbar/templates/debug_toolbar/panels/profiling.html @@ -4,17 +4,17 @@  	<thead>  		<tr>  			<th>{% trans "Call" %}</th> -			<th>{% trans "TotTime" %}</th> -			<th>{% trans "Per" %}</th>  			<th>{% trans "CumTime" %}</th>  			<th>{% trans "Per" %}</th> +			<th>{% trans "TotTime" %}</th> +			<th>{% trans "Per" %}</th>  			<th>{% trans "Count" %}</th>  		</tr>  	</thead>  	<tbody>  		{% for call in func_list %}  			<!--  style="background:{{ call.background }}" --> -			<tr id="{{ call.id }}" class="djDebugProfileRow{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" depth="{{ call.depth }}"> +			<tr class="djDebugProfileRow{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" depth="{{ call.depth }}">  				<td>  					<div style="padding-left: {{ call.indent }}px;">  						{% if call.has_subfuncs %} @@ -25,12 +25,19 @@  						<span class="stack">{{ call.func_std_string }}</span>  					</div>  				</td> -				<td>{{ call.tottime|floatformat:3 }}</td> -				<td>{{ call.tottime_per_call|floatformat:3 }}</td>  				<td>{{ call.cumtime|floatformat:3 }}</td>  				<td>{{ call.cumtime_per_call|floatformat:3 }}</td> +				<td>{{ call.tottime|floatformat:3 }}</td> +				<td>{{ call.tottime_per_call|floatformat:3 }}</td>  				<td>{{ call.count }}</td>  			</tr> +			{% if call.line_stats_text %} +				<tr class="djToggleDetails_{{ call.id }}{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}"> +					<td colspan="6"> +						<div style="padding-left: {{ call.indent }}px;"><pre>{{ call.line_stats_text }}</pre></div> +					</td> +				</tr> +			{% endif %}  		{% endfor %}  	</tbody> -</table> +</table>
\ No newline at end of file diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html index f6f231c..9b282ca 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/sql.html +++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html @@ -1,4 +1,5 @@  {% load i18n %} +{% load debug_toolbar_utils %}  <div class="clearfix">  	<ul class="stats">  		{% for alias, info in databases %} @@ -34,7 +35,7 @@  						</div>  					</td>  					<td class="timeline"> -						<div class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} djDebugLineChartWarning{% endif %}" style="left:{{ query.start_offset }}%;"><strong style="width:{{ query.width_ratio }}%;">{{ query.width_ratio }}%</strong></div></div> +						<div class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} djDebugLineChartWarning{% endif %}" style="left:{{ query.start_offset|dotted_number }}%;"><strong style="width:{{ query.width_ratio_relative|dotted_number }}%;">{{ query.width_ratio }}%</strong></div></div>  					</td>  					<td class="time">  						{{ query.duration|floatformat:"2" }} diff --git a/debug_toolbar/tests/templates/404.html b/debug_toolbar/templatetags/__init__.py index e69de29..e69de29 100644 --- a/debug_toolbar/tests/templates/404.html +++ b/debug_toolbar/templatetags/__init__.py diff --git a/debug_toolbar/templatetags/debug_toolbar_utils.py b/debug_toolbar/templatetags/debug_toolbar_utils.py new file mode 100644 index 0000000..6b204eb --- /dev/null +++ b/debug_toolbar/templatetags/debug_toolbar_utils.py @@ -0,0 +1,11 @@ + +from django import template +from django.utils.numberformat import format + +register = template.Library() + +@register.filter +def dotted_number(number): +    number = float(number) +    return format(number, '.', 6) +     diff --git a/debug_toolbar/tests/__init__.py b/debug_toolbar/tests/__init__.py deleted file mode 100644 index f853b10..0000000 --- a/debug_toolbar/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from tests import *
\ No newline at end of file diff --git a/debug_toolbar/tests/tests.py b/debug_toolbar/tests/tests.py deleted file mode 100644 index fe1904a..0000000 --- a/debug_toolbar/tests/tests.py +++ /dev/null @@ -1,174 +0,0 @@ -from debug_toolbar.middleware import DebugToolbarMiddleware -from debug_toolbar.panels.sql import SQLDebugPanel -from debug_toolbar.toolbar.loader import DebugToolbar -from debug_toolbar.utils.tracking import pre_dispatch, post_dispatch, callbacks - -from django.contrib.auth.models import User -from django.test import TestCase - -from dingus import Dingus -import thread - -class BaseTestCase(TestCase): -    def setUp(self): -        request = Dingus('request') -        toolbar = DebugToolbar(request) -        DebugToolbarMiddleware.debug_toolbars[thread.get_ident()] = toolbar -        self.toolbar = toolbar - -class DebugToolbarTestCase(BaseTestCase): -    urls = 'debug_toolbar.tests.urls' -     -    def test_middleware(self): -        resp = self.client.get('/execute_sql/') -        self.assertEquals(resp.status_code, 200) - -class SQLPanelTestCase(BaseTestCase): -    def test_recording(self): -        panel = self.toolbar.get_panel(SQLDebugPanel) -        self.assertEquals(len(panel._queries), 0) -         -        list(User.objects.all()) -         -        # ensure query was logged -        self.assertEquals(len(panel._queries), 1) -        query = panel._queries[0] -        self.assertEquals(query[0], 'default') -        self.assertTrue('sql' in query[1]) -        self.assertTrue('duration' in query[1]) -        self.assertTrue('stacktrace' in query[1]) - -def module_func(*args, **kwargs): -    """Used by dispatch tests""" -    return 'blah' - -class TrackingTestCase(BaseTestCase): -    @classmethod -    def class_method(cls, *args, **kwargs): -        return 'blah' - -    def class_func(self, *args, **kwargs): -        """Used by dispatch tests""" -        return 'blah' -     -    def test_pre_hook(self): -        foo = {} -         -        @pre_dispatch(module_func) -        def test(**kwargs): -            foo.update(kwargs) -             -        self.assertTrue(hasattr(module_func, '__wrapped__')) -        self.assertEquals(len(callbacks['before']), 1) -         -        module_func('hi', foo='bar') -         -        self.assertTrue('sender' in foo, foo) -        # best we can do -        self.assertEquals(foo['sender'].__name__, 'module_func') -        self.assertTrue('start' in foo, foo) -        self.assertTrue(foo['start'] > 0) -        self.assertTrue('stop' not in foo, foo) -        self.assertTrue('args' in foo, foo) -        self.assertTrue(len(foo['args']), 1) -        self.assertEquals(foo['args'][0], 'hi') -        self.assertTrue('kwargs' in foo, foo) -        self.assertTrue(len(foo['kwargs']), 1) -        self.assertTrue('foo' in foo['kwargs']) -        self.assertEquals(foo['kwargs']['foo'], 'bar') -     -        callbacks['before'] = {} -     -        @pre_dispatch(TrackingTestCase.class_func) -        def test(**kwargs): -            foo.update(kwargs) -     -        self.assertTrue(hasattr(TrackingTestCase.class_func, '__wrapped__')) -        self.assertEquals(len(callbacks['before']), 1) - -        self.class_func('hello', foo='bar') - -        self.assertTrue('sender' in foo, foo) -        # best we can do -        self.assertEquals(foo['sender'].__name__, 'class_func') -        self.assertTrue('start' in foo, foo) -        self.assertTrue(foo['start'] > 0) -        self.assertTrue('stop' not in foo, foo) -        self.assertTrue('args' in foo, foo) -        self.assertTrue(len(foo['args']), 2) -        self.assertEquals(foo['args'][1], 'hello') -        self.assertTrue('kwargs' in foo, foo) -        self.assertTrue(len(foo['kwargs']), 1) -        self.assertTrue('foo' in foo['kwargs']) -        self.assertEquals(foo['kwargs']['foo'], 'bar') - -        # callbacks['before'] = {} -        #      -        #         @pre_dispatch(TrackingTestCase.class_method) -        #         def test(**kwargs): -        #             foo.update(kwargs) -        #      -        #         self.assertTrue(hasattr(TrackingTestCase.class_method, '__wrapped__')) -        #         self.assertEquals(len(callbacks['before']), 1) -        #  -        #         TrackingTestCase.class_method() -        #  -        #         self.assertTrue('sender' in foo, foo) -        #         # best we can do -        #         self.assertEquals(foo['sender'].__name__, 'class_method') -        #         self.assertTrue('start' in foo, foo) -        #         self.assertTrue('stop' not in foo, foo) -        #         self.assertTrue('args' in foo, foo) - -    def test_post_hook(self): -        foo = {} -         -        @post_dispatch(module_func) -        def test(**kwargs): -            foo.update(kwargs) -             -        self.assertTrue(hasattr(module_func, '__wrapped__')) -        self.assertEquals(len(callbacks['after']), 1) -         -        module_func('hi', foo='bar') -         -        self.assertTrue('sender' in foo, foo) -        # best we can do -        self.assertEquals(foo['sender'].__name__, 'module_func') -        self.assertTrue('start' in foo, foo) -        self.assertTrue(foo['start'] > 0) -        self.assertTrue('stop' in foo, foo) -        self.assertTrue(foo['stop'] > foo['start']) -        self.assertTrue('args' in foo, foo) -        self.assertTrue(len(foo['args']), 1) -        self.assertEquals(foo['args'][0], 'hi') -        self.assertTrue('kwargs' in foo, foo) -        self.assertTrue(len(foo['kwargs']), 1) -        self.assertTrue('foo' in foo['kwargs']) -        self.assertEquals(foo['kwargs']['foo'], 'bar') -     -        callbacks['after'] = {} -     -        @post_dispatch(TrackingTestCase.class_func) -        def test(**kwargs): -            foo.update(kwargs) -     -        self.assertTrue(hasattr(TrackingTestCase.class_func, '__wrapped__')) -        self.assertEquals(len(callbacks['after']), 1) - -        self.class_func('hello', foo='bar') - -        self.assertTrue('sender' in foo, foo) -        # best we can do -        self.assertEquals(foo['sender'].__name__, 'class_func') -        self.assertTrue('start' in foo, foo) -        self.assertTrue(foo['start'] > 0) -        self.assertTrue('stop' in foo, foo) -        self.assertTrue(foo['stop'] > foo['start']) -        self.assertTrue('args' in foo, foo) -        self.assertTrue(len(foo['args']), 2) -        self.assertEquals(foo['args'][1], 'hello') -        self.assertTrue('kwargs' in foo, foo) -        self.assertTrue(len(foo['kwargs']), 1) -        self.assertTrue('foo' in foo['kwargs']) -        self.assertEquals(foo['kwargs']['foo'], 'bar')
\ No newline at end of file diff --git a/debug_toolbar/toolbar/loader.py b/debug_toolbar/toolbar/loader.py index 3501c69..cf7a243 100644 --- a/debug_toolbar/toolbar/loader.py +++ b/debug_toolbar/toolbar/loader.py @@ -9,7 +9,7 @@ from django.utils.datastructures import SortedDict  from django.utils.safestring import mark_safe  class DebugToolbar(object): - +          def __init__(self, request):          self.request = request          self._panels = SortedDict() @@ -38,25 +38,26 @@ class DebugToolbar(object):              'debug_toolbar.panels.logger.LoggingPanel',          )          self.load_panels() +        self.stats = {}      def _get_panels(self):          return self._panels.values()      panels = property(_get_panels) - +          def get_panel(self, cls):          return self._panels[cls] - +          def load_panels(self):          """          Populate debug panels          """          from django.conf import settings          from django.core import exceptions - +                  # Check if settings has a DEBUG_TOOLBAR_PANELS, otherwise use default          if hasattr(settings, 'DEBUG_TOOLBAR_PANELS'):              self.default_panels = settings.DEBUG_TOOLBAR_PANELS - +                  for panel_path in self.default_panels:              try:                  dot = panel_path.rindex('.') @@ -71,14 +72,14 @@ class DebugToolbar(object):                  panel_class = getattr(mod, panel_classname)              except AttributeError:                  raise exceptions.ImproperlyConfigured, 'Toolbar Panel module "%s" does not define a "%s" class' % (panel_module, panel_classname) - +                          try:                  panel_instance = panel_class(context=self.template_context)              except:                  raise # Bubble up problem loading panel - +                          self._panels[panel_class] = panel_instance - +          def render_toolbar(self):          """          Renders the overall Toolbar with panels inside. @@ -91,5 +92,5 @@ class DebugToolbar(object):              'js': mark_safe(open(os.path.join(media_path, 'js', 'toolbar.min.js'), 'r').read()),              'css': mark_safe(open(os.path.join(media_path, 'css', 'toolbar.min.css'), 'r').read()),          }) - +                  return render_to_string('debug_toolbar/base.html', context) diff --git a/debug_toolbar/utils/__init__.py b/debug_toolbar/utils/__init__.py index 3f035e6..c4dc160 100644 --- a/debug_toolbar/utils/__init__.py +++ b/debug_toolbar/utils/__init__.py @@ -36,14 +36,18 @@ def tidy_stacktrace(stack):              continue          if socketserver_path in s_path:              continue -        trace.append((path, line_no, func_name, (''.join(text)).strip())) +        if not text: +            text = '' +        else: +            text = (''.join(text)).strip() +        trace.append((path, line_no, func_name, text))      return trace  def get_template_info(source, context_lines=3):      line = 0      upto = 0      source_lines = [] -    before = during = after = "" +    # before = during = after = ""      origin, (start, end) = source      template_source = origin.reload() @@ -51,9 +55,9 @@ def get_template_info(source, context_lines=3):      for num, next in enumerate(linebreak_iter(template_source)):          if start >= upto and end <= next:              line = num -            before = template_source[upto:start] -            during = template_source[start:end] -            after = template_source[end:next] +            # before = template_source[upto:start] +            # during = template_source[start:end] +            # after = template_source[end:next]          source_lines.append((num, template_source[upto:next]))          upto = next @@ -71,4 +75,18 @@ def get_template_info(source, context_lines=3):      return {          'name': origin.name,          'context': context, -    }
\ No newline at end of file +    } + +def get_name_from_obj(obj): +    if hasattr(obj, '__name__'): +        name = obj.__name__ +    elif hasattr(obj, '__class__') and hasattr(obj.__class__, '__name__'): +        name = obj.__class__.__name__ +    else: +        name = '<unknown>' +     +    if hasattr(obj, '__module__'): +        module = obj.__module__ +        name = '%s.%s' % (module, name) + +    return name
\ No newline at end of file diff --git a/debug_toolbar/utils/sqlparse/__init__.py b/debug_toolbar/utils/sqlparse/__init__.py index 69873ca..99db30e 100644 --- a/debug_toolbar/utils/sqlparse/__init__.py +++ b/debug_toolbar/utils/sqlparse/__init__.py @@ -6,10 +6,7 @@  """Parse SQL statements.""" -__version__ = '0.1.1' - - -import os +__version__ = '0.1.3'  class SQLParseError(Exception): @@ -56,4 +53,3 @@ def split(sql):      stack = engine.FilterStack()      stack.split_statements = True      return [unicode(stmt) for stmt in stack.run(sql)] - diff --git a/debug_toolbar/utils/sqlparse/engine/__init__.py b/debug_toolbar/utils/sqlparse/engine/__init__.py index cae0793..e838a3e 100644 --- a/debug_toolbar/utils/sqlparse/engine/__init__.py +++ b/debug_toolbar/utils/sqlparse/engine/__init__.py @@ -5,9 +5,7 @@  """filter""" -import re - -from debug_toolbar.utils.sqlparse import lexer, SQLParseError +from debug_toolbar.utils.sqlparse import lexer  from debug_toolbar.utils.sqlparse.engine import grouping  from debug_toolbar.utils.sqlparse.engine.filter import StatementFilter @@ -42,8 +40,8 @@ class FilterStack(object):          stream = lexer.tokenize(sql)          # Process token stream          if self.preprocess: -           for filter_ in self.preprocess: -               stream = filter_.process(self, stream) +            for filter_ in self.preprocess: +                stream = filter_.process(self, stream)          if (self.stmtprocess or self.postprocess or self.split_statements              or self._grouping): @@ -51,6 +49,7 @@ class FilterStack(object):              stream = splitter.process(self, stream)          if self._grouping: +              def _group(stream):                  for stmt in stream:                      grouping.group(stmt) @@ -58,23 +57,24 @@ class FilterStack(object):              stream = _group(stream)          if self.stmtprocess: -            def _run(stream): + +            def _run1(stream):                  ret = []                  for stmt in stream:                      for filter_ in self.stmtprocess:                          filter_.process(self, stmt)                      ret.append(stmt)                  return ret -            stream = _run(stream) +            stream = _run1(stream)          if self.postprocess: -            def _run(stream): + +            def _run2(stream):                  for stmt in stream:                      stmt.tokens = list(self._flatten(stmt.tokens))                      for filter_ in self.postprocess:                          stmt = filter_.process(self, stmt)                      yield stmt -            stream = _run(stream) +            stream = _run2(stream)          return stream - diff --git a/debug_toolbar/utils/sqlparse/engine/filter.py b/debug_toolbar/utils/sqlparse/engine/filter.py index 8d1c7b2..c1c0d6a 100644 --- a/debug_toolbar/utils/sqlparse/engine/filter.py +++ b/debug_toolbar/utils/sqlparse/engine/filter.py @@ -1,7 +1,7 @@  # -*- coding: utf-8 -*- +from debug_toolbar.utils.sqlparse.sql import Statement, Token  from debug_toolbar.utils.sqlparse import tokens as T -from debug_toolbar.utils.sqlparse.engine.grouping import Statement, Token  class TokenFilter(object): @@ -21,11 +21,13 @@ class StatementFilter(TokenFilter):          self._in_declare = False          self._in_dbldollar = False          self._is_create = False +        self._begin_depth = 0      def _reset(self):          self._in_declare = False          self._in_dbldollar = False          self._is_create = False +        self._begin_depth = 0      def _change_splitlevel(self, ttype, value):          # PostgreSQL @@ -41,29 +43,32 @@ class StatementFilter(TokenFilter):              return 0          # ANSI -        if ttype is not T.Keyword: +        if ttype not in T.Keyword:              return 0          unified = value.upper() -        if unified == 'DECLARE': +        if unified == 'DECLARE' and self._is_create:              self._in_declare = True              return 1          if unified == 'BEGIN': -            if self._in_declare: +            self._begin_depth += 1 +            if self._in_declare:  # FIXME(andi): This makes no sense.                  return 0              return 0          if unified == 'END':              # Should this respect a preceeding BEGIN?              # In CASE ... WHEN ... END this results in a split level -1. +            self._begin_depth = max(0, self._begin_depth-1)              return -1          if ttype is T.Keyword.DDL and unified.startswith('CREATE'):              self._is_create = True +            return 0 -        if unified in ('IF', 'FOR') and self._is_create: +        if unified in ('IF', 'FOR') and self._is_create and self._begin_depth > 0:              return 1          # Default diff --git a/debug_toolbar/utils/sqlparse/engine/grouping.py b/debug_toolbar/utils/sqlparse/engine/grouping.py index 532ccec..4e50c7b 100644 --- a/debug_toolbar/utils/sqlparse/engine/grouping.py +++ b/debug_toolbar/utils/sqlparse/engine/grouping.py @@ -1,16 +1,19 @@  # -*- coding: utf-8 -*-  import itertools -import re -import types +from debug_toolbar.utils.sqlparse import sql  from debug_toolbar.utils.sqlparse import tokens as T -from debug_toolbar.utils.sqlparse.sql import * +try: +    next +except NameError:  # Python < 2.6 +    next = lambda i: i.next()  def _group_left_right(tlist, ttype, value, cls,                        check_right=lambda t: True, +                      check_left=lambda t: True,                        include_semicolon=False):      [_group_left_right(sgroup, ttype, value, cls, check_right,                         include_semicolon) for sgroup in tlist.get_sublists() @@ -20,14 +23,20 @@ def _group_left_right(tlist, ttype, value, cls,      while token:          right = tlist.token_next(tlist.token_index(token))          left = tlist.token_prev(tlist.token_index(token)) -        if (right is None or not check_right(right) -            or left is None): -            token = tlist.token_next_match(tlist.token_index(token)+1, +        if right is None or not check_right(right): +            token = tlist.token_next_match(tlist.token_index(token) + 1, +                                           ttype, value) +        elif left is None or not check_right(left): +            token = tlist.token_next_match(tlist.token_index(token) + 1,                                             ttype, value)          else:              if include_semicolon: -                right = tlist.token_next_match(tlist.token_index(right), -                                               T.Punctuation, ';') +                sright = tlist.token_next_match(tlist.token_index(right), +                                                T.Punctuation, ';') +                if sright is not None: +                    # only overwrite "right" if a semicolon is actually +                    # present. +                    right = sright              tokens = tlist.tokens_between(left, right)[1:]              if not isinstance(left, cls):                  new = cls([left]) @@ -38,9 +47,10 @@ def _group_left_right(tlist, ttype, value, cls,              left.tokens.extend(tokens)              for t in tokens:                  tlist.tokens.remove(t) -            token = tlist.token_next_match(tlist.token_index(left)+1, +            token = tlist.token_next_match(tlist.token_index(left) + 1,                                             ttype, value) +  def _group_matching(tlist, start_ttype, start_value, end_ttype, end_value,                      cls, include_semicolon=False, recurse=False):      def _find_matching(i, tl, stt, sva, ett, eva): @@ -66,7 +76,7 @@ def _group_matching(tlist, start_ttype, start_value, end_ttype, end_value,          end = _find_matching(tidx, tlist, start_ttype, start_value,                               end_ttype, end_value)          if end is None: -            idx = tidx+1 +            idx = tidx + 1          else:              if include_semicolon:                  next_ = tlist.token_next(tlist.token_index(end)) @@ -75,71 +85,102 @@ def _group_matching(tlist, start_ttype, start_value, end_ttype, end_value,              group = tlist.group_tokens(cls, tlist.tokens_between(token, end))              _group_matching(group, start_ttype, start_value,                              end_ttype, end_value, cls, include_semicolon) -            idx = tlist.token_index(group)+1 +            idx = tlist.token_index(group) + 1          token = tlist.token_next_match(idx, start_ttype, start_value) +  def group_if(tlist): -    _group_matching(tlist, T.Keyword, 'IF', T.Keyword, 'END IF', If, True) +    _group_matching(tlist, T.Keyword, 'IF', T.Keyword, 'END IF', sql.If, True) +  def group_for(tlist): -    _group_matching(tlist, T.Keyword, 'FOR', T.Keyword, 'END LOOP', For, True) +    _group_matching(tlist, T.Keyword, 'FOR', T.Keyword, 'END LOOP', +                    sql.For, True) +  def group_as(tlist): -    _group_left_right(tlist, T.Keyword, 'AS', Identifier) + +    def _right_valid(token): +        # Currently limited to DML/DDL. Maybe additional more non SQL reserved +        # keywords should appear here (see issue8). +        return not token.ttype in (T.DML, T.DDL) +    _group_left_right(tlist, T.Keyword, 'AS', sql.Identifier, +                      check_right=_right_valid) +  def group_assignment(tlist): -    _group_left_right(tlist, T.Assignment, ':=', Assignment, +    _group_left_right(tlist, T.Assignment, ':=', sql.Assignment,                        include_semicolon=True) -def group_comparsion(tlist): -    _group_left_right(tlist, T.Operator, None, Comparsion) + +def group_comparison(tlist): + +    def _parts_valid(token): +        return (token.ttype in (T.String.Symbol, T.Name, T.Number, +                                T.Number.Integer, T.Literal, +                                T.Literal.Number.Integer) +                or isinstance(token, (sql.Identifier,))) +    _group_left_right(tlist, T.Operator.Comparison, None, sql.Comparison, +                      check_left=_parts_valid, check_right=_parts_valid)  def group_case(tlist): -    _group_matching(tlist, T.Keyword, 'CASE', T.Keyword, 'END', Case, +    _group_matching(tlist, T.Keyword, 'CASE', T.Keyword, 'END', sql.Case,                      include_semicolon=True, recurse=True)  def group_identifier(tlist):      def _consume_cycle(tl, i): -        x = itertools.cycle((lambda y: y.match(T.Punctuation, '.'), -                             lambda y: y.ttype in (T.String.Symbol, -                                                   T.Name, -                                                   T.Wildcard))) +        x = itertools.cycle(( +            lambda y: (y.match(T.Punctuation, '.') +                       or y.ttype is T.Operator), +            lambda y: (y.ttype in (T.String.Symbol, +                                   T.Name, +                                   T.Wildcard, +                                   T.Literal.Number.Integer))))          for t in tl.tokens[i:]: -            if x.next()(t): +            if next(x)(t):                  yield t              else:                  raise StopIteration      # bottom up approach: group subgroups first      [group_identifier(sgroup) for sgroup in tlist.get_sublists() -     if not isinstance(sgroup, Identifier)] +     if not isinstance(sgroup, sql.Identifier)]      # real processing      idx = 0 -    token = tlist.token_next_by_type(idx, (T.String.Symbol, T.Name)) +    token = tlist.token_next_by_instance(idx, sql.Function) +    if token is None: +        token = tlist.token_next_by_type(idx, (T.String.Symbol, T.Name))      while token: -        identifier_tokens = [token]+list( +        identifier_tokens = [token] + list(              _consume_cycle(tlist, -                           tlist.token_index(token)+1)) -        group = tlist.group_tokens(Identifier, identifier_tokens) -        idx = tlist.token_index(group)+1 -        token = tlist.token_next_by_type(idx, (T.String.Symbol, T.Name)) +                           tlist.token_index(token) + 1)) +        if not (len(identifier_tokens) == 1 +                and isinstance(identifier_tokens[0], sql.Function)): +            group = tlist.group_tokens(sql.Identifier, identifier_tokens) +            idx = tlist.token_index(group) + 1 +        else: +            idx += 1 +        token = tlist.token_next_by_instance(idx, sql.Function) +        if token is None: +            token = tlist.token_next_by_type(idx, (T.String.Symbol, T.Name))  def group_identifier_list(tlist):      [group_identifier_list(sgroup) for sgroup in tlist.get_sublists() -     if not isinstance(sgroup, (Identifier, IdentifierList))] +     if not isinstance(sgroup, sql.IdentifierList)]      idx = 0      # Allowed list items -    fend1_funcs = [lambda t: isinstance(t, Identifier), +    fend1_funcs = [lambda t: isinstance(t, (sql.Identifier, sql.Function)),                     lambda t: t.is_whitespace(), +                   lambda t: t.ttype == T.Name,                     lambda t: t.ttype == T.Wildcard,                     lambda t: t.match(T.Keyword, 'null'),                     lambda t: t.ttype == T.Number.Integer,                     lambda t: t.ttype == T.String.Single, -                   lambda t: isinstance(t, Comparsion), +                   lambda t: isinstance(t, sql.Comparison),                     ]      tcomma = tlist.token_next_match(idx, T.Punctuation, ',')      start = None @@ -156,7 +197,7 @@ def group_identifier_list(tlist):          if not bpassed or not apassed:              # Something's wrong here, skip ahead to next ","              start = None -            tcomma = tlist.token_next_match(tlist.token_index(tcomma)+1, +            tcomma = tlist.token_next_match(tlist.token_index(tcomma) + 1,                                              T.Punctuation, ',')          else:              if start is None: @@ -165,25 +206,27 @@ def group_identifier_list(tlist):              if next_ is None or not next_.match(T.Punctuation, ','):                  # Reached the end of the list                  tokens = tlist.tokens_between(start, after) -                group = tlist.group_tokens(IdentifierList, tokens) +                group = tlist.group_tokens(sql.IdentifierList, tokens)                  start = None -                tcomma = tlist.token_next_match(tlist.token_index(group)+1, +                tcomma = tlist.token_next_match(tlist.token_index(group) + 1,                                                  T.Punctuation, ',')              else:                  tcomma = next_  def group_parenthesis(tlist): -    _group_matching(tlist, T.Punctuation, '(', T.Punctuation, ')', Parenthesis) +    _group_matching(tlist, T.Punctuation, '(', T.Punctuation, ')', +                    sql.Parenthesis) +  def group_comments(tlist):      [group_comments(sgroup) for sgroup in tlist.get_sublists() -     if not isinstance(sgroup, Comment)] +     if not isinstance(sgroup, sql.Comment)]      idx = 0      token = tlist.token_next_by_type(idx, T.Comment)      while token:          tidx = tlist.token_index(token) -        end = tlist.token_not_matching(tidx+1, +        end = tlist.token_not_matching(tidx + 1,                                         [lambda t: t.ttype in T.Comment,                                          lambda t: t.is_whitespace()])          if end is None: @@ -192,49 +235,70 @@ def group_comments(tlist):              eidx = tlist.token_index(end)              grp_tokens = tlist.tokens_between(token,                                                tlist.token_prev(eidx, False)) -            group = tlist.group_tokens(Comment, grp_tokens) +            group = tlist.group_tokens(sql.Comment, grp_tokens)              idx = tlist.token_index(group)          token = tlist.token_next_by_type(idx, T.Comment) +  def group_where(tlist):      [group_where(sgroup) for sgroup in tlist.get_sublists() -     if not isinstance(sgroup, Where)] +     if not isinstance(sgroup, sql.Where)]      idx = 0      token = tlist.token_next_match(idx, T.Keyword, 'WHERE')      stopwords = ('ORDER', 'GROUP', 'LIMIT', 'UNION')      while token:          tidx = tlist.token_index(token) -        end = tlist.token_next_match(tidx+1, T.Keyword, stopwords) +        end = tlist.token_next_match(tidx + 1, T.Keyword, stopwords)          if end is None: -            end = tlist.tokens[-1] +            end = tlist._groupable_tokens[-1]          else: -            end = tlist.tokens[tlist.token_index(end)-1] -        group = tlist.group_tokens(Where, tlist.tokens_between(token, end)) +            end = tlist.tokens[tlist.token_index(end) - 1] +        group = tlist.group_tokens(sql.Where, +                                   tlist.tokens_between(token, end), +                                   ignore_ws=True)          idx = tlist.token_index(group)          token = tlist.token_next_match(idx, T.Keyword, 'WHERE') +  def group_aliased(tlist):      [group_aliased(sgroup) for sgroup in tlist.get_sublists() -     if not isinstance(sgroup, Identifier)] +     if not isinstance(sgroup, (sql.Identifier, sql.Function))]      idx = 0 -    token = tlist.token_next_by_instance(idx, Identifier) +    token = tlist.token_next_by_instance(idx, (sql.Identifier, sql.Function))      while token:          next_ = tlist.token_next(tlist.token_index(token)) -        if next_ is not None and isinstance(next_, Identifier): +        if next_ is not None and isinstance(next_, (sql.Identifier, sql.Function)):              grp = tlist.tokens_between(token, next_)[1:]              token.tokens.extend(grp)              for t in grp:                  tlist.tokens.remove(t) -        idx = tlist.token_index(token)+1 -        token = tlist.token_next_by_instance(idx, Identifier) +        idx = tlist.token_index(token) + 1 +        token = tlist.token_next_by_instance(idx, (sql.Identifier, sql.Function))  def group_typecasts(tlist): -    _group_left_right(tlist, T.Punctuation, '::', Identifier) +    _group_left_right(tlist, T.Punctuation, '::', sql.Identifier) + + +def group_functions(tlist): +    [group_functions(sgroup) for sgroup in tlist.get_sublists() +     if not isinstance(sgroup, sql.Function)] +    idx = 0 +    token = tlist.token_next_by_type(idx, T.Name) +    while token: +        next_ = tlist.token_next(token) +        if not isinstance(next_, sql.Parenthesis): +            idx = tlist.token_index(token) + 1 +        else: +            func = tlist.group_tokens(sql.Function, +                                      tlist.tokens_between(token, next_)) +            idx = tlist.token_index(func) + 1 +        token = tlist.token_next_by_type(idx, T.Name)  def group(tlist):      for func in [group_parenthesis, +                 group_functions,                   group_comments,                   group_where,                   group_case, @@ -243,8 +307,8 @@ def group(tlist):                   group_as,                   group_aliased,                   group_assignment, -                 group_comparsion, +                 group_comparison,                   group_identifier_list,                   group_if, -                 group_for,]: +                 group_for]:          func(tlist) diff --git a/debug_toolbar/utils/sqlparse/filters.py b/debug_toolbar/utils/sqlparse/filters.py index 3c92791..2d247e7 100644 --- a/debug_toolbar/utils/sqlparse/filters.py +++ b/debug_toolbar/utils/sqlparse/filters.py @@ -2,7 +2,6 @@  import re -from debug_toolbar.utils.sqlparse.engine import grouping  from debug_toolbar.utils.sqlparse import tokens as T  from debug_toolbar.utils.sqlparse import sql @@ -19,34 +18,6 @@ class TokenFilter(Filter):          raise NotImplementedError -# FIXME: Should be removed -def rstrip(stream): -    buff = [] -    for token in stream: -        if token.is_whitespace() and '\n' in token.value: -            # assuming there's only one \n in value -            before, rest = token.value.split('\n', 1) -            token.value = '\n%s' % rest -            buff = [] -            yield token -        elif token.is_whitespace(): -            buff.append(token) -        elif token.is_group(): -            token.tokens = list(rstrip(token.tokens)) -            # process group and look if it starts with a nl -            if token.tokens and token.tokens[0].is_whitespace(): -                before, rest = token.tokens[0].value.split('\n', 1) -                token.tokens[0].value = '\n%s' % rest -                buff = [] -            while buff: -                yield buff.pop(0) -            yield token -        else: -            while buff: -                yield buff.pop(0) -            yield token - -  # --------------------------  # token process @@ -74,17 +45,28 @@ class KeywordCaseFilter(_CaseFilter):  class IdentifierCaseFilter(_CaseFilter):      ttype = (T.Name, T.String.Symbol) +    def process(self, stack, stream): +        for ttype, value in stream: +            if ttype in self.ttype and not value.strip()[0] == '"': +                value = self.convert(value) +            yield ttype, value +  # ----------------------  # statement process  class StripCommentsFilter(Filter): +    def _get_next_comment(self, tlist): +        # TODO(andi) Comment types should be unified, see related issue38 +        token = tlist.token_next_by_instance(0, sql.Comment) +        if token is None: +            token = tlist.token_next_by_type(0, T.Comment) +        return token +      def _process(self, tlist): -        idx = 0 -        clss = set([x.__class__ for x in tlist.tokens]) -        while grouping.Comment in clss: -            token = tlist.token_next_by_instance(0, grouping.Comment) +        token = self._get_next_comment(tlist) +        while token:              tidx = tlist.token_index(token)              prev = tlist.token_prev(tidx, False)              next_ = tlist.token_next(tidx, False) @@ -94,10 +76,10 @@ class StripCommentsFilter(Filter):                  and not prev.is_whitespace() and not next_.is_whitespace()                  and not (prev.match(T.Punctuation, '(')                           or next_.match(T.Punctuation, ')'))): -                tlist.tokens[tidx] = grouping.Token(T.Whitespace, ' ') +                tlist.tokens[tidx] = sql.Token(T.Whitespace, ' ')              else:                  tlist.tokens.pop(tidx) -            clss = set([x.__class__ for x in tlist.tokens]) +            token = self._get_next_comment(tlist)      def process(self, stack, stmt):          [self.process(stack, sgroup) for sgroup in stmt.get_sublists()] @@ -149,24 +131,32 @@ class ReindentFilter(Filter):      def _get_offset(self, token):          all_ = list(self._curr_stmt.flatten())          idx = all_.index(token) -        raw = ''.join(unicode(x) for x in all_[:idx+1]) +        raw = ''.join(unicode(x) for x in all_[:idx + 1])          line = raw.splitlines()[-1]          # Now take current offset into account and return relative offset. -        full_offset = len(line)-(len(self.char*(self.width*self.indent))) +        full_offset = len(line) - len(self.char * (self.width * self.indent))          return full_offset - self.offset      def nl(self):          # TODO: newline character should be configurable -        ws = '\n'+(self.char*((self.indent*self.width)+self.offset)) -        return grouping.Token(T.Whitespace, ws) +        ws = '\n' + (self.char * ((self.indent * self.width) + self.offset)) +        return sql.Token(T.Whitespace, ws)      def _split_kwds(self, tlist):          split_words = ('FROM', 'JOIN$', 'AND', 'OR',                         'GROUP', 'ORDER', 'UNION', 'VALUES', -                       'SET') -        idx = 0 -        token = tlist.token_next_match(idx, T.Keyword, split_words, +                       'SET', 'BETWEEN') +        def _next_token(i): +            t = tlist.token_next_match(i, T.Keyword, split_words,                                         regex=True) +            if t and t.value.upper() == 'BETWEEN': +                t = _next_token(tlist.token_index(t)+1) +                if t and t.value.upper() == 'AND': +                    t = _next_token(tlist.token_index(t)+1) +            return t + +        idx = 0 +        token = _next_token(idx)          while token:              prev = tlist.token_prev(tlist.token_index(token), False)              offset = 1 @@ -181,8 +171,7 @@ class ReindentFilter(Filter):              else:                  nl = self.nl()                  tlist.insert_before(token, nl) -            token = tlist.token_next_match(tlist.token_index(nl)+offset, -                                           T.Keyword, split_words, regex=True) +            token = _next_token(tlist.token_index(nl) + offset)      def _split_statements(self, tlist):          idx = 0 @@ -195,7 +184,7 @@ class ReindentFilter(Filter):              if prev:                  nl = self.nl()                  tlist.insert_before(token, nl) -            token = tlist.token_next_by_type(tlist.token_index(token)+1, +            token = tlist.token_next_by_type(tlist.token_index(token) + 1,                                               (T.Keyword.DDL, T.Keyword.DML))      def _process(self, tlist): @@ -227,9 +216,9 @@ class ReindentFilter(Filter):      def _process_identifierlist(self, tlist):          identifiers = tlist.get_identifiers() -        if len(identifiers) > 1: +        if len(identifiers) > 1 and not tlist.within(sql.Function):              first = list(identifiers[0].flatten())[0] -            num_offset = self._get_offset(first)-len(first.value) +            num_offset = self._get_offset(first) - len(first.value)              self.offset += num_offset              for token in identifiers[1:]:                  tlist.insert_before(token, self.nl()) @@ -237,16 +226,16 @@ class ReindentFilter(Filter):          self._process_default(tlist)      def _process_case(self, tlist): -        cases = tlist.get_cases()          is_first = True          num_offset = None          case = tlist.tokens[0] -        outer_offset = self._get_offset(case)-len(case.value) +        outer_offset = self._get_offset(case) - len(case.value)          self.offset += outer_offset          for cond, value in tlist.get_cases():              if is_first: +                tcond = list(cond[0].flatten())[0]                  is_first = False -                num_offset = self._get_offset(cond[0])-len(cond[0].value) +                num_offset = self._get_offset(tcond) - len(tcond.value)                  self.offset += num_offset                  continue              if cond is None: @@ -273,17 +262,17 @@ class ReindentFilter(Filter):          [self._process(sgroup) for sgroup in tlist.get_sublists()]      def process(self, stack, stmt): -        if isinstance(stmt, grouping.Statement): +        if isinstance(stmt, sql.Statement):              self._curr_stmt = stmt          self._process(stmt) -        if isinstance(stmt, grouping.Statement): +        if isinstance(stmt, sql.Statement):              if self._last_stmt is not None:                  if self._last_stmt.to_unicode().endswith('\n'):                      nl = '\n'                  else:                      nl = '\n\n'                  stmt.tokens.insert(0, -                    grouping.Token(T.Whitespace, nl)) +                    sql.Token(T.Whitespace, nl))              if self._last_stmt != stmt:                  self._last_stmt = stmt @@ -292,7 +281,7 @@ class ReindentFilter(Filter):  class RightMarginFilter(Filter):      keep_together = ( -#        grouping.TypeCast, grouping.Identifier, grouping.Alias, +#        sql.TypeCast, sql.Identifier, sql.Alias,      )      def __init__(self, width=79): @@ -317,7 +306,7 @@ class RightMarginFilter(Filter):                          indent = match.group()                      else:                          indent = '' -                    yield grouping.Token(T.Whitespace, '\n%s' % indent) +                    yield sql.Token(T.Whitespace, '\n%s' % indent)                      self.line = indent                  self.line += val              yield token @@ -349,14 +338,14 @@ class OutputPythonFilter(Filter):      def _process(self, stream, varname, count, has_nl):          if count > 1: -            yield grouping.Token(T.Whitespace, '\n') -        yield grouping.Token(T.Name, varname) -        yield grouping.Token(T.Whitespace, ' ') -        yield grouping.Token(T.Operator, '=') -        yield grouping.Token(T.Whitespace, ' ') +            yield sql.Token(T.Whitespace, '\n') +        yield sql.Token(T.Name, varname) +        yield sql.Token(T.Whitespace, ' ') +        yield sql.Token(T.Operator, '=') +        yield sql.Token(T.Whitespace, ' ')          if has_nl: -            yield grouping.Token(T.Operator, '(') -        yield grouping.Token(T.Text, "'") +            yield sql.Token(T.Operator, '(') +        yield sql.Token(T.Text, "'")          cnt = 0          for token in stream:              cnt += 1 @@ -364,20 +353,20 @@ class OutputPythonFilter(Filter):                  if cnt == 1:                      continue                  after_lb = token.value.split('\n', 1)[1] -                yield grouping.Token(T.Text, " '") -                yield grouping.Token(T.Whitespace, '\n') -                for i in range(len(varname)+4): -                    yield grouping.Token(T.Whitespace, ' ') -                yield grouping.Token(T.Text, "'") +                yield sql.Token(T.Text, " '") +                yield sql.Token(T.Whitespace, '\n') +                for i in range(len(varname) + 4): +                    yield sql.Token(T.Whitespace, ' ') +                yield sql.Token(T.Text, "'")                  if after_lb:  # it's the indendation -                    yield grouping.Token(T.Whitespace, after_lb) +                    yield sql.Token(T.Whitespace, after_lb)                  continue              elif token.value and "'" in token.value:                  token.value = token.value.replace("'", "\\'") -            yield grouping.Token(T.Text, token.value or '') -        yield grouping.Token(T.Text, "'") +            yield sql.Token(T.Text, token.value or '') +        yield sql.Token(T.Text, "'")          if has_nl: -            yield grouping.Token(T.Operator, ')') +            yield sql.Token(T.Operator, ')')      def process(self, stack, stmt):          self.cnt += 1 @@ -398,36 +387,32 @@ class OutputPHPFilter(Filter):      def _process(self, stream, varname):          if self.count > 1: -            yield grouping.Token(T.Whitespace, '\n') -        yield grouping.Token(T.Name, varname) -        yield grouping.Token(T.Whitespace, ' ') -        yield grouping.Token(T.Operator, '=') -        yield grouping.Token(T.Whitespace, ' ') -        yield grouping.Token(T.Text, '"') -        cnt = 0 +            yield sql.Token(T.Whitespace, '\n') +        yield sql.Token(T.Name, varname) +        yield sql.Token(T.Whitespace, ' ') +        yield sql.Token(T.Operator, '=') +        yield sql.Token(T.Whitespace, ' ') +        yield sql.Token(T.Text, '"')          for token in stream:              if token.is_whitespace() and '\n' in token.value: -#                cnt += 1 -#                if cnt == 1: -#                    continue                  after_lb = token.value.split('\n', 1)[1] -                yield grouping.Token(T.Text, ' "') -                yield grouping.Token(T.Operator, ';') -                yield grouping.Token(T.Whitespace, '\n') -                yield grouping.Token(T.Name, varname) -                yield grouping.Token(T.Whitespace, ' ') -                yield grouping.Token(T.Punctuation, '.') -                yield grouping.Token(T.Operator, '=') -                yield grouping.Token(T.Whitespace, ' ') -                yield grouping.Token(T.Text, '"') +                yield sql.Token(T.Text, ' "') +                yield sql.Token(T.Operator, ';') +                yield sql.Token(T.Whitespace, '\n') +                yield sql.Token(T.Name, varname) +                yield sql.Token(T.Whitespace, ' ') +                yield sql.Token(T.Punctuation, '.') +                yield sql.Token(T.Operator, '=') +                yield sql.Token(T.Whitespace, ' ') +                yield sql.Token(T.Text, '"')                  if after_lb: -                    yield grouping.Token(T.Text, after_lb) +                    yield sql.Token(T.Text, after_lb)                  continue              elif '"' in token.value:                  token.value = token.value.replace('"', '\\"') -            yield grouping.Token(T.Text, token.value) -        yield grouping.Token(T.Text, '"') -        yield grouping.Token(T.Punctuation, ';') +            yield sql.Token(T.Text, token.value) +        yield sql.Token(T.Text, '"') +        yield sql.Token(T.Punctuation, ';')      def process(self, stack, stmt):          self.count += 1 @@ -437,4 +422,3 @@ class OutputPHPFilter(Filter):              varname = self.varname          stmt.tokens = tuple(self._process(stmt.tokens, varname))          return stmt - diff --git a/debug_toolbar/utils/sqlparse/formatter.py b/debug_toolbar/utils/sqlparse/formatter.py index 34e9fe0..3acece9 100644 --- a/debug_toolbar/utils/sqlparse/formatter.py +++ b/debug_toolbar/utils/sqlparse/formatter.py @@ -76,11 +76,11 @@ def build_filter_stack(stack, options):        options: Dictionary with options validated by validate_options.      """      # Token filter -    if 'keyword_case' in options: +    if options.get('keyword_case', None):          stack.preprocess.append(              filters.KeywordCaseFilter(options['keyword_case'])) -    if 'identifier_case' in options: +    if options.get('identifier_case', None):          stack.preprocess.append(              filters.IdentifierCaseFilter(options['identifier_case'])) @@ -118,5 +118,3 @@ def build_filter_stack(stack, options):              stack.postprocess.append(fltr)      return stack - - diff --git a/debug_toolbar/utils/sqlparse/keywords.py b/debug_toolbar/utils/sqlparse/keywords.py index cada139..4782cfe 100644 --- a/debug_toolbar/utils/sqlparse/keywords.py +++ b/debug_toolbar/utils/sqlparse/keywords.py @@ -1,590 +1,565 @@ -from debug_toolbar.utils.sqlparse.tokens import * +from debug_toolbar.utils.sqlparse import tokens  KEYWORDS = { -    'ABORT': Keyword, -    'ABS': Keyword, -    'ABSOLUTE': Keyword, -    'ACCESS': Keyword, -    'ADA': Keyword, -    'ADD': Keyword, -    'ADMIN': Keyword, -    'AFTER': Keyword, -    'AGGREGATE': Keyword, -    'ALIAS': Keyword, -    'ALL': Keyword, -    'ALLOCATE': Keyword, -    'ANALYSE': Keyword, -    'ANALYZE': Keyword, -    'AND': Keyword, -    'ANY': Keyword, -    'ARE': Keyword, -    'AS': Keyword, -    'ASC': Keyword, -    'ASENSITIVE': Keyword, -    'ASSERTION': Keyword, -    'ASSIGNMENT': Keyword, -    'ASYMMETRIC': Keyword, -    'AT': Keyword, -    'ATOMIC': Keyword, -    'AUTHORIZATION': Keyword, -    'AVG': Keyword, - -    'BACKWARD': Keyword, -    'BEFORE': Keyword, -    'BEGIN': Keyword, -    'BETWEEN': Keyword, -    'BITVAR': Keyword, -    'BIT_LENGTH': Keyword, -    'BOTH': Keyword, -    'BREADTH': Keyword, -    'BY': Keyword, - -#    'C': Keyword,  # most likely this is an alias -    'CACHE': Keyword, -    'CALL': Keyword, -    'CALLED': Keyword, -    'CARDINALITY': Keyword, -    'CASCADE': Keyword, -    'CASCADED': Keyword, -    'CASE': Keyword, -    'CAST': Keyword, -    'CATALOG': Keyword, -    'CATALOG_NAME': Keyword, -    'CHAIN': Keyword, -    'CHARACTERISTICS': Keyword, -    'CHARACTER_LENGTH': Keyword, -    'CHARACTER_SET_CATALOG': Keyword, -    'CHARACTER_SET_NAME': Keyword, -    'CHARACTER_SET_SCHEMA': Keyword, -    'CHAR_LENGTH': Keyword, -    'CHECK': Keyword, -    'CHECKED': Keyword, -    'CHECKPOINT': Keyword, -    'CLASS': Keyword, -    'CLASS_ORIGIN': Keyword, -    'CLOB': Keyword, -    'CLOSE': Keyword, -    'CLUSTER': Keyword, -    'COALSECE': Keyword, -    'COBOL': Keyword, -    'COLLATE': Keyword, -    'COLLATION': Keyword, -    'COLLATION_CATALOG': Keyword, -    'COLLATION_NAME': Keyword, -    'COLLATION_SCHEMA': Keyword, -    'COLUMN': Keyword, -    'COLUMN_NAME': Keyword, -    'COMMAND_FUNCTION': Keyword, -    'COMMAND_FUNCTION_CODE': Keyword, -    'COMMENT': Keyword, -    'COMMIT': Keyword, -    'COMMITTED': Keyword, -    'COMPLETION': Keyword, -    'CONDITION_NUMBER': Keyword, -    'CONNECT': Keyword, -    'CONNECTION': Keyword, -    'CONNECTION_NAME': Keyword, -    'CONSTRAINT': Keyword, -    'CONSTRAINTS': Keyword, -    'CONSTRAINT_CATALOG': Keyword, -    'CONSTRAINT_NAME': Keyword, -    'CONSTRAINT_SCHEMA': Keyword, -    'CONSTRUCTOR': Keyword, -    'CONTAINS': Keyword, -    'CONTINUE': Keyword, -    'CONVERSION': Keyword, -    'CONVERT': Keyword, -    'COPY': Keyword, -    'CORRESPONTING': Keyword, -    'COUNT': Keyword, -    'CREATEDB': Keyword, -    'CREATEUSER': Keyword, -    'CROSS': Keyword, -    'CUBE': Keyword, -    'CURRENT': Keyword, -    'CURRENT_DATE': Keyword, -    'CURRENT_PATH': Keyword, -    'CURRENT_ROLE': Keyword, -    'CURRENT_TIME': Keyword, -    'CURRENT_TIMESTAMP': Keyword, -    'CURRENT_USER': Keyword, -    'CURSOR': Keyword, -    'CURSOR_NAME': Keyword, -    'CYCLE': Keyword, - -    'DATA': Keyword, -    'DATABASE': Keyword, -    'DATETIME_INTERVAL_CODE': Keyword, -    'DATETIME_INTERVAL_PRECISION': Keyword, -    'DAY': Keyword, -    'DEALLOCATE': Keyword, -    'DECLARE': Keyword, -    'DEFAULT': Keyword, -    'DEFAULTS': Keyword, -    'DEFERRABLE': Keyword, -    'DEFERRED': Keyword, -    'DEFINED': Keyword, -    'DEFINER': Keyword, -    'DELIMITER': Keyword, -    'DELIMITERS': Keyword, -    'DEREF': Keyword, -    'DESC': Keyword, -    'DESCRIBE': Keyword, -    'DESCRIPTOR': Keyword, -    'DESTROY': Keyword, -    'DESTRUCTOR': Keyword, -    'DETERMINISTIC': Keyword, -    'DIAGNOSTICS': Keyword, -    'DICTIONARY': Keyword, -    'DISCONNECT': Keyword, -    'DISPATCH': Keyword, -    'DISTINCT': Keyword, -    'DO': Keyword, -    'DOMAIN': Keyword, -    'DYNAMIC': Keyword, -    'DYNAMIC_FUNCTION': Keyword, -    'DYNAMIC_FUNCTION_CODE': Keyword, - -    'EACH': Keyword, -    'ELSE': Keyword, -    'ENCODING': Keyword, -    'ENCRYPTED': Keyword, -    'END': Keyword, -    'END-EXEC': Keyword, -    'EQUALS': Keyword, -    'ESCAPE': Keyword, -    'EVERY': Keyword, -    'EXCEPT': Keyword, -    'ESCEPTION': Keyword, -    'EXCLUDING': Keyword, -    'EXCLUSIVE': Keyword, -    'EXEC': Keyword, -    'EXECUTE': Keyword, -    'EXISTING': Keyword, -    'EXISTS': Keyword, -    'EXTERNAL': Keyword, -    'EXTRACT': Keyword, - -    'FALSE': Keyword, -    'FETCH': Keyword, -    'FINAL': Keyword, -    'FIRST': Keyword, -    'FOR': Keyword, -    'FORCE': Keyword, -    'FOREIGN': Keyword, -    'FORTRAN': Keyword, -    'FORWARD': Keyword, -    'FOUND': Keyword, -    'FREE': Keyword, -    'FREEZE': Keyword, -    'FROM': Keyword, -    'FULL': Keyword, -    'FUNCTION': Keyword, - -    'G': Keyword, -    'GENERAL': Keyword, -    'GENERATED': Keyword, -    'GET': Keyword, -    'GLOBAL': Keyword, -    'GO': Keyword, -    'GOTO': Keyword, -    'GRANT': Keyword, -    'GRANTED': Keyword, -    'GROUP': Keyword, -    'GROUPING': Keyword, - -    'HANDLER': Keyword, -    'HAVING': Keyword, -    'HIERARCHY': Keyword, -    'HOLD': Keyword, -    'HOST': Keyword, - -    'IDENTITY': Keyword, -    'IF': Keyword, -    'IGNORE': Keyword, -    'ILIKE': Keyword, -    'IMMEDIATE': Keyword, -    'IMMUTABLE': Keyword, - -    'IMPLEMENTATION': Keyword, -    'IMPLICIT': Keyword, -    'IN': Keyword, -    'INCLUDING': Keyword, -    'INCREMENT': Keyword, -    'INDEX': Keyword, - -    'INDITCATOR': Keyword, -    'INFIX': Keyword, -    'INHERITS': Keyword, -    'INITIALIZE': Keyword, -    'INITIALLY': Keyword, -    'INNER': Keyword, -    'INOUT': Keyword, -    'INPUT': Keyword, -    'INSENSITIVE': Keyword, -    'INSTANTIABLE': Keyword, -    'INSTEAD': Keyword, -    'INTERSECT': Keyword, -    'INTO': Keyword, -    'INVOKER': Keyword, -    'IS': Keyword, -    'ISNULL': Keyword, -    'ISOLATION': Keyword, -    'ITERATE': Keyword, - -    'JOIN': Keyword, - -    'K': Keyword, -    'KEY': Keyword, -    'KEY_MEMBER': Keyword, -    'KEY_TYPE': Keyword, - -    'LANCOMPILER': Keyword, -    'LANGUAGE': Keyword, -    'LARGE': Keyword, -    'LAST': Keyword, -    'LATERAL': Keyword, -    'LEADING': Keyword, -    'LEFT': Keyword, -    'LENGTH': Keyword, -    'LESS': Keyword, -    'LEVEL': Keyword, -    'LIKE': Keyword, -    'LIMIT': Keyword, -    'LISTEN': Keyword, -    'LOAD': Keyword, -    'LOCAL': Keyword, -    'LOCALTIME': Keyword, -    'LOCALTIMESTAMP': Keyword, -    'LOCATION': Keyword, -    'LOCATOR': Keyword, -    'LOCK': Keyword, -    'LOWER': Keyword, - -    'M': Keyword, -    'MAP': Keyword, -    'MATCH': Keyword, -    'MAX': Keyword, -    'MAXVALUE': Keyword, -    'MESSAGE_LENGTH': Keyword, -    'MESSAGE_OCTET_LENGTH': Keyword, -    'MESSAGE_TEXT': Keyword, -    'METHOD': Keyword, -    'MIN': Keyword, -    'MINUTE': Keyword, -    'MINVALUE': Keyword, -    'MOD': Keyword, -    'MODE': Keyword, -    'MODIFIES': Keyword, -    'MODIFY': Keyword, -    'MONTH': Keyword, -    'MORE': Keyword, -    'MOVE': Keyword, -    'MUMPS': Keyword, - -    'NAMES': Keyword, -    'NATIONAL': Keyword, -    'NATURAL': Keyword, -    'NCHAR': Keyword, -    'NCLOB': Keyword, -    'NEW': Keyword, -    'NEXT': Keyword, -    'NO': Keyword, -    'NOCREATEDB': Keyword, -    'NOCREATEUSER': Keyword, -    'NONE': Keyword, -    'NOT': Keyword, -    'NOTHING': Keyword, -    'NOTIFY': Keyword, -    'NOTNULL': Keyword, -    'NULL': Keyword, -    'NULLABLE': Keyword, -    'NULLIF': Keyword, - -    'OBJECT': Keyword, -    'OCTET_LENGTH': Keyword, -    'OF': Keyword, -    'OFF': Keyword, -    'OFFSET': Keyword, -    'OIDS': Keyword, -    'OLD': Keyword, -    'ON': Keyword, -    'ONLY': Keyword, -    'OPEN': Keyword, -    'OPERATION': Keyword, -    'OPERATOR': Keyword, -    'OPTION': Keyword, -    'OPTIONS': Keyword, -    'OR': Keyword, -    'ORDER': Keyword, -    'ORDINALITY': Keyword, -    'OUT': Keyword, -    'OUTER': Keyword, -    'OUTPUT': Keyword, -    'OVERLAPS': Keyword, -    'OVERLAY': Keyword, -    'OVERRIDING': Keyword, -    'OWNER': Keyword, - -    'PAD': Keyword, -    'PARAMETER': Keyword, -    'PARAMETERS': Keyword, -    'PARAMETER_MODE': Keyword, -    'PARAMATER_NAME': Keyword, -    'PARAMATER_ORDINAL_POSITION': Keyword, -    'PARAMETER_SPECIFIC_CATALOG': Keyword, -    'PARAMETER_SPECIFIC_NAME': Keyword, -    'PARAMATER_SPECIFIC_SCHEMA': Keyword, -    'PARTIAL': Keyword, -    'PASCAL': Keyword, -    'PENDANT': Keyword, -    'PLACING': Keyword, -    'PLI': Keyword, -    'POSITION': Keyword, -    'POSTFIX': Keyword, -    'PRECISION': Keyword, -    'PREFIX': Keyword, -    'PREORDER': Keyword, -    'PREPARE': Keyword, -    'PRESERVE': Keyword, -    'PRIMARY': Keyword, -    'PRIOR': Keyword, -    'PRIVILEGES': Keyword, -    'PROCEDURAL': Keyword, -    'PROCEDURE': Keyword, -    'PUBLIC': Keyword, - -    'RAISE': Keyword, -    'READ': Keyword, -    'READS': Keyword, -    'RECHECK': Keyword, -    'RECURSIVE': Keyword, -    'REF': Keyword, -    'REFERENCES': Keyword, -    'REFERENCING': Keyword, -    'REINDEX': Keyword, -    'RELATIVE': Keyword, -    'RENAME': Keyword, -    'REPEATABLE': Keyword, -    'REPLACE': Keyword, -    'RESET': Keyword, -    'RESTART': Keyword, -    'RESTRICT': Keyword, -    'RESULT': Keyword, -    'RETURN': Keyword, -    'RETURNED_LENGTH': Keyword, -    'RETURNED_OCTET_LENGTH': Keyword, -    'RETURNED_SQLSTATE': Keyword, -    'RETURNS': Keyword, -    'REVOKE': Keyword, -    'RIGHT': Keyword, -    'ROLE': Keyword, -    'ROLLBACK': Keyword, -    'ROLLUP': Keyword, -    'ROUTINE': Keyword, -    'ROUTINE_CATALOG': Keyword, -    'ROUTINE_NAME': Keyword, -    'ROUTINE_SCHEMA': Keyword, -    'ROW': Keyword, -    'ROWS': Keyword, -    'ROW_COUNT': Keyword, -    'RULE': Keyword, - -    'SAVE_POINT': Keyword, -    'SCALE': Keyword, -    'SCHEMA': Keyword, -    'SCHEMA_NAME': Keyword, -    'SCOPE': Keyword, -    'SCROLL': Keyword, -    'SEARCH': Keyword, -    'SECOND': Keyword, -    'SECURITY': Keyword, -    'SELF': Keyword, -    'SENSITIVE': Keyword, -    'SERIALIZABLE': Keyword, -    'SERVER_NAME': Keyword, -    'SESSION': Keyword, -    'SESSION_USER': Keyword, -    'SETOF': Keyword, -    'SETS': Keyword, -    'SHARE': Keyword, -    'SHOW': Keyword, -    'SIMILAR': Keyword, -    'SIMPLE': Keyword, -    'SIZE': Keyword, -    'SOME': Keyword, -    'SOURCE': Keyword, -    'SPACE': Keyword, -    'SPECIFIC': Keyword, -    'SPECIFICTYPE': Keyword, -    'SPECIFIC_NAME': Keyword, -    'SQL': Keyword, -    'SQLCODE': Keyword, -    'SQLERROR': Keyword, -    'SQLEXCEPTION': Keyword, -    'SQLSTATE': Keyword, -    'SQLWARNINIG': Keyword, -    'STABLE': Keyword, -    'START': Keyword, -    'STATE': Keyword, -    'STATEMENT': Keyword, -    'STATIC': Keyword, -    'STATISTICS': Keyword, -    'STDIN': Keyword, -    'STDOUT': Keyword, -    'STORAGE': Keyword, -    'STRICT': Keyword, -    'STRUCTURE': Keyword, -    'STYPE': Keyword, -    'SUBCLASS_ORIGIN': Keyword, -    'SUBLIST': Keyword, -    'SUBSTRING': Keyword, -    'SUM': Keyword, -    'SYMMETRIC': Keyword, -    'SYSID': Keyword, -    'SYSTEM': Keyword, -    'SYSTEM_USER': Keyword, - -    'TABLE': Keyword, -    'TABLE_NAME': Keyword, -    ' TEMP': Keyword, -    'TEMPLATE': Keyword, -    'TEMPORARY': Keyword, -    'TERMINATE': Keyword, -    'THAN': Keyword, -    'THEN': Keyword, -    'TIMESTAMP': Keyword, -    'TIMEZONE_HOUR': Keyword, -    'TIMEZONE_MINUTE': Keyword, -    'TO': Keyword, -    'TOAST': Keyword, -    'TRAILING': Keyword, -    'TRANSATION': Keyword, -    'TRANSACTIONS_COMMITTED': Keyword, -    'TRANSACTIONS_ROLLED_BACK': Keyword, -    'TRANSATION_ACTIVE': Keyword, -    'TRANSFORM': Keyword, -    'TRANSFORMS': Keyword, -    'TRANSLATE': Keyword, -    'TRANSLATION': Keyword, -    'TREAT': Keyword, -    'TRIGGER': Keyword, -    'TRIGGER_CATALOG': Keyword, -    'TRIGGER_NAME': Keyword, -    'TRIGGER_SCHEMA': Keyword, -    'TRIM': Keyword, -    'TRUE': Keyword, -    'TRUNCATE': Keyword, -    'TRUSTED': Keyword, -    'TYPE': Keyword, - -    'UNCOMMITTED': Keyword, -    'UNDER': Keyword, -    'UNENCRYPTED': Keyword, -    'UNION': Keyword, -    'UNIQUE': Keyword, -    'UNKNOWN': Keyword, -    'UNLISTEN': Keyword, -    'UNNAMED': Keyword, -    'UNNEST': Keyword, -    'UNTIL': Keyword, -    'UPPER': Keyword, -    'USAGE': Keyword, -    'USER': Keyword, -    'USER_DEFINED_TYPE_CATALOG': Keyword, -    'USER_DEFINED_TYPE_NAME': Keyword, -    'USER_DEFINED_TYPE_SCHEMA': Keyword, -    'USING': Keyword, - -    'VACUUM': Keyword, -    'VALID': Keyword, -    'VALIDATOR': Keyword, -    'VALUES': Keyword, -    'VARIABLE': Keyword, -    'VERBOSE': Keyword, -    'VERSION': Keyword, -    'VIEW': Keyword, -    'VOLATILE': Keyword, - -    'WHEN': Keyword, -    'WHENEVER': Keyword, -    'WHERE': Keyword, -    'WITH': Keyword, -    'WITHOUT': Keyword, -    'WORK': Keyword, -    'WRITE': Keyword, - -    'YEAR': Keyword, - -    'ZONE': Keyword, - - -    'ARRAY': Name.Builtin, -    'BIGINT': Name.Builtin, -    'BINARY': Name.Builtin, -    'BIT': Name.Builtin, -    'BLOB': Name.Builtin, -    'BOOLEAN': Name.Builtin, -    'CHAR': Name.Builtin, -    'CHARACTER': Name.Builtin, -    'DATE': Name.Builtin, -    'DEC': Name.Builtin, -    'DECIMAL': Name.Builtin, -    'FLOAT': Name.Builtin, -    'INT': Name.Builtin, -    'INTEGER': Name.Builtin, -    'INTERVAL': Name.Builtin, -    'NUMBER': Name.Builtin, -    'NUMERIC': Name.Builtin, -    'REAL': Name.Builtin, -    'SERIAL': Name.Builtin, -    'SMALLINT': Name.Builtin, -    'VARCHAR': Name.Builtin, -    'VARYING': Name.Builtin, -    'INT8': Name.Builtin, -    'SERIAL8': Name.Builtin, -    'TEXT': Name.Builtin, +    'ABORT': tokens.Keyword, +    'ABS': tokens.Keyword, +    'ABSOLUTE': tokens.Keyword, +    'ACCESS': tokens.Keyword, +    'ADA': tokens.Keyword, +    'ADD': tokens.Keyword, +    'ADMIN': tokens.Keyword, +    'AFTER': tokens.Keyword, +    'AGGREGATE': tokens.Keyword, +    'ALIAS': tokens.Keyword, +    'ALL': tokens.Keyword, +    'ALLOCATE': tokens.Keyword, +    'ANALYSE': tokens.Keyword, +    'ANALYZE': tokens.Keyword, +    'ANY': tokens.Keyword, +    'ARE': tokens.Keyword, +    'ASC': tokens.Keyword, +    'ASENSITIVE': tokens.Keyword, +    'ASSERTION': tokens.Keyword, +    'ASSIGNMENT': tokens.Keyword, +    'ASYMMETRIC': tokens.Keyword, +    'AT': tokens.Keyword, +    'ATOMIC': tokens.Keyword, +    'AUTHORIZATION': tokens.Keyword, +    'AVG': tokens.Keyword, + +    'BACKWARD': tokens.Keyword, +    'BEFORE': tokens.Keyword, +    'BEGIN': tokens.Keyword, +    'BETWEEN': tokens.Keyword, +    'BITVAR': tokens.Keyword, +    'BIT_LENGTH': tokens.Keyword, +    'BOTH': tokens.Keyword, +    'BREADTH': tokens.Keyword, + +#    'C': tokens.Keyword,  # most likely this is an alias +    'CACHE': tokens.Keyword, +    'CALL': tokens.Keyword, +    'CALLED': tokens.Keyword, +    'CARDINALITY': tokens.Keyword, +    'CASCADE': tokens.Keyword, +    'CASCADED': tokens.Keyword, +    'CAST': tokens.Keyword, +    'CATALOG': tokens.Keyword, +    'CATALOG_NAME': tokens.Keyword, +    'CHAIN': tokens.Keyword, +    'CHARACTERISTICS': tokens.Keyword, +    'CHARACTER_LENGTH': tokens.Keyword, +    'CHARACTER_SET_CATALOG': tokens.Keyword, +    'CHARACTER_SET_NAME': tokens.Keyword, +    'CHARACTER_SET_SCHEMA': tokens.Keyword, +    'CHAR_LENGTH': tokens.Keyword, +    'CHECK': tokens.Keyword, +    'CHECKED': tokens.Keyword, +    'CHECKPOINT': tokens.Keyword, +    'CLASS': tokens.Keyword, +    'CLASS_ORIGIN': tokens.Keyword, +    'CLOB': tokens.Keyword, +    'CLOSE': tokens.Keyword, +    'CLUSTER': tokens.Keyword, +    'COALSECE': tokens.Keyword, +    'COBOL': tokens.Keyword, +    'COLLATE': tokens.Keyword, +    'COLLATION': tokens.Keyword, +    'COLLATION_CATALOG': tokens.Keyword, +    'COLLATION_NAME': tokens.Keyword, +    'COLLATION_SCHEMA': tokens.Keyword, +    'COLUMN': tokens.Keyword, +    'COLUMN_NAME': tokens.Keyword, +    'COMMAND_FUNCTION': tokens.Keyword, +    'COMMAND_FUNCTION_CODE': tokens.Keyword, +    'COMMENT': tokens.Keyword, +    'COMMIT': tokens.Keyword, +    'COMMITTED': tokens.Keyword, +    'COMPLETION': tokens.Keyword, +    'CONDITION_NUMBER': tokens.Keyword, +    'CONNECT': tokens.Keyword, +    'CONNECTION': tokens.Keyword, +    'CONNECTION_NAME': tokens.Keyword, +    'CONSTRAINT': tokens.Keyword, +    'CONSTRAINTS': tokens.Keyword, +    'CONSTRAINT_CATALOG': tokens.Keyword, +    'CONSTRAINT_NAME': tokens.Keyword, +    'CONSTRAINT_SCHEMA': tokens.Keyword, +    'CONSTRUCTOR': tokens.Keyword, +    'CONTAINS': tokens.Keyword, +    'CONTINUE': tokens.Keyword, +    'CONVERSION': tokens.Keyword, +    'CONVERT': tokens.Keyword, +    'COPY': tokens.Keyword, +    'CORRESPONTING': tokens.Keyword, +    'COUNT': tokens.Keyword, +    'CREATEDB': tokens.Keyword, +    'CREATEUSER': tokens.Keyword, +    'CROSS': tokens.Keyword, +    'CUBE': tokens.Keyword, +    'CURRENT': tokens.Keyword, +    'CURRENT_DATE': tokens.Keyword, +    'CURRENT_PATH': tokens.Keyword, +    'CURRENT_ROLE': tokens.Keyword, +    'CURRENT_TIME': tokens.Keyword, +    'CURRENT_TIMESTAMP': tokens.Keyword, +    'CURRENT_USER': tokens.Keyword, +    'CURSOR': tokens.Keyword, +    'CURSOR_NAME': tokens.Keyword, +    'CYCLE': tokens.Keyword, + +    'DATA': tokens.Keyword, +    'DATABASE': tokens.Keyword, +    'DATETIME_INTERVAL_CODE': tokens.Keyword, +    'DATETIME_INTERVAL_PRECISION': tokens.Keyword, +    'DAY': tokens.Keyword, +    'DEALLOCATE': tokens.Keyword, +    'DECLARE': tokens.Keyword, +    'DEFAULT': tokens.Keyword, +    'DEFAULTS': tokens.Keyword, +    'DEFERRABLE': tokens.Keyword, +    'DEFERRED': tokens.Keyword, +    'DEFINED': tokens.Keyword, +    'DEFINER': tokens.Keyword, +    'DELIMITER': tokens.Keyword, +    'DELIMITERS': tokens.Keyword, +    'DEREF': tokens.Keyword, +    'DESC': tokens.Keyword, +    'DESCRIBE': tokens.Keyword, +    'DESCRIPTOR': tokens.Keyword, +    'DESTROY': tokens.Keyword, +    'DESTRUCTOR': tokens.Keyword, +    'DETERMINISTIC': tokens.Keyword, +    'DIAGNOSTICS': tokens.Keyword, +    'DICTIONARY': tokens.Keyword, +    'DISCONNECT': tokens.Keyword, +    'DISPATCH': tokens.Keyword, +    'DO': tokens.Keyword, +    'DOMAIN': tokens.Keyword, +    'DYNAMIC': tokens.Keyword, +    'DYNAMIC_FUNCTION': tokens.Keyword, +    'DYNAMIC_FUNCTION_CODE': tokens.Keyword, + +    'EACH': tokens.Keyword, +    'ENCODING': tokens.Keyword, +    'ENCRYPTED': tokens.Keyword, +    'END-EXEC': tokens.Keyword, +    'EQUALS': tokens.Keyword, +    'ESCAPE': tokens.Keyword, +    'EVERY': tokens.Keyword, +    'EXCEPT': tokens.Keyword, +    'ESCEPTION': tokens.Keyword, +    'EXCLUDING': tokens.Keyword, +    'EXCLUSIVE': tokens.Keyword, +    'EXEC': tokens.Keyword, +    'EXECUTE': tokens.Keyword, +    'EXISTING': tokens.Keyword, +    'EXISTS': tokens.Keyword, +    'EXTERNAL': tokens.Keyword, +    'EXTRACT': tokens.Keyword, + +    'FALSE': tokens.Keyword, +    'FETCH': tokens.Keyword, +    'FINAL': tokens.Keyword, +    'FIRST': tokens.Keyword, +    'FORCE': tokens.Keyword, +    'FOREIGN': tokens.Keyword, +    'FORTRAN': tokens.Keyword, +    'FORWARD': tokens.Keyword, +    'FOUND': tokens.Keyword, +    'FREE': tokens.Keyword, +    'FREEZE': tokens.Keyword, +    'FULL': tokens.Keyword, +    'FUNCTION': tokens.Keyword, + +#    'G': tokens.Keyword, +    'GENERAL': tokens.Keyword, +    'GENERATED': tokens.Keyword, +    'GET': tokens.Keyword, +    'GLOBAL': tokens.Keyword, +    'GO': tokens.Keyword, +    'GOTO': tokens.Keyword, +    'GRANT': tokens.Keyword, +    'GRANTED': tokens.Keyword, +    'GROUPING': tokens.Keyword, + +    'HANDLER': tokens.Keyword, +    'HAVING': tokens.Keyword, +    'HIERARCHY': tokens.Keyword, +    'HOLD': tokens.Keyword, +    'HOST': tokens.Keyword, + +    'IDENTITY': tokens.Keyword, +    'IGNORE': tokens.Keyword, +    'ILIKE': tokens.Keyword, +    'IMMEDIATE': tokens.Keyword, +    'IMMUTABLE': tokens.Keyword, + +    'IMPLEMENTATION': tokens.Keyword, +    'IMPLICIT': tokens.Keyword, +    'INCLUDING': tokens.Keyword, +    'INCREMENT': tokens.Keyword, +    'INDEX': tokens.Keyword, + +    'INDITCATOR': tokens.Keyword, +    'INFIX': tokens.Keyword, +    'INHERITS': tokens.Keyword, +    'INITIALIZE': tokens.Keyword, +    'INITIALLY': tokens.Keyword, +    'INOUT': tokens.Keyword, +    'INPUT': tokens.Keyword, +    'INSENSITIVE': tokens.Keyword, +    'INSTANTIABLE': tokens.Keyword, +    'INSTEAD': tokens.Keyword, +    'INTERSECT': tokens.Keyword, +    'INTO': tokens.Keyword, +    'INVOKER': tokens.Keyword, +    'IS': tokens.Keyword, +    'ISNULL': tokens.Keyword, +    'ISOLATION': tokens.Keyword, +    'ITERATE': tokens.Keyword, + +#    'K': tokens.Keyword, +    'KEY': tokens.Keyword, +    'KEY_MEMBER': tokens.Keyword, +    'KEY_TYPE': tokens.Keyword, + +    'LANCOMPILER': tokens.Keyword, +    'LANGUAGE': tokens.Keyword, +    'LARGE': tokens.Keyword, +    'LAST': tokens.Keyword, +    'LATERAL': tokens.Keyword, +    'LEADING': tokens.Keyword, +    'LENGTH': tokens.Keyword, +    'LESS': tokens.Keyword, +    'LEVEL': tokens.Keyword, +    'LIMIT': tokens.Keyword, +    'LISTEN': tokens.Keyword, +    'LOAD': tokens.Keyword, +    'LOCAL': tokens.Keyword, +    'LOCALTIME': tokens.Keyword, +    'LOCALTIMESTAMP': tokens.Keyword, +    'LOCATION': tokens.Keyword, +    'LOCATOR': tokens.Keyword, +    'LOCK': tokens.Keyword, +    'LOWER': tokens.Keyword, + +#    'M': tokens.Keyword, +    'MAP': tokens.Keyword, +    'MATCH': tokens.Keyword, +    'MAXVALUE': tokens.Keyword, +    'MESSAGE_LENGTH': tokens.Keyword, +    'MESSAGE_OCTET_LENGTH': tokens.Keyword, +    'MESSAGE_TEXT': tokens.Keyword, +    'METHOD': tokens.Keyword, +    'MINUTE': tokens.Keyword, +    'MINVALUE': tokens.Keyword, +    'MOD': tokens.Keyword, +    'MODE': tokens.Keyword, +    'MODIFIES': tokens.Keyword, +    'MODIFY': tokens.Keyword, +    'MONTH': tokens.Keyword, +    'MORE': tokens.Keyword, +    'MOVE': tokens.Keyword, +    'MUMPS': tokens.Keyword, + +    'NAMES': tokens.Keyword, +    'NATIONAL': tokens.Keyword, +    'NATURAL': tokens.Keyword, +    'NCHAR': tokens.Keyword, +    'NCLOB': tokens.Keyword, +    'NEW': tokens.Keyword, +    'NEXT': tokens.Keyword, +    'NO': tokens.Keyword, +    'NOCREATEDB': tokens.Keyword, +    'NOCREATEUSER': tokens.Keyword, +    'NONE': tokens.Keyword, +    'NOT': tokens.Keyword, +    'NOTHING': tokens.Keyword, +    'NOTIFY': tokens.Keyword, +    'NOTNULL': tokens.Keyword, +    'NULL': tokens.Keyword, +    'NULLABLE': tokens.Keyword, +    'NULLIF': tokens.Keyword, + +    'OBJECT': tokens.Keyword, +    'OCTET_LENGTH': tokens.Keyword, +    'OF': tokens.Keyword, +    'OFF': tokens.Keyword, +    'OFFSET': tokens.Keyword, +    'OIDS': tokens.Keyword, +    'OLD': tokens.Keyword, +    'ONLY': tokens.Keyword, +    'OPEN': tokens.Keyword, +    'OPERATION': tokens.Keyword, +    'OPERATOR': tokens.Keyword, +    'OPTION': tokens.Keyword, +    'OPTIONS': tokens.Keyword, +    'ORDINALITY': tokens.Keyword, +    'OUT': tokens.Keyword, +    'OUTPUT': tokens.Keyword, +    'OVERLAPS': tokens.Keyword, +    'OVERLAY': tokens.Keyword, +    'OVERRIDING': tokens.Keyword, +    'OWNER': tokens.Keyword, + +    'PAD': tokens.Keyword, +    'PARAMETER': tokens.Keyword, +    'PARAMETERS': tokens.Keyword, +    'PARAMETER_MODE': tokens.Keyword, +    'PARAMATER_NAME': tokens.Keyword, +    'PARAMATER_ORDINAL_POSITION': tokens.Keyword, +    'PARAMETER_SPECIFIC_CATALOG': tokens.Keyword, +    'PARAMETER_SPECIFIC_NAME': tokens.Keyword, +    'PARAMATER_SPECIFIC_SCHEMA': tokens.Keyword, +    'PARTIAL': tokens.Keyword, +    'PASCAL': tokens.Keyword, +    'PENDANT': tokens.Keyword, +    'PLACING': tokens.Keyword, +    'PLI': tokens.Keyword, +    'POSITION': tokens.Keyword, +    'POSTFIX': tokens.Keyword, +    'PRECISION': tokens.Keyword, +    'PREFIX': tokens.Keyword, +    'PREORDER': tokens.Keyword, +    'PREPARE': tokens.Keyword, +    'PRESERVE': tokens.Keyword, +    'PRIMARY': tokens.Keyword, +    'PRIOR': tokens.Keyword, +    'PRIVILEGES': tokens.Keyword, +    'PROCEDURAL': tokens.Keyword, +    'PROCEDURE': tokens.Keyword, +    'PUBLIC': tokens.Keyword, + +    'RAISE': tokens.Keyword, +    'READ': tokens.Keyword, +    'READS': tokens.Keyword, +    'RECHECK': tokens.Keyword, +    'RECURSIVE': tokens.Keyword, +    'REF': tokens.Keyword, +    'REFERENCES': tokens.Keyword, +    'REFERENCING': tokens.Keyword, +    'REINDEX': tokens.Keyword, +    'RELATIVE': tokens.Keyword, +    'RENAME': tokens.Keyword, +    'REPEATABLE': tokens.Keyword, +    'RESET': tokens.Keyword, +    'RESTART': tokens.Keyword, +    'RESTRICT': tokens.Keyword, +    'RESULT': tokens.Keyword, +    'RETURN': tokens.Keyword, +    'RETURNED_LENGTH': tokens.Keyword, +    'RETURNED_OCTET_LENGTH': tokens.Keyword, +    'RETURNED_SQLSTATE': tokens.Keyword, +    'RETURNS': tokens.Keyword, +    'REVOKE': tokens.Keyword, +    'RIGHT': tokens.Keyword, +    'ROLE': tokens.Keyword, +    'ROLLBACK': tokens.Keyword, +    'ROLLUP': tokens.Keyword, +    'ROUTINE': tokens.Keyword, +    'ROUTINE_CATALOG': tokens.Keyword, +    'ROUTINE_NAME': tokens.Keyword, +    'ROUTINE_SCHEMA': tokens.Keyword, +    'ROW': tokens.Keyword, +    'ROWS': tokens.Keyword, +    'ROW_COUNT': tokens.Keyword, +    'RULE': tokens.Keyword, + +    'SAVE_POINT': tokens.Keyword, +    'SCALE': tokens.Keyword, +    'SCHEMA': tokens.Keyword, +    'SCHEMA_NAME': tokens.Keyword, +    'SCOPE': tokens.Keyword, +    'SCROLL': tokens.Keyword, +    'SEARCH': tokens.Keyword, +    'SECOND': tokens.Keyword, +    'SECURITY': tokens.Keyword, +    'SELF': tokens.Keyword, +    'SENSITIVE': tokens.Keyword, +    'SERIALIZABLE': tokens.Keyword, +    'SERVER_NAME': tokens.Keyword, +    'SESSION': tokens.Keyword, +    'SESSION_USER': tokens.Keyword, +    'SETOF': tokens.Keyword, +    'SETS': tokens.Keyword, +    'SHARE': tokens.Keyword, +    'SHOW': tokens.Keyword, +    'SIMILAR': tokens.Keyword, +    'SIMPLE': tokens.Keyword, +    'SIZE': tokens.Keyword, +    'SOME': tokens.Keyword, +    'SOURCE': tokens.Keyword, +    'SPACE': tokens.Keyword, +    'SPECIFIC': tokens.Keyword, +    'SPECIFICTYPE': tokens.Keyword, +    'SPECIFIC_NAME': tokens.Keyword, +    'SQL': tokens.Keyword, +    'SQLCODE': tokens.Keyword, +    'SQLERROR': tokens.Keyword, +    'SQLEXCEPTION': tokens.Keyword, +    'SQLSTATE': tokens.Keyword, +    'SQLWARNING': tokens.Keyword, +    'STABLE': tokens.Keyword, +    'START': tokens.Keyword, +    'STATE': tokens.Keyword, +    'STATEMENT': tokens.Keyword, +    'STATIC': tokens.Keyword, +    'STATISTICS': tokens.Keyword, +    'STDIN': tokens.Keyword, +    'STDOUT': tokens.Keyword, +    'STORAGE': tokens.Keyword, +    'STRICT': tokens.Keyword, +    'STRUCTURE': tokens.Keyword, +    'STYPE': tokens.Keyword, +    'SUBCLASS_ORIGIN': tokens.Keyword, +    'SUBLIST': tokens.Keyword, +    'SUBSTRING': tokens.Keyword, +    'SUM': tokens.Keyword, +    'SYMMETRIC': tokens.Keyword, +    'SYSID': tokens.Keyword, +    'SYSTEM': tokens.Keyword, +    'SYSTEM_USER': tokens.Keyword, + +    'TABLE': tokens.Keyword, +    'TABLE_NAME': tokens.Keyword, +    ' TEMP': tokens.Keyword, +    'TEMPLATE': tokens.Keyword, +    'TEMPORARY': tokens.Keyword, +    'TERMINATE': tokens.Keyword, +    'THAN': tokens.Keyword, +    'TIMESTAMP': tokens.Keyword, +    'TIMEZONE_HOUR': tokens.Keyword, +    'TIMEZONE_MINUTE': tokens.Keyword, +    'TO': tokens.Keyword, +    'TOAST': tokens.Keyword, +    'TRAILING': tokens.Keyword, +    'TRANSATION': tokens.Keyword, +    'TRANSACTIONS_COMMITTED': tokens.Keyword, +    'TRANSACTIONS_ROLLED_BACK': tokens.Keyword, +    'TRANSATION_ACTIVE': tokens.Keyword, +    'TRANSFORM': tokens.Keyword, +    'TRANSFORMS': tokens.Keyword, +    'TRANSLATE': tokens.Keyword, +    'TRANSLATION': tokens.Keyword, +    'TREAT': tokens.Keyword, +    'TRIGGER': tokens.Keyword, +    'TRIGGER_CATALOG': tokens.Keyword, +    'TRIGGER_NAME': tokens.Keyword, +    'TRIGGER_SCHEMA': tokens.Keyword, +    'TRIM': tokens.Keyword, +    'TRUE': tokens.Keyword, +    'TRUNCATE': tokens.Keyword, +    'TRUSTED': tokens.Keyword, +    'TYPE': tokens.Keyword, + +    'UNCOMMITTED': tokens.Keyword, +    'UNDER': tokens.Keyword, +    'UNENCRYPTED': tokens.Keyword, +    'UNION': tokens.Keyword, +    'UNIQUE': tokens.Keyword, +    'UNKNOWN': tokens.Keyword, +    'UNLISTEN': tokens.Keyword, +    'UNNAMED': tokens.Keyword, +    'UNNEST': tokens.Keyword, +    'UNTIL': tokens.Keyword, +    'UPPER': tokens.Keyword, +    'USAGE': tokens.Keyword, +    'USER': tokens.Keyword, +    'USER_DEFINED_TYPE_CATALOG': tokens.Keyword, +    'USER_DEFINED_TYPE_NAME': tokens.Keyword, +    'USER_DEFINED_TYPE_SCHEMA': tokens.Keyword, +    'USING': tokens.Keyword, + +    'VACUUM': tokens.Keyword, +    'VALID': tokens.Keyword, +    'VALIDATOR': tokens.Keyword, +    'VALUES': tokens.Keyword, +    'VARIABLE': tokens.Keyword, +    'VERBOSE': tokens.Keyword, +    'VERSION': tokens.Keyword, +    'VIEW': tokens.Keyword, +    'VOLATILE': tokens.Keyword, + +    'WHENEVER': tokens.Keyword, +    'WITH': tokens.Keyword, +    'WITHOUT': tokens.Keyword, +    'WORK': tokens.Keyword, +    'WRITE': tokens.Keyword, + +    'YEAR': tokens.Keyword, + +    'ZONE': tokens.Keyword, + + +    'ARRAY': tokens.Name.Builtin, +    'BIGINT': tokens.Name.Builtin, +    'BINARY': tokens.Name.Builtin, +    'BIT': tokens.Name.Builtin, +    'BLOB': tokens.Name.Builtin, +    'BOOLEAN': tokens.Name.Builtin, +    'CHAR': tokens.Name.Builtin, +    'CHARACTER': tokens.Name.Builtin, +    'DATE': tokens.Name.Builtin, +    'DEC': tokens.Name.Builtin, +    'DECIMAL': tokens.Name.Builtin, +    'FLOAT': tokens.Name.Builtin, +    'INT': tokens.Name.Builtin, +    'INTEGER': tokens.Name.Builtin, +    'INTERVAL': tokens.Name.Builtin, +    'LONG': tokens.Name.Builtin, +    'NUMBER': tokens.Name.Builtin, +    'NUMERIC': tokens.Name.Builtin, +    'REAL': tokens.Name.Builtin, +    'SERIAL': tokens.Name.Builtin, +    'SMALLINT': tokens.Name.Builtin, +    'VARCHAR': tokens.Name.Builtin, +    'VARCHAR2': tokens.Name.Builtin, +    'VARYING': tokens.Name.Builtin, +    'INT8': tokens.Name.Builtin, +    'SERIAL8': tokens.Name.Builtin, +    'TEXT': tokens.Name.Builtin,      }  KEYWORDS_COMMON = { -    'SELECT': Keyword.DML, -    'INSERT': Keyword.DML, -    'DELETE': Keyword.DML, -    'UPDATE': Keyword.DML, -    'DROP': Keyword.DDL, -    'CREATE': Keyword.DDL, -    'ALTER': Keyword.DDL, - -    'WHERE': Keyword, -    'FROM': Keyword, -    'INNER': Keyword, -    'JOIN': Keyword, -    'AND': Keyword, -    'OR': Keyword, -    'LIKE': Keyword, -    'ON': Keyword, -    'IN': Keyword, -    'SET': Keyword, - -    'BY': Keyword, -    'GROUP': Keyword, -    'ORDER': Keyword, -    'LEFT': Keyword, -    'OUTER': Keyword, - -    'IF': Keyword, -    'END': Keyword, -    'THEN': Keyword, -    'LOOP': Keyword, -    'AS': Keyword, -    'ELSE': Keyword, -    'FOR': Keyword, - -    'CASE': Keyword, -    'WHEN': Keyword, -    'MIN': Keyword, -    'MAX': Keyword, -    'DISTINCT': Keyword, - +    'SELECT': tokens.Keyword.DML, +    'INSERT': tokens.Keyword.DML, +    'DELETE': tokens.Keyword.DML, +    'UPDATE': tokens.Keyword.DML, +    'REPLACE': tokens.Keyword.DML, +    'DROP': tokens.Keyword.DDL, +    'CREATE': tokens.Keyword.DDL, +    'ALTER': tokens.Keyword.DDL, + +    'WHERE': tokens.Keyword, +    'FROM': tokens.Keyword, +    'INNER': tokens.Keyword, +    'JOIN': tokens.Keyword, +    'AND': tokens.Keyword, +    'OR': tokens.Keyword, +    'LIKE': tokens.Keyword, +    'ON': tokens.Keyword, +    'IN': tokens.Keyword, +    'SET': tokens.Keyword, + +    'BY': tokens.Keyword, +    'GROUP': tokens.Keyword, +    'ORDER': tokens.Keyword, +    'LEFT': tokens.Keyword, +    'OUTER': tokens.Keyword, + +    'IF': tokens.Keyword, +    'END': tokens.Keyword, +    'THEN': tokens.Keyword, +    'LOOP': tokens.Keyword, +    'AS': tokens.Keyword, +    'ELSE': tokens.Keyword, +    'FOR': tokens.Keyword, + +    'CASE': tokens.Keyword, +    'WHEN': tokens.Keyword, +    'MIN': tokens.Keyword, +    'MAX': tokens.Keyword, +    'DISTINCT': tokens.Keyword,      } diff --git a/debug_toolbar/utils/sqlparse/lexer.py b/debug_toolbar/utils/sqlparse/lexer.py index 727a4ff..ae3fc2e 100644 --- a/debug_toolbar/utils/sqlparse/lexer.py +++ b/debug_toolbar/utils/sqlparse/lexer.py @@ -14,14 +14,14 @@  import re +from debug_toolbar.utils.sqlparse import tokens  from debug_toolbar.utils.sqlparse.keywords import KEYWORDS, KEYWORDS_COMMON -from debug_toolbar.utils.sqlparse.tokens import * -from debug_toolbar.utils.sqlparse.tokens import _TokenType  class include(str):      pass +  class combined(tuple):      """Indicates a state combined from multiple states.""" @@ -32,9 +32,10 @@ class combined(tuple):          # tuple.__init__ doesn't do anything          pass +  def is_keyword(value):      test = value.upper() -    return KEYWORDS_COMMON.get(test, KEYWORDS.get(test, Name)), value +    return KEYWORDS_COMMON.get(test, KEYWORDS.get(test, tokens.Name)), value  def apply_filters(stream, filters, lexer=None): @@ -43,9 +44,11 @@ def apply_filters(stream, filters, lexer=None):      a stream. If lexer is given it's forwarded to the      filter, otherwise the filter receives `None`.      """ +      def _apply(filter_, stream):          for token in filter_.filter(lexer, stream):              yield token +      for filter_ in filters:          stream = _apply(filter_, stream)      return stream @@ -62,13 +65,14 @@ class LexerMeta(type):          assert state[0] != '#', "invalid state name %r" % state          if state in processed:              return processed[state] -        tokens = processed[state] = [] +        tokenlist = processed[state] = []          rflags = cls.flags          for tdef in unprocessed[state]:              if isinstance(tdef, include):                  # it's a state reference                  assert tdef != state, "circular state reference %r" % state -                tokens.extend(cls._process_state(unprocessed, processed, str(tdef))) +                tokenlist.extend(cls._process_state( +                    unprocessed, processed, str(tdef)))                  continue              assert type(tdef) is tuple, "wrong rule def %r" % tdef @@ -76,11 +80,13 @@ class LexerMeta(type):              try:                  rex = re.compile(tdef[0], rflags).match              except Exception, err: -                raise ValueError("uncompilable regex %r in state %r of %r: %s" % -                                 (tdef[0], state, cls, err)) +                raise ValueError(("uncompilable regex %r in state" +                                  " %r of %r: %s" +                                  % (tdef[0], state, cls, err))) -            assert type(tdef[1]) is _TokenType or callable(tdef[1]), \ -                   'token type must be simple type or callable, not %r' % (tdef[1],) +            assert type(tdef[1]) is tokens._TokenType or callable(tdef[1]), \ +                   ('token type must be simple type or callable, not %r' +                    % (tdef[1],))              if len(tdef) == 2:                  new_state = None @@ -104,7 +110,8 @@ class LexerMeta(type):                      cls._tmpname += 1                      itokens = []                      for istate in tdef2: -                        assert istate != state, 'circular state ref %r' % istate +                        assert istate != state, \ +                               'circular state ref %r' % istate                          itokens.extend(cls._process_state(unprocessed,                                                            processed, istate))                      processed[new_state] = itokens @@ -118,8 +125,8 @@ class LexerMeta(type):                      new_state = tdef2                  else:                      assert False, 'unknown new state def %r' % tdef2 -            tokens.append((rex, tdef[1], new_state)) -        return tokens +            tokenlist.append((rex, tdef[1], new_state)) +        return tokenlist      def process_tokendef(cls):          cls._all_tokens = {} @@ -143,9 +150,7 @@ class LexerMeta(type):          return type.__call__(cls, *args, **kwds) - - -class Lexer: +class Lexer(object):      __metaclass__ = LexerMeta @@ -157,41 +162,53 @@ class Lexer:      tokens = {          'root': [ -            (r'--.*?(\r|\n|\r\n)', Comment.Single), -            (r'(\r|\n|\r\n)', Newline), -            (r'\s+', Whitespace), -            (r'/\*', Comment.Multiline, 'multiline-comments'), -            (r':=', Assignment), -            (r'::', Punctuation), -            (r'[*]', Wildcard), -            (r"`(``|[^`])*`", Name), -            (r"´(´´|[^´])*´", Name), -            (r'@[a-zA-Z_][a-zA-Z0-9_]+', Name), -            (r'[+/<>=~!@#%^&|`?^-]', Operator), -            (r'[0-9]+', Number.Integer), +            (r'--.*?(\r\n|\r|\n)', tokens.Comment.Single), +            # $ matches *before* newline, therefore we have two patterns +            # to match Comment.Single +            (r'--.*?$', tokens.Comment.Single), +            (r'(\r|\n|\r\n)', tokens.Newline), +            (r'\s+', tokens.Whitespace), +            (r'/\*', tokens.Comment.Multiline, 'multiline-comments'), +            (r':=', tokens.Assignment), +            (r'::', tokens.Punctuation), +            (r'[*]', tokens.Wildcard), +            (r'CASE\b', tokens.Keyword),  # extended CASE(foo) +            (r"`(``|[^`])*`", tokens.Name), +            (r"´(´´|[^´])*´", tokens.Name), +            (r'\$([a-zA-Z_][a-zA-Z0-9_]*)?\$', tokens.Name.Builtin), +            (r'\?{1}', tokens.Name.Placeholder), +            (r'[$:?%][a-zA-Z0-9_]+[^$:?%]?', tokens.Name.Placeholder), +            (r'@[a-zA-Z_][a-zA-Z0-9_]+', tokens.Name), +            (r'[a-zA-Z_][a-zA-Z0-9_]*(?=[.(])', tokens.Name),  # see issue39 +            (r'[<>=~!]+', tokens.Operator.Comparison), +            (r'[+/@#%^&|`?^-]+', tokens.Operator), +            (r'0x[0-9a-fA-F]+', tokens.Number.Hexadecimal), +            (r'[0-9]*\.[0-9]+', tokens.Number.Float), +            (r'[0-9]+', tokens.Number.Integer),              # TODO: Backslash escapes? -            (r"'(''|[^'])*'", String.Single), -            (r'"(""|[^"])*"', String.Symbol), # not a real string literal in ANSI SQL -            (r'(LEFT |RIGHT )?(INNER |OUTER )?JOIN', Keyword), -            (r'END( IF| LOOP)?', Keyword), -            (r'CREATE( OR REPLACE)?', Keyword.DDL), +            (r"(''|'.*?[^\\]')", tokens.String.Single), +            # not a real string literal in ANSI SQL: +            (r'(""|".*?[^\\]")', tokens.String.Symbol), +            (r'(\[.*[^\]]\])', tokens.Name), +            (r'(LEFT |RIGHT )?(INNER |OUTER )?JOIN\b', tokens.Keyword), +            (r'END( IF| LOOP)?\b', tokens.Keyword), +            (r'NOT NULL\b', tokens.Keyword), +            (r'CREATE( OR REPLACE)?\b', tokens.Keyword.DDL),              (r'[a-zA-Z_][a-zA-Z0-9_]*', is_keyword), -            (r'\$([a-zA-Z_][a-zA-Z0-9_]*)?\$', Name.Builtin), -            (r'[;:()\[\],\.]', Punctuation), +            (r'[;:()\[\],\.]', tokens.Punctuation),          ],          'multiline-comments': [ -            (r'/\*', Comment.Multiline, 'multiline-comments'), -            (r'\*/', Comment.Multiline, '#pop'), -            (r'[^/\*]+', Comment.Multiline), -            (r'[/*]', Comment.Multiline) -        ] -    } +            (r'/\*', tokens.Comment.Multiline, 'multiline-comments'), +            (r'\*/', tokens.Comment.Multiline, '#pop'), +            (r'[^/\*]+', tokens.Comment.Multiline), +            (r'[/*]', tokens.Comment.Multiline) +        ]}      def __init__(self):          self.filters = []      def add_filter(self, filter_, **options): -        from sqlparse.filters import Filter +        from debug_toolbar.utils.sqlparse.filters import Filter          if not isinstance(filter_, Filter):              filter_ = filter_(**options)          self.filters.append(filter_) @@ -241,7 +258,6 @@ class Lexer:              stream = apply_filters(stream, self.filters, self)          return stream -      def get_tokens_unprocessed(self, text, stack=('root',)):          """          Split ``text`` into (tokentype, text) pairs. @@ -261,7 +277,7 @@ class Lexer:                      value = m.group()                      if value in known_names:                          yield pos, known_names[value], value -                    elif type(action) is _TokenType: +                    elif type(action) is tokens._TokenType:                          yield pos, action, value                      elif hasattr(action, '__call__'):                          ttype, value = action(value) @@ -297,9 +313,9 @@ class Lexer:                          pos += 1                          statestack = ['root']                          statetokens = tokendefs['root'] -                        yield pos, Text, u'\n' +                        yield pos, tokens.Text, u'\n'                          continue -                    yield pos, Error, text[pos] +                    yield pos, tokens.Error, text[pos]                      pos += 1                  except IndexError:                      break diff --git a/debug_toolbar/utils/sqlparse/sql.py b/debug_toolbar/utils/sqlparse/sql.py index 5bbb977..55bf804 100644 --- a/debug_toolbar/utils/sqlparse/sql.py +++ b/debug_toolbar/utils/sqlparse/sql.py @@ -3,7 +3,6 @@  """This module contains classes representing syntactical elements of SQL."""  import re -import types  from debug_toolbar.utils.sqlparse import tokens as T @@ -16,14 +15,15 @@ class Token(object):      the type of the token.      """ -    __slots__ = ('value', 'ttype',) +    __slots__ = ('value', 'ttype', 'parent')      def __init__(self, ttype, value):          self.value = value          self.ttype = ttype +        self.parent = None      def __str__(self): -        return unicode(self).encode('latin-1') +        return unicode(self).encode('utf-8')      def __repr__(self):          short = self._get_repr_value() @@ -43,7 +43,7 @@ class Token(object):      def _get_repr_value(self):          raw = unicode(self)          if len(raw) > 7: -            short = raw[:6]+u'...' +            short = raw[:6] + u'...'          else:              short = raw          return re.sub('\s+', ' ', short) @@ -59,12 +59,12 @@ class Token(object):          type.          *values* is a list of possible values for this token. The values          are OR'ed together so if only one of the values matches ``True`` -        is returned. Except for keyword tokens the comparsion is +        is returned. Except for keyword tokens the comparison is          case-sensitive. For convenience it's ok to pass in a single string.          If *regex* is ``True`` (default is ``False``) the given values are          treated as regular expressions.          """ -        type_matched = self.ttype in ttype +        type_matched = self.ttype is ttype          if not type_matched or values is None:              return type_matched          if isinstance(values, basestring): @@ -79,7 +79,7 @@ class Token(object):                      return True              return False          else: -            if self.ttype is T.Keyword: +            if self.ttype in T.Keyword:                  values = set([v.upper() for v in values])                  return self.value.upper() in values              else: @@ -93,6 +93,32 @@ class Token(object):          """Return ``True`` if this token is a whitespace token."""          return self.ttype and self.ttype in T.Whitespace +    def within(self, group_cls): +        """Returns ``True`` if this token is within *group_cls*. + +        Use this method for example to check if an identifier is within +        a function: ``t.within(sql.Function)``. +        """ +        parent = self.parent +        while parent: +            if isinstance(parent, group_cls): +                return True +            parent = parent.parent +        return False + +    def is_child_of(self, other): +        """Returns ``True`` if this token is a direct child of *other*.""" +        return self.parent == other + +    def has_ancestor(self, other): +        """Returns ``True`` if *other* is in this tokens ancestry.""" +        parent = self.parent +        while parent: +            if parent == other: +                return True +            parent = parent.parent +        return False +  class TokenList(Token):      """A group of tokens. @@ -113,24 +139,24 @@ class TokenList(Token):          return ''.join(unicode(x) for x in self.flatten())      def __str__(self): -        return unicode(self).encode('latin-1') +        return unicode(self).encode('utf-8')      def _get_repr_name(self):          return self.__class__.__name__ -    ## def _pprint_tree(self, max_depth=None, depth=0): -    ##     """Pretty-print the object tree.""" -    ##     indent = ' '*(depth*2) -    ##     for token in self.tokens: -    ##         if token.is_group(): -    ##             pre = ' | ' -    ##         else: -    ##             pre = ' | ' -    ##         print '%s%s%s \'%s\'' % (indent, pre, token._get_repr_name(), -    ##                                  token._get_repr_value()) -    ##         if (token.is_group() and max_depth is not None -    ##             and depth < max_depth): -    ##             token._pprint_tree(max_depth, depth+1) +    def _pprint_tree(self, max_depth=None, depth=0): +        """Pretty-print the object tree.""" +        indent = ' '*(depth*2) +        for idx, token in enumerate(self.tokens): +            if token.is_group(): +                pre = ' +-' +            else: +                pre = ' | ' +            print '%s%s%d %s \'%s\'' % (indent, pre, idx, +                                        token._get_repr_name(), +                                        token._get_repr_value()) +            if (token.is_group() and (max_depth is None or depth < max_depth)): +                token._pprint_tree(max_depth, depth+1)      def flatten(self):          """Generator yielding ungrouped tokens. @@ -150,6 +176,10 @@ class TokenList(Token):      def get_sublists(self):          return [x for x in self.tokens if isinstance(x, TokenList)] +    @property +    def _groupable_tokens(self): +        return self.tokens +      def token_first(self, ignore_whitespace=True):          """Returns the first child token. @@ -190,7 +220,7 @@ class TokenList(Token):      def token_next_match(self, idx, ttype, value, regex=False):          """Returns next token where it's ``match`` method returns ``True``.""" -        if type(idx) != types.IntType: +        if not isinstance(idx, int):              idx = self.token_index(idx)          for token in self.tokens[idx:]:              if token.match(ttype, value, regex): @@ -202,8 +232,8 @@ class TokenList(Token):              passed = False              for func in funcs:                  if func(token): -                   passed = True -                   break +                    passed = True +                    break              if not passed:                  return token          return None @@ -241,7 +271,7 @@ class TokenList(Token):              return None          if not isinstance(idx, int):              idx = self.token_index(idx) -        while idx < len(self.tokens)-1: +        while idx < len(self.tokens) - 1:              idx += 1              if self.tokens[idx].is_whitespace() and skip_ws:                  continue @@ -257,18 +287,27 @@ class TokenList(Token):          If *exclude_end* is ``True`` (default is ``False``) the end token          is included too.          """ +        # FIXME(andi): rename exclude_end to inlcude_end          if exclude_end:              offset = 0          else:              offset = 1 -        return self.tokens[self.token_index(start):self.token_index(end)+offset] +        end_idx = self.token_index(end) + offset +        start_idx = self.token_index(start) +        return self.tokens[start_idx:end_idx] -    def group_tokens(self, grp_cls, tokens): +    def group_tokens(self, grp_cls, tokens, ignore_ws=False):          """Replace tokens by an instance of *grp_cls*."""          idx = self.token_index(tokens[0]) +        if ignore_ws: +            while tokens and tokens[-1].is_whitespace(): +                tokens = tokens[:-1]          for t in tokens:              self.tokens.remove(t)          grp = grp_cls(tokens) +        for token in tokens: +            token.parent = grp +        grp.parent = self          self.tokens.insert(idx, grp)          return grp @@ -290,7 +329,11 @@ class Statement(TokenList):          isn't a DML or DDL keyword "UNKNOWN" is returned.          """          first_token = self.token_first() -        if first_token.ttype in (T.Keyword.DML, T.Keyword.DDL): +        if first_token is None: +            # An "empty" statement that either has not tokens at all +            # or only whitespace tokens. +            return 'UNKNOWN' +        elif first_token.ttype in (T.Keyword.DML, T.Keyword.DDL):              return first_token.value.upper()          else:              return 'UNKNOWN' @@ -397,27 +440,36 @@ class Parenthesis(TokenList):      """Tokens between parenthesis."""      __slots__ = ('value', 'ttype', 'tokens') +    @property +    def _groupable_tokens(self): +        return self.tokens[1:-1] +  class Assignment(TokenList):      """An assignment like 'var := val;'"""      __slots__ = ('value', 'ttype', 'tokens') +  class If(TokenList):      """An 'if' clause with possible 'else if' or 'else' parts."""      __slots__ = ('value', 'ttype', 'tokens') +  class For(TokenList):      """A 'FOR' loop."""      __slots__ = ('value', 'ttype', 'tokens') -class Comparsion(TokenList): -    """A comparsion used for example in WHERE clauses.""" + +class Comparison(TokenList): +    """A comparison used for example in WHERE clauses."""      __slots__ = ('value', 'ttype', 'tokens') +  class Comment(TokenList):      """A comment."""      __slots__ = ('value', 'ttype', 'tokens') +  class Where(TokenList):      """A WHERE clause."""      __slots__ = ('value', 'ttype', 'tokens') @@ -434,9 +486,12 @@ class Case(TokenList):          If an ELSE exists condition is None.          """          ret = [] -        in_condition = in_value = False +        in_value = False +        in_condition = True          for token in self.tokens: -            if token.match(T.Keyword, 'WHEN'): +            if token.match(T.Keyword, 'CASE'): +                continue +            elif token.match(T.Keyword, 'WHEN'):                  ret.append(([], []))                  in_condition = True                  in_value = False @@ -450,8 +505,25 @@ class Case(TokenList):              elif token.match(T.Keyword, 'END'):                  in_condition = False                  in_value = False +            if (in_condition or in_value) and not ret: +                # First condition withou preceding WHEN +                ret.append(([], []))              if in_condition:                  ret[-1][0].append(token)              elif in_value:                  ret[-1][1].append(token)          return ret + + +class Function(TokenList): +    """A function or procedure call.""" + +    __slots__ = ('value', 'ttype', 'tokens') + +    def get_parameters(self): +        """Return a list of parameters.""" +        parenthesis = self.tokens[-1] +        for t in parenthesis.tokens: +            if isinstance(t, IdentifierList): +                return t.get_identifiers() +        return [] diff --git a/debug_toolbar/utils/sqlparse/tokens.py b/debug_toolbar/utils/sqlparse/tokens.py index 2c63c41..01a9b89 100644 --- a/debug_toolbar/utils/sqlparse/tokens.py +++ b/debug_toolbar/utils/sqlparse/tokens.py @@ -9,11 +9,6 @@  """Tokens""" -try: -    set -except NameError: -    from sets import Set as set -  class _TokenType(tuple):      parent = None @@ -27,22 +22,14 @@ class _TokenType(tuple):          buf.reverse()          return buf -    def __init__(self, *args): -        # no need to call super.__init__ -        self.subtypes = set() -      def __contains__(self, val): -        return self is val or ( -            type(val) is self.__class__ and -            val[:len(self)] == self -        ) +        return val is not None and (self is val or val[:len(self)] == self)      def __getattr__(self, val):          if not val or not val[0].isupper():              return tuple.__getattribute__(self, val)          new = _TokenType(self + (val,))          setattr(self, val, new) -        self.subtypes.add(new)          new.parent = self          return new @@ -53,30 +40,31 @@ class _TokenType(tuple):          return 'Token' + (self and '.' or '') + '.'.join(self) -Token       = _TokenType() +Token = _TokenType()  # Special token types -Text        = Token.Text -Whitespace  = Text.Whitespace -Newline     = Whitespace.Newline -Error       = Token.Error +Text = Token.Text +Whitespace = Text.Whitespace +Newline = Whitespace.Newline +Error = Token.Error  # Text that doesn't belong to this lexer (e.g. HTML in PHP) -Other       = Token.Other +Other = Token.Other  # Common token types for source code -Keyword     = Token.Keyword -Name        = Token.Name -Literal     = Token.Literal -String      = Literal.String -Number      = Literal.Number +Keyword = Token.Keyword +Name = Token.Name +Literal = Token.Literal +String = Literal.String +Number = Literal.Number  Punctuation = Token.Punctuation -Operator    = Token.Operator -Wildcard    = Token.Wildcard -Comment     = Token.Comment -Assignment  = Token.Assignement +Operator = Token.Operator +Comparison = Operator.Comparison +Wildcard = Token.Wildcard +Comment = Token.Comment +Assignment = Token.Assignement  # Generic types for non-source code -Generic     = Token.Generic +Generic = Token.Generic  # String and some others are not direct childs of Token.  # alias them: @@ -93,39 +81,3 @@ Group = Token.Group  Group.Parenthesis = Token.Group.Parenthesis  Group.Comment = Token.Group.Comment  Group.Where = Token.Group.Where - - -def is_token_subtype(ttype, other): -    """ -    Return True if ``ttype`` is a subtype of ``other``. - -    exists for backwards compatibility. use ``ttype in other`` now. -    """ -    return ttype in other - - -def string_to_tokentype(s): -    """ -    Convert a string into a token type:: - -        >>> string_to_token('String.Double') -        Token.Literal.String.Double -        >>> string_to_token('Token.Literal.Number') -        Token.Literal.Number -        >>> string_to_token('') -        Token - -    Tokens that are already tokens are returned unchanged: - -        >>> string_to_token(String) -        Token.Literal.String -    """ -    if isinstance(s, _TokenType): -        return s -    if not s: -        return Token -    node = Token -    for item in s.split('.'): -        node = getattr(node, item) -    return node - diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py index 7ffacef..97a9241 100644 --- a/debug_toolbar/utils/tracking/db.py +++ b/debug_toolbar/utils/tracking/db.py @@ -2,6 +2,7 @@ import inspect  import sys  from datetime import datetime +from threading import local  from django.conf import settings  from django.template import Node @@ -16,7 +17,41 @@ from debug_toolbar.utils.compat.db import connections  SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \                              .get('SQL_WARNING_THRESHOLD', 500) -class CursorWrapper(object): +class SQLQueryTriggered(Exception): +    """Thrown when template panel triggers a query""" +    pass + +class ThreadLocalState(local): +    def __init__(self): +        self.enabled = True + +    @property +    def Wrapper(self): +        if self.enabled: +            return NormalCursorWrapper +        return ExceptionCursorWrapper + +    def recording(self, v): +        self.enabled = v + +state = ThreadLocalState() +recording = state.recording # export function + +def CursorWrapper(*args, **kwds):  # behave like a class +    return state.Wrapper(*args, **kwds) + +class ExceptionCursorWrapper(object): +    """ +    Wraps a cursor and raises an exception on any operation. +    Used in Templates panel. +    """ +    def __init__(self, cursor, db, logger): +        pass + +    def __getattr__(self, attr): +        raise SQLQueryTriggered() + +class NormalCursorWrapper(object):      """      Wraps a cursor and logs queries.      """ @@ -103,4 +138,4 @@ class CursorWrapper(object):              return getattr(self.cursor, attr)      def __iter__(self): -        return iter(self.cursor)
\ No newline at end of file +        return iter(self.cursor) diff --git a/example/example.db b/example/example.dbBinary files differ index 1339622..7acdc0d 100644 --- a/example/example.db +++ b/example/example.db diff --git a/example/settings.py b/example/settings.py index 11b0117..fac99af 100644 --- a/example/settings.py +++ b/example/settings.py @@ -41,7 +41,11 @@ DEBUG_TOOLBAR_PANELS = (      'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',      'debug_toolbar.panels.sql.SQLDebugPanel',      'debug_toolbar.panels.template.TemplateDebugPanel', -    #'debug_toolbar.panels.cache.CacheDebugPanel', +    'debug_toolbar.panels.cache.CacheDebugPanel',      'debug_toolbar.panels.signals.SignalDebugPanel',      'debug_toolbar.panels.logger.LoggingPanel', -)
\ No newline at end of file +) + +CACHE_BACKEND = 'dummy://' +#CACHE_BACKEND = 'memcached://127.0.0.1:11211' + diff --git a/example/templates/index.html b/example/templates/index.html index 6fd3a92..d7d8a2b 100644 --- a/example/templates/index.html +++ b/example/templates/index.html @@ -1,16 +1,18 @@ +{% load cache %}  <html>  <head> -	<meta http-equiv="content-type" content="text/html; charset=utf-8"> -	<title>Index of Tests</title> +    <meta http-equiv="content-type" content="text/html; charset=utf-8"> +    <title>Index of Tests</title>  </head>  <body> -	<h1>Index of Tests</h1> -	<ul> -		<li><a href="/jquery/index/">jQuery 1.2.6</a></li> -		<li><a href="/mootools/index/">MooTools 1.2.4</a></li> -		<li><a href="/prototype/index/">Prototype 1.6.1</a></li> -	</ul> - +    <h1>Index of Tests</h1> +    {% cache 10 index_cache %} +    <ul> +        <li><a href="/jquery/index/">jQuery 1.2.6</a></li> +        <li><a href="/mootools/index/">MooTools 1.2.4</a></li> +        <li><a href="/prototype/index/">Prototype 1.6.1</a></li> +    </ul> +    {% endcache %}  </body>  </html> diff --git a/debug_toolbar/runtests.py b/runtests.py index f16882a..dc5f6d0 100644 --- a/debug_toolbar/runtests.py +++ b/runtests.py @@ -1,8 +1,9 @@  #!/usr/bin/env python  import sys  from os.path import dirname, abspath +from optparse import OptionParser -from django.conf import settings +from django.conf import settings, global_settings  if not settings.configured:      settings.configure( @@ -16,32 +17,37 @@ if not settings.configured:              'django.contrib.contenttypes',              'django.contrib.sessions',              'django.contrib.sites', - +                          'debug_toolbar', -            'debug_toolbar.tests', +            'tests',          ], +        MIDDLEWARE_CLASSES = global_settings.MIDDLEWARE_CLASSES + ( +            'debug_toolbar.middleware.DebugToolbarMiddleware', +        ),          ROOT_URLCONF='',          DEBUG=False,          SITE_ID=1,      ) -    import djcelery -    djcelery.setup_loader()  from django.test.simple import run_tests -def runtests(*test_args): +def runtests(*test_args, **kwargs):      if 'south' in settings.INSTALLED_APPS:          from south.management.commands import patch_for_test_db_setup          patch_for_test_db_setup() - +          if not test_args: -        test_args = ['debug_toolbar'] +        test_args = ['tests']      parent = dirname(abspath(__file__))      sys.path.insert(0, parent) -    failures = run_tests(test_args, verbosity=1, interactive=True) +    failures = run_tests(test_args, verbosity=kwargs.get('verbosity', 1), interactive=kwargs.get('interactive', False), failfast=kwargs.get('failfast'))      sys.exit(failures) -  if __name__ == '__main__': -    runtests(*sys.argv[1:])
\ No newline at end of file +    parser = OptionParser() +    parser.add_option('--failfast', action='store_true', default=False, dest='failfast') +     +    (options, args) = parser.parse_args() +     +    runtests(failfast=options.failfast, *args)
\ No newline at end of file @@ -2,7 +2,7 @@ from setuptools import setup, find_packages  setup(      name='django-debug-toolbar', -    version='0.8.6-dev', +    version='0.9.0-dev',      description='A configurable set of panels that display various debug information about the current request/response.',      long_description=open('README.rst').read(),      # Get more strings from http://www.python.org/pypi?:action=list_classifiers @@ -11,12 +11,12 @@ setup(      url='https://github.com/django-debug-toolbar/django-debug-toolbar',      download_url='https://github.com/django-debug-toolbar/django-debug-toolbar/downloads',      license='BSD', -    packages=find_packages(exclude=['ez_setup']), +    packages=find_packages(exclude=('ez_setup', 'tests', 'example')),      tests_require=[ -        'django', +        'django>=1.1,<1.4',          'dingus',      ], -    test_suite='debug_toolbar.runtests.runtests', +    test_suite='runtests.runtests',      include_package_data=True,      zip_safe=False, # because we're including media that Django needs      classifiers=[ diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/models.py b/tests/models.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/models.py diff --git a/tests/templates/404.html b/tests/templates/404.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/templates/404.html diff --git a/tests/tests.py b/tests/tests.py new file mode 100644 index 0000000..154615a --- /dev/null +++ b/tests/tests.py @@ -0,0 +1,354 @@ +from debug_toolbar.middleware import DebugToolbarMiddleware +from debug_toolbar.panels.sql import SQLDebugPanel +from debug_toolbar.panels.request_vars import RequestVarsDebugPanel +from debug_toolbar.panels.template import TemplateDebugPanel +from debug_toolbar.toolbar.loader import DebugToolbar +from debug_toolbar.utils import get_name_from_obj +from debug_toolbar.utils.tracking import pre_dispatch, post_dispatch, callbacks + +from django.conf import settings +from django.contrib.auth.models import User +from django.http import HttpResponse +from django.test import TestCase +from django.template import Template, Context + +from dingus import Dingus +import thread + + +class Settings(object): +    """Allows you to define settings that are required for this function to work""" + +    NotDefined = object() + +    def __init__(self, **overrides): +        self.overrides = overrides +        self._orig = {} + +    def __enter__(self): +        for k, v in self.overrides.iteritems(): +            self._orig[k] = getattr(settings, k, self.NotDefined) +            setattr(settings, k, v) + +    def __exit__(self, exc_type, exc_value, traceback): +        for k, v in self._orig.iteritems(): +            if v is self.NotDefined: +                delattr(settings, k) +            else: +                setattr(settings, k, v) +     +class BaseTestCase(TestCase): +    def setUp(self): +        request = Dingus('request') +        response = Dingus('response') +        toolbar = DebugToolbar(request) + +        DebugToolbarMiddleware.debug_toolbars[thread.get_ident()] = toolbar + +        self.request = request +        self.response = response +        self.toolbar = toolbar +        self.toolbar.stats = {} + +class DebugToolbarTestCase(BaseTestCase): +    urls = 'tests.urls' +     +    def test_middleware(self): +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            resp = self.client.get('/execute_sql/') +        self.assertEquals(resp.status_code, 200) + +    def test_show_toolbar_DEBUG(self): +        request = self.request +         +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            self.assertTrue(middleware._show_toolbar(request)) + +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=False): +            self.assertFalse(middleware._show_toolbar(request)) + +    def test_show_toolbar_TEST(self): +        request = self.request +         +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], TEST=True, DEBUG=True): +            self.assertFalse(middleware._show_toolbar(request)) + +        with Settings(INTERNAL_IPS=['127.0.0.1'], TEST=False, DEBUG=True): +            self.assertTrue(middleware._show_toolbar(request)) + +    def test_show_toolbar_INTERNAL_IPS(self): +        request = self.request +         +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            self.assertTrue(middleware._show_toolbar(request)) + +        with Settings(INTERNAL_IPS=[], DEBUG=True): +            self.assertFalse(middleware._show_toolbar(request)) + +    def test_request_urlconf_string(self): +        request = self.request +         +        request.urlconf = 'tests.urls' +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            middleware.process_request(request) +             +            self.assertFalse(isinstance(request.urlconf, basestring)) +             +            self.assertTrue(hasattr(request.urlconf.urlpatterns[0], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[0]._callback_str, 'debug_toolbar.views.debug_media') +            self.assertTrue(hasattr(request.urlconf.urlpatterns[1], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[-1]._callback_str, 'tests.views.execute_sql') + +    def test_request_urlconf_string_per_request(self): +        request = self.request +         +        request.urlconf = 'debug_toolbar.urls' +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            middleware.process_request(request) +            request.urlconf = 'tests.urls' +            middleware.process_request(request) + +            self.assertFalse(isinstance(request.urlconf, basestring)) +             +            self.assertTrue(hasattr(request.urlconf.urlpatterns[0], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[0]._callback_str, 'debug_toolbar.views.debug_media') +            self.assertTrue(hasattr(request.urlconf.urlpatterns[1], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[-1]._callback_str, 'tests.views.execute_sql') + +    def test_request_urlconf_module(self): +        request = self.request +         +        request.urlconf = __import__('tests.urls').urls +        request.META = {'REMOTE_ADDR': '127.0.0.1'} +        middleware = DebugToolbarMiddleware() +         +        with Settings(INTERNAL_IPS=['127.0.0.1'], DEBUG=True): +            middleware.process_request(request) +             +            self.assertFalse(isinstance(request.urlconf, basestring)) +             +            self.assertTrue(hasattr(request.urlconf.urlpatterns[0], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[0]._callback_str, 'debug_toolbar.views.debug_media') +            self.assertTrue(hasattr(request.urlconf.urlpatterns[1], '_callback_str')) +            self.assertEquals(request.urlconf.urlpatterns[-1]._callback_str, 'tests.views.execute_sql') + +    def test_with_process_view(self): +        request = self.request +        response = self.response +         +        def _test_view(request): +            return HttpResponse('') +         +        with Settings(DEBUG=True): +            panel = self.toolbar.get_panel(RequestVarsDebugPanel) +            panel.process_request(request) +            panel.process_view(request, _test_view, [], {}) +            panel.process_response(request, response) +            content = panel.content() +            self.assertTrue('tests.tests._test_view' in content, content) + +    def test_without_process_view(self): +        request = self.request +        response = self.response + +        with Settings(DEBUG=True): +            panel = self.toolbar.get_panel(RequestVarsDebugPanel) +            panel.process_request(request) +            panel.process_response(request, response) +            content = panel.content() +            self.assertTrue('<no view>' in content, content) + +class DebugToolbarNameFromObjectTest(BaseTestCase): +    def test_func(self): +        def x(): +            return 1 +        res = get_name_from_obj(x) +        self.assertEquals(res, 'tests.tests.x') + +    def test_lambda(self): +        res = get_name_from_obj(lambda:1) +        self.assertEquals(res, 'tests.tests.<lambda>') + +    def test_class(self): +        class A: pass +        res = get_name_from_obj(A) +        self.assertEquals(res, 'tests.tests.A') + +class SQLPanelTestCase(BaseTestCase): +    def test_recording(self): +        panel = self.toolbar.get_panel(SQLDebugPanel) +        self.assertEquals(len(panel._queries), 0) +         +        list(User.objects.all()) +         +        # ensure query was logged +        self.assertEquals(len(panel._queries), 1) +        query = panel._queries[0] +        self.assertEquals(query[0], 'default') +        self.assertTrue('sql' in query[1]) +        self.assertTrue('duration' in query[1]) +        self.assertTrue('stacktrace' in query[1]) + +class TemplatePanelTestCase(BaseTestCase): +    def test_queryset_hook(self): +        template_panel = self.toolbar.get_panel(TemplateDebugPanel) +        sql_panel = self.toolbar.get_panel(SQLDebugPanel) +        t = Template("No context variables here!") +        c = Context({ 'queryset' : User.objects.all(), 'deep_queryset' : { 'queryset' : User.objects.all() } }) +        t.render(c) +        # ensure the query was NOT logged +        self.assertEquals(len(sql_panel._queries), 0) +        ctx = template_panel.templates[0]['context'][0] +        ctx = eval(ctx) # convert back to Python +        self.assertEquals(ctx['queryset'], '<<queryset of auth.User>>') +        self.assertEquals(ctx['deep_queryset'], '<<triggers database query>>') + +def module_func(*args, **kwargs): +    """Used by dispatch tests""" +    return 'blah' + +class TrackingTestCase(BaseTestCase): +    @classmethod +    def class_method(cls, *args, **kwargs): +        return 'blah' + +    def class_func(self, *args, **kwargs): +        """Used by dispatch tests""" +        return 'blah' +     +    def test_pre_hook(self): +        foo = {} +         +        @pre_dispatch(module_func) +        def test(**kwargs): +            foo.update(kwargs) +             +        self.assertTrue(hasattr(module_func, '__wrapped__')) +        self.assertEquals(len(callbacks['before']), 1) +         +        module_func('hi', foo='bar') +         +        self.assertTrue('sender' in foo, foo) +        # best we can do +        self.assertEquals(foo['sender'].__name__, 'module_func') +        self.assertTrue('start' in foo, foo) +        self.assertTrue(foo['start'] > 0) +        self.assertTrue('stop' not in foo, foo) +        self.assertTrue('args' in foo, foo) +        self.assertTrue(len(foo['args']), 1) +        self.assertEquals(foo['args'][0], 'hi') +        self.assertTrue('kwargs' in foo, foo) +        self.assertTrue(len(foo['kwargs']), 1) +        self.assertTrue('foo' in foo['kwargs']) +        self.assertEquals(foo['kwargs']['foo'], 'bar') +     +        callbacks['before'] = {} +     +        @pre_dispatch(TrackingTestCase.class_func) +        def test(**kwargs): +            foo.update(kwargs) +     +        self.assertTrue(hasattr(TrackingTestCase.class_func, '__wrapped__')) +        self.assertEquals(len(callbacks['before']), 1) + +        self.class_func('hello', foo='bar') + +        self.assertTrue('sender' in foo, foo) +        # best we can do +        self.assertEquals(foo['sender'].__name__, 'class_func') +        self.assertTrue('start' in foo, foo) +        self.assertTrue(foo['start'] > 0) +        self.assertTrue('stop' not in foo, foo) +        self.assertTrue('args' in foo, foo) +        self.assertTrue(len(foo['args']), 2) +        self.assertEquals(foo['args'][1], 'hello') +        self.assertTrue('kwargs' in foo, foo) +        self.assertTrue(len(foo['kwargs']), 1) +        self.assertTrue('foo' in foo['kwargs']) +        self.assertEquals(foo['kwargs']['foo'], 'bar') + +        # callbacks['before'] = {} +        #      +        #         @pre_dispatch(TrackingTestCase.class_method) +        #         def test(**kwargs): +        #             foo.update(kwargs) +        #      +        #         self.assertTrue(hasattr(TrackingTestCase.class_method, '__wrapped__')) +        #         self.assertEquals(len(callbacks['before']), 1) +        #  +        #         TrackingTestCase.class_method() +        #  +        #         self.assertTrue('sender' in foo, foo) +        #         # best we can do +        #         self.assertEquals(foo['sender'].__name__, 'class_method') +        #         self.assertTrue('start' in foo, foo) +        #         self.assertTrue('stop' not in foo, foo) +        #         self.assertTrue('args' in foo, foo) + +    def test_post_hook(self): +        foo = {} +         +        @post_dispatch(module_func) +        def test(**kwargs): +            foo.update(kwargs) +             +        self.assertTrue(hasattr(module_func, '__wrapped__')) +        self.assertEquals(len(callbacks['after']), 1) +         +        module_func('hi', foo='bar') +         +        self.assertTrue('sender' in foo, foo) +        # best we can do +        self.assertEquals(foo['sender'].__name__, 'module_func') +        self.assertTrue('start' in foo, foo) +        self.assertTrue(foo['start'] > 0) +        self.assertTrue('stop' in foo, foo) +        self.assertTrue(foo['stop'] > foo['start']) +        self.assertTrue('args' in foo, foo) +        self.assertTrue(len(foo['args']), 1) +        self.assertEquals(foo['args'][0], 'hi') +        self.assertTrue('kwargs' in foo, foo) +        self.assertTrue(len(foo['kwargs']), 1) +        self.assertTrue('foo' in foo['kwargs']) +        self.assertEquals(foo['kwargs']['foo'], 'bar') +     +        callbacks['after'] = {} +     +        @post_dispatch(TrackingTestCase.class_func) +        def test(**kwargs): +            foo.update(kwargs) +     +        self.assertTrue(hasattr(TrackingTestCase.class_func, '__wrapped__')) +        self.assertEquals(len(callbacks['after']), 1) + +        self.class_func('hello', foo='bar') + +        self.assertTrue('sender' in foo, foo) +        # best we can do +        self.assertEquals(foo['sender'].__name__, 'class_func') +        self.assertTrue('start' in foo, foo) +        self.assertTrue(foo['start'] > 0) +        self.assertTrue('stop' in foo, foo) +        self.assertTrue(foo['stop'] > foo['start']) +        self.assertTrue('args' in foo, foo) +        self.assertTrue(len(foo['args']), 2) +        self.assertEquals(foo['args'][1], 'hello') +        self.assertTrue('kwargs' in foo, foo) +        self.assertTrue(len(foo['kwargs']), 1) +        self.assertTrue('foo' in foo['kwargs']) +        self.assertEquals(foo['kwargs']['foo'], 'bar') diff --git a/debug_toolbar/tests/urls.py b/tests/urls.py index 7c99b03..359fd8f 100644 --- a/debug_toolbar/tests/urls.py +++ b/tests/urls.py @@ -10,5 +10,6 @@ from django.contrib import admin  admin.autodiscover()  urlpatterns = patterns('', -    url(r'^execute_sql/$', 'debug_toolbar.tests.views.execute_sql'), +    # This pattern should be last to ensure tests still work +    url(r'^execute_sql/$', 'tests.views.execute_sql'),  ) diff --git a/debug_toolbar/tests/views.py b/tests/views.py index f989dcd..f989dcd 100644 --- a/debug_toolbar/tests/views.py +++ b/tests/views.py | 
