gjman 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/HISTORY.txt +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +65 -0
- data/Rakefile +83 -0
- data/VERSION +1 -0
- data/gjman.gemspec +116 -0
- data/lib/ext/multivalent/Multivalent20060102.jar +0 -0
- data/lib/ext/pdfc/CCLib.jar +0 -0
- data/lib/ext/pdfc/CREDIT +2 -0
- data/lib/ext/pdfc/PDFC.bat +1 -0
- data/lib/ext/pdfc/PDFC.jar +0 -0
- data/lib/ext/pdfc/PDFC.sh +3 -0
- data/lib/ext/pdfc/PDFParser.jar +0 -0
- data/lib/ext/pdfc/config.xml +24 -0
- data/lib/ext/pdfc/license/LICENSE.log4j +48 -0
- data/lib/ext/pdfc/license/lgpl-3.0.txt +165 -0
- data/lib/ext/pdfc/license/overview.txt +9 -0
- data/lib/ext/pdfc/log4j-1.2.15.jar +0 -0
- data/lib/ext/pdfc/readme.txt +89 -0
- data/lib/gjman.rb +29 -0
- data/lib/gjman/file_system.rb +46 -0
- data/lib/gjman/java_hacks/ForbidSystemExit$1.class +0 -0
- data/lib/gjman/java_hacks/ForbidSystemExit$Exception.class +0 -0
- data/lib/gjman/java_hacks/ForbidSystemExit.class +0 -0
- data/lib/gjman/java_hacks/ForbidSystemExit.java +23 -0
- data/lib/gjman/jruby.rb +34 -0
- data/lib/gjman/pdf.rb +30 -0
- data/lib/gjman/pdf/base.rb +31 -0
- data/lib/gjman/pdf/compressor.rb +50 -0
- data/lib/gjman/pdf/matcher.rb +28 -0
- data/lib/gjman/pdf/merger.rb +25 -0
- data/lib/gjman/pdf/utils.rb +2 -0
- data/lib/gjman/pdf/utils/multivalent.rb +58 -0
- data/lib/gjman/pdf/utils/pdfc.rb +52 -0
- data/lib/gjman/rjb.rb +32 -0
- data/spec/generic/file_system_spec.rb +100 -0
- data/spec/generic/spec_helper.rb +2 -0
- data/spec/pdf/compressor_spec.rb +114 -0
- data/spec/pdf/data/compressed.pdf +0 -0
- data/spec/pdf/data/merged_pages.pdf +0 -0
- data/spec/pdf/data/page1.pdf +0 -0
- data/spec/pdf/data/page2.pdf +0 -0
- data/spec/pdf/data/page3.pdf +0 -0
- data/spec/pdf/data/picture_x1.pdf +0 -0
- data/spec/pdf/data/picture_x2.pdf +0 -0
- data/spec/pdf/data/picture_x3_diff_pos.pdf +0 -0
- data/spec/pdf/data/picture_x4_diff_size.pdf +0 -0
- data/spec/pdf/data/picture_y1.pdf +0 -0
- data/spec/pdf/data/text_x1.pdf +0 -0
- data/spec/pdf/data/text_x2.pdf +0 -0
- data/spec/pdf/data/text_y1.pdf +0 -0
- data/spec/pdf/data/text_y2_diff_pos.pdf +0 -0
- data/spec/pdf/data/text_y3_diff_size.pdf +0 -0
- data/spec/pdf/data/text_y4_diff_font.pdf +0 -0
- data/spec/pdf/data/text_y5_diff_style.pdf +0 -0
- data/spec/pdf/data/text_y6_diff_color.pdf +0 -0
- data/spec/pdf/data/text_y7_diff_bg.pdf +0 -0
- data/spec/pdf/data/uncompressed.pdf +0 -0
- data/spec/pdf/matcher_spec.rb +65 -0
- data/spec/pdf/merger_spec.rb +27 -0
- data/spec/pdf/spec_helper.rb +13 -0
- data/spec/spec_helper.rb +42 -0
- metadata +150 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
Here is an overview of the licenses in the various jar files provided with PDFC.
|
2
|
+
|
3
|
+
|
4
|
+
JAR file License Info
|
5
|
+
---------------------------------------------------------------------------------------------
|
6
|
+
log4j-1.2.15.jar See license/LICENSE.log4j
|
7
|
+
PDFCParser.jar LGPL license - see lgpl-3.0.txt
|
8
|
+
PDFC.jar Copyright 2009-2010, i-net software. All rights reserved.
|
9
|
+
CCLib.jar Copyright 2009-2010, i-net software. All rights reserved.
|
Binary file
|
@@ -0,0 +1,89 @@
|
|
1
|
+
i-net PDF Comparer v1.01
|
2
|
+
-------------------------
|
3
|
+
Copyright i-net software GmbH 2009-2010
|
4
|
+
All rights reserved
|
5
|
+
|
6
|
+
1. Introduction
|
7
|
+
---------------
|
8
|
+
The PDF Comparer is a tool specifically for comparing two PDF files (or folders containing PDF files)
|
9
|
+
for differences.
|
10
|
+
It is useful for comparing the PDF output of a Crystal Reports report with the PDF output of this same
|
11
|
+
report as exported by i-net Crystal-Clear, or for comparing the PDF output of two different versions
|
12
|
+
of i-net Crystal-Clear for any differences or behavioral changes. The following elements are compared
|
13
|
+
and any differences logged:
|
14
|
+
|
15
|
+
* Text differences (letters or words missing)
|
16
|
+
* Line/Arc/Box differences (lines or boxes missing or with different styles)
|
17
|
+
* Image differences (images missing)
|
18
|
+
* Margin differences (page margins different)
|
19
|
+
|
20
|
+
These differences each have a configurable tolerance value so that minor differences can be
|
21
|
+
ignored if necessary. (See point 3 - Configuration)
|
22
|
+
|
23
|
+
2. Parameters
|
24
|
+
-------------
|
25
|
+
Usage:
|
26
|
+
PDFC [-c <config file>] [-[i][o]] [<Folder1> <Folder2> | <File1> <File2>]
|
27
|
+
|
28
|
+
-c Specify a configuration file (config.xml) for PDFC. If none is specified, the default "config.xml" is taken
|
29
|
+
-i Creates diff images in <Folder1>/differences for any differences found (recommended for a graphical comparison)
|
30
|
+
-o Creates images for each page of each version (need only be used for debug purposes)
|
31
|
+
|
32
|
+
Note that if using two folders, the PDF files must have the same names in each folder.
|
33
|
+
|
34
|
+
Will result in an output on the console for any differences found between the PDFs being compared.
|
35
|
+
|
36
|
+
Example usage:
|
37
|
+
|
38
|
+
PDFC -i CRFolder CCFolder
|
39
|
+
|
40
|
+
This would compare all PDF files in the folder "CRFolder" with the PDF files of the same name in the folder "CCFolder".
|
41
|
+
|
42
|
+
3. Configuration
|
43
|
+
----------------
|
44
|
+
The following tolerance values can be set in the config.xml file:
|
45
|
+
|
46
|
+
CHART_DENSITY_THRESHOLD
|
47
|
+
(Decimal) density threshold: ((number of shapes)^3 / area size)
|
48
|
+
CHART_REMOVAL_MARGIN
|
49
|
+
(Decimal) percent of shape height to use as margin for removing PDF elements above and below detected charts
|
50
|
+
CREATE_DIFFIMAGES
|
51
|
+
True to create png files with the marked difference of the compared pages
|
52
|
+
CREATE_ORIGIMAGES
|
53
|
+
True to create a png file for each page that is compared
|
54
|
+
LOG_LEVEL
|
55
|
+
Level for Logging (OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL). The default is set to WARN
|
56
|
+
MAX_ERRORS_PER_REPORT
|
57
|
+
maximum number of errors that can occur before the comparison is canceled for the current pdf file.
|
58
|
+
MAX_WORD_DIFFERENCES
|
59
|
+
maximum number of differences that can occur before the comparison is canceled
|
60
|
+
MODULES
|
61
|
+
comma separated list of modules to be executed for each page
|
62
|
+
NORMALIZERS
|
63
|
+
comma separated list of normalizers to be executed before and after each page
|
64
|
+
TOLERANCE_BOX_ROUND_EDGES
|
65
|
+
(Integer) maximum number of pixels that a curve control point may differ in total
|
66
|
+
TOLERANCE_IMAGE_DISTANCE
|
67
|
+
maximum number of pixels that the position of an image can differ
|
68
|
+
TOLERANCE_IMAGE_SIZE
|
69
|
+
maximum difference in percent, that the area spanned by an image may differ
|
70
|
+
TOLERANCE_LINE_POSITION
|
71
|
+
(Decimal) maximum number of pixels that the position of a line or curves can differ per axis
|
72
|
+
TOLERANCE_LINE_SIZE
|
73
|
+
(Integer) maximum number of pixels that the length of a line can differ in total
|
74
|
+
TOLERANCE_LINE_STYLE
|
75
|
+
(Boolean) if true, different stroke styles will be an error
|
76
|
+
TOLERANCE_LINE_THICKNESS
|
77
|
+
(Integer) maximum difference in stroke thickness of two lines or curves
|
78
|
+
TOLERANCE_PAGE_LEFTCORNER
|
79
|
+
maximum number of pixels that the left or top margin of a page can differ (is the upper left corner of all elements)
|
80
|
+
TOLERANCE_PAGE_RATIO
|
81
|
+
tolerance for the aspect ratio of the pdf page
|
82
|
+
TOLERANCE_PAGE_SIZE
|
83
|
+
maximum number of pixels that the width or height of a page can differ
|
84
|
+
TOLERANCE_UNDERLINE_LENGTH
|
85
|
+
(Decimal) the maximum difference in percent, which the length of underlines may differ
|
86
|
+
|
87
|
+
4. Support
|
88
|
+
|
89
|
+
If you have any questions or problems, please do not hesitate to contact tools@inetsoftware.de for technical support.
|
data/lib/gjman.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'gjman/file_system'
|
2
|
+
require 'gjman/jruby'
|
3
|
+
require 'gjman/rjb'
|
4
|
+
|
5
|
+
module Gjman
|
6
|
+
|
7
|
+
ROOT = File.join(File.expand_path(File.dirname(__FILE__)))
|
8
|
+
JAVA_LIBS = []
|
9
|
+
JAVA_MODE = RUBY_PLATFORM =~ /java/i ? :JRuby : (
|
10
|
+
begin
|
11
|
+
require 'rjb'
|
12
|
+
:Rjb
|
13
|
+
rescue LoadError
|
14
|
+
:Shell
|
15
|
+
end
|
16
|
+
)
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
def root(*args)
|
21
|
+
args.size == 0 ? ROOT : File.join(ROOT, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def ext(*args)
|
25
|
+
root(*['ext', args].flatten)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'ftools'
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module Gjman
|
6
|
+
|
7
|
+
class FileNotFoundError < Exception ; end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
module FileSystem
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def tmp_dir(&block)
|
15
|
+
Dir.mktmpdir(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def file_must_exist!(path, timeout=0)
|
19
|
+
if timeout.zero?
|
20
|
+
File.exists?(path) or raise_file_not_found_error(path)
|
21
|
+
else
|
22
|
+
0.upto(timeout.pred) {|i| File.exists?(path) ? (return true) : sleep(1) }
|
23
|
+
raise_file_not_found_error(path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def trash_tmp_files
|
28
|
+
(@trashable_tmp_files || []).each {|f| f.path && f.unlink }
|
29
|
+
@trashable_tmp_files = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def tmp_file(basename = nil)
|
33
|
+
basename ||= Digest::MD5.hexdigest(Time.now.to_s)
|
34
|
+
((@trashable_tmp_files ||= []) << Tempfile.new(basename))[-1]
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def raise_file_not_found_error(path)
|
40
|
+
raise FileNotFoundError.new("File '#{path}' not found.")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import java.security.Permission;
|
2
|
+
|
3
|
+
// Copy-&-pasted (almost) from
|
4
|
+
// http://www.jroller.com/ethdsy/entry/disabling_system_exit
|
5
|
+
class ForbidSystemExit
|
6
|
+
{
|
7
|
+
public static class Exception extends SecurityException { }
|
8
|
+
|
9
|
+
public static void apply() {
|
10
|
+
final SecurityManager securityManager = new SecurityManager() {
|
11
|
+
public void checkPermission( Permission permission ) {
|
12
|
+
if( permission.getName().startsWith("exitVM") ) {
|
13
|
+
throw new Exception() ;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
} ;
|
17
|
+
System.setSecurityManager( securityManager ) ;
|
18
|
+
}
|
19
|
+
|
20
|
+
public static void unapply() {
|
21
|
+
System.setSecurityManager( null ) ;
|
22
|
+
}
|
23
|
+
}
|
data/lib/gjman/jruby.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Gjman
|
2
|
+
module JRuby
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@initialized ||= (
|
7
|
+
include Java
|
8
|
+
Gjman::JAVA_LIBS.join(':').split(':').each{|jar| require jar }
|
9
|
+
$CLASSPATH << Gjman.root('gjman','java_hacks')
|
10
|
+
java_import 'ForbidSystemExit'
|
11
|
+
true
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def classify(klass)
|
16
|
+
java_import klass
|
17
|
+
Java.send(klass)
|
18
|
+
end
|
19
|
+
|
20
|
+
def sandbox(&block)
|
21
|
+
initialize
|
22
|
+
begin
|
23
|
+
ForbidSystemExit.apply
|
24
|
+
@result = yield
|
25
|
+
rescue ForbidSystemExit::Exception
|
26
|
+
@result
|
27
|
+
ensure
|
28
|
+
ForbidSystemExit.unapply
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/gjman/pdf.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'gjman'
|
2
|
+
require 'gjman/pdf/utils'
|
3
|
+
require 'gjman/pdf/base'
|
4
|
+
require 'gjman/pdf/matcher'
|
5
|
+
require 'gjman/pdf/merger'
|
6
|
+
require 'gjman/pdf/compressor'
|
7
|
+
|
8
|
+
module Gjman
|
9
|
+
module PDF
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def match?(x, y)
|
13
|
+
Matcher.test(x, y)
|
14
|
+
end
|
15
|
+
|
16
|
+
def merge(*args)
|
17
|
+
Merger.do(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def compress(src, opts={})
|
21
|
+
Compressor.do(src, opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
def uncompress(src, opts={})
|
25
|
+
Compressor.undo(src, opts)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Gjman
|
4
|
+
module PDF
|
5
|
+
class Base
|
6
|
+
class << self
|
7
|
+
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def_delegators Utils::PDFC, :diff
|
11
|
+
def_delegators Utils::Multivalent, :merge, :compress, :uncompress, :fonts, :images
|
12
|
+
|
13
|
+
def same_contents?(pdf_x, pdf_y)
|
14
|
+
diff(pdf_x, pdf_y) !~ %r{\| # of Differences.*\-+.*(\| [1-9]+)}m
|
15
|
+
end
|
16
|
+
|
17
|
+
def same_fonts?(pdf_x, pdf_y)
|
18
|
+
# The last line shows processing stats (which we don't need)
|
19
|
+
fonts(pdf_x).split("\n")[0..-2] == fonts(pdf_y).split("\n")[0..-2]
|
20
|
+
end
|
21
|
+
|
22
|
+
def same_images?(pdf_x, pdf_y)
|
23
|
+
# The fist line shows file name (which we don't need)
|
24
|
+
images(pdf_x).split("\n")[1..-1] == images(pdf_y).split("\n")[1..-1]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Gjman
|
2
|
+
module PDF
|
3
|
+
class Compressor < Base
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def do(src, opts={})
|
7
|
+
default_dest = src.sub(/\.pdf$/, '-o.pdf')
|
8
|
+
work(:compress, src, opts.delete(:to) || default_dest, default_dest)
|
9
|
+
end
|
10
|
+
|
11
|
+
def undo(src, opts={})
|
12
|
+
default_dest = src.sub(/\.pdf$/, '-u.pdf')
|
13
|
+
work(:uncompress, src, opts.delete(:to) || default_dest, default_dest)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def work(action, src, dest, tmp_dest)
|
19
|
+
case send(action, src)
|
20
|
+
when /Already compressed\. \(Force recompression with \-force\.\)/,
|
21
|
+
/java\.lang\.ArrayIndexOutOfBoundsException/
|
22
|
+
File.copy(src, dest)
|
23
|
+
else
|
24
|
+
File.move(tmp_dest, dest)
|
25
|
+
end
|
26
|
+
dest
|
27
|
+
end
|
28
|
+
|
29
|
+
# NOTE: Since pdftk is almost as dead as multivalent (last updated in 2006),
|
30
|
+
# there is really no good reason to choose it over multivalent. Moreover,
|
31
|
+
# since pdf comparison requires java solution, it makes sense to be consistent,
|
32
|
+
# which is essentially sticking to java.
|
33
|
+
#
|
34
|
+
# def do(src, dest)
|
35
|
+
# pdftk(:compress, src, dest)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def undo(src, dest)
|
39
|
+
# pdftk(:uncompress, src, dest)
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# def pdftk(mode, src, dest)
|
43
|
+
# shell(:pdftk, [src, :output, dest, mode, :verbose])
|
44
|
+
# dest
|
45
|
+
# end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gjman
|
2
|
+
module PDF
|
3
|
+
class Matcher < Base
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def test(pdf_x, pdf_y)
|
7
|
+
begin
|
8
|
+
tmp_x, tmp_y = uncompress(pdf_x, pdf_y)
|
9
|
+
! [:same_fonts?, :same_images?, :same_contents?].
|
10
|
+
any?{|test| !send(test, tmp_x, tmp_y) }
|
11
|
+
ensure
|
12
|
+
FileSystem.trash_tmp_files
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def uncompress(*pdfs)
|
19
|
+
[pdfs].flatten.map do |pdf|
|
20
|
+
tmp = FileSystem.tmp_file([Digest::MD5.hexdigest(pdf),'.pdf']).path
|
21
|
+
PDF.uncompress(pdf, :to => tmp)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Gjman
|
2
|
+
module PDF
|
3
|
+
class Merger < Base
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def do(*args)
|
7
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
srcs = [args].flatten
|
9
|
+
default_dest = srcs[0].sub(/\.pdf$/,'-m.pdf')
|
10
|
+
dest = opts.delete(:to) || default_dest
|
11
|
+
work(srcs, dest, default_dest)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def work(srcs, dest, tmp_dest)
|
17
|
+
merge(srcs)
|
18
|
+
File.move(tmp_dest, dest) unless dest == tmp_dest
|
19
|
+
dest
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Gjman
|
2
|
+
module PDF
|
3
|
+
module Utils
|
4
|
+
module Multivalent
|
5
|
+
|
6
|
+
class NotSupportedServiceError < Exception ; end
|
7
|
+
|
8
|
+
JARS = Gjman.ext('multivalent', 'Multivalent20060102.jar')
|
9
|
+
Gjman::JAVA_LIBS << JARS
|
10
|
+
|
11
|
+
SERVICES = {
|
12
|
+
:compress => %w{tool.pdf.Compress},
|
13
|
+
:uncompress => %w{tool.pdf.Uncompress},
|
14
|
+
:merge => %w{tool.pdf.Merge},
|
15
|
+
:fonts => %w{tool.doc.ExtractText --output xml --style},
|
16
|
+
:images => %w{tool.pdf.Info --images},
|
17
|
+
}
|
18
|
+
|
19
|
+
module JRuby
|
20
|
+
def method_missing(mode, *args)
|
21
|
+
Gjman::JRuby.sandbox do
|
22
|
+
service, args = extract_args(mode, args)
|
23
|
+
Gjman::JRuby.classify(service).main(args.split(' '))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Rjb
|
29
|
+
def method_missing(mode, *args)
|
30
|
+
Gjman::Rjb.sandbox do
|
31
|
+
service, args = extract_args(mode, args)
|
32
|
+
Gjman::Rjb.classify(service).main(args.split(' '))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module Shell
|
38
|
+
def method_missing(mode, *args)
|
39
|
+
service, args = extract_args(mode, args)
|
40
|
+
@cmd ||= 'java -cp %s' % JARS
|
41
|
+
%x|#{@cmd} #{service} #{args} 2>&1|
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.extract_args(mode, args)
|
46
|
+
(service_args = SERVICES[mode]) or raise NotSupportedServiceError
|
47
|
+
[
|
48
|
+
service_args[0],
|
49
|
+
[service_args[1..-1], args].flatten.compact.join(' ')
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
extend const_get(Gjman::JAVA_MODE)
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|