mongodb_logger 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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:"$"}]}};