pidgin2adium 1.0.0 → 2.0.0
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.
- data/History.txt +6 -0
- data/Manifest.txt +10 -0
- data/README.rdoc +106 -0
- data/Rakefile.rb +26 -0
- data/bin/pidgin2adium +72 -0
- data/lib/pidgin2adium.rb +120 -0
- data/lib/pidgin2adium/{balance-tags.rb → balance_tags.rb} +32 -29
- data/lib/pidgin2adium/log_converter.rb +68 -0
- data/lib/pidgin2adium/log_file.rb +101 -0
- data/lib/pidgin2adium/log_parser.rb +590 -0
- metadata +39 -19
- data/bin/pidgin2adium_logs +0 -67
- data/bin/pidgin2adium_status +0 -15
- data/lib/pidgin2adium/ChatFileGenerator.rb +0 -59
- data/lib/pidgin2adium/SrcFileParse.rb +0 -485
- data/lib/pidgin2adium/logs.rb +0 -250
- data/lib/pidgin2adium/status.rb +0 -113
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
== pidgin2adium
|
2
|
+
* http://rubyforge.org/projects/pidgin2adium/
|
3
|
+
|
4
|
+
== DESCRIPTION:
|
5
|
+
Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the
|
6
|
+
Adium format.
|
7
|
+
Note that it assumes a Mac OS X environment with Adium installed.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
* No problems (well, hopefully).
|
11
|
+
|
12
|
+
== SYNOPSIS:
|
13
|
+
|
14
|
+
There are two ways you can use this gem: as a script or as a library.
|
15
|
+
Both require you to provide aliases, which may require a bit of explanation.
|
16
|
+
Adium and Pidgin allow you to set aliases for buddies as well as for yourself,
|
17
|
+
so that you show up in chats as (for example) "Me" instead of as
|
18
|
+
"best_screen_name_ever_018845".
|
19
|
+
|
20
|
+
However, Pidgin then uses aliases in the log file instead of the actual screen
|
21
|
+
name, which complicates things. To parse properly, this gem needs to know which
|
22
|
+
aliases belong to you so it can map them to the correct screen name.
|
23
|
+
If it encounters an alias that you did not list, it assumes that it belongs to
|
24
|
+
the person to whom you are chatting.
|
25
|
+
Note that aliases are lower-cased and space is removed, so providing "Gabe B-W,
|
26
|
+
GBW" is the same as providing "gabeb-w,gbw".
|
27
|
+
|
28
|
+
===Example (using script)
|
29
|
+
Assuming that:
|
30
|
+
* your Pidgin log files are in the "pidgin-logs" folder
|
31
|
+
* your various aliases in your chats are "Gabe", "Gabe B-W", and "gbw"
|
32
|
+
Then run:
|
33
|
+
pidgin2adium -i pidgin-logs -a "Gabe, Gabe B-W, gbw"
|
34
|
+
|
35
|
+
===Example (using library)
|
36
|
+
The library style allows you to parse a log file and get back a
|
37
|
+
LogFile instance for easy reading, manipulation, etc.
|
38
|
+
You can also create log files yourself using Pidgin2Adium.parse_and_generate.
|
39
|
+
|
40
|
+
require 'pidgin2adium'
|
41
|
+
logfile = Pidgin2Adium.parse("/path/to/log/file.html", "gabe,gbw,gabeb-w")
|
42
|
+
if logfile == false
|
43
|
+
puts "Oh no! Could not parse!"
|
44
|
+
else
|
45
|
+
logfile.each do |message|
|
46
|
+
# Every message has these properties
|
47
|
+
puts "Sender's screen name: #{message.sender}"
|
48
|
+
puts "Time message was sent: #{message.time}"
|
49
|
+
puts "Sender's alias: #{message.buddy_alias}"
|
50
|
+
if [Pidgin2Adium::XMLMessage, Pidgin2Adium::AutoReplyMessage, Pidgin2Adium::Event].include?(message.class)
|
51
|
+
# All of these have a body
|
52
|
+
puts "Message body: #{message.body}"
|
53
|
+
if message.class == Pidgin2Adium::Event
|
54
|
+
puts "Event type: #{message.event_type}"
|
55
|
+
end
|
56
|
+
elsif message.class == Pidgin2Adium::StatusMessage
|
57
|
+
# Only StatusMessage has status
|
58
|
+
puts "Status: #{message.status}"
|
59
|
+
end
|
60
|
+
# Prints out the message in Adium log format
|
61
|
+
puts message.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
===Example 2 (using library)
|
66
|
+
If you want to output the logfile to an output dir instead of just parsing it, use Pidgin2Adium.parse_and_generate:
|
67
|
+
|
68
|
+
require 'pidgin2adium'
|
69
|
+
opts = {:overwrite => true, :output_dir => "/my/output/dir"}
|
70
|
+
path_to_converted_log = Pidgin2Adium.parse_and_generate("/path/to/log/file.html", "gabe,gbw,gabeb-w", opts)
|
71
|
+
|
72
|
+
== REQUIREMENTS:
|
73
|
+
* None
|
74
|
+
|
75
|
+
== INSTALL:
|
76
|
+
* sudo gem install pidgin2adium
|
77
|
+
|
78
|
+
== THANKS
|
79
|
+
With thanks to Li Ma, whose blog post at
|
80
|
+
http://li-ma.blogspot.com/2008/10/pidgin-log-file-to-adium-log-converter.html
|
81
|
+
helped tremendously.
|
82
|
+
|
83
|
+
== LICENSE:
|
84
|
+
|
85
|
+
(The MIT License)
|
86
|
+
|
87
|
+
Copyright (c) 2009 Gabriel Berke-Williams
|
88
|
+
|
89
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
90
|
+
a copy of this software and associated documentation files (the
|
91
|
+
'Software'), to deal in the Software without restriction, including
|
92
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
93
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
94
|
+
permit persons to whom the Software is furnished to do so, subject to
|
95
|
+
the following conditions:
|
96
|
+
|
97
|
+
The above copyright notice and this permission notice shall be
|
98
|
+
included in all copies or substantial portions of the Software.
|
99
|
+
|
100
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
101
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
102
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
103
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
104
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
105
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
106
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'hoe', '>= 2.1.0'
|
3
|
+
require 'hoe'
|
4
|
+
require 'fileutils'
|
5
|
+
require './lib/pidgin2adium.rb'
|
6
|
+
|
7
|
+
Hoe.plugin :newgem
|
8
|
+
# Hoe.plugin :website
|
9
|
+
# Hoe.plugin :cucumberfeatures
|
10
|
+
|
11
|
+
# Generate all the Rake tasks
|
12
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
13
|
+
$hoe = Hoe.spec 'pidgin2adium' do
|
14
|
+
self.developer('Gabe B-W', 'gbw@brandeis.edu')
|
15
|
+
self.extra_rdoc_files = %w{README.rdoc}
|
16
|
+
#self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
17
|
+
self.rubyforge_name = self.name # this is default value
|
18
|
+
# self.extra_deps = [['activesupport','>= 2.0.2']]
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'newgem/tasks'
|
22
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
23
|
+
|
24
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
25
|
+
# remove_task :default
|
26
|
+
# task :default => [:spec, :features]
|
data/bin/pidgin2adium
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
=begin
|
4
|
+
Author: Gabe Berke-Williams, 2008
|
5
|
+
Usage:
|
6
|
+
This is the shell script, which is a wrapper around Pidgin2Adium::LogConverter.
|
7
|
+
Call it like so:
|
8
|
+
<tt>pidgin2adium -i ~/in_logs/ -a "me,my_pidgin_alias,other_pidgin_alias"</tt>
|
9
|
+
For <tt>-a/--aliases</tt>, there is no need to use spaces or capitalization,
|
10
|
+
since spaces will be stripped out and the aliases will be lowercased anyway.
|
11
|
+
Aliases doesn't have to include screennames, either, since these are
|
12
|
+
automatically recognized.
|
13
|
+
=end
|
14
|
+
|
15
|
+
require 'pidgin2adium/log_converter'
|
16
|
+
require 'optparse'
|
17
|
+
|
18
|
+
options = {}
|
19
|
+
oparser = OptionParser.new do |opts|
|
20
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
21
|
+
opts.on('-i', '--in=IN_DIR', String, 'Specify directory where pidgin logs are stored') do |i|
|
22
|
+
options[:in] = i
|
23
|
+
end
|
24
|
+
opts.on('-a alias1,alias2', "--aliases alias1,alias2",
|
25
|
+
"A comma-separated list of your alias(es) so this script knows
|
26
|
+
which person in a chat is you.", "Whitespace and case do not matter.") do |aliases|
|
27
|
+
options[:aliases] = aliases
|
28
|
+
end
|
29
|
+
opts.on('-f', '--force', 'If this is set, then logs in the Adium log folder that have the same name as converted logs will be overwritten.') do |f|
|
30
|
+
options[:force] = f
|
31
|
+
end
|
32
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
33
|
+
puts opts
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
begin
|
38
|
+
oparser.parse!
|
39
|
+
rescue => bang
|
40
|
+
if bang.class == OptionParser::MissingArgument
|
41
|
+
# No argument provided for a switch that requires an argument.
|
42
|
+
puts '"%s" requires an argument.' % bang.args[0]
|
43
|
+
exit 1
|
44
|
+
elsif bang.class == OptionParser::InvalidOption
|
45
|
+
# Provided a switch that we don't handle.
|
46
|
+
puts '"%s" is not a valid switch.' % bang.args[0]
|
47
|
+
elsif bang.class == OptionParser::NeedlessArgument
|
48
|
+
# Raised when argument provided for a switch that doesn't take an argument.
|
49
|
+
puts bang.message
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
need_opts = false
|
54
|
+
required_opts = [[:i, :in], [:a, :aliases]]
|
55
|
+
required_opts.each do |short, long|
|
56
|
+
if options.has_key?(long)
|
57
|
+
next
|
58
|
+
else
|
59
|
+
need_opts = true
|
60
|
+
puts "Required option -#{short}/--#{long} missing."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
if need_opts
|
64
|
+
puts oparser.to_s
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
log_converter = Pidgin2Adium::LogConverter.new(options[:in],
|
69
|
+
options[:aliases],
|
70
|
+
{:overwrite => options[:force]}
|
71
|
+
)
|
72
|
+
log_converter.start
|
data/lib/pidgin2adium.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Author: Gabe Berke-Williams, 2008
|
2
|
+
#
|
3
|
+
# A ruby program to convert Pidgin log files to Adium log files, then place
|
4
|
+
# them in the Adium log directory.
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
require 'pidgin2adium/log_parser'
|
10
|
+
|
11
|
+
module Pidgin2Adium
|
12
|
+
# Returned by LogFile.write_out if the output logfile already exists.
|
13
|
+
FILE_EXISTS = 42
|
14
|
+
ADIUM_LOG_DIR = File.expand_path('~/Library/Application Support/Adium 2.0/Users/Default/Logs/') << '/'
|
15
|
+
# These files/directories show up in Dir.entries()
|
16
|
+
BAD_DIRS = %w{. .. .DS_Store Thumbs.db .system}
|
17
|
+
VERSION = "2.0.0"
|
18
|
+
|
19
|
+
def log_msg(str) #:nodoc
|
20
|
+
puts str.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def oops(str) #:nodoc
|
24
|
+
warn("Oops: #{str}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def error(str) #:nodoc
|
28
|
+
warn("Error: #{str}")
|
29
|
+
end
|
30
|
+
|
31
|
+
#######################
|
32
|
+
private :log_msg, :oops, :error
|
33
|
+
#######################
|
34
|
+
|
35
|
+
# Returns a LogFile instance or false if an error occurred.
|
36
|
+
def parse(logfile_path, my_aliases)
|
37
|
+
logfile_path = File.expand_path(logfile_path)
|
38
|
+
ext = File.extname(logfile_path).sub('.', '').downcase
|
39
|
+
|
40
|
+
if(ext == "html" || ext == "htm")
|
41
|
+
parser = HtmlLogParser.new(logfile_path, my_aliases)
|
42
|
+
elsif(ext == "txt")
|
43
|
+
parser = TextLogParser.new(logfile_path, my_aliases)
|
44
|
+
else
|
45
|
+
error("logfile (#{logfile_path}) is not a text or html file. Doing nothing.")
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
|
49
|
+
return parser.parse()
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the path to the converted log, false if an error occurred, or
|
53
|
+
# Pidgin2Adium::FILE_EXISTS if file already exists AND opts[:overwrite] =
|
54
|
+
# false.
|
55
|
+
#
|
56
|
+
# You can add options using the _opts_ hash, which can have the following
|
57
|
+
# keys, all of which are optional:
|
58
|
+
# * *overwrite*: If true, then overwrite even if log is found.
|
59
|
+
# Defaults to false.
|
60
|
+
# * *output_dir*: The top-level dir to put the logs in.
|
61
|
+
# Logs under output_dir are still each in their own folders, etc.
|
62
|
+
# Defaults to Pidgin2Adium::ADIUM_LOG_DIR
|
63
|
+
def parse_and_generate(logfile_path, my_aliases, opts = {})
|
64
|
+
opts = {} unless opts.is_a?(Hash)
|
65
|
+
overwrite = !!opts[:overwrite]
|
66
|
+
if opts.key?(:output_dir)
|
67
|
+
output_dir = opts[:output_dir]
|
68
|
+
else
|
69
|
+
output_dir = ADIUM_LOG_DIR
|
70
|
+
end
|
71
|
+
|
72
|
+
unless File.directory?(output_dir)
|
73
|
+
puts "Output log directory (#{output_dir}) does not exist or is not a directory."
|
74
|
+
raise Errno::ENOENT
|
75
|
+
end
|
76
|
+
|
77
|
+
logfile_obj = parse(logfile_path, my_aliases)
|
78
|
+
return false if logfile_obj == false
|
79
|
+
dest_file_path = logfile_obj.write_out(overwrite, output_dir)
|
80
|
+
if dest_file_path == false
|
81
|
+
error("Converting #{logfile_path} failed.")
|
82
|
+
return false
|
83
|
+
elsif dest_file_path == FILE_EXISTS
|
84
|
+
log_msg("File already exists.")
|
85
|
+
return FILE_EXISTS
|
86
|
+
else
|
87
|
+
log_msg("Output to: #{dest_file_path}")
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Newly-converted logs are viewable in the Adium Chat Transcript
|
93
|
+
# Viewer, but are not indexed, so a search of the logs doesn't give
|
94
|
+
# results from the converted logs. To fix this, we delete the cached log
|
95
|
+
# indexes, which forces Adium to re-index.
|
96
|
+
#
|
97
|
+
# Note: This function is run by LogConverter after converting all of its
|
98
|
+
# files. LogFile.write_out intentionally does _not_ run it in order to
|
99
|
+
# allow for batch-processing of files. Thus, you will probably want to run
|
100
|
+
# Pidgin2Adium.delete_search_indexes after running LogFile.write_out in
|
101
|
+
# your own scripts.
|
102
|
+
def delete_search_indexes()
|
103
|
+
log_msg "Deleting log search indexes in order to force re-indexing of imported logs..."
|
104
|
+
dirty_file = File.expand_path("~/Library/Caches/Adium/Default/DirtyLogs.plist")
|
105
|
+
log_index_file = File.expand_path("~/Library/Caches/Adium/Default/Logs.index")
|
106
|
+
[dirty_file, log_index_file].each do |f|
|
107
|
+
if File.exist?(f)
|
108
|
+
if File.writable?(f)
|
109
|
+
File.delete(f)
|
110
|
+
else
|
111
|
+
error("#{f} exists but is not writable. Please delete it yourself.")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
log_msg "...done."
|
116
|
+
log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while."
|
117
|
+
end
|
118
|
+
|
119
|
+
module_function :parse, :parse_and_generate, :delete_search_indexes
|
120
|
+
end
|
@@ -1,19 +1,23 @@
|
|
1
|
-
|
2
1
|
module Pidgin2Adium
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
2
|
+
# Balances tags of string using a modified stack. Returns a balanced
|
3
|
+
# string, but also affects the text passed into it!
|
4
|
+
# Use text = balance_tags(text).
|
5
|
+
|
6
|
+
# From Wordpress's formatting.php; rewritten in Ruby by Gabe
|
7
|
+
# Berke-Williams, 2009.
|
8
|
+
# Author:: Leonard Lin <leonard@acm.org>
|
9
|
+
# License:: GPL v2.0
|
10
|
+
# Copyright:: November 4, 2001
|
11
|
+
def balance_tags( text )
|
11
12
|
tagstack = []
|
12
13
|
stacksize = 0
|
13
14
|
tagqueue = ''
|
14
15
|
newtext = ''
|
15
|
-
single_tags =
|
16
|
-
nestable_tags =
|
16
|
+
single_tags = %w{br hr img input meta} # Known single-entity/self-closing tags
|
17
|
+
#nestable_tags = %w{blockquote div span} # Tags that can be immediately nested within themselves
|
18
|
+
nestable_tags = %w{blockquote div span font} # Tags that can be immediately nested within themselves
|
19
|
+
# 1: tagname, with possible leading "/"
|
20
|
+
# 2: attributes
|
17
21
|
tag_regex = /<(\/?\w*)\s*([^>]*)>/
|
18
22
|
|
19
23
|
# WP bug fix for comments - in case you REALLY meant to type '< !--'
|
@@ -22,24 +26,24 @@ module Pidgin2Adium
|
|
22
26
|
# WP bug fix for LOVE <3 (and other situations with '<' before a number)
|
23
27
|
text.gsub!(/<([0-9]{1})/, '<\1')
|
24
28
|
|
25
|
-
while (
|
26
|
-
regex = regex.to_a
|
29
|
+
while ( pos = (text =~ tag_regex) )
|
27
30
|
newtext << tagqueue
|
28
|
-
|
29
|
-
|
31
|
+
tag = $1.downcase
|
32
|
+
attributes = $2
|
33
|
+
matchlen = $~[0].size
|
30
34
|
|
31
35
|
# clear the shifter
|
32
36
|
tagqueue = ''
|
33
37
|
# Pop or Push
|
34
|
-
if (
|
35
|
-
tag
|
38
|
+
if (tag[0,1] == "/") # End Tag
|
39
|
+
tag.slice!(0,1)
|
36
40
|
# if too many closing tags
|
37
41
|
if(stacksize <= 0)
|
38
42
|
tag = ''
|
39
|
-
#or close to be safe tag = '/'
|
40
|
-
# if stacktop value = tag close value then pop
|
43
|
+
#or close to be safe: tag = '/' << tag
|
41
44
|
elsif (tagstack[stacksize - 1] == tag) # found closing tag
|
42
|
-
|
45
|
+
# if stacktop value == tag close value then pop
|
46
|
+
tag = '</' << tag << '>' # Close Tag
|
43
47
|
# Pop
|
44
48
|
tagstack.pop
|
45
49
|
stacksize -= 1
|
@@ -59,14 +63,13 @@ module Pidgin2Adium
|
|
59
63
|
end
|
60
64
|
else
|
61
65
|
# Begin Tag
|
62
|
-
tag = regex[1].downcase
|
63
66
|
|
64
67
|
# Tag Cleaning
|
65
|
-
if( (
|
68
|
+
if( (attributes[-1,1] == '/') || (tag == '') )
|
66
69
|
# If: self-closing or '', don't do anything.
|
67
70
|
elsif ( single_tags.include?(tag) )
|
68
71
|
# ElseIf: it's a known single-entity tag but it doesn't close itself, do so
|
69
|
-
|
72
|
+
attributes << '/'
|
70
73
|
else
|
71
74
|
# Push the tag onto the stack
|
72
75
|
# If the top of the stack is the same as the tag we want to push, close previous tag
|
@@ -76,11 +79,11 @@ module Pidgin2Adium
|
|
76
79
|
tagqueue = '</' << tagstack.pop << '>'
|
77
80
|
stacksize -= 1
|
78
81
|
end
|
79
|
-
|
82
|
+
tagstack.push(tag)
|
83
|
+
stacksize += 1
|
80
84
|
end
|
81
85
|
|
82
86
|
# Attributes
|
83
|
-
attributes = regex[2]
|
84
87
|
if(attributes != '')
|
85
88
|
attributes = ' ' << attributes
|
86
89
|
end
|
@@ -91,8 +94,8 @@ module Pidgin2Adium
|
|
91
94
|
tag = ''
|
92
95
|
end
|
93
96
|
end
|
94
|
-
newtext << text[0,
|
95
|
-
text = text[
|
97
|
+
newtext << text[0,pos] << tag
|
98
|
+
text = text[pos+matchlen, text.length - (pos+matchlen)]
|
96
99
|
end
|
97
100
|
|
98
101
|
# Clear Tag Queue
|
@@ -102,8 +105,8 @@ module Pidgin2Adium
|
|
102
105
|
newtext << text
|
103
106
|
|
104
107
|
# Empty Stack
|
105
|
-
|
106
|
-
newtext << '</' <<
|
108
|
+
tagstack.reverse_each do |t|
|
109
|
+
newtext << '</' << t << '>' # Add remaining tags to close
|
107
110
|
end
|
108
111
|
|
109
112
|
# WP fix for the bug with HTML comments
|