pidgin2adium 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +0 -3
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/History.txt +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +15 -25
- data/Rakefile +68 -0
- data/VERSION +1 -0
- data/bin/pidgin2adium_profiler +1 -0
- data/config/website.yml +2 -0
- data/ext/balance_tags_c/balance_tags_c.c +7 -7
- data/lib/pidgin2adium.rb +108 -108
- data/lib/pidgin2adium/balance_tags.rb +118 -0
- data/lib/pidgin2adium/log_converter.rb +59 -59
- data/lib/pidgin2adium/log_file.rb +91 -91
- data/lib/pidgin2adium/log_parser.rb +590 -589
- data/pidgin2adium.gemspec +79 -0
- data/spec/pidgin2adium_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/build_profiler.rake +49 -0
- data/tasks/extconf.rake +0 -5
- metadata +72 -41
- data/Rakefile.rb +0 -41
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/test/test_balance_tags_c_extn.rb +0 -10
data/.autotest
CHANGED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 3.0.1 / 2010-08-07
|
2
|
+
Bugfix release:
|
3
|
+
* balance_tags_c.c: Use rb_eval_string instead of rb_reg_regcomp to avoid
|
4
|
+
segfaults (commit #733ce88b0836256e14f0, fixes #27811)
|
5
|
+
Non-user-facing stuff:
|
6
|
+
* Switched to Jeweler, RSpec, and Bundler
|
7
|
+
* Rakefile now doesn't choke if Hanna gem isn't installed
|
8
|
+
|
1
9
|
=== 3.0.0 / 2010-01-31
|
2
10
|
* balance_tags.rb is now a C extension (Pidgin2Adium.balance_tags_c)
|
3
11
|
- the pure-ruby mixin balance_tags (without the trailing "_c") is gone
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Gabe Berke-Williams
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
* http://
|
1
|
+
= pidgin2adium
|
2
|
+
* http://github.com/gabebw/pidgin2adium
|
3
|
+
* http://rubygems.org/gems/pidgin2adium
|
3
4
|
|
4
5
|
== DESCRIPTION:
|
5
6
|
Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the
|
@@ -38,7 +39,7 @@ Or:
|
|
38
39
|
|
39
40
|
===Example (using library)
|
40
41
|
The library style allows you to parse a log file and get back a LogFile[link:classes/Pidgin2Adium/LogFile.html] instance for easy reading, manipulation, etc. If you don't need to do anything with the individual messages, use Pidgin2Adium.parse[link:classes/Pidgin2Adium.html#M000002].
|
41
|
-
|
42
|
+
|
42
43
|
require 'pidgin2adium'
|
43
44
|
logfile = Pidgin2Adium.parse("/path/to/log/file.html", "gabe,gbw,gabeb-w")
|
44
45
|
if logfile == false
|
@@ -89,7 +90,7 @@ The library style allows you to parse a log file and get back a LogFile[link:cla
|
|
89
90
|
If you want to parse the file and write it out instead of just parsing it, use Pidgin2Adium.parse_and_generate.
|
90
91
|
|
91
92
|
Note: For batch processing, use LogConverter[link:classes/Pidgin2Adium/LogConverter.html].
|
92
|
-
|
93
|
+
|
93
94
|
require 'pidgin2adium'
|
94
95
|
# Both options are optional; without :output_dir, writes to Adium log dir
|
95
96
|
# (which is usually what you want anyway).
|
@@ -107,27 +108,16 @@ With thanks to Li Ma, whose blog post at
|
|
107
108
|
http://li-ma.blogspot.com/2008/10/pidgin-log-file-to-adium-log-converter.html
|
108
109
|
helped tremendously.
|
109
110
|
|
110
|
-
==
|
111
|
-
|
112
|
-
(The MIT License)
|
113
|
-
|
114
|
-
Copyright (c) 2009 Gabriel Berke-Williams
|
111
|
+
== Note on Patches/Pull Requests
|
115
112
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
113
|
+
* Fork the project.
|
114
|
+
* Make your feature addition or bug fix.
|
115
|
+
* Add tests for it. This is important so I don't break it in a
|
116
|
+
future version unintentionally.
|
117
|
+
* Commit, do not mess with rakefile, version, or history.
|
118
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
119
|
+
* Send me a pull request. Bonus points for topic branches.
|
123
120
|
|
124
|
-
|
125
|
-
included in all copies or substantial portions of the Software.
|
121
|
+
== Copyright
|
126
122
|
|
127
|
-
|
128
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
129
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
130
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
131
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
132
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
133
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
123
|
+
Copyright (c) 2010 Gabe Berke-Williams. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = "pidgin2adium"
|
9
|
+
gem.summary = %Q{Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format}
|
10
|
+
gem.description = %Q{Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format.}
|
11
|
+
gem.email = "gbw@brandeis.edu"
|
12
|
+
gem.homepage = "http://github.com/gabebw/pidgin2adium"
|
13
|
+
gem.authors = ["Gabe Berke-Williams"]
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
gem.add_bundler_dependencies
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
# RSpec 2
|
24
|
+
gem "rspec", ">= 2.0.0.beta.18"
|
25
|
+
require 'rspec/core/rake_task'
|
26
|
+
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.spec_opts << %w{-Ilib -Ispec}
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
33
|
+
spec.spec_opts << %w{-Ilib -Ispec}
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
rescue Gem::LoadError
|
38
|
+
# RSpec 1
|
39
|
+
gem "rspec"
|
40
|
+
require 'spec/rake/spectask'
|
41
|
+
|
42
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
43
|
+
spec.libs << 'lib' << 'spec'
|
44
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
45
|
+
end
|
46
|
+
|
47
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
48
|
+
spec.libs << 'lib' << 'spec'
|
49
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
50
|
+
spec.rcov = true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
task :spec => :check_dependencies
|
55
|
+
|
56
|
+
task :default => :spec
|
57
|
+
|
58
|
+
require 'rake/rdoctask'
|
59
|
+
Rake::RDocTask.new do |rdoc|
|
60
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
61
|
+
|
62
|
+
rdoc.rdoc_dir = 'rdoc'
|
63
|
+
rdoc.title = "pidgin2adium #{version}"
|
64
|
+
rdoc.rdoc_files.include('README*')
|
65
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
66
|
+
end
|
67
|
+
|
68
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.1
|
@@ -0,0 +1 @@
|
|
1
|
+
|
data/config/website.yml
ADDED
@@ -1,9 +1,9 @@
|
|
1
1
|
/*
|
2
2
|
* Balances tags of string using a modified stack. Returns a balanced string.
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* From Wordpress's formatting.php and rewritten in C by
|
5
5
|
* Gabe Berke-Williams, 2010.
|
6
|
-
*
|
6
|
+
*
|
7
7
|
* Original Author:: Leonard Lin <leonard@acm.org>
|
8
8
|
* License:: GPL v2.0
|
9
9
|
* Copyright:: November 4, 2001
|
@@ -52,7 +52,7 @@ VALUE balance_tags_c(VALUE mod, VALUE text){
|
|
52
52
|
rb_str_new2("font"));
|
53
53
|
// 1: tagname, with possible leading "/"
|
54
54
|
// 2: attributes
|
55
|
-
VALUE tag_regex =
|
55
|
+
VALUE tag_regex = rb_eval_string("/<(\\/?\\w*)\\s*([^>]*)>/");
|
56
56
|
VALUE pos; // position in text
|
57
57
|
VALUE match;
|
58
58
|
VALUE tag;
|
@@ -68,8 +68,8 @@ VALUE balance_tags_c(VALUE mod, VALUE text){
|
|
68
68
|
rb_str_new2("< !--"));
|
69
69
|
|
70
70
|
// WP bug fix for LOVE <3 (and other situations with '<' before a number)
|
71
|
-
rb_funcall(text,
|
72
|
-
|
71
|
+
rb_funcall(text,rb_intern("gsub!"), 2,
|
72
|
+
rb_eval_string("/<([0-9]{1})/"),
|
73
73
|
rb_str_new2("<\\1"));
|
74
74
|
|
75
75
|
pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
|
@@ -96,7 +96,7 @@ VALUE balance_tags_c(VALUE mod, VALUE text){
|
|
96
96
|
// if stacktop value == tag close value then pop
|
97
97
|
// Close Tag
|
98
98
|
tag = rb_str_append(rb_str_new2("</"), tag);
|
99
|
-
rb_str_concat(tag, rb_str_new2(">"));
|
99
|
+
rb_str_concat(tag, rb_str_new2(">"));
|
100
100
|
// Pop
|
101
101
|
rb_ary_pop(tagstack);
|
102
102
|
stacksize--;
|
@@ -137,7 +137,7 @@ VALUE balance_tags_c(VALUE mod, VALUE text){
|
|
137
137
|
tagqueue = rb_str_new2("</");
|
138
138
|
rb_str_concat(tagqueue, rb_ary_pop(tagstack));
|
139
139
|
rb_str_concat(tagqueue, rb_str_new2(">"));
|
140
|
-
stacksize--;
|
140
|
+
stacksize--;
|
141
141
|
}
|
142
142
|
rb_ary_push(tagstack, tag);
|
143
143
|
stacksize++;
|
data/lib/pidgin2adium.rb
CHANGED
@@ -9,125 +9,125 @@ require 'fileutils'
|
|
9
9
|
require 'pidgin2adium/log_parser'
|
10
10
|
|
11
11
|
module Pidgin2Adium
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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 = "3.0.1"
|
18
|
+
# For displaying after we finish converting
|
19
|
+
@@oops_messages = []
|
20
|
+
@@error_messages = []
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
def log_msg(str) #:nodoc:
|
23
|
+
puts str.to_s
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def oops(str) #:nodoc:
|
27
|
+
@@oops_messages << str
|
28
|
+
warn("Oops: #{str}")
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
def error(str) #:nodoc:
|
32
|
+
@@error_messages << str
|
33
|
+
warn("Error: #{str}")
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
#######################
|
37
|
+
#So that we can use log_msg when calling delete_search_indexes() by itself
|
38
|
+
module_function :log_msg, :oops, :error
|
39
|
+
#######################
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
# Parses the provided log.
|
42
|
+
# Returns a LogFile instance or false if an error occurred.
|
43
|
+
def parse(logfile_path, my_aliases)
|
44
|
+
logfile_path = File.expand_path(logfile_path)
|
45
|
+
ext = File.extname(logfile_path).sub('.', '').downcase
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
if(ext == "html" || ext == "htm")
|
48
|
+
parser = HtmlLogParser.new(logfile_path, my_aliases)
|
49
|
+
elsif(ext == "txt")
|
50
|
+
parser = TextLogParser.new(logfile_path, my_aliases)
|
51
|
+
else
|
52
|
+
error("Doing nothing, logfile is not a text or html file. Path: #{logfile_path}.")
|
53
|
+
return false
|
54
|
+
end
|
55
|
+
|
56
|
+
return parser.parse()
|
57
|
+
end
|
58
|
+
|
59
|
+
# Parses the provided log and writes out the log in Adium format.
|
60
|
+
# Returns the path to the converted log, false if an error occurred, or
|
61
|
+
# Pidgin2Adium::FILE_EXISTS if file already exists AND opts[:overwrite] =
|
62
|
+
# false.
|
63
|
+
#
|
64
|
+
# You can add options using the _opts_ hash, which can have the following
|
65
|
+
# keys, all of which are optional:
|
66
|
+
# * *overwrite*: If true, then overwrite even if log is found.
|
67
|
+
# Defaults to false.
|
68
|
+
# * *output_dir*: The top-level dir to put the logs in.
|
69
|
+
# Logs under output_dir are still each in their own folders, etc.
|
70
|
+
# Defaults to Pidgin2Adium::ADIUM_LOG_DIR
|
71
|
+
def parse_and_generate(logfile_path, my_aliases, opts = {})
|
72
|
+
opts = {} unless opts.is_a?(Hash)
|
73
|
+
overwrite = !!opts[:overwrite]
|
74
|
+
if opts.key?(:output_dir)
|
75
|
+
output_dir = opts[:output_dir]
|
76
|
+
else
|
77
|
+
output_dir = ADIUM_LOG_DIR
|
78
|
+
end
|
55
79
|
|
56
|
-
|
80
|
+
unless File.directory?(output_dir)
|
81
|
+
puts "Output log directory (#{output_dir}) does not exist or is not a directory."
|
82
|
+
begin
|
83
|
+
FileUtils.mkdir_p(output_dir)
|
84
|
+
rescue Errno::EACCES
|
85
|
+
puts "Permission denied, could not create output directory (#{output_dir})"
|
86
|
+
return false
|
87
|
+
end
|
57
88
|
end
|
58
|
-
|
59
|
-
# Parses the provided log and writes out the log in Adium format.
|
60
|
-
# Returns the path to the converted log, false if an error occurred, or
|
61
|
-
# Pidgin2Adium::FILE_EXISTS if file already exists AND opts[:overwrite] =
|
62
|
-
# false.
|
63
|
-
#
|
64
|
-
# You can add options using the _opts_ hash, which can have the following
|
65
|
-
# keys, all of which are optional:
|
66
|
-
# * *overwrite*: If true, then overwrite even if log is found.
|
67
|
-
# Defaults to false.
|
68
|
-
# * *output_dir*: The top-level dir to put the logs in.
|
69
|
-
# Logs under output_dir are still each in their own folders, etc.
|
70
|
-
# Defaults to Pidgin2Adium::ADIUM_LOG_DIR
|
71
|
-
def parse_and_generate(logfile_path, my_aliases, opts = {})
|
72
|
-
opts = {} unless opts.is_a?(Hash)
|
73
|
-
overwrite = !!opts[:overwrite]
|
74
|
-
if opts.key?(:output_dir)
|
75
|
-
output_dir = opts[:output_dir]
|
76
|
-
else
|
77
|
-
output_dir = ADIUM_LOG_DIR
|
78
|
-
end
|
79
|
-
|
80
|
-
unless File.directory?(output_dir)
|
81
|
-
puts "Output log directory (#{output_dir}) does not exist or is not a directory."
|
82
|
-
begin
|
83
|
-
FileUtils.mkdir_p(output_dir)
|
84
|
-
rescue Errno::EACCES
|
85
|
-
puts "Permission denied, could not create output directory (#{output_dir})"
|
86
|
-
return false
|
87
|
-
end
|
88
|
-
end
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
90
|
+
logfile_obj = parse(logfile_path, my_aliases)
|
91
|
+
return false if logfile_obj == false
|
92
|
+
dest_file_path = logfile_obj.write_out(overwrite, output_dir)
|
93
|
+
if dest_file_path == false
|
94
|
+
error("Successfully parsed file, but failed to write it out. Path: #{logfile_path}.")
|
95
|
+
return false
|
96
|
+
elsif dest_file_path == FILE_EXISTS
|
97
|
+
log_msg("File already exists.")
|
98
|
+
return FILE_EXISTS
|
99
|
+
else
|
100
|
+
log_msg("Output to: #{dest_file_path}")
|
101
|
+
return true
|
103
102
|
end
|
103
|
+
end
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
log_msg "...done."
|
129
|
-
log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while."
|
105
|
+
# Newly-converted logs are viewable in the Adium Chat Transcript
|
106
|
+
# Viewer, but are not indexed, so a search of the logs doesn't give
|
107
|
+
# results from the converted logs. To fix this, we delete the cached log
|
108
|
+
# indexes, which forces Adium to re-index.
|
109
|
+
#
|
110
|
+
# Note: This function is run by LogConverter after converting all of its
|
111
|
+
# files. LogFile.write_out intentionally does _not_ run it in order to
|
112
|
+
# allow for batch-processing of files. Thus, you will probably want to run
|
113
|
+
# Pidgin2Adium.delete_search_indexes after running LogFile.write_out in
|
114
|
+
# your own scripts.
|
115
|
+
def delete_search_indexes()
|
116
|
+
log_msg "Deleting log search indexes in order to force re-indexing of imported logs..."
|
117
|
+
dirty_file = File.expand_path("~/Library/Caches/Adium/Default/DirtyLogs.plist")
|
118
|
+
log_index_file = File.expand_path("~/Library/Caches/Adium/Default/Logs.index")
|
119
|
+
[dirty_file, log_index_file].each do |f|
|
120
|
+
if File.exist?(f)
|
121
|
+
if File.writable?(f)
|
122
|
+
File.delete(f)
|
123
|
+
else
|
124
|
+
error("File exists but is not writable. Please delete it yourself: #{f}")
|
125
|
+
end
|
126
|
+
end
|
130
127
|
end
|
128
|
+
log_msg "...done."
|
129
|
+
log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while."
|
130
|
+
end
|
131
131
|
|
132
|
-
|
132
|
+
module_function :parse, :parse_and_generate, :delete_search_indexes
|
133
133
|
end
|