swf_recompress 0.0.6
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/bin/swf_recompress +69 -0
- data/lib/kzip +0 -0
- data/lib/swf_recompress.rb +208 -0
- data/src/SWFExtract.class +0 -0
- data/src/SWFExtract.java +61 -0
- data/src/SWFInject.class +0 -0
- data/src/SWFInject.java +55 -0
- metadata +73 -0
data/bin/swf_recompress
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require File.join(File.dirname(__FILE__), '../lib/swf_recompress')
|
|
5
|
+
|
|
6
|
+
ACQUIRE_KZIP_TEXT = "Run with --acquire-kzip to download the kzip tool"
|
|
7
|
+
SWF_RECOMPRESS_BANNER = "swf_recompress version #{SWFRecompress::VERSION}#{SWFRecompress.kzip_available? ? '' : ', but no kzip installed'}"
|
|
8
|
+
|
|
9
|
+
options = {}
|
|
10
|
+
OptionParser.new do |opts|
|
|
11
|
+
opts.banner = "#{SWF_RECOMPRESS_BANNER}\nRecompress a swf file with more aggressive DEFLATE settings\nUsage: swf_recompress [options] swf_filename [output_swf_filename]"
|
|
12
|
+
opts.on('-i', '--in-place', 'Compress the swf in-place, replacing the original file') do
|
|
13
|
+
options[:use_input_filename] = true
|
|
14
|
+
end
|
|
15
|
+
opts.on('-a', '--acquire-kzip', 'Download kzip tool') do
|
|
16
|
+
options[:acquire_kzip] = true
|
|
17
|
+
end
|
|
18
|
+
opts.on_tail('-v', '--version', 'Show version & contributors') do
|
|
19
|
+
puts SWF_RECOMPRESS_BANNER
|
|
20
|
+
puts " Based on Jos-Iven Hirth's \"Improving SWF Compression\": http://kaioa.com/node/87"
|
|
21
|
+
puts SWFRecompress::KZIP_ABOUT
|
|
22
|
+
if !SWFRecompress.kzip_available?
|
|
23
|
+
puts SWFRecompress::KZIP_INSTALL_TEXT
|
|
24
|
+
end
|
|
25
|
+
exit
|
|
26
|
+
end
|
|
27
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
28
|
+
puts opts
|
|
29
|
+
puts "If only one filename is given and the -i flag is not supplied, a new swf"
|
|
30
|
+
puts "with the suffix '_compressed' will be created alongside the original file."
|
|
31
|
+
exit
|
|
32
|
+
end
|
|
33
|
+
end.parse!(ARGV)
|
|
34
|
+
|
|
35
|
+
options[:input_filename] = ARGV[0]
|
|
36
|
+
options[:output_filename] = ARGV[0] if options[:use_input_filename]
|
|
37
|
+
|
|
38
|
+
def require_kzip!
|
|
39
|
+
if !SWFRecompress.kzip_available?
|
|
40
|
+
$stderr.puts "No kzip installed"
|
|
41
|
+
$stderr.puts "#{ACQUIRE_KZIP_TEXT}\n#{SWFRecompress::KZIP_ABOUT}"
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
if options[:acquire_kzip]
|
|
48
|
+
if SWFRecompress.kzip_available?
|
|
49
|
+
puts "kzip already available"
|
|
50
|
+
else
|
|
51
|
+
SWFRecompress.acquire_kzip
|
|
52
|
+
puts "Installed lib/kzip"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if options[:output_filename]
|
|
57
|
+
require_kzip!
|
|
58
|
+
SWFRecompress.recompress_to(options[:input_filename], options[:output_filename])
|
|
59
|
+
elsif options[:input_filename]
|
|
60
|
+
require_kzip!
|
|
61
|
+
SWFRecompress.recompress(options[:input_filename])
|
|
62
|
+
elsif !options[:acquire_kzip]
|
|
63
|
+
$stderr.puts "Please specify a swf file to recompress"
|
|
64
|
+
exit 1
|
|
65
|
+
end
|
|
66
|
+
rescue => e
|
|
67
|
+
$stderr.puts "There was an error recompressing #{options[:input_filename].inspect}\n#{e}"
|
|
68
|
+
exit 1
|
|
69
|
+
end
|
data/lib/kzip
ADDED
|
Binary file
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
module SWFRecompress
|
|
2
|
+
VERSION = "0.0.6"
|
|
3
|
+
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'tempfile'
|
|
7
|
+
|
|
8
|
+
ROOT = File.join(File.dirname(__FILE__), '..')
|
|
9
|
+
TMP_DIR = Dir::tmpdir
|
|
10
|
+
|
|
11
|
+
KZIP_HOST = 'static.jonof.id.au'
|
|
12
|
+
KZIP_MD5 = 'fdbf05e2bd12b16e899df0f3b6a3e87d'
|
|
13
|
+
KZIP_PATH = '/dl/kenutils/kzipmix-20091108-darwin.tar.gz'
|
|
14
|
+
KZIP_ABOUT = <<-END_KZIP_ABOUT
|
|
15
|
+
kzip by Ken Silverman: http://advsys.net/ken/utils.htm
|
|
16
|
+
Mac OS X and Linux binaries maintained by Jonathan Fowler: http://www.jonof.id.au/
|
|
17
|
+
END_KZIP_ABOUT
|
|
18
|
+
KZIP_INSTALL_TEXT = " Install kzip binary to #{File.expand_path(File.join(ROOT, 'lib/kzip'))}"
|
|
19
|
+
|
|
20
|
+
class Tempfile
|
|
21
|
+
def self.open(temp_stem, write_mode = nil)
|
|
22
|
+
begin
|
|
23
|
+
instance_tmp_dir = nil
|
|
24
|
+
begin
|
|
25
|
+
instance_tmp_dir = File.join(TMP_DIR, rand(1_000_000).to_s)
|
|
26
|
+
end until !File.exists?(instance_tmp_dir)
|
|
27
|
+
FileUtils.mkdir_p(instance_tmp_dir)
|
|
28
|
+
ext = File.extname(temp_stem)
|
|
29
|
+
temp_filename = Pathname.new(
|
|
30
|
+
File.expand_path(File.join(instance_tmp_dir, '%s%s' % [ File.basename(temp_stem, ext), ext ]))
|
|
31
|
+
).relative_path_from(Pathname.new(Dir.pwd))
|
|
32
|
+
File.open(temp_filename, write_mode || 'w') do |f|
|
|
33
|
+
yield(f)
|
|
34
|
+
end
|
|
35
|
+
rescue => e
|
|
36
|
+
raise "Error during Tempfile open #{e.message}"
|
|
37
|
+
ensure
|
|
38
|
+
FileUtils.rm(temp_filename)
|
|
39
|
+
FileUtils.rm_rf(instance_tmp_dir)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class SWFRecompressor
|
|
45
|
+
attr_reader :data_filename, :data_zip_filename, :info_filename, :swf_filename, :output_filename
|
|
46
|
+
def initialize(swf_filename, output_filename)
|
|
47
|
+
if !File.exists?(swf_filename)
|
|
48
|
+
raise "The file #{swf_filename.inspect} does not exist"
|
|
49
|
+
end
|
|
50
|
+
@swf_filename = swf_filename
|
|
51
|
+
@output_filename = output_filename
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def recompress!
|
|
55
|
+
with_tempfiles do
|
|
56
|
+
SWFRecompress.execute(swf_extract, kzip_data, swf_inject)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
def swf_extract
|
|
62
|
+
java('SWFExtract', swf_filename, data_filename, info_filename)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def swf_inject
|
|
66
|
+
java('SWFInject', data_zip_filename, info_filename, output_filename)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def kzip_data
|
|
70
|
+
kzip('-y', '-k0', data_zip_filename, data_filename)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def with_tempfiles
|
|
74
|
+
Dir.chdir(ROOT) do
|
|
75
|
+
with_temp_info_file do
|
|
76
|
+
with_temp_data_file do
|
|
77
|
+
with_temp_data_zip_file do
|
|
78
|
+
yield
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def with_temp_info_file
|
|
86
|
+
Tempfile.open('INFO') do |f|
|
|
87
|
+
f.close
|
|
88
|
+
@info_filename = f.path
|
|
89
|
+
yield
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def with_temp_data_file
|
|
94
|
+
Tempfile.open('SWF_DATA') do |f|
|
|
95
|
+
f.close
|
|
96
|
+
@data_filename = f.path
|
|
97
|
+
yield
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def with_temp_data_zip_file
|
|
102
|
+
Tempfile.open('SWF_DATA.zip') do |f|
|
|
103
|
+
f.close
|
|
104
|
+
@data_zip_filename = f.path
|
|
105
|
+
yield
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def java(*args)
|
|
110
|
+
command('java', '-classpath', 'src', *args)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def kzip(*args)
|
|
114
|
+
command('lib/kzip', *args)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def zip(*args)
|
|
118
|
+
command('zip', *args)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def command(*args)
|
|
122
|
+
SWFRecompress.command(*args)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
module ClassMethods
|
|
127
|
+
def recompress(filename)
|
|
128
|
+
expanded_filename = File.expand_path(filename)
|
|
129
|
+
ext = File.extname(expanded_filename)
|
|
130
|
+
dirname = File.dirname(expanded_filename)
|
|
131
|
+
new_filename = File.join(dirname, '%s%s%s' % [ File.basename(expanded_filename, ext), '_compressed', ext ])
|
|
132
|
+
compressor = SWFRecompressor.new(expanded_filename, new_filename)
|
|
133
|
+
compressor.recompress!
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def recompress_to(filename, new_filename)
|
|
137
|
+
expanded_filename = File.expand_path(filename)
|
|
138
|
+
compressor = SWFRecompressor.new(
|
|
139
|
+
File.expand_path(filename),
|
|
140
|
+
File.expand_path(new_filename))
|
|
141
|
+
compressor.recompress!
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def execute(*ramulons)
|
|
145
|
+
execution = ramulons.join(' && ')
|
|
146
|
+
results = ramulons.map { |command| `#{command} 2&> /dev/null` }
|
|
147
|
+
puts results.join("\n")
|
|
148
|
+
results
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def command(*args)
|
|
152
|
+
args.map { |arg| '"%s"' % arg }.join(' ')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def kzip_available?
|
|
156
|
+
@kzip_available ||= File.exists?('lib/kzip') && KZIP_MD5 == kzip_md5('lib/kzip')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def kzip_md5(kzip_filename)
|
|
160
|
+
require 'digest/md5'
|
|
161
|
+
Digest::MD5.hexdigest(File.read(kzip_filename))
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def acquire_kzip
|
|
165
|
+
begin
|
|
166
|
+
Tempfile.open('kzipmix.tar.gz', 'wb') do |f|
|
|
167
|
+
begin
|
|
168
|
+
download_kzipmix(f)
|
|
169
|
+
rescue => e
|
|
170
|
+
raise "There was an error downloading kzipmix"
|
|
171
|
+
end
|
|
172
|
+
extracted_kzip_filename = extract_kzipmix(f)
|
|
173
|
+
if File.exists?(extracted_kzip_filename)
|
|
174
|
+
extracted_kzip_md5 = kzip_md5(extracted_zip_filename)
|
|
175
|
+
if KZIP_MD5 == extracted_kzip_md5
|
|
176
|
+
FileUtils.cp(extracted_kzip_filename, File.expand_path(File.join(ROOT, 'lib/kzip')))
|
|
177
|
+
else
|
|
178
|
+
raise "The MD5 of the downloaded kzip #{extracted_kzip_md5} did not match the expected MD5 #{KZIP_MD5}"
|
|
179
|
+
end
|
|
180
|
+
else
|
|
181
|
+
raise "Failed to extract kzip from the downloaded kzipmix archive"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
rescue => e
|
|
185
|
+
raise "Unable to acquire kzip utility: #{e.message}\n#{KZIP_ABOUT}#{KZIP_INSTALL_TEXT}"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
def download_kzipmix(f)
|
|
191
|
+
require 'net/http'
|
|
192
|
+
Net::HTTP.start(KZIP_HOST) do |http|
|
|
193
|
+
f.write(http.get(KZIP_PATH).body)
|
|
194
|
+
f.close
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def extract_kzipmix(f)
|
|
199
|
+
fdir = Pathname.new(File.dirname(f.path))
|
|
200
|
+
Dir.chdir(fdir) do
|
|
201
|
+
execute(command('tar', 'xvzf', Pathname.new(f.path).relative_path_from(fdir), '--include', '*/kzip', '-s', '/.*kzip$/kzip/'))
|
|
202
|
+
end
|
|
203
|
+
File.join(File.dirname(f.path), 'kzip')
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
extend ClassMethods
|
|
208
|
+
end
|
|
Binary file
|
data/src/SWFExtract.java
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import java.io.*;
|
|
2
|
+
import java.util.zip.*;
|
|
3
|
+
public class SWFExtract{
|
|
4
|
+
public static void main(String[]args)throws Exception{
|
|
5
|
+
String name = args[0];
|
|
6
|
+
String dataOutputFileName = args[1];
|
|
7
|
+
String infoOutputFileName = args[2];
|
|
8
|
+
File file = new File(name);
|
|
9
|
+
DataInputStream in = new DataInputStream(new FileInputStream(file));
|
|
10
|
+
|
|
11
|
+
boolean compressed = true;
|
|
12
|
+
byte first = in.readByte();
|
|
13
|
+
|
|
14
|
+
if (first == 0x46) //'F'
|
|
15
|
+
compressed = false;
|
|
16
|
+
else if (first != 0x43) //'C'
|
|
17
|
+
noSWF(name, "Not a swf file");
|
|
18
|
+
if (in.readByte() != 0x57) //'W'
|
|
19
|
+
noSWF(name, "Not a swf file");
|
|
20
|
+
if (in.readByte() != 0x53) //'S'
|
|
21
|
+
noSWF(name, "Not a swf file");
|
|
22
|
+
|
|
23
|
+
byte version = in.readByte();
|
|
24
|
+
int reportedFileSize = Integer.reverseBytes(in.readInt());
|
|
25
|
+
int actualFileSize = (int)file.length();
|
|
26
|
+
if (compressed) {
|
|
27
|
+
System.out.println("Initially compressed");
|
|
28
|
+
} else {
|
|
29
|
+
System.out.println("Initially uncompressed");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
DataOutputStream out=new DataOutputStream(new FileOutputStream(dataOutputFileName));
|
|
33
|
+
InputStream in2;
|
|
34
|
+
if(compressed)
|
|
35
|
+
in2=new InflaterInputStream(in);
|
|
36
|
+
else
|
|
37
|
+
in2=new DataInputStream(in);
|
|
38
|
+
byte[]data=new byte[4096];
|
|
39
|
+
int r;
|
|
40
|
+
Adler32 a32=new Adler32();
|
|
41
|
+
while((r=in2.read(data))!=-1){
|
|
42
|
+
out.write(data,0,r);
|
|
43
|
+
a32.update(data,0,r);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
in2.close();
|
|
47
|
+
out.flush();
|
|
48
|
+
out.close();
|
|
49
|
+
|
|
50
|
+
DataOutputStream iout=new DataOutputStream(new FileOutputStream(infoOutputFileName));
|
|
51
|
+
iout.write(version);
|
|
52
|
+
iout.writeInt((int)a32.getValue());
|
|
53
|
+
iout.writeLong(file.length());
|
|
54
|
+
iout.flush();
|
|
55
|
+
iout.close();
|
|
56
|
+
}
|
|
57
|
+
private static void noSWF(String filename, String message){
|
|
58
|
+
System.err.printf("Could not compress swf [%s]: %s", filename, message);
|
|
59
|
+
System.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
data/src/SWFInject.class
ADDED
|
Binary file
|
data/src/SWFInject.java
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import java.io.*;
|
|
2
|
+
import java.util.zip.*;
|
|
3
|
+
import java.text.*;
|
|
4
|
+
public class SWFInject{
|
|
5
|
+
public static void main(String[]args)throws Exception{
|
|
6
|
+
String zipInputFileName = args[0];
|
|
7
|
+
String infoInputFileName = args[1];
|
|
8
|
+
String outputFileName = args[2];
|
|
9
|
+
|
|
10
|
+
DataInputStream iin=new DataInputStream(new FileInputStream(infoInputFileName));
|
|
11
|
+
byte version = iin.readByte();
|
|
12
|
+
int a32 = iin.readInt();
|
|
13
|
+
long oldLength = iin.readLong();
|
|
14
|
+
iin.close();
|
|
15
|
+
|
|
16
|
+
File outFile = new File(outputFileName);
|
|
17
|
+
DataInputStream in = new DataInputStream(new FileInputStream(zipInputFileName));
|
|
18
|
+
DataOutputStream out = new DataOutputStream(new FileOutputStream(outFile));
|
|
19
|
+
|
|
20
|
+
// Skip zipfile header
|
|
21
|
+
in.skipBytes(4 + 2 + 2 + 2 + 2 + 2 + 4);
|
|
22
|
+
int compressedSize = Integer.reverseBytes(in.readInt());
|
|
23
|
+
int uncompressedSize = Integer.reverseBytes(in.readInt());
|
|
24
|
+
// Skip some more
|
|
25
|
+
in.skipBytes(2 + 2 + 8);
|
|
26
|
+
|
|
27
|
+
byte[]data = new byte[compressedSize];
|
|
28
|
+
in.readFully(data);
|
|
29
|
+
in.close();
|
|
30
|
+
int newSize = 1 + 1 + 1 // Header fields CWS
|
|
31
|
+
+ 1 // SWF version
|
|
32
|
+
+ 4 // File length
|
|
33
|
+
+ 2 // For DEFLATE - maximum compression sigil
|
|
34
|
+
+ uncompressedSize
|
|
35
|
+
+ 4; // Adler32 checksum
|
|
36
|
+
|
|
37
|
+
out.write(0x43); //'C'
|
|
38
|
+
out.write(0x57); //'W'
|
|
39
|
+
out.write(0x53); //'S'
|
|
40
|
+
out.write(version < 6 ? 6 : version);
|
|
41
|
+
out.writeInt(Integer.reverseBytes(newSize));
|
|
42
|
+
|
|
43
|
+
out.writeShort(0x78DA);
|
|
44
|
+
out.write(data, 0, data.length);
|
|
45
|
+
out.writeInt(a32);
|
|
46
|
+
out.flush();
|
|
47
|
+
out.close();
|
|
48
|
+
|
|
49
|
+
DecimalFormat byteFormat = new DecimalFormat("###,###");
|
|
50
|
+
long newLength = outFile.length();
|
|
51
|
+
System.out.printf("old Length: %10s\n",byteFormat.format(oldLength));
|
|
52
|
+
System.out.printf("new Length: %10s\n",byteFormat.format(newLength));
|
|
53
|
+
System.out.printf("saved : %10s (%.2f%%)\n",byteFormat.format(oldLength-newLength),100-(100.0/oldLength*newLength));
|
|
54
|
+
}
|
|
55
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: swf_recompress
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 19
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
- 6
|
|
10
|
+
version: 0.0.6
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Duncan Beevers
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-05-21 00:00:00 -07:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies: []
|
|
21
|
+
|
|
22
|
+
description: Recompress a swf file with more aggressive DEFLATE settings
|
|
23
|
+
email: duncan@dweebd.com
|
|
24
|
+
executables:
|
|
25
|
+
- swf_recompress
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files: []
|
|
29
|
+
|
|
30
|
+
files:
|
|
31
|
+
- lib/kzip
|
|
32
|
+
- lib/swf_recompress.rb
|
|
33
|
+
- src/SWFExtract.class
|
|
34
|
+
- src/SWFExtract.java
|
|
35
|
+
- src/SWFInject.class
|
|
36
|
+
- src/SWFInject.java
|
|
37
|
+
- bin/swf_recompress
|
|
38
|
+
has_rdoc: true
|
|
39
|
+
homepage: http://github.com/duncanbeevers/swf_recompress
|
|
40
|
+
licenses: []
|
|
41
|
+
|
|
42
|
+
post_install_message:
|
|
43
|
+
rdoc_options: []
|
|
44
|
+
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
none: false
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
hash: 3
|
|
53
|
+
segments:
|
|
54
|
+
- 0
|
|
55
|
+
version: "0"
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
hash: 3
|
|
62
|
+
segments:
|
|
63
|
+
- 0
|
|
64
|
+
version: "0"
|
|
65
|
+
requirements:
|
|
66
|
+
- none
|
|
67
|
+
rubyforge_project:
|
|
68
|
+
rubygems_version: 1.3.7
|
|
69
|
+
signing_key:
|
|
70
|
+
specification_version: 3
|
|
71
|
+
summary: Recompress a swf file with more aggressive DEFLATE settings
|
|
72
|
+
test_files: []
|
|
73
|
+
|