mongodb_logger 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/README.md +1 -1
  2. data/SUPPORTED_RAILS_VERSIONS +3 -1
  3. data/config.ru +1 -1
  4. data/examples/server_config.yml +1 -0
  5. data/lib/mongodb_logger/logger.rb +2 -1
  6. data/lib/mongodb_logger/server/coffee/{application.coffee → logs.coffee} +59 -8
  7. data/lib/mongodb_logger/server/content_for.rb +58 -0
  8. data/lib/mongodb_logger/server/model/additional_filter.rb +70 -0
  9. data/lib/mongodb_logger/server/model/filter.rb +52 -32
  10. data/lib/mongodb_logger/server/public/images/date.png +0 -0
  11. data/lib/mongodb_logger/server/public/images/external.png +0 -0
  12. data/lib/mongodb_logger/server/public/javascripts/{application.js → logs.js} +68 -10
  13. data/lib/mongodb_logger/server/public/javascripts/vendors/highlight.pack.js +1 -0
  14. data/lib/mongodb_logger/server/public/javascripts/{jquery-1.7.min.js → vendors/jquery-1.7.min.js} +0 -0
  15. data/lib/mongodb_logger/server/public/javascripts/{jquery-ui-1.8.16.effects.min.js → vendors/jquery-ui-1.8.16.effects.min.js} +0 -0
  16. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery.pjax.js +264 -0
  17. data/lib/mongodb_logger/server/public/stylesheets/all.css +2 -1
  18. data/lib/mongodb_logger/server/public/stylesheets/group-buttons.css +27 -29
  19. data/lib/mongodb_logger/server/public/stylesheets/group-forms.css +1 -1
  20. data/lib/mongodb_logger/server/public/stylesheets/group-tables.css +29 -1
  21. data/lib/mongodb_logger/server/public/stylesheets/highlight/zenburn.css +115 -0
  22. data/lib/mongodb_logger/server/public/stylesheets/layout.css +32 -10
  23. data/lib/mongodb_logger/server/public/stylesheets/library.css +169 -19
  24. data/lib/mongodb_logger/server/view_helpers.rb +35 -0
  25. data/lib/mongodb_logger/server/views/layout.erb +31 -7
  26. data/lib/mongodb_logger/server/views/overview.erb +40 -51
  27. data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +30 -0
  28. data/lib/mongodb_logger/server/views/shared/_log.erb +6 -6
  29. data/lib/mongodb_logger/server/views/shared/_log_info.erb +9 -7
  30. data/lib/mongodb_logger/server/views/shared/_message_tabs.erb +15 -0
  31. data/lib/mongodb_logger/server/views/shared/_tabs.erb +2 -2
  32. data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +13 -0
  33. data/lib/mongodb_logger/server/views/shared/_top_panel.erb +7 -0
  34. data/lib/mongodb_logger/server/views/show_log.erb +31 -15
  35. data/lib/mongodb_logger/server.rb +17 -3
  36. data/lib/mongodb_logger/version.rb +1 -1
  37. data/mongodb_logger.gemspec +9 -9
  38. metadata +47 -36
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MongodbLogger [![Build Status](https://secure.travis-ci.org/le0pard/mongodb_logger.png)](http://travis-ci.org/le0pard/mongodb_logger)
2
2
 
3
- MongodbLogger is a alternative logger for Rails 3, which log all requests off you application into MongoDB database.
3
+ MongodbLogger is a alternative logger for Rails 3, which log all requests of you application into MongoDB database.
4
4
  It:
5
5
 
6
6
  * simple to integrate into existing Rails 3 application;
@@ -10,4 +10,6 @@
10
10
  3.0.9
11
11
  3.0.10
12
12
  3.1.0
13
- 3.1.1
13
+ 3.1.1
14
+ 3.1.2
15
+ 3.1.3
data/config.ru CHANGED
@@ -4,7 +4,7 @@ require 'logger'
4
4
  $LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
5
5
  require 'mongodb_logger/server'
6
6
 
7
- # Set the RESQUECONFIG env variable if you've a `resque.rb` or similar
7
+ # Set the MONGODBLOGGERCONFIG env variable
8
8
  # config file you want loaded on boot.
9
9
  if ENV['MONGODBLOGGERCONFIG'] && ::File.exists?(::File.expand_path(ENV['MONGODBLOGGERCONFIG']))
10
10
  MongodbLogger::ServerConfig.set_config(::File.expand_path(ENV['MONGODBLOGGERCONFIG']))
@@ -2,3 +2,4 @@ database: monkey_logs_dev
2
2
  host: localhost
3
3
  port: 27017
4
4
  collection: development_log
5
+ #collection: prod_imported
@@ -142,7 +142,8 @@ module MongodbLogger
142
142
  def connect
143
143
  @mongo_connection ||= Mongo::Connection.new(@db_configuration['host'],
144
144
  @db_configuration['port'],
145
- :auto_reconnect => true).db(@db_configuration['database'])
145
+ :auto_reconnect => true,
146
+ :pool_timeout => 6).db(@db_configuration['database'])
146
147
 
147
148
  if @db_configuration['username'] && @db_configuration['password']
148
149
  # the driver stores credentials in case reconnection is required
@@ -35,16 +35,65 @@ MongodbLoggerJS =
35
35
  # filter tougle
36
36
  $('div.filter-toggle').live 'click', (event) =>
37
37
  $('div.filter').slideToggle()
38
- # log info window
39
- MongodbLoggerJS.log_info_offset = $("#log_info").offset()
40
- $(window).scroll =>
41
- if $(window).scrollTop() > MongodbLoggerJS.log_info_offset.top
38
+
39
+ # additional filters
40
+ $('#add_more_filter').live 'click', (event) =>
41
+ url = $(event.target).attr('href')
42
+ $.ajax
43
+ url: url
44
+ success: (data) ->
45
+ content = $('<li></li>').html(data)
46
+ $('#more_filter_list').append(content)
47
+ return false
48
+
49
+ $('.close_more_filter').live 'click', (event) =>
50
+ $(event.target).parents('li').remove()
51
+ return false
52
+
53
+ # message tabs
54
+ $('li.message_tab').live 'click', (event) =>
55
+ elm_obj = $(event.target)
56
+ tab = elm_obj.attr('data-tab')
57
+ if tab?
58
+ $('li.message_tab').removeClass('active')
59
+ $('pre.tab_content').addClass('hidden')
60
+ elm_obj.addClass('active')
61
+ $('.' + tab).removeClass('hidden')
62
+
63
+ # init pjax
64
+ this.init_pjax()
65
+ this.init_on_pages()
66
+
67
+ init_pjax: ->
68
+ $('a[data-pjax]').pjax()
69
+ $('body').bind 'pjax:start', () =>
70
+ $('#ajax_loader').show()
71
+ $('body').bind 'pjax:end', () =>
72
+ $('#ajax_loader').hide()
73
+ # stop tailing
74
+ MongodbLoggerJS.tail_log_started = false
75
+ # scroll on top
76
+ if ($(window).scrollTop() > 100)
77
+ $('html, body').stop().animate({ scrollTop: 0 }, 'slow')
78
+ # init pages
79
+ MongodbLoggerJS.init_on_pages()
80
+
81
+ init_on_pages: ->
82
+ # code highlight
83
+ $('pre code').each (i, e) ->
84
+ hljs.highlightBlock(e, ' ')
85
+
86
+ # log info window
87
+ if $("#log_info").length > 0
88
+ MongodbLoggerJS.log_info_offset = $("#log_info").offset()
89
+ $(window).scroll =>
90
+ if $(window).scrollTop() > MongodbLoggerJS.log_info_offset.top
42
91
  $("#log_info").stop().animate
43
92
  marginTop: $(window).scrollTop() - MongodbLoggerJS.log_info_offset.top + MongodbLoggerJS.log_info_padding
44
- else
45
- $("#log_info").stop().animate
46
- marginTop: 0
47
-
93
+ else
94
+ $("#log_info").stop().animate
95
+ marginTop: 0
96
+
48
97
  tail_logs: (count) ->
49
98
  url = MongodbLoggerJS.tail_logs_url
50
99
  if count?
@@ -61,6 +110,8 @@ MongodbLoggerJS =
61
110
  $('#tail_logs_time').text(data.time)
62
111
  if count != data.count
63
112
  count = data.count
113
+ if $("#db_collection_count").length > 0
114
+ $("#db_collection_count").text(count)
64
115
  if data.content? && data.content.length > 0
65
116
  elements = $(data.content)
66
117
  elements.addClass('newlog')
@@ -0,0 +1,58 @@
1
+ module Sinatra
2
+ module ContentFor
3
+ # Capture a block of content to be rendered later. For example:
4
+ #
5
+ # <% content_for :head do %>
6
+ # <script type="text/javascript" src="/foo.js"></script>
7
+ # <% end %>
8
+ #
9
+ # You can call +content_for+ multiple times with the same key
10
+ # (in the example +:head+), and when you render the blocks for
11
+ # that key all of them will be rendered, in the same order you
12
+ # captured them.
13
+ #
14
+ # Your blocks can also receive values, which are passed to them
15
+ # by <tt>yield_content</tt>
16
+ def content_for(key, &block)
17
+ content_blocks[key.to_sym] << block
18
+ end
19
+
20
+ # Render the captured blocks for a given key. For example:
21
+ #
22
+ # <head>
23
+ # <title>Example</title>
24
+ # <% yield_content :head %>
25
+ # </head>
26
+ #
27
+ # Would render everything you declared with <tt>content_for
28
+ # :head</tt> before closing the <tt><head></tt> tag.
29
+ #
30
+ # You can also pass values to the content blocks by passing them
31
+ # as arguments after the key:
32
+ #
33
+ # <% yield_content :head, 1, 2 %>
34
+ #
35
+ # Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered
36
+ # for <tt>:head</tt>.
37
+ #
38
+ # *NOTICE* that you call this without an <tt>=</tt> sign. IE,
39
+ # in a <tt><% %></tt> block, and not in a <tt><%= %></tt> block.
40
+ def yield_content(key, *args)
41
+ content_blocks[key.to_sym].map do |content|
42
+ if respond_to?(:block_is_haml?) && block_is_haml?(content)
43
+ capture_haml(*args, &content)
44
+ else
45
+ content.call(*args)
46
+ end
47
+ end.join
48
+ end
49
+
50
+ private
51
+
52
+ def content_blocks
53
+ @content_blocks ||= Hash.new {|h,k| h[k] = [] }
54
+ end
55
+ end
56
+
57
+ helpers ContentFor
58
+ end
@@ -0,0 +1,70 @@
1
+ module MongodbLogger
2
+ module ServerModel
3
+ class AdditionalFilter
4
+
5
+ FORM_NAME = "more"
6
+ FIXED_PARAMS_ON_FORM = ['type', 'key', 'condition', 'value']
7
+
8
+ VAR_TYPES = ["int", "str", "bool"]
9
+ DEFAULT_CONDITIONS = ["equals", "not equals", "exists", "regexes", "<", "<=", ">=", ">"]
10
+
11
+ attr_reader :form_data, :filter_model
12
+
13
+ def initialize(params, filter_model)
14
+ @filter_model = filter_model
15
+ @params = params
16
+ FIXED_PARAMS_ON_FORM.each do |key|
17
+ create_variable(key, nil)
18
+ end
19
+ @params.each do |k,v|
20
+ self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
21
+ end unless @params.blank?
22
+ end
23
+
24
+ def create_variable(k, v)
25
+ self.instance_variable_set("@#{k}", v) ## create instance variable
26
+ self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
27
+ self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
28
+ end
29
+
30
+ def form_name
31
+ "#{filter_model.form_name}[#{FORM_NAME}][]"
32
+ end
33
+
34
+ def mongo_conditions
35
+ data = Hash.new
36
+ return data if self.key.blank?
37
+ m_value = case self.type
38
+ when "int"
39
+ self.value.to_i
40
+ when "bool"
41
+ ("true" == self.value || "1" == self.value) ? true : false
42
+ else
43
+ self.value
44
+ end
45
+ data = case self.condition
46
+ when "equals"
47
+ {"#{self.key}" => m_value }
48
+ when "not equals"
49
+ {"#{self.key}" => { "$ne" => m_value }}
50
+ when "exists"
51
+ {"#{self.key}" => { "$exists" => m_value }}
52
+ when "regexes"
53
+ {"#{self.key}" => { "$regex" => m_value, "$options" => 'i' }}
54
+ when "<"
55
+ {"#{self.key}" => { "$lt" => m_value }}
56
+ when "<="
57
+ {"#{self.key}" => { "$lte" => m_value }}
58
+ when ">"
59
+ {"#{self.key}" => { "$gt" => m_value }}
60
+ when ">="
61
+ {"#{self.key}" => { "$gte" => m_value }}
62
+ else
63
+ Hash.new
64
+ end
65
+ data
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -1,50 +1,70 @@
1
+ require 'mongodb_logger/server/model/additional_filter'
2
+
1
3
  module MongodbLogger
2
4
  module ServerModel
3
5
  class Filter
4
6
 
5
7
  DEFAULT_LIMIT = 100
6
- FIXED_PARAMS = ['action', 'controller', 'ip', 'application_name', 'is_exception']
7
- attr_reader :params, :mongo_conditions, :mongo_limit
8
+ FIXED_PARAMS_ON_FORM = ['action', 'controller', 'ip', 'application_name', 'is_exception', 'limit']
9
+ attr_reader :params, :mongo_conditions
10
+ # dynamic filters
11
+ FORM_NAME = "filter"
12
+ attr_accessor :more_filters
8
13
 
9
14
  def initialize(params)
10
- if params.nil?
11
- params = Hash.new
12
- FIXED_PARAMS.each do |key|
13
- params[key] = nil
14
- end
15
+ FIXED_PARAMS_ON_FORM.each do |key|
16
+ create_variable(key, nil)
15
17
  end
16
18
  @params = params
17
- params.each do |k,v|
18
- self.instance_variable_set("@#{k}", v) ## create instance variable
19
- self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
20
- self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
21
- end
22
-
23
- if !self.respond_to?("limit")
24
- self.instance_variable_set("@limit", DEFAULT_LIMIT.to_s) ## create instance variable
25
- self.class.send(:define_method, "limit", proc{self.instance_variable_get("@limit")}) ## method to return instance variable
26
- self.class.send(:define_method, "limit=", proc{|v| self.instance_variable_set("@limit", DEFAULT_LIMIT.to_s)}) ## method to set instance variable
27
- elsif self.limit.nil?
28
- self.limit = DEFAULT_LIMIT.to_s
29
- end
19
+ @params.each do |k,v|
20
+ self.send("#{k}=", v) if self.respond_to?(k) && v && !v.blank?
21
+ end unless @params.blank?
22
+ # limits
23
+ self.limit = DEFAULT_LIMIT.to_s if self.limit.nil?
24
+ # dynamic filters
25
+ create_dynamic_filters
26
+ # build mongo conditions
30
27
  build_mongo_conditions
31
28
  end
32
29
 
30
+ def create_variable(k, v)
31
+ self.instance_variable_set("@#{k}", v) ## create instance variable
32
+ self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")}) ## method to return instance variable
33
+ self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)}) ## method to set instance variable
34
+ end
35
+
36
+ def create_dynamic_filters
37
+ self.more_filters = []
38
+ @params[AdditionalFilter::FORM_NAME].each do |filter|
39
+ self.more_filters << AdditionalFilter.new(filter, self)
40
+ end if !@params.blank? && @params[AdditionalFilter::FORM_NAME] && !@params[AdditionalFilter::FORM_NAME].blank?
41
+ end
42
+
33
43
  def build_mongo_conditions
34
44
  @mongo_conditions = Hash.new
35
- FIXED_PARAMS.each do |param_key|
36
- if self.respond_to?(param_key)
37
- value = self.send param_key
38
- if 'is_exception' == param_key
39
- @mongo_conditions[param_key.to_s] = true if value && !value.blank?
45
+ FIXED_PARAMS_ON_FORM.each do |param_key|
46
+ value = self.send param_key
47
+ mkey_val = case param_key
48
+ when 'is_exception'
49
+ (value ? true : nil)
50
+ when 'limit'
51
+ nil # skip
52
+ else
53
+ value
54
+ end
55
+ @mongo_conditions[param_key.to_s] = mkey_val if !mkey_val.nil? && !mkey_val.blank?
56
+ end
57
+
58
+ self.more_filters.each do |m_filter|
59
+ unless m_filter.mongo_conditions.blank?
60
+ cond = m_filter.mongo_conditions
61
+ if @mongo_conditions[m_filter.key]
62
+ @mongo_conditions[m_filter.key].merge!(cond[m_filter.key])
40
63
  else
41
- @mongo_conditions[param_key.to_s] = value unless value.blank?
64
+ @mongo_conditions.merge!(m_filter.mongo_conditions)
42
65
  end
43
66
  end
44
- end
45
- # set limit
46
- @mongo_limit = DEFAULT_LIMIT
47
- @mongo_limit = self.limit.to_i if self.respond_to?("limit")
67
+ end unless self.more_filters.blank?
48
68
  end
49
69
 
50
70
  def get_mongo_conditions
@@ -52,11 +72,11 @@ module MongodbLogger
52
72
  end
53
73
 
54
74
  def get_mongo_limit
55
- @mongo_limit
75
+ self.limit.to_i
56
76
  end
57
77
 
58
78
  def form_name
59
- "filter"
79
+ FORM_NAME
60
80
  end
61
81
 
62
82
  end
@@ -44,18 +44,73 @@
44
44
  $('div.filter-toggle').live('click', function(event) {
45
45
  return $('div.filter').slideToggle();
46
46
  });
47
- MongodbLoggerJS.log_info_offset = $("#log_info").offset();
48
- return $(window).scroll(function() {
49
- if ($(window).scrollTop() > MongodbLoggerJS.log_info_offset.top) {
50
- return $("#log_info").stop().animate({
51
- marginTop: $(window).scrollTop() - MongodbLoggerJS.log_info_offset.top + MongodbLoggerJS.log_info_padding
52
- });
53
- } else {
54
- return $("#log_info").stop().animate({
55
- marginTop: 0
56
- });
47
+ $('#add_more_filter').live('click', function(event) {
48
+ var url;
49
+ url = $(event.target).attr('href');
50
+ $.ajax({
51
+ url: url,
52
+ success: function(data) {
53
+ var content;
54
+ content = $('<li></li>').html(data);
55
+ return $('#more_filter_list').append(content);
56
+ }
57
+ });
58
+ return false;
59
+ });
60
+ $('.close_more_filter').live('click', function(event) {
61
+ $(event.target).parents('li').remove();
62
+ return false;
63
+ });
64
+ $('li.message_tab').live('click', function(event) {
65
+ var elm_obj, tab;
66
+ elm_obj = $(event.target);
67
+ tab = elm_obj.attr('data-tab');
68
+ if (tab != null) {
69
+ $('li.message_tab').removeClass('active');
70
+ $('pre.tab_content').addClass('hidden');
71
+ elm_obj.addClass('active');
72
+ return $('.' + tab).removeClass('hidden');
57
73
  }
58
74
  });
75
+ this.init_pjax();
76
+ return this.init_on_pages();
77
+ },
78
+ init_pjax: function() {
79
+ var _this = this;
80
+ $('a[data-pjax]').pjax();
81
+ $('body').bind('pjax:start', function() {
82
+ return $('#ajax_loader').show();
83
+ });
84
+ return $('body').bind('pjax:end', function() {
85
+ $('#ajax_loader').hide();
86
+ MongodbLoggerJS.tail_log_started = false;
87
+ if ($(window).scrollTop() > 100) {
88
+ $('html, body').stop().animate({
89
+ scrollTop: 0
90
+ }, 'slow');
91
+ }
92
+ return MongodbLoggerJS.init_on_pages();
93
+ });
94
+ },
95
+ init_on_pages: function() {
96
+ var _this = this;
97
+ $('pre code').each(function(i, e) {
98
+ return hljs.highlightBlock(e, ' ');
99
+ });
100
+ if ($("#log_info").length > 0) {
101
+ MongodbLoggerJS.log_info_offset = $("#log_info").offset();
102
+ return $(window).scroll(function() {
103
+ if ($(window).scrollTop() > MongodbLoggerJS.log_info_offset.top) {
104
+ return $("#log_info").stop().animate({
105
+ marginTop: $(window).scrollTop() - MongodbLoggerJS.log_info_offset.top + MongodbLoggerJS.log_info_padding
106
+ });
107
+ } else {
108
+ return $("#log_info").stop().animate({
109
+ marginTop: 0
110
+ });
111
+ }
112
+ });
113
+ }
59
114
  },
60
115
  tail_logs: function(count) {
61
116
  var url;
@@ -76,6 +131,9 @@
76
131
  $('#tail_logs_time').text(data.time);
77
132
  if (count !== data.count) {
78
133
  count = data.count;
134
+ if ($("#db_collection_count").length > 0) {
135
+ $("#db_collection_count").text(count);
136
+ }
79
137
  if ((data.content != null) && data.content.length > 0) {
80
138
  elements = $(data.content);
81
139
  elements.addClass('newlog');
@@ -0,0 +1 @@
1
+ var hljs=new function(){function m(p){return p.replace(/&/gm,"&amp;").replace(/</gm,"&lt;")}function c(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function j(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function g(t,s){var r="";for(var q=0;q<t.childNodes.length;q++){if(t.childNodes[q].nodeType==3){var p=t.childNodes[q].nodeValue;if(s){p=p.replace(/\n/g,"")}r+=p}else{if(t.childNodes[q].nodeName=="BR"){r+="\n"}else{r+=g(t.childNodes[q])}}}if(/MSIE [678]/.test(navigator.userAgent)){r=r.replace(/\r/g,"\n")}return r}function a(s){var q=s.className.split(/\s+/);q=q.concat(s.parentNode.className.split(/\s+/));for(var p=0;p<q.length;p++){var r=q[p].replace(/^language-/,"");if(d[r]||r=="no-highlight"){return r}}}function b(p){var q=[];(function(s,t){for(var r=0;r<s.childNodes.length;r++){if(s.childNodes[r].nodeType==3){t+=s.childNodes[r].nodeValue.length}else{if(s.childNodes[r].nodeName=="BR"){t+=1}else{q.push({event:"start",offset:t,node:s.childNodes[r]});t=arguments.callee(s.childNodes[r],t);q.push({event:"stop",offset:t,node:s.childNodes[r]})}}}return t})(p,0);return q}function l(y,z,x){var r=0;var w="";var t=[];function u(){if(y.length&&z.length){if(y[0].offset!=z[0].offset){return(y[0].offset<z[0].offset)?y:z}else{return z[0].event=="start"?y:z}}else{return y.length?y:z}}function s(C){var D="<"+C.nodeName.toLowerCase();for(var A=0;A<C.attributes.length;A++){var B=C.attributes[A];D+=" "+B.nodeName.toLowerCase();if(B.nodeValue!=undefined&&B.nodeValue!=false&&B.nodeValue!=null){D+='="'+m(B.nodeValue)+'"'}}return D+">"}while(y.length||z.length){var v=u().splice(0,1)[0];w+=m(x.substr(r,v.offset-r));r=v.offset;if(v.event=="start"){w+=s(v.node);t.push(v.node)}else{if(v.event=="stop"){var q=t.length;do{q--;var p=t[q];w+=("</"+p.nodeName.toLowerCase()+">")}while(p!=v.node);t.splice(q,1);while(q<t.length){w+=s(t[q]);q++}}}}w+=x.substr(r);return w}function i(){function p(u,t,v){if(u.compiled){return}if(!v){u.bR=c(t,u.b?u.b:"\\B|\\b");if(!u.e&&!u.eW){u.e="\\B|\\b"}if(u.e){u.eR=c(t,u.e)}}if(u.i){u.iR=c(t,u.i)}if(u.r==undefined){u.r=1}if(u.k){u.lR=c(t,u.l||hljs.IR,true)}for(var s in u.k){if(!u.k.hasOwnProperty(s)){continue}if(u.k[s] instanceof Object){u.kG=u.k}else{u.kG={keyword:u.k}}break}if(!u.c){u.c=[]}u.compiled=true;for(var r=0;r<u.c.length;r++){p(u.c[r],t,false)}if(u.starts){p(u.starts,t,false)}}for(var q in d){if(!d.hasOwnProperty(q)){continue}p(d[q].dM,d[q],true)}}function e(J,D){if(!i.called){i();i.called=true}function z(r,M){for(var L=0;L<M.c.length;L++){if(M.c[L].bR.test(r)){return M.c[L]}}}function w(L,r){if(C[L].e&&C[L].eR.test(r)){return 1}if(C[L].eW){var M=w(L-1,r);return M?M+1:0}return 0}function x(r,L){return L.iR&&L.iR.test(r)}function A(O,N){var M=[];for(var L=0;L<O.c.length;L++){M.push(O.c[L].b)}var r=C.length-1;do{if(C[r].e){M.push(C[r].e)}r--}while(C[r+1].eW);if(O.i){M.push(O.i)}return c(N,"("+M.join("|")+")",true)}function s(M,L){var N=C[C.length-1];if(!N.t){N.t=A(N,H)}N.t.lastIndex=L;var r=N.t.exec(M);if(r){return[M.substr(L,r.index-L),r[0],false]}else{return[M.substr(L),"",true]}}function p(O,r){var L=H.cI?r[0].toLowerCase():r[0];for(var N in O.kG){if(!O.kG.hasOwnProperty(N)){continue}var M=O.kG[N].hasOwnProperty(L);if(M){return[N,M]}}return false}function F(M,O){if(!O.k){return m(M)}var N="";var P=0;O.lR.lastIndex=0;var L=O.lR.exec(M);while(L){N+=m(M.substr(P,L.index-P));var r=p(O,L);if(r){t+=r[1];N+='<span class="'+r[0]+'">'+m(L[0])+"</span>"}else{N+=m(L[0])}P=O.lR.lastIndex;L=O.lR.exec(M)}N+=m(M.substr(P,M.length-P));return N}function K(r,M){if(M.sL&&d[M.sL]){var L=e(M.sL,r);t+=L.keyword_count;return L.value}else{return F(r,M)}}function I(M,r){var L=M.cN?'<span class="'+M.cN+'">':"";if(M.rB){q+=L;M.buffer=""}else{if(M.eB){q+=m(r)+L;M.buffer=""}else{q+=L;M.buffer=r}}C.push(M);B+=M.r}function E(O,L,Q){var R=C[C.length-1];if(Q){q+=K(R.buffer+O,R);return false}var M=z(L,R);if(M){q+=K(R.buffer+O,R);I(M,L);return M.rB}var r=w(C.length-1,L);if(r){var N=R.cN?"</span>":"";if(R.rE){q+=K(R.buffer+O,R)+N}else{if(R.eE){q+=K(R.buffer+O,R)+N+m(L)}else{q+=K(R.buffer+O+L,R)+N}}while(r>1){N=C[C.length-2].cN?"</span>":"";q+=N;r--;C.length--}var P=C[C.length-1];C.length--;C[C.length-1].buffer="";if(P.starts){I(P.starts,"")}return R.rE}if(x(L,R)){throw"Illegal"}}var H=d[J];var C=[H.dM];var B=0;var t=0;var q="";try{var v=0;H.dM.buffer="";do{var y=s(D,v);var u=E(y[0],y[1],y[2]);v+=y[0].length;if(!u){v+=y[1].length}}while(!y[2]);if(C.length>1){throw"Illegal"}return{r:B,keyword_count:t,value:q}}catch(G){if(G=="Illegal"){return{r:0,keyword_count:0,value:m(D)}}else{throw G}}}function f(t){var r={keyword_count:0,r:0,value:m(t)};var q=r;for(var p in d){if(!d.hasOwnProperty(p)){continue}var s=e(p,t);s.language=p;if(s.keyword_count+s.r>q.keyword_count+q.r){q=s}if(s.keyword_count+s.r>r.keyword_count+r.r){q=r;r=s}}if(q.language){r.second_best=q}return r}function h(r,q,p){if(q){r=r.replace(/^((<[^>]+>|\t)+)/gm,function(t,w,v,u){return w.replace(/\t/g,q)})}if(p){r=r.replace(/\n/g,"<br>")}return r}function o(u,x,q){var y=g(u,q);var s=a(u);if(s=="no-highlight"){return}if(s){var w=e(s,y)}else{var w=f(y);s=w.language}var p=b(u);if(p.length){var r=document.createElement("pre");r.innerHTML=w.value;w.value=l(p,b(r),y)}w.value=h(w.value,x,q);var t=u.className;if(!t.match("(\\s|^)(language-)?"+s+"(\\s|$)")){t=t?(t+" "+s):s}if(/MSIE [678]/.test(navigator.userAgent)&&u.tagName=="CODE"&&u.parentNode.tagName=="PRE"){var r=u.parentNode;var v=document.createElement("div");v.innerHTML="<pre><code>"+w.value+"</code></pre>";u=v.firstChild.firstChild;v.firstChild.cN=r.cN;r.parentNode.replaceChild(v.firstChild,r)}else{u.innerHTML=w.value}u.className=t;u.result={language:s,kw:w.keyword_count,re:w.r};if(w.second_best){u.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function k(){if(k.called){return}k.called=true;var r=document.getElementsByTagName("pre");for(var p=0;p<r.length;p++){var q=j(r[p]);if(q){o(q,hljs.tabReplace)}}}function n(){if(window.addEventListener){window.addEventListener("DOMContentLoaded",k,false);window.addEventListener("load",k,false)}else{if(window.attachEvent){window.attachEvent("onload",k)}else{window.onload=k}}}var d={};this.LANGUAGES=d;this.highlight=e;this.highlightAuto=f;this.fixMarkup=h;this.highlightBlock=o;this.initHighlighting=k;this.initHighlightingOnLoad=n;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\.",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.inherit=function(p,s){var r={};for(var q in p){r[q]=p[q]}if(s){for(var q in s){r[q]=s[q]}}return r}}();hljs.LANGUAGES.bash=function(){var d={"true":1,"false":1};var b={cN:"variable",b:"\\$([a-zA-Z0-9_]+)\\b"};var a={cN:"variable",b:"\\$\\{(([^}])|(\\\\}))+\\}",c:[hljs.CNM]};var c={cN:"string",b:'"',e:'"',i:"\\n",c:[hljs.BE,b,a],r:0};var e={cN:"test_condition",b:"",e:"",c:[c,b,a,hljs.CNM],k:{literal:d},r:0};return{dM:{k:{keyword:{"if":1,then:1,"else":1,fi:1,"for":1,"break":1,"continue":1,"while":1,"in":1,"do":1,done:1,echo:1,exit:1,"return":1,set:1,declare:1},literal:d},c:[{cN:"shebang",b:"(#!\\/bin\\/bash)|(#!\\/bin\\/sh)",r:10},hljs.HCM,hljs.CNM,c,b,a,hljs.inherit(e,{b:"\\[ ",e:" \\]",r:0}),hljs.inherit(e,{b:"\\[\\[ ",e:" \\]\\]"})]}}}();hljs.LANGUAGES.ruby=function(){var g="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?";var a="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var n={keyword:{and:1,"false":1,then:1,defined:1,module:1,"in":1,"return":1,redo:1,"if":1,BEGIN:1,retry:1,end:1,"for":1,"true":1,self:1,when:1,next:1,until:1,"do":1,begin:1,unless:1,END:1,rescue:1,nil:1,"else":1,"break":1,undef:1,not:1,"super":1,"class":1,"case":1,require:1,yield:1,alias:1,"while":1,ensure:1,elsif:1,or:1,def:1},keymethods:{__id__:1,__send__:1,abort:1,abs:1,"all?":1,allocate:1,ancestors:1,"any?":1,arity:1,assoc:1,at:1,at_exit:1,autoload:1,"autoload?":1,"between?":1,binding:1,binmode:1,"block_given?":1,call:1,callcc:1,caller:1,capitalize:1,"capitalize!":1,casecmp:1,"catch":1,ceil:1,center:1,chomp:1,"chomp!":1,chop:1,"chop!":1,chr:1,"class":1,class_eval:1,"class_variable_defined?":1,class_variables:1,clear:1,clone:1,close:1,close_read:1,close_write:1,"closed?":1,coerce:1,collect:1,"collect!":1,compact:1,"compact!":1,concat:1,"const_defined?":1,const_get:1,const_missing:1,const_set:1,constants:1,count:1,crypt:1,"default":1,default_proc:1,"delete":1,"delete!":1,delete_at:1,delete_if:1,detect:1,display:1,div:1,divmod:1,downcase:1,"downcase!":1,downto:1,dump:1,dup:1,each:1,each_byte:1,each_index:1,each_key:1,each_line:1,each_pair:1,each_value:1,each_with_index:1,"empty?":1,entries:1,eof:1,"eof?":1,"eql?":1,"equal?":1,"eval":1,exec:1,exit:1,"exit!":1,extend:1,fail:1,fcntl:1,fetch:1,fileno:1,fill:1,find:1,find_all:1,first:1,flatten:1,"flatten!":1,floor:1,flush:1,for_fd:1,foreach:1,fork:1,format:1,freeze:1,"frozen?":1,fsync:1,getc:1,gets:1,global_variables:1,grep:1,gsub:1,"gsub!":1,"has_key?":1,"has_value?":1,hash:1,hex:1,id:1,include:1,"include?":1,included_modules:1,index:1,indexes:1,indices:1,induced_from:1,inject:1,insert:1,inspect:1,instance_eval:1,instance_method:1,instance_methods:1,"instance_of?":1,"instance_variable_defined?":1,instance_variable_get:1,instance_variable_set:1,instance_variables:1,"integer?":1,intern:1,invert:1,ioctl:1,"is_a?":1,isatty:1,"iterator?":1,join:1,"key?":1,keys:1,"kind_of?":1,lambda:1,last:1,length:1,lineno:1,ljust:1,load:1,local_variables:1,loop:1,lstrip:1,"lstrip!":1,map:1,"map!":1,match:1,max:1,"member?":1,merge:1,"merge!":1,method:1,"method_defined?":1,method_missing:1,methods:1,min:1,module_eval:1,modulo:1,name:1,nesting:1,"new":1,next:1,"next!":1,"nil?":1,nitems:1,"nonzero?":1,object_id:1,oct:1,open:1,pack:1,partition:1,pid:1,pipe:1,pop:1,popen:1,pos:1,prec:1,prec_f:1,prec_i:1,print:1,printf:1,private_class_method:1,private_instance_methods:1,"private_method_defined?":1,private_methods:1,proc:1,protected_instance_methods:1,"protected_method_defined?":1,protected_methods:1,public_class_method:1,public_instance_methods:1,"public_method_defined?":1,public_methods:1,push:1,putc:1,puts:1,quo:1,raise:1,rand:1,rassoc:1,read:1,read_nonblock:1,readchar:1,readline:1,readlines:1,readpartial:1,rehash:1,reject:1,"reject!":1,remainder:1,reopen:1,replace:1,require:1,"respond_to?":1,reverse:1,"reverse!":1,reverse_each:1,rewind:1,rindex:1,rjust:1,round:1,rstrip:1,"rstrip!":1,scan:1,seek:1,select:1,send:1,set_trace_func:1,shift:1,singleton_method_added:1,singleton_methods:1,size:1,sleep:1,slice:1,"slice!":1,sort:1,"sort!":1,sort_by:1,split:1,sprintf:1,squeeze:1,"squeeze!":1,srand:1,stat:1,step:1,store:1,strip:1,"strip!":1,sub:1,"sub!":1,succ:1,"succ!":1,sum:1,superclass:1,swapcase:1,"swapcase!":1,sync:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,taint:1,"tainted?":1,tell:1,test:1,"throw":1,times:1,to_a:1,to_ary:1,to_f:1,to_hash:1,to_i:1,to_int:1,to_io:1,to_proc:1,to_s:1,to_str:1,to_sym:1,tr:1,"tr!":1,tr_s:1,"tr_s!":1,trace_var:1,transpose:1,trap:1,truncate:1,"tty?":1,type:1,ungetc:1,uniq:1,"uniq!":1,unpack:1,unshift:1,untaint:1,untrace_var:1,upcase:1,"upcase!":1,update:1,upto:1,"value?":1,values:1,values_at:1,warn:1,write:1,write_nonblock:1,"zero?":1,zip:1}};var h={cN:"yardoctag",b:"@[A-Za-z]+"};var d={cN:"comment",b:"#",e:"$",c:[h]};var c={cN:"comment",b:"^\\=begin",e:"^\\=end",c:[h],r:10};var b={cN:"comment",b:"^__END__",e:"\\n$"};var u={cN:"subst",b:"#\\{",e:"}",l:g,k:n};var p=[hljs.BE,u];var s={cN:"string",b:"'",e:"'",c:p,r:0};var r={cN:"string",b:'"',e:'"',c:p,r:0};var q={cN:"string",b:"%[qw]?\\(",e:"\\)",c:p,r:10};var o={cN:"string",b:"%[qw]?\\[",e:"\\]",c:p,r:10};var m={cN:"string",b:"%[qw]?{",e:"}",c:p,r:10};var l={cN:"string",b:"%[qw]?<",e:">",c:p,r:10};var k={cN:"string",b:"%[qw]?/",e:"/",c:p,r:10};var j={cN:"string",b:"%[qw]?%",e:"%",c:p,r:10};var i={cN:"string",b:"%[qw]?-",e:"-",c:p,r:10};var t={cN:"string",b:"%[qw]?\\|",e:"\\|",c:p,r:10};var e={cN:"function",b:"\\bdef\\s+",e:" |$|;",l:g,k:n,c:[{cN:"title",b:a,l:g,k:n},{cN:"params",b:"\\(",e:"\\)",l:g,k:n},d,c,b]};var f={cN:"identifier",b:g,l:g,k:n,r:0};var v=[d,c,b,s,r,q,o,m,l,k,j,i,t,{cN:"class",b:"\\b(class|module)\\b",e:"$|;",k:{"class":1,module:1},c:[{cN:"title",b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",r:0},{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+hljs.IR+"::)?"+hljs.IR}]},d,c,b]},e,{cN:"constant",b:"(::)?([A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[s,r,q,o,m,l,k,j,i,t,f],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"number",b:"\\?\\w"},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},f,{b:"("+hljs.RSR+")\\s*",c:[d,c,b,{cN:"regexp",b:"/",e:"/[a-z]*",i:"\\n",c:[hljs.BE]}],r:0}];u.c=v;e.c[1].c=v;return{dM:{l:g,k:n,c:v}}}();hljs.LANGUAGES.javascript={dM:{k:{keyword:{"in":1,"if":1,"for":1,"while":1,"finally":1,"var":1,"new":1,"function":1,"do":1,"return":1,"void":1,"else":1,"break":1,"catch":1,"instanceof":1,"with":1,"throw":1,"case":1,"default":1,"try":1,"this":1,"switch":1,"continue":1,"typeof":1,"delete":1},literal:{"true":1,"false":1,"null":1}},c:[hljs.ASM,hljs.QSM,hljs.CLCM,hljs.CBLCLM,hljs.CNM,{b:"("+hljs.RSR+"|case|return|throw)\\s*",k:{"return":1,"throw":1,"case":1},c:[hljs.CLCM,hljs.CBLCLM,{cN:"regexp",b:"/",e:"/[gim]*",c:[{b:"\\\\/"}]}],r:0},{cN:"function",b:"\\bfunction\\b",e:"{",k:{"function":1},c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[hljs.ASM,hljs.QSM,hljs.CLCM,hljs.CBLCLM]}]}]}};hljs.LANGUAGES.xml=function(){var b="[A-Za-z0-9\\._:-]+";var a={eW:true,c:[{cN:"attribute",b:b,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,dM:{c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"<!--",e:"-->",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"<style",e:">",k:{title:{style:1}},c:[a],starts:{cN:"css",e:"</style>",rE:true,sL:"css"}},{cN:"tag",b:"<script",e:">",k:{title:{script:1}},c:[a],starts:{cN:"javascript",e:"<\/script>",rE:true,sL:"javascript"}},{cN:"vbscript",b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"title",b:"[^ />]+"},a]}]}}}();hljs.LANGUAGES.python=function(){var c={cN:"string",b:"(u|b)?r?'''",e:"'''",r:10};var b={cN:"string",b:'(u|b)?r?"""',e:'"""',r:10};var a={cN:"string",b:"(u|r|ur|b|br)'",e:"'",c:[hljs.BE],r:10};var f={cN:"string",b:'(u|r|ur|b|br)"',e:'"',c:[hljs.BE],r:10};var d={cN:"title",b:hljs.UIR};var e={cN:"params",b:"\\(",e:"\\)",c:[c,b,a,f,hljs.ASM,hljs.QSM]};return{dM:{k:{keyword:{and:1,elif:1,is:1,global:1,as:1,"in":1,"if":1,from:1,raise:1,"for":1,except:1,"finally":1,print:1,"import":1,pass:1,"return":1,exec:1,"else":1,"break":1,not:1,"with":1,"class":1,assert:1,yield:1,"try":1,"while":1,"continue":1,del:1,or:1,def:1,lambda:1,nonlocal:10},built_in:{None:1,True:1,False:1,Ellipsis:1,NotImplemented:1}},i:"(</|->|\\?)",c:[hljs.HCM,c,b,a,f,hljs.ASM,hljs.QSM,{cN:"function",b:"\\bdef ",e:":",i:"$",k:{def:1},c:[d,e],r:10},{cN:"class",b:"\\bclass ",e:":",i:"[${]",k:{"class":1},c:[d,e],r:10},hljs.CNM,{cN:"decorator",b:"@",e:"$"}]}}}();hljs.LANGUAGES.sql={cI:true,dM:{i:"[^\\s]",c:[{cN:"operator",b:"(begin|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma)\\b",e:";|$",k:{keyword:{all:1,partial:1,global:1,month:1,current_timestamp:1,using:1,go:1,revoke:1,smallint:1,indicator:1,"end-exec":1,disconnect:1,zone:1,"with":1,character:1,assertion:1,to:1,add:1,current_user:1,usage:1,input:1,local:1,alter:1,match:1,collate:1,real:1,then:1,rollback:1,get:1,read:1,timestamp:1,session_user:1,not:1,integer:1,bit:1,unique:1,day:1,minute:1,desc:1,insert:1,execute:1,like:1,ilike:2,level:1,decimal:1,drop:1,"continue":1,isolation:1,found:1,where:1,constraints:1,domain:1,right:1,national:1,some:1,module:1,transaction:1,relative:1,second:1,connect:1,escape:1,close:1,system_user:1,"for":1,deferred:1,section:1,cast:1,current:1,sqlstate:1,allocate:1,intersect:1,deallocate:1,numeric:1,"public":1,preserve:1,full:1,"goto":1,initially:1,asc:1,no:1,key:1,output:1,collation:1,group:1,by:1,union:1,session:1,both:1,last:1,language:1,constraint:1,column:1,of:1,space:1,foreign:1,deferrable:1,prior:1,connection:1,unknown:1,action:1,commit:1,view:1,or:1,first:1,into:1,"float":1,year:1,primary:1,cascaded:1,except:1,restrict:1,set:1,references:1,names:1,table:1,outer:1,open:1,select:1,size:1,are:1,rows:1,from:1,prepare:1,distinct:1,leading:1,create:1,only:1,next:1,inner:1,authorization:1,schema:1,corresponding:1,option:1,declare:1,precision:1,immediate:1,"else":1,timezone_minute:1,external:1,varying:1,translation:1,"true":1,"case":1,exception:1,join:1,hour:1,"default":1,"double":1,scroll:1,value:1,cursor:1,descriptor:1,values:1,dec:1,fetch:1,procedure:1,"delete":1,and:1,"false":1,"int":1,is:1,describe:1,"char":1,as:1,at:1,"in":1,varchar:1,"null":1,trailing:1,any:1,absolute:1,current_time:1,end:1,grant:1,privileges:1,when:1,cross:1,check:1,write:1,current_date:1,pad:1,begin:1,temporary:1,exec:1,time:1,update:1,catalog:1,user:1,sql:1,date:1,on:1,identity:1,timezone_hour:1,natural:1,whenever:1,interval:1,work:1,order:1,cascade:1,diagnostics:1,nchar:1,having:1,left:1,call:1,"do":1,handler:1,load:1,replace:1,truncate:1,start:1,lock:1,show:1,pragma:1},aggregate:{count:1,sum:1,min:1,max:1,avg:1}},c:[{cN:"string",b:"'",e:"'",c:[hljs.BE,{b:"''"}],r:0},{cN:"string",b:'"',e:'"',c:[hljs.BE,{b:'""'}],r:0},{cN:"string",b:"`",e:"`",c:[hljs.BE]},hljs.CNM,{b:"\\n"}]},hljs.CBLCLM,{cN:"comment",b:"--",e:"$"}]}};