sisu 7.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.
- checksums.yaml +7 -0
- data/bin/sisu +367 -0
- data/bin/sisugem +367 -0
- data/data/sisu/image/arrow_next_red.png +0 -0
- data/data/sisu/image/arrow_prev_red.png +0 -0
- data/data/sisu/image/arrow_up_red.png +0 -0
- data/data/sisu/image/b_bluebell.png +0 -0
- data/data/sisu/image/b_doc.png +0 -0
- data/data/sisu/image/b_epub.png +0 -0
- data/data/sisu/image/b_home.png +0 -0
- data/data/sisu/image/b_info.png +0 -0
- data/data/sisu/image/b_odf.png +0 -0
- data/data/sisu/image/b_pdf.png +0 -0
- data/data/sisu/image/b_search.png +0 -0
- data/data/sisu/image/b_toc.png +0 -0
- data/data/sisu/image/bullet_08.png +0 -0
- data/data/sisu/image/bullet_09.png +0 -0
- data/data/sisu/image/bullet_10.png +0 -0
- data/data/sisu/image/bullet_11.png +0 -0
- data/data/sisu/image/bullet_12.png +0 -0
- data/data/sisu/image/bullet_doc.png +0 -0
- data/data/sisu/image/bullet_red.png +0 -0
- data/data/sisu/image/dot_clear.png +0 -0
- data/data/sisu/image/dot_white.png +0 -0
- data/data/sisu/image/gplv3.png +0 -0
- data/data/sisu/image/gplv3_free_software.png +0 -0
- data/data/sisu/image/next.png +0 -0
- data/data/sisu/image/previous.png +0 -0
- data/data/sisu/image/rb7.ico +0 -0
- data/data/sisu/image/sisu.png +0 -0
- data/data/sisu/image/toctoc.png +0 -0
- data/data/sisu/version.yml +5 -0
- data/lib/sisu.rb +94 -0
- data/lib/sisu/air.rb +80 -0
- data/lib/sisu/ao.rb +590 -0
- data/lib/sisu/ao_character_check.rb +102 -0
- data/lib/sisu/ao_composite.rb +286 -0
- data/lib/sisu/ao_doc_objects.rb +565 -0
- data/lib/sisu/ao_doc_str.rb +2269 -0
- data/lib/sisu/ao_endnotes.rb +136 -0
- data/lib/sisu/ao_expand_insertions.rb +514 -0
- data/lib/sisu/ao_hash_digest.rb +174 -0
- data/lib/sisu/ao_idx.rb +422 -0
- data/lib/sisu/ao_images.rb +187 -0
- data/lib/sisu/ao_metadata.rb +86 -0
- data/lib/sisu/ao_misc_arrange.rb +207 -0
- data/lib/sisu/ao_numbering.rb +720 -0
- data/lib/sisu/ao_persist.rb +194 -0
- data/lib/sisu/ao_references.rb +502 -0
- data/lib/sisu/ao_syntax.rb +640 -0
- data/lib/sisu/cgi.rb +84 -0
- data/lib/sisu/cgi_pgsql.rb +270 -0
- data/lib/sisu/cgi_sql_common.rb +986 -0
- data/lib/sisu/cgi_sqlite.rb +244 -0
- data/lib/sisu/conf.rb +287 -0
- data/lib/sisu/constants.rb +388 -0
- data/lib/sisu/css.rb +3484 -0
- data/lib/sisu/db_columns.rb +1997 -0
- data/lib/sisu/db_create.rb +689 -0
- data/lib/sisu/db_dbi.rb +90 -0
- data/lib/sisu/db_drop.rb +207 -0
- data/lib/sisu/db_import.rb +877 -0
- data/lib/sisu/db_indexes.rb +146 -0
- data/lib/sisu/db_load_tuple.rb +323 -0
- data/lib/sisu/db_remove.rb +182 -0
- data/lib/sisu/db_select.rb +230 -0
- data/lib/sisu/db_sqltxt.rb +173 -0
- data/lib/sisu/db_tests.rb +114 -0
- data/lib/sisu/dbi.rb +166 -0
- data/lib/sisu/dbi_discrete.rb +206 -0
- data/lib/sisu/digests.rb +306 -0
- data/lib/sisu/dp.rb +1606 -0
- data/lib/sisu/dp_identify_markup.rb +161 -0
- data/lib/sisu/dp_make.rb +668 -0
- data/lib/sisu/embedded.rb +149 -0
- data/lib/sisu/errors.rb +84 -0
- data/lib/sisu/generic_parts.rb +131 -0
- data/lib/sisu/git.rb +277 -0
- data/lib/sisu/html.rb +775 -0
- data/lib/sisu/html_concordance.rb +391 -0
- data/lib/sisu/html_format.rb +1348 -0
- data/lib/sisu/html_harvest.rb +109 -0
- data/lib/sisu/html_harvest_author_format.rb +111 -0
- data/lib/sisu/html_harvest_authors.rb +466 -0
- data/lib/sisu/html_harvest_topics.rb +893 -0
- data/lib/sisu/html_lite_shared.rb +324 -0
- data/lib/sisu/html_manifest.rb +1032 -0
- data/lib/sisu/html_minitoc.rb +230 -0
- data/lib/sisu/html_parts.rb +437 -0
- data/lib/sisu/html_persist.rb +237 -0
- data/lib/sisu/html_promo.rb +440 -0
- data/lib/sisu/html_scroll.rb +235 -0
- data/lib/sisu/html_segments.rb +716 -0
- data/lib/sisu/html_shared.rb +62 -0
- data/lib/sisu/html_table.rb +64 -0
- data/lib/sisu/html_tune.rb +301 -0
- data/lib/sisu/hub.rb +277 -0
- data/lib/sisu/hub_actions.rb +1122 -0
- data/lib/sisu/hub_loop_markup_files.rb +170 -0
- data/lib/sisu/hub_options.rb +1695 -0
- data/lib/sisu/i18n.rb +702 -0
- data/lib/sisu/manpage.rb +377 -0
- data/lib/sisu/manpage_format.rb +85 -0
- data/lib/sisu/object_munge.rb +307 -0
- data/lib/sisu/prog_text_translation.rb +1702 -0
- data/lib/sisu/qrcode.rb +754 -0
- data/lib/sisu/relaxng.rb +1153 -0
- data/lib/sisu/remote.rb +246 -0
- data/lib/sisu/rexml.rb +148 -0
- data/lib/sisu/se.rb +158 -0
- data/lib/sisu/se_cleanoutput.rb +145 -0
- data/lib/sisu/se_clear.rb +105 -0
- data/lib/sisu/se_createsite.rb +273 -0
- data/lib/sisu/se_css.rb +221 -0
- data/lib/sisu/se_date.rb +92 -0
- data/lib/sisu/se_db.rb +214 -0
- data/lib/sisu/se_envcall.rb +326 -0
- data/lib/sisu/se_file_op.rb +2758 -0
- data/lib/sisu/se_filemap.rb +247 -0
- data/lib/sisu/se_get_init.rb +238 -0
- data/lib/sisu/se_hub_particulars.rb +234 -0
- data/lib/sisu/se_info_env.rb +2179 -0
- data/lib/sisu/se_info_port.rb +70 -0
- data/lib/sisu/se_info_system.rb +202 -0
- data/lib/sisu/se_load.rb +108 -0
- data/lib/sisu/se_processing.rb +659 -0
- data/lib/sisu/se_programs.rb +394 -0
- data/lib/sisu/se_remotes.rb +553 -0
- data/lib/sisu/se_standardise_lang.rb +176 -0
- data/lib/sisu/se_version.rb +174 -0
- data/lib/sisu/shared_images.rb +137 -0
- data/lib/sisu/shared_markup_alt.rb +336 -0
- data/lib/sisu/shared_metadata.rb +1361 -0
- data/lib/sisu/shared_sem.rb +156 -0
- data/lib/sisu/sisu_thor_lib.rb +407 -0
- data/lib/sisu/sitemaps.rb +224 -0
- data/lib/sisu/src_kdissert_share.rb +102 -0
- data/lib/sisu/src_po4a_share.rb +309 -0
- data/lib/sisu/src_po4a_shelf.rb +1217 -0
- data/lib/sisu/src_po4a_shelf_set.rb +297 -0
- data/lib/sisu/src_po4a_sst_ao_sst.rb +893 -0
- data/lib/sisu/src_po4a_sst_ao_sst_set.rb +284 -0
- data/lib/sisu/src_po4a_sstm.rb +135 -0
- data/lib/sisu/src_shared.rb +347 -0
- data/lib/sisu/src_sisupod_make.rb +171 -0
- data/lib/sisu/src_sisupod_sstm.rb +109 -0
- data/lib/sisu/sst_convert_markup.rb +323 -0
- data/lib/sisu/sst_do_inline_footnotes.rb +440 -0
- data/lib/sisu/sst_from_xml.rb +178 -0
- data/lib/sisu/sst_identify_markup.rb +482 -0
- data/lib/sisu/sst_to_s_xml_sax.rb +471 -0
- data/lib/sisu/termsheet.rb +163 -0
- data/lib/sisu/texinfo.rb +430 -0
- data/lib/sisu/texinfo_format.rb +541 -0
- data/lib/sisu/texpdf.rb +1162 -0
- data/lib/sisu/texpdf_format.rb +1689 -0
- data/lib/sisu/texpdf_parts.rb +235 -0
- data/lib/sisu/txt_asciidoc.rb +354 -0
- data/lib/sisu/txt_asciidoc_decorate.rb +207 -0
- data/lib/sisu/txt_markdown.rb +389 -0
- data/lib/sisu/txt_markdown_decorate.rb +207 -0
- data/lib/sisu/txt_orgmode.rb +376 -0
- data/lib/sisu/txt_orgmode_decorate.rb +186 -0
- data/lib/sisu/txt_output.rb +86 -0
- data/lib/sisu/txt_plain.rb +410 -0
- data/lib/sisu/txt_plain_decorate.rb +189 -0
- data/lib/sisu/txt_read.rb +109 -0
- data/lib/sisu/txt_rst.rb +371 -0
- data/lib/sisu/txt_rst_decorate.rb +186 -0
- data/lib/sisu/txt_shared.rb +241 -0
- data/lib/sisu/txt_textile.rb +367 -0
- data/lib/sisu/txt_textile_decorate.rb +186 -0
- data/lib/sisu/update.rb +141 -0
- data/lib/sisu/urls.rb +696 -0
- data/lib/sisu/utils.rb +232 -0
- data/lib/sisu/utils_composite.rb +115 -0
- data/lib/sisu/utils_response.rb +114 -0
- data/lib/sisu/utils_screen_text_color.rb +472 -0
- data/lib/sisu/utils_spell.rb +99 -0
- data/lib/sisu/webrick.rb +191 -0
- data/lib/sisu/wikispeak.rb +375 -0
- data/lib/sisu/xhtml.rb +472 -0
- data/lib/sisu/xhtml_epub2.rb +890 -0
- data/lib/sisu/xhtml_epub2_concordance.rb +322 -0
- data/lib/sisu/xhtml_epub2_format.rb +2272 -0
- data/lib/sisu/xhtml_epub2_persist.rb +278 -0
- data/lib/sisu/xhtml_epub2_segments.rb +599 -0
- data/lib/sisu/xhtml_epub2_tune.rb +330 -0
- data/lib/sisu/xhtml_parts.rb +183 -0
- data/lib/sisu/xhtml_shared.rb +62 -0
- data/lib/sisu/xhtml_table.rb +97 -0
- data/lib/sisu/xml_docbook5.rb +376 -0
- data/lib/sisu/xml_dom.rb +624 -0
- data/lib/sisu/xml_fictionbook2.rb +389 -0
- data/lib/sisu/xml_format.rb +865 -0
- data/lib/sisu/xml_md_oai_pmh_dc.rb +229 -0
- data/lib/sisu/xml_odf_odt.rb +887 -0
- data/lib/sisu/xml_odf_odt_format.rb +674 -0
- data/lib/sisu/xml_parts.rb +191 -0
- data/lib/sisu/xml_persist.rb +126 -0
- data/lib/sisu/xml_sax.rb +521 -0
- data/lib/sisu/xml_scaffold_structure_collapsed.rb +198 -0
- data/lib/sisu/xml_scaffold_structure_sisu.rb +201 -0
- data/lib/sisu/xml_shared.rb +665 -0
- data/lib/sisu/xml_tables.rb +261 -0
- data/lib/sisu/zap.rb +90 -0
- metadata +251 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
=begin
|
|
3
|
+
|
|
4
|
+
* Name: SiSU
|
|
5
|
+
|
|
6
|
+
** Description: documents, structuring, processing, publishing, search
|
|
7
|
+
*** modules shared by the different db types, dbi, postgresql, sqlite
|
|
8
|
+
|
|
9
|
+
** Author: Ralph Amissah
|
|
10
|
+
<ralph@amissah.com>
|
|
11
|
+
<ralph.amissah@gmail.com>
|
|
12
|
+
|
|
13
|
+
** Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
|
14
|
+
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Ralph Amissah,
|
|
15
|
+
All Rights Reserved.
|
|
16
|
+
|
|
17
|
+
** License: GPL 3 or later:
|
|
18
|
+
|
|
19
|
+
SiSU, a framework for document structuring, publishing and search
|
|
20
|
+
|
|
21
|
+
Copyright (C) Ralph Amissah
|
|
22
|
+
|
|
23
|
+
This program is free software: you can redistribute it and/or modify it
|
|
24
|
+
under the terms of the GNU General Public License as published by the Free
|
|
25
|
+
Software Foundation, either version 3 of the License, or (at your option)
|
|
26
|
+
any later version.
|
|
27
|
+
|
|
28
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
29
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
31
|
+
more details.
|
|
32
|
+
|
|
33
|
+
You should have received a copy of the GNU General Public License along with
|
|
34
|
+
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
35
|
+
|
|
36
|
+
If you have Internet connection, the latest version of the GPL should be
|
|
37
|
+
available at these locations:
|
|
38
|
+
<http://www.fsf.org/licensing/licenses/gpl.html>
|
|
39
|
+
<http://www.gnu.org/licenses/gpl.html>
|
|
40
|
+
|
|
41
|
+
<http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
|
|
42
|
+
|
|
43
|
+
** SiSU uses:
|
|
44
|
+
* Standard SiSU markup syntax,
|
|
45
|
+
* Standard SiSU meta-markup syntax, and the
|
|
46
|
+
* Standard SiSU object citation numbering and system
|
|
47
|
+
|
|
48
|
+
** Hompages:
|
|
49
|
+
<http://www.jus.uio.no/sisu>
|
|
50
|
+
<http://www.sisudoc.org>
|
|
51
|
+
|
|
52
|
+
** Git
|
|
53
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary>
|
|
54
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=lib/sisu/db_remove.rb;hb=HEAD>
|
|
55
|
+
|
|
56
|
+
=end
|
|
57
|
+
module SiSU_DbRemove
|
|
58
|
+
class Remove
|
|
59
|
+
include SiSU_DbAction
|
|
60
|
+
def initialize(opt,conn,file,sql_type)
|
|
61
|
+
@opt,@conn,@file,@sql_type=opt,conn,file,sql_type
|
|
62
|
+
@md=SiSU_Param::Parameters.new(@opt).get
|
|
63
|
+
@fnb=@md.fnb
|
|
64
|
+
@db=SiSU_Env::InfoDb.new
|
|
65
|
+
end
|
|
66
|
+
def remove
|
|
67
|
+
driver_sqlite3=if @sql_type==:sqlite
|
|
68
|
+
(@conn.inspect.match(/^(.{10})/)[1]==@db.sqlite.conn_sqlite3.inspect.match(/^(.{10})/)[1]) \
|
|
69
|
+
? true
|
|
70
|
+
: false
|
|
71
|
+
end
|
|
72
|
+
del_id=if driver_sqlite3
|
|
73
|
+
begin
|
|
74
|
+
remove_selected=%{
|
|
75
|
+
SELECT tid
|
|
76
|
+
FROM metadata_and_text
|
|
77
|
+
WHERE src_filename = '#{@md.fns}'
|
|
78
|
+
AND metadata_and_text.language_document_char = '#{@opt.lng}'
|
|
79
|
+
;} # note, for .ssm: @md.fns (is set during runtime & is) != @opt.fns @md.opt.fns
|
|
80
|
+
@conn.get_first_value(remove_selected).to_i
|
|
81
|
+
rescue SQLite3::Exception => e
|
|
82
|
+
#not tested
|
|
83
|
+
puts "Exception occurred"
|
|
84
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark(e.inspect)
|
|
85
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
|
|
86
|
+
"\n" \
|
|
87
|
+
+ 'Attempting to initialize db' + "\n" \
|
|
88
|
+
+ 'Creating db tables'
|
|
89
|
+
)
|
|
90
|
+
sdb={
|
|
91
|
+
create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
|
|
92
|
+
index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
|
|
93
|
+
}
|
|
94
|
+
db_action(sdb).create
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
begin
|
|
98
|
+
remove_selected=%{
|
|
99
|
+
SELECT metadata_and_text.tid
|
|
100
|
+
FROM metadata_and_text
|
|
101
|
+
WHERE metadata_and_text.src_filename = '#{@md.fns}'
|
|
102
|
+
AND metadata_and_text.language_document_char = '#{@opt.lng}'
|
|
103
|
+
;} # note, for .ssm: @md.fns (is set during runtime & is) != @opt.fns @md.opt.fns
|
|
104
|
+
x=@conn.exec(remove_selected)
|
|
105
|
+
x.field_values("tid")[0]
|
|
106
|
+
rescue PG::Error => e
|
|
107
|
+
err=[
|
|
108
|
+
e.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
|
|
109
|
+
e.result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
|
|
110
|
+
e.result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
|
|
111
|
+
e.result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
|
|
112
|
+
e.result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
|
|
113
|
+
e.result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
|
|
114
|
+
e.result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
|
|
115
|
+
e.result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
|
|
116
|
+
e.result.error_field( PG::Result::PG_DIAG_CONTEXT ),
|
|
117
|
+
e.result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
|
|
118
|
+
e.result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
|
|
119
|
+
e.result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
|
|
120
|
+
]
|
|
121
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:fuchsia).mark("\n" + err.inspect)
|
|
122
|
+
if err[2] =~/relation "\S+?" does not exist/ \
|
|
123
|
+
or err.inspect =~/relation "\S+?" does not exist/
|
|
124
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
|
|
125
|
+
"\n" \
|
|
126
|
+
+ err[2] + "\n" \
|
|
127
|
+
+ 'Attempting to initialize db' + "\n" \
|
|
128
|
+
+ 'Creating db tables'
|
|
129
|
+
)
|
|
130
|
+
sdb={
|
|
131
|
+
create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
|
|
132
|
+
index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
|
|
133
|
+
}
|
|
134
|
+
db_action(sdb).create
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
if del_id
|
|
139
|
+
sql_entry=[
|
|
140
|
+
"DELETE FROM endnotes WHERE metadata_tid = '#{del_id}';",
|
|
141
|
+
"DELETE FROM endnotes_asterisk WHERE metadata_tid = '#{del_id}';",
|
|
142
|
+
"DELETE FROM endnotes_plus WHERE metadata_tid = '#{del_id}';",
|
|
143
|
+
"DELETE FROM doc_objects WHERE metadata_tid = '#{del_id}';",
|
|
144
|
+
"DELETE FROM urls WHERE metadata_tid = '#{del_id}';",
|
|
145
|
+
"DELETE FROM metadata_and_text WHERE metadata_and_text.tid = '#{del_id}';",
|
|
146
|
+
]
|
|
147
|
+
if driver_sqlite3
|
|
148
|
+
@conn.transaction
|
|
149
|
+
sql_entry.each do |s|
|
|
150
|
+
begin
|
|
151
|
+
@conn.execute(s)
|
|
152
|
+
rescue
|
|
153
|
+
next
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
@conn.commit if driver_sqlite3
|
|
157
|
+
else
|
|
158
|
+
sql_entry.each do |s|
|
|
159
|
+
begin
|
|
160
|
+
@conn.exec_params(s)
|
|
161
|
+
rescue
|
|
162
|
+
next
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
if @opt.act[:maintenance][:set]==:on
|
|
167
|
+
@file.puts sql_entry
|
|
168
|
+
end
|
|
169
|
+
else
|
|
170
|
+
if (@opt.act[:verbose][:set]==:on \
|
|
171
|
+
|| @opt.act[:verbose_plus][:set]==:on \
|
|
172
|
+
|| @opt.act[:maintenance][:set]==:on)
|
|
173
|
+
SiSU_Screen::Ansi.new(
|
|
174
|
+
@opt.selections.str,
|
|
175
|
+
"no such file in database #{@db.psql.db}::#{@opt.fns}"
|
|
176
|
+
).puts_grey
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
__END__
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
=begin
|
|
3
|
+
|
|
4
|
+
* Name: SiSU
|
|
5
|
+
|
|
6
|
+
** Description: documents, structuring, processing, publishing, search
|
|
7
|
+
*** modules shared by the different db types, dbi, postgresql, sqlite
|
|
8
|
+
|
|
9
|
+
** Author: Ralph Amissah
|
|
10
|
+
<ralph@amissah.com>
|
|
11
|
+
<ralph.amissah@gmail.com>
|
|
12
|
+
|
|
13
|
+
** Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
|
14
|
+
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Ralph Amissah,
|
|
15
|
+
All Rights Reserved.
|
|
16
|
+
|
|
17
|
+
** License: GPL 3 or later:
|
|
18
|
+
|
|
19
|
+
SiSU, a framework for document structuring, publishing and search
|
|
20
|
+
|
|
21
|
+
Copyright (C) Ralph Amissah
|
|
22
|
+
|
|
23
|
+
This program is free software: you can redistribute it and/or modify it
|
|
24
|
+
under the terms of the GNU General Public License as published by the Free
|
|
25
|
+
Software Foundation, either version 3 of the License, or (at your option)
|
|
26
|
+
any later version.
|
|
27
|
+
|
|
28
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
29
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
31
|
+
more details.
|
|
32
|
+
|
|
33
|
+
You should have received a copy of the GNU General Public License along with
|
|
34
|
+
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
35
|
+
|
|
36
|
+
If you have Internet connection, the latest version of the GPL should be
|
|
37
|
+
available at these locations:
|
|
38
|
+
<http://www.fsf.org/licensing/licenses/gpl.html>
|
|
39
|
+
<http://www.gnu.org/licenses/gpl.html>
|
|
40
|
+
|
|
41
|
+
<http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
|
|
42
|
+
|
|
43
|
+
** SiSU uses:
|
|
44
|
+
* Standard SiSU markup syntax,
|
|
45
|
+
* Standard SiSU meta-markup syntax, and the
|
|
46
|
+
* Standard SiSU object citation numbering and system
|
|
47
|
+
|
|
48
|
+
** Hompages:
|
|
49
|
+
<http://www.jus.uio.no/sisu>
|
|
50
|
+
<http://www.sisudoc.org>
|
|
51
|
+
|
|
52
|
+
** Git
|
|
53
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary>
|
|
54
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=lib/sisu/db_select.rb;hb=HEAD>
|
|
55
|
+
|
|
56
|
+
=end
|
|
57
|
+
module SiSU_DbAction
|
|
58
|
+
def db_action(sdb)
|
|
59
|
+
@sdb=sdb
|
|
60
|
+
def createdb
|
|
61
|
+
@sdb[:create].output_dir?
|
|
62
|
+
begin
|
|
63
|
+
@sdb[:create].create_db
|
|
64
|
+
rescue
|
|
65
|
+
@sdb[:create].output_dir?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
def drop
|
|
69
|
+
@sdb[:drop].drop.tables
|
|
70
|
+
end
|
|
71
|
+
def create
|
|
72
|
+
@sdb[:create].output_dir?
|
|
73
|
+
begin
|
|
74
|
+
@sdb[:create].create_table.metadata_and_text
|
|
75
|
+
@sdb[:create].create_table.doc_objects
|
|
76
|
+
@sdb[:create].create_table.endnotes
|
|
77
|
+
@sdb[:create].create_table.endnotes_asterisk
|
|
78
|
+
@sdb[:create].create_table.endnotes_plus
|
|
79
|
+
@sdb[:create].create_table.urls
|
|
80
|
+
@sdb[:index].create_indexes
|
|
81
|
+
rescue
|
|
82
|
+
SiSU_Errors::Rescued.new($!,$@,'--sqlite').location
|
|
83
|
+
@sdb[:create].output_dir? do
|
|
84
|
+
__LINE__.to_s + ':' + __FILE__
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
def import
|
|
89
|
+
db_exist?
|
|
90
|
+
@sdb[:import].marshal_load
|
|
91
|
+
tell=case @sql_type
|
|
92
|
+
when :sqlite
|
|
93
|
+
SiSU_Screen::Ansi.new(
|
|
94
|
+
@opt.act[:color_state][:set],
|
|
95
|
+
"sqlite3 #{@db.sqlite.db} database?"
|
|
96
|
+
)
|
|
97
|
+
when :pg
|
|
98
|
+
SiSU_Screen::Ansi.new(
|
|
99
|
+
@opt.act[:color_state][:set],
|
|
100
|
+
"pgaccess or psql #{@db.psql.db} database?"
|
|
101
|
+
)
|
|
102
|
+
else '???'
|
|
103
|
+
end
|
|
104
|
+
tell.puts_grey if @opt.act[:verbose][:set]==:on
|
|
105
|
+
end
|
|
106
|
+
def remove
|
|
107
|
+
db_exist?
|
|
108
|
+
@sdb[:remove_doc].remove
|
|
109
|
+
end
|
|
110
|
+
def update
|
|
111
|
+
remove
|
|
112
|
+
import
|
|
113
|
+
end
|
|
114
|
+
self
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
module SiSU_DbSelect
|
|
118
|
+
class Case
|
|
119
|
+
include SiSU_DbAction
|
|
120
|
+
def initialize(opt,conn='',sql_type=:pg)
|
|
121
|
+
@opt,@conn,@sql_type=opt,conn,sql_type
|
|
122
|
+
@db=SiSU_Env::InfoDb.new
|
|
123
|
+
@file_maint=sql_maintenance_file
|
|
124
|
+
@sdb={
|
|
125
|
+
create: SiSU_DbDBI::Create.new(@opt,@conn,@file_maint,@sql_type),
|
|
126
|
+
index: SiSU_DbDBI::Index.new(@opt,@conn,@file_maint,@sql_type),
|
|
127
|
+
drop: SiSU_DbDBI::Drop.new(@opt,@conn,@db,@sql_type),
|
|
128
|
+
}
|
|
129
|
+
if (@opt.act[:psql_import][:set]==:on \
|
|
130
|
+
|| @opt.act[:psql_update][:set]==:on) \
|
|
131
|
+
or (@opt.act[:sqlite_import][:set]==:on \
|
|
132
|
+
|| @opt.act[:sqlite_update][:set]==:on)
|
|
133
|
+
@sdb[:import]=SiSU_DbDBI::Import.new(@opt,@conn,@file_maint,@sql_type)
|
|
134
|
+
@sdb[:remove_doc]=SiSU_DbDBI::Remove.new(@opt,@conn,@file_maint,@sql_type)
|
|
135
|
+
elsif (@opt.act[:psql_remove][:set]==:on \
|
|
136
|
+
or @opt.act[:sqlite_remove][:set]==:on)
|
|
137
|
+
@sdb[:remove_doc]=SiSU_DbDBI::Remove.new(@opt,@conn,@file_maint,@sql_type)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
def db_exist?
|
|
141
|
+
if @sql_type==:sqlite \
|
|
142
|
+
and (not (FileTest.file?(@db.sqlite.db)) \
|
|
143
|
+
or FileTest.zero?(@db.sqlite.db))
|
|
144
|
+
puts %{no connection with sqlite database established, you may need to run:\n} \
|
|
145
|
+
+ %{ sisu --sqlite --createall\n} \
|
|
146
|
+
+ %{ before attempting to populate the database}
|
|
147
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
|
|
148
|
+
"\n" \
|
|
149
|
+
+ 'Attempting to initialize db' + "\n" \
|
|
150
|
+
+ 'Creating db tables'
|
|
151
|
+
)
|
|
152
|
+
db_action(@sdb).create
|
|
153
|
+
end
|
|
154
|
+
if @conn.is_a?(NilClass)
|
|
155
|
+
if @sql_type==:sqlite
|
|
156
|
+
puts %{no connection with sqlite database established, you may need to run:\n} \
|
|
157
|
+
+ %{ sisu --sqlite --createall\n} \
|
|
158
|
+
+ %{ before attempting to populate the database}
|
|
159
|
+
SiSU_Utils::CodeMarker.new(__LINE__,__FILE__,:yellow).mark(
|
|
160
|
+
"\n" \
|
|
161
|
+
+ 'Attempting to initialize db' + "\n" \
|
|
162
|
+
+ 'Creating db tables'
|
|
163
|
+
)
|
|
164
|
+
db_action(@sdb).create
|
|
165
|
+
@db.sqlite.db
|
|
166
|
+
else
|
|
167
|
+
puts %{no connection with pg database established, you may need to run:\n} \
|
|
168
|
+
+ %{ createdb "#{@db.psql.db}"\n} \
|
|
169
|
+
+ %{ after that don't forget to run:\n} \
|
|
170
|
+
+ %{ sisu --pg --createall\n} \
|
|
171
|
+
+ %{ before attempting to populate the database}
|
|
172
|
+
@db.psql.db
|
|
173
|
+
end
|
|
174
|
+
exit
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
def sql_maintenance_file
|
|
178
|
+
file=if @opt.act[:maintenance][:set]==:on
|
|
179
|
+
if @opt.fns and not @opt.fns.empty?
|
|
180
|
+
@env=SiSU_Env::InfoEnv.new(@opt.fns) if @opt.fns
|
|
181
|
+
if @sql_type ==:sqlite
|
|
182
|
+
puts "\n#{@env.processing_path.sqlite}/#{@opt.fns}.sql"
|
|
183
|
+
end
|
|
184
|
+
@db=SiSU_Env::InfoDb.new
|
|
185
|
+
@job="sqlite3 #{@db.sqlite.db} < #{@env.processing_path.sqlite}/#{@opt.fns}.sql"
|
|
186
|
+
if @sql_type ==:sqlite
|
|
187
|
+
File.new("#{@env.processing_path.sqlite}/#{@opt.fns}.sql",'w+')
|
|
188
|
+
else
|
|
189
|
+
File.new("#{@env.processing_path.postgresql}/#{@opt.fns}.sql",'w+')
|
|
190
|
+
end
|
|
191
|
+
elsif @opt.fns \
|
|
192
|
+
and (@opt.act[:sqlite_create][:set] ==:on \
|
|
193
|
+
|| @opt.act[:psql_create][:set] ==:on)
|
|
194
|
+
nil #sort variations later
|
|
195
|
+
else nil
|
|
196
|
+
end
|
|
197
|
+
else nil
|
|
198
|
+
end
|
|
199
|
+
file
|
|
200
|
+
end
|
|
201
|
+
def cases
|
|
202
|
+
if @opt.act[:psql_drop][:set] ==:on \
|
|
203
|
+
or @opt.act[:sqlite_drop][:set] ==:on
|
|
204
|
+
db_action(@sdb).drop
|
|
205
|
+
end
|
|
206
|
+
if @opt.act[:psql_createdb][:set] ==:on \
|
|
207
|
+
or @opt.act[:sqlite_createdb][:set] ==:on
|
|
208
|
+
db_action(@sdb).createdb
|
|
209
|
+
end
|
|
210
|
+
if @opt.act[:psql_create][:set] ==:on \
|
|
211
|
+
or @opt.act[:sqlite_create][:set] ==:on
|
|
212
|
+
db_action(@sdb).create
|
|
213
|
+
end
|
|
214
|
+
if @opt.act[:psql_update][:set] ==:on \
|
|
215
|
+
or @opt.act[:sqlite_update][:set] ==:on
|
|
216
|
+
db_action(@sdb).update
|
|
217
|
+
else
|
|
218
|
+
if @opt.act[:psql_remove][:set] ==:on \
|
|
219
|
+
or @opt.act[:sqlite_remove][:set] ==:on
|
|
220
|
+
db_action(@sdb).remove
|
|
221
|
+
end
|
|
222
|
+
if @opt.act[:psql_import][:set] ==:on \
|
|
223
|
+
or @opt.act[:sqlite_import][:set] ==:on
|
|
224
|
+
db_action(@sdb).import
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
__END__
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
=begin
|
|
3
|
+
|
|
4
|
+
* Name: SiSU
|
|
5
|
+
|
|
6
|
+
** Description: documents, structuring, processing, publishing, search
|
|
7
|
+
*** system environment, resource control and configuration details
|
|
8
|
+
|
|
9
|
+
** Author: Ralph Amissah
|
|
10
|
+
<ralph@amissah.com>
|
|
11
|
+
<ralph.amissah@gmail.com>
|
|
12
|
+
|
|
13
|
+
** Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
|
14
|
+
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Ralph Amissah,
|
|
15
|
+
All Rights Reserved.
|
|
16
|
+
|
|
17
|
+
** License: GPL 3 or later:
|
|
18
|
+
|
|
19
|
+
SiSU, a framework for document structuring, publishing and search
|
|
20
|
+
|
|
21
|
+
Copyright (C) Ralph Amissah
|
|
22
|
+
|
|
23
|
+
This program is free software: you can redistribute it and/or modify it
|
|
24
|
+
under the terms of the GNU General Public License as published by the Free
|
|
25
|
+
Software Foundation, either version 3 of the License, or (at your option)
|
|
26
|
+
any later version.
|
|
27
|
+
|
|
28
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
29
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
31
|
+
more details.
|
|
32
|
+
|
|
33
|
+
You should have received a copy of the GNU General Public License along with
|
|
34
|
+
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
35
|
+
|
|
36
|
+
If you have Internet connection, the latest version of the GPL should be
|
|
37
|
+
available at these locations:
|
|
38
|
+
<http://www.fsf.org/licensing/licenses/gpl.html>
|
|
39
|
+
<http://www.gnu.org/licenses/gpl.html>
|
|
40
|
+
|
|
41
|
+
<http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>
|
|
42
|
+
|
|
43
|
+
** SiSU uses:
|
|
44
|
+
* Standard SiSU markup syntax,
|
|
45
|
+
* Standard SiSU meta-markup syntax, and the
|
|
46
|
+
* Standard SiSU object citation numbering and system
|
|
47
|
+
|
|
48
|
+
** Hompages:
|
|
49
|
+
<http://www.jus.uio.no/sisu>
|
|
50
|
+
<http://www.sisudoc.org>
|
|
51
|
+
|
|
52
|
+
** Git
|
|
53
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary>
|
|
54
|
+
<http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=lib/sisu/db_sqltxt.rb;hb=HEAD>
|
|
55
|
+
|
|
56
|
+
=end
|
|
57
|
+
module SiSU_DbText
|
|
58
|
+
class Prepare
|
|
59
|
+
def special_character_escape(str)
|
|
60
|
+
str=str.gsub(/'/m,"''"). #string.gsub!(/'/,"\047") #string.gsub!(/'/,"\\'")
|
|
61
|
+
gsub(/(\\)/m,'\1\1'). #ok but with warnings, double backslash on sqlite #str.gsub!(/[\\]/m,'\\x5C') #ok but with warnings, but not for sqlite #str.gsub!(/(\\)/m,'\1') #ok for sqlite not for pgsql
|
|
62
|
+
gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/m,"<br>\n").
|
|
63
|
+
gsub(/#{Mx[:tag_o]}\S+?#{Mx[:tag_c]}/m,''). #check
|
|
64
|
+
gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg))(?:\s+\d+x\d+)?(.+?)#{Mx[:lnk_c]}\S+/m,'[image: \1] \2').
|
|
65
|
+
gsub(/#{Mx[:lnk_o]}\s*(.+?)\s*#{Mx[:lnk_c]}(?:file|ftp):\/\/\S+?([.,!?]?(?:\s|$))/m,'\1\2').
|
|
66
|
+
gsub(/#{Mx[:lnk_o]}\s*(.+?)\s*#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/m,'\1')
|
|
67
|
+
end
|
|
68
|
+
def clean_searchable_text_from_document_objects(arr)
|
|
69
|
+
en=[]
|
|
70
|
+
arr=(arr.is_a?(String)) ? [ arr ] : arr
|
|
71
|
+
txt_arr=arr.each.map do |s|
|
|
72
|
+
s=s.gsub(/#{Mx[:fa_o]}[a-z]{1,4}#{Mx[:fa_o_c]}/m,'').
|
|
73
|
+
gsub(/#{Mx[:fa_c_o]}[a-z]{1,4}#{Mx[:fa_c]}/m,'').
|
|
74
|
+
gsub(/<br>/m,' ')
|
|
75
|
+
en << s.scan(/#{Mx[:en_a_o]}\s*(.+?)\s*#{Mx[:en_a_c]}/m)
|
|
76
|
+
s=s.gsub(/#{Mx[:en_a_o]}.+?#{Mx[:en_a_c]}/m,'').
|
|
77
|
+
gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/m,'').
|
|
78
|
+
gsub(/ \s+/m,' ')
|
|
79
|
+
#p s if s =~/[^ \nA-Za-z0-9'"`?!#@$%^&*=+,.;:\[\]()<>{}‹›|\\\/~_-]/
|
|
80
|
+
s
|
|
81
|
+
end
|
|
82
|
+
txt_arr=txt_arr << en
|
|
83
|
+
txt=txt_arr.flatten.join("\n")
|
|
84
|
+
special_character_escape(txt)
|
|
85
|
+
end
|
|
86
|
+
def clean_document_objects_body(arr)
|
|
87
|
+
en=[]
|
|
88
|
+
arr=(arr.is_a?(String)) ? [ arr ] : arr
|
|
89
|
+
txt_arr=arr.each.map do |s|
|
|
90
|
+
en << s.scan(/#{Mx[:en_a_o]}\s*(.+?)\s*#{Mx[:en_a_c]}/m)
|
|
91
|
+
s=s.
|
|
92
|
+
gsub(/#{Mx[:en_a_o]}\s*(\d+).+?#{Mx[:en_a_c]}/m,
|
|
93
|
+
'<sup>\1</sup>').
|
|
94
|
+
gsub(/#{Mx[:en_b_o]}.+?#{Mx[:en_b_c]}/m,'').
|
|
95
|
+
gsub(/ \s+/m,' ')
|
|
96
|
+
s
|
|
97
|
+
end
|
|
98
|
+
en_arr=en.flatten.each.map do |e|
|
|
99
|
+
e.sub(/^(\d+)\s*/,'<sup>\1</sup> ')
|
|
100
|
+
end
|
|
101
|
+
txt_arr=txt_arr << en_arr
|
|
102
|
+
txt=txt_arr.flatten.join("\n<br>")
|
|
103
|
+
special_character_escape(txt)
|
|
104
|
+
end
|
|
105
|
+
def clean_searchable_text_from_document_source(arr)
|
|
106
|
+
txt_arr,en=[],[]
|
|
107
|
+
arr=(arr.is_a?(String)) ? arr.split(/\n+/m) : arr
|
|
108
|
+
arr.each do |s|
|
|
109
|
+
s=s.gsub(/([*\/_-])\{(.+?)\}\1/m,'\2').
|
|
110
|
+
gsub(/^(?:block|group|poem|code)\{/m,'').
|
|
111
|
+
gsub(/^\}(?:block|group|poem|code)/m,'').
|
|
112
|
+
gsub(/\A(?:@\S+:\s+.+)\Z/m,'')
|
|
113
|
+
if s =~/^:A~/
|
|
114
|
+
if defined? @md.creator \
|
|
115
|
+
and defined? @md.creator.author \
|
|
116
|
+
and not @md.creator.author.empty?
|
|
117
|
+
s=s.gsub(/@author/,@md.creator.author)
|
|
118
|
+
else
|
|
119
|
+
SiSU_Screen::Ansi.new(
|
|
120
|
+
'v',
|
|
121
|
+
'WARNING Document Author information missing; provide @creator: :author:',
|
|
122
|
+
@md.fnb
|
|
123
|
+
).warn unless @md.opt.act[:quiet][:set]==:on
|
|
124
|
+
end
|
|
125
|
+
if defined? @md.title \
|
|
126
|
+
and defined? @md.title.full \
|
|
127
|
+
and not @md.title.full.empty?
|
|
128
|
+
s=s.gsub(/@title/,@md.title.full)
|
|
129
|
+
else
|
|
130
|
+
SiSU_Screen::Ansi.new(
|
|
131
|
+
'v',
|
|
132
|
+
'WARNING Document Title missing; provide @title:',
|
|
133
|
+
@md.fnb
|
|
134
|
+
).warn unless @md.opt.act[:quiet][:set]==:on
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
s=s.gsub(/^(?:_[1-9]\*?|_\*)\s+/m,'').
|
|
138
|
+
gsub(/^(?:[1-9]\~(\S+)?)\s+/m,'').
|
|
139
|
+
gsub(/^(?::?[A-C]\~(\S+)?)\s+/m,'').
|
|
140
|
+
gsub(/^%{1,3} .+/m,''). #removed even if contained in code block
|
|
141
|
+
gsub(/<br>/m,' ')
|
|
142
|
+
#en << s.scan(/~\{\s*(.+?)\s*\}~/m)
|
|
143
|
+
s=s.gsub(/~\{.+?\}~/m,'').
|
|
144
|
+
gsub(/ \s+/m,' ')
|
|
145
|
+
##special_character_escape(s)
|
|
146
|
+
#p s if s =~/[^ \nA-Za-z0-9'"`?!#@$%^&*=+,.;:\[\]()<>{}‹›|\\\/~_-]/
|
|
147
|
+
s
|
|
148
|
+
end
|
|
149
|
+
txt_arr << arr << en
|
|
150
|
+
txt=txt_arr.flatten.join("\n")
|
|
151
|
+
txt=special_character_escape(txt)
|
|
152
|
+
txt
|
|
153
|
+
end
|
|
154
|
+
def strip_markup(str) #define rules, make same as in dal clean
|
|
155
|
+
str=str.gsub(/#{Mx[:fa_superscript_o]}(\d+)#{Mx[:fa_superscript_c]}/,'[\1]').
|
|
156
|
+
gsub(/(?: \\;|#{Mx[:nbsp]})+/,' ').
|
|
157
|
+
gsub(/#{Mx[:tc_o]}#{Mx[:tc_p]}#{Mx[:tc_p]}\d+(.+)#{Mx[:tc_c]}/u,'\1'). #tables
|
|
158
|
+
gsub(/#{Mx[:tc_p]}#{Mx[:tc_p]}\d+#{Mx[:tc_p]}/u,' '). #tables
|
|
159
|
+
gsub(/#{Mx[:tc_p]}/u,' '). #tables tidy later
|
|
160
|
+
gsub(/<.+?>/,'').
|
|
161
|
+
gsub(/#{Mx[:lnk_o]}.+?\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}(?:file|ftp)\/\/:\S+ /,' [image] '). # else image names found in search
|
|
162
|
+
gsub(/#{Mx[:lnk_o]}.+?\.(?:png|jpg|gif).+?#{Mx[:lnk_c]}#{Mx[:url_o]}\S+?#{Mx[:url_c]}/,' [image]'). # else image names found in search
|
|
163
|
+
gsub(/\s\s+/,' ').
|
|
164
|
+
strip
|
|
165
|
+
end
|
|
166
|
+
def unique_words(str)
|
|
167
|
+
a=str.scan(/[a-zA-Z0-9\\\/_-]{2,}/) #a=str.scan(/\S+{2,}/)
|
|
168
|
+
str=a.uniq.sort.join(' ')
|
|
169
|
+
str
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
__END__
|