tifffile 0.0.1 → 0.0.2
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 +4 -4
- data/.gemspec +2 -2
- data/Rakefile +8 -0
- data/analyzer.py +28 -0
- data/ext/tifffile/extconf.rb +7 -2
- data/ext/tifffile/tifffile.cpp +237 -0
- data/lib/tifffile.rb +26 -0
- data/lib/tifffile/version.rb +2 -2
- data/spec/tifffile_spec.rb +7 -0
- metadata +5 -4
- data/ext/tifffile/tifffile.c +0 -74
- data/ext/tifffile/tifffile.h +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73ee12cfcfb7b19f45966c553780006c9e2ea981
|
4
|
+
data.tar.gz: aadabb05a8725757870334ebdffec87f22d0451d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7713c2989ad9be58d24c32cdb9dc63ea10971f32c376102627e442efe013b0e7d5492118ace195b65af387c0538a3e77b96d93f1d23a06f955880712d57a590a
|
7
|
+
data.tar.gz: 072ec891538ef01d00efd6210417ad0d90e7cf6b877f716cf72a8caab050841f14bfc9c50d4c37d9dee9373d60d8da2bab112f53c187e30aa64d1a2f55f23612
|
data/.gemspec
CHANGED
@@ -2,8 +2,8 @@ require File.expand_path("../lib/tifffile/version", __FILE__)
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'tifffile'
|
5
|
-
gem.version =
|
6
|
-
gem.date = '2016-03-
|
5
|
+
gem.version = TiffFileVersion::VERSION
|
6
|
+
gem.date = '2016-03-22'
|
7
7
|
|
8
8
|
gem.summary = "TIFF reader and writer"
|
9
9
|
gem.description = ""
|
data/Rakefile
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
require "rake/extensiontask"
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
2
5
|
|
3
6
|
Rake::ExtensionTask.new "tifffile" do |ext|
|
4
7
|
ext.lib_dir = "lib/tifffile"
|
5
8
|
end
|
6
9
|
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
+
Rake::Task['compile'].invoke
|
12
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
data/analyzer.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/python
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
from libtiff import TIFFfile
|
5
|
+
from libtiff import TIFF
|
6
|
+
|
7
|
+
def read(fileName):
|
8
|
+
"""
|
9
|
+
Script to import tif file from imageJ,
|
10
|
+
usage: zstack = tiff.read(inFileName)
|
11
|
+
PTW 2015/01/29
|
12
|
+
"""
|
13
|
+
tiff = TIFFfile(fileName)
|
14
|
+
samples, sample_names = tiff.get_samples()
|
15
|
+
|
16
|
+
outList = []
|
17
|
+
for sample in samples:
|
18
|
+
outList.append(np.copy(sample)[...,np.newaxis])
|
19
|
+
|
20
|
+
out = np.concatenate(outList,axis=-1)
|
21
|
+
out = np.rollaxis(out,0,3)
|
22
|
+
out = np.flipud(out)
|
23
|
+
|
24
|
+
tiff.close()
|
25
|
+
|
26
|
+
return out
|
27
|
+
|
28
|
+
print(read('a.tiff'))
|
data/ext/tifffile/extconf.rb
CHANGED
@@ -0,0 +1,237 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string>
|
5
|
+
#include "tiffio.h"
|
6
|
+
#include <vector>
|
7
|
+
#include <algorithm>
|
8
|
+
|
9
|
+
using namespace std;
|
10
|
+
|
11
|
+
template <class T>
|
12
|
+
static bool rows_size_compare(std::vector<T> & a, std::vector<T> & b)
|
13
|
+
{
|
14
|
+
return (a.size() < b.size());
|
15
|
+
}
|
16
|
+
|
17
|
+
template <class T>
|
18
|
+
void calculate_width_height(std::vector<std::vector<T> > & data, uint32 & width, uint32 & height){
|
19
|
+
height = data.size();
|
20
|
+
width = std::max_element(data.begin(), data.end(), rows_size_compare<T>)->size();
|
21
|
+
}
|
22
|
+
|
23
|
+
|
24
|
+
template <class T>
|
25
|
+
void write_data_to_row_buffer(std::vector<T> & data, unsigned char *buf, uint64 buff_size, uint8 sampleperpixel, uint8 bitspersample){
|
26
|
+
memset(buf, 0, buff_size);
|
27
|
+
buff_size = std::min<uint64>(buff_size, sizeof(T) * data.size());
|
28
|
+
memcpy(buf, (void *)(&(data[0])), buff_size);
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
template <class T>
|
33
|
+
bool write_tiff_file(std::string filename, std::vector<std::vector<T> > & data, uint8 sampleperpixel, uint8 bitspersample, std::string description, std::string software){
|
34
|
+
try {
|
35
|
+
TIFF* tif = TIFFOpen(filename.c_str(), "w");
|
36
|
+
|
37
|
+
uint32 width, height;
|
38
|
+
calculate_width_height(data, width, height);
|
39
|
+
|
40
|
+
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
|
41
|
+
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
|
42
|
+
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, sampleperpixel);
|
43
|
+
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
|
44
|
+
TIFFSetField(tif, TIFFTAG_ORIENTATION, (int)ORIENTATION_TOPLEFT);
|
45
|
+
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
46
|
+
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
47
|
+
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
48
|
+
TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, (char*)description.c_str());
|
49
|
+
TIFFSetField(tif, TIFFTAG_SOFTWARE, (char*)software.c_str());
|
50
|
+
|
51
|
+
uint64 linebytes = sampleperpixel * width * (bitspersample / 8);
|
52
|
+
unsigned char *buf = NULL;
|
53
|
+
buf = (unsigned char *)_TIFFmalloc(linebytes);
|
54
|
+
|
55
|
+
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
|
56
|
+
|
57
|
+
for (uint32 row = 0; row < height; row++){
|
58
|
+
std::vector<T> row_data = data[row];
|
59
|
+
write_data_to_row_buffer(row_data, buf, linebytes, sampleperpixel, bitspersample);
|
60
|
+
if (TIFFWriteScanline(tif, buf, row, 0) < 0)
|
61
|
+
break;
|
62
|
+
}
|
63
|
+
|
64
|
+
if (buf)
|
65
|
+
_TIFFfree(buf);
|
66
|
+
|
67
|
+
TIFFClose(tif);
|
68
|
+
}
|
69
|
+
catch (...){
|
70
|
+
return false;
|
71
|
+
}
|
72
|
+
return true;
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
bool get_matrix_element_type(VALUE data_matrix, bool &is_float){
|
77
|
+
if (!RB_TYPE_P(data_matrix, T_ARRAY) || RARRAY_LEN(data_matrix) < 1)
|
78
|
+
return false;
|
79
|
+
|
80
|
+
VALUE first_row = RARRAY_PTR(data_matrix)[0];
|
81
|
+
|
82
|
+
if (!RB_TYPE_P(first_row, T_ARRAY) || RARRAY_LEN(first_row) < 1)
|
83
|
+
return false;
|
84
|
+
|
85
|
+
VALUE first_item = RARRAY_PTR(first_row)[0];
|
86
|
+
|
87
|
+
if (!RB_TYPE_P(first_item, T_FIXNUM) && !RB_TYPE_P(first_item, T_FLOAT))
|
88
|
+
return false;
|
89
|
+
|
90
|
+
is_float = RB_TYPE_P(first_item, T_FLOAT);
|
91
|
+
|
92
|
+
return true;
|
93
|
+
}
|
94
|
+
|
95
|
+
template <class F, class T>
|
96
|
+
vector<vector<T> > matrix_type_cast(vector<vector<F> > & from){
|
97
|
+
vector<vector<T> > result;
|
98
|
+
result.resize(from.size());
|
99
|
+
|
100
|
+
for (int i = 0; i < from.size(); i++)
|
101
|
+
result[i].assign(from[i].begin(), from[i].end());
|
102
|
+
|
103
|
+
return result;
|
104
|
+
};
|
105
|
+
|
106
|
+
VALUE TiffFile = Qnil;
|
107
|
+
|
108
|
+
VALUE method_tifffile_converter_to_tiff(VALUE self, VALUE filename, VALUE data_matrix, VALUE sample_size, VALUE sample_unsigned, VALUE description, VALUE software){
|
109
|
+
data_matrix = rb_check_array_type(data_matrix);
|
110
|
+
|
111
|
+
|
112
|
+
Check_Type(filename, T_STRING);
|
113
|
+
Check_Type(data_matrix, T_ARRAY);
|
114
|
+
Check_Type(sample_size, T_FIXNUM);
|
115
|
+
Check_Type(description, T_STRING);
|
116
|
+
Check_Type(software, T_STRING);
|
117
|
+
|
118
|
+
uint8 size = std::min<uint8>(NUM2USHORT(sample_size), 8);
|
119
|
+
|
120
|
+
bool unsigned_flag = RTEST(sample_unsigned);
|
121
|
+
|
122
|
+
bool is_float_matrix;
|
123
|
+
if (!get_matrix_element_type(data_matrix, is_float_matrix))
|
124
|
+
rb_raise(rb_eRuntimeError, "Invalid matrix items type");
|
125
|
+
|
126
|
+
if (size != 1 && size != 2 && size != 4 && size != 8)
|
127
|
+
rb_raise(rb_eRuntimeError, "Sample size should be in range [1, 2, 4, 8]");
|
128
|
+
|
129
|
+
if (is_float_matrix && (size % 4) != 0)
|
130
|
+
rb_raise(rb_eRuntimeError, "Sample size should be 4 or 8 on non-fixnum matrix");
|
131
|
+
|
132
|
+
vector<vector<double> > data_d;
|
133
|
+
vector<double> temp_d;
|
134
|
+
vector<vector<int64> > data_i;
|
135
|
+
vector<int64> temp_i;
|
136
|
+
|
137
|
+
VALUE row, item;
|
138
|
+
|
139
|
+
if (is_float_matrix)
|
140
|
+
data_d.resize(RARRAY_LEN(data_matrix));
|
141
|
+
else
|
142
|
+
data_i.resize(RARRAY_LEN(data_matrix));
|
143
|
+
|
144
|
+
|
145
|
+
for (long i = 0; i < RARRAY_LEN(data_matrix); i++){
|
146
|
+
row = RARRAY_PTR(data_matrix)[i];
|
147
|
+
|
148
|
+
if (!RB_TYPE_P(row, T_ARRAY))
|
149
|
+
rb_raise(rb_eRuntimeError, "Matrix row %ld is not an array", i);
|
150
|
+
|
151
|
+
// Clear row buffer
|
152
|
+
if (is_float_matrix){
|
153
|
+
temp_d.clear();
|
154
|
+
temp_d.resize(RARRAY_LEN(row));
|
155
|
+
} else {
|
156
|
+
temp_i.clear();
|
157
|
+
temp_i.resize(RARRAY_LEN(row));
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
// Read row
|
162
|
+
for (long j = 0; j < RARRAY_LEN(row); j++){
|
163
|
+
item = RARRAY_PTR(row)[j];
|
164
|
+
Check_Type(item, is_float_matrix ? T_FLOAT : T_FIXNUM);
|
165
|
+
if (is_float_matrix)
|
166
|
+
temp_d[j] = RFLOAT_VALUE(item);
|
167
|
+
else
|
168
|
+
temp_i[j] = FIX2LONG(item);
|
169
|
+
}
|
170
|
+
|
171
|
+
if (is_float_matrix)
|
172
|
+
data_d[i] = temp_d;
|
173
|
+
else
|
174
|
+
data_i[i] = temp_i;
|
175
|
+
}
|
176
|
+
|
177
|
+
|
178
|
+
bool result = false;
|
179
|
+
if (is_float_matrix){
|
180
|
+
if (size == 8)
|
181
|
+
result = write_tiff_file<double>(StringValuePtr(filename), data_d, 1, 64, StringValuePtr(description), StringValuePtr(software));
|
182
|
+
else if (size == 4){
|
183
|
+
vector<vector<float> > cast_buffer = matrix_type_cast<double, float>(data_d);
|
184
|
+
result = write_tiff_file<float>(StringValuePtr(filename), cast_buffer, 1, 32, StringValuePtr(description), StringValuePtr(software));
|
185
|
+
}
|
186
|
+
else
|
187
|
+
rb_raise(rb_eRuntimeError, "unrecognized sample size for float matrix : %d", size);
|
188
|
+
}
|
189
|
+
else {
|
190
|
+
if (unsigned_flag){
|
191
|
+
if (size == 8){
|
192
|
+
vector<vector<uint64> > cast_buffer = matrix_type_cast<int64, uint64>(data_i);
|
193
|
+
result = write_tiff_file<uint64>(StringValuePtr(filename), cast_buffer, 1, 64, StringValuePtr(description), StringValuePtr(software));
|
194
|
+
}
|
195
|
+
else if (size == 4){
|
196
|
+
vector<vector<uint32> > cast_buffer = matrix_type_cast<int64, uint32>(data_i);
|
197
|
+
result = write_tiff_file<uint32>(StringValuePtr(filename), cast_buffer, 1, 32, StringValuePtr(description), StringValuePtr(software));
|
198
|
+
}
|
199
|
+
else if (size == 2){
|
200
|
+
vector<vector<uint16> > cast_buffer = matrix_type_cast<int64, uint16>(data_i);
|
201
|
+
result = write_tiff_file<uint16>(StringValuePtr(filename), cast_buffer, 1, 16, StringValuePtr(description), StringValuePtr(software));
|
202
|
+
}
|
203
|
+
else if (size == 1){
|
204
|
+
vector<vector<uint8> > cast_buffer = matrix_type_cast<int64, uint8>(data_i);
|
205
|
+
result = write_tiff_file<uint8>(StringValuePtr(filename), cast_buffer, 1, 8, StringValuePtr(description), StringValuePtr(software));
|
206
|
+
}
|
207
|
+
else
|
208
|
+
rb_raise(rb_eRuntimeError, "unrecognized sample size for unsigned numeric matrix : %d", size);
|
209
|
+
}
|
210
|
+
else {
|
211
|
+
if (size == 8){
|
212
|
+
result = write_tiff_file<int64>(StringValuePtr(filename), data_i, 1, 64, StringValuePtr(description), StringValuePtr(software));
|
213
|
+
}
|
214
|
+
else if (size == 4){
|
215
|
+
vector<vector<int32> > cast_buffer = matrix_type_cast<int64, int32>(data_i);
|
216
|
+
result = write_tiff_file<int32>(StringValuePtr(filename), cast_buffer, 1, 32, StringValuePtr(description), StringValuePtr(software));
|
217
|
+
}
|
218
|
+
else if (size == 2){
|
219
|
+
vector<vector<int16> > cast_buffer = matrix_type_cast<int64, int16>(data_i);
|
220
|
+
result = write_tiff_file<int16>(StringValuePtr(filename), cast_buffer, 1, 16, StringValuePtr(description), StringValuePtr(software));
|
221
|
+
}
|
222
|
+
else if (size == 1){
|
223
|
+
vector<vector<int8> > cast_buffer = matrix_type_cast<int64, int8>(data_i);
|
224
|
+
result = write_tiff_file<int8>(StringValuePtr(filename), cast_buffer, 1, 8, StringValuePtr(description), StringValuePtr(software));
|
225
|
+
}
|
226
|
+
else
|
227
|
+
rb_raise(rb_eRuntimeError, "unrecognized sample size for signed numeric matrix : %d", size);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
return result ? Qtrue : Qfalse;
|
232
|
+
}
|
233
|
+
|
234
|
+
extern "C" void Init_tifffile(){
|
235
|
+
TiffFile = rb_define_module("TiffFile");
|
236
|
+
rb_define_singleton_method(TiffFile, "to_tiff", (VALUE(*)(ANYARGS))method_tifffile_converter_to_tiff, 6);
|
237
|
+
}
|
data/lib/tifffile.rb
CHANGED
@@ -1,2 +1,28 @@
|
|
1
1
|
require 'tifffile/version'
|
2
2
|
require "tifffile/tifffile"
|
3
|
+
|
4
|
+
module TiffFile
|
5
|
+
|
6
|
+
include TiffFileVersion
|
7
|
+
|
8
|
+
# Will write a TIFF file +destination+, that contains +values+ matrix (in one channel), each sample has +sample_size+ in bytes (1, 2, 4 or 8), +sample_unsigned+.
|
9
|
+
# Also, image have +description+ and reference to +software+
|
10
|
+
def self.tiff2file(destination, values, sample_size=16, sample_unsigned=false, description=nil, software=nil)
|
11
|
+
self.to_tiff(destination.to_s, values, sample_size.to_i, sample_unsigned == true, description.to_s, software.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
# Binary get TIFF file that contains +values+ matrix (in one channel), each sample has +sample_size+ in bytes (1, 2, 4 or 8), +sample_unsigned+.
|
16
|
+
# Also, image have +description+ and reference to +software+
|
17
|
+
def self.tiff2binary(values, sample_size=16, description=nil, software=nil)
|
18
|
+
file = Tempfile.new('tiff2binary')
|
19
|
+
file.close
|
20
|
+
|
21
|
+
tiff2file(file.path, values, sample_size, description, software)
|
22
|
+
|
23
|
+
data = File.read(file)
|
24
|
+
file.unlink
|
25
|
+
data
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/tifffile/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.
|
1
|
+
module TiffFileVersion
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tifffile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kirill Makhonin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: ''
|
14
14
|
email: kroks.rus@gmail.com
|
@@ -25,11 +25,12 @@ files:
|
|
25
25
|
- ".idea/tifffile-ruby.iml"
|
26
26
|
- LICENSE
|
27
27
|
- Rakefile
|
28
|
+
- analyzer.py
|
28
29
|
- ext/tifffile/extconf.rb
|
29
|
-
- ext/tifffile/tifffile.
|
30
|
-
- ext/tifffile/tifffile.h
|
30
|
+
- ext/tifffile/tifffile.cpp
|
31
31
|
- lib/tifffile.rb
|
32
32
|
- lib/tifffile/version.rb
|
33
|
+
- spec/tifffile_spec.rb
|
33
34
|
homepage: https://github.com/kirillmakhonin/tifffile-ruby
|
34
35
|
licenses:
|
35
36
|
- MIT
|
data/ext/tifffile/tifffile.c
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
#include <tifffile.h>
|
2
|
-
|
3
|
-
struct my_malloc {
|
4
|
-
size_t size;
|
5
|
-
void *ptr;
|
6
|
-
};
|
7
|
-
|
8
|
-
static void
|
9
|
-
my_malloc_free(void *p) {
|
10
|
-
struct my_malloc *ptr = p;
|
11
|
-
|
12
|
-
if (ptr->size > 0)
|
13
|
-
free(ptr->ptr);
|
14
|
-
}
|
15
|
-
|
16
|
-
static VALUE
|
17
|
-
my_malloc_alloc(VALUE klass) {
|
18
|
-
VALUE obj;
|
19
|
-
struct my_malloc *ptr;
|
20
|
-
|
21
|
-
obj = Data_Make_Struct(klass, struct my_malloc, NULL, my_malloc_free, ptr);
|
22
|
-
|
23
|
-
ptr->size = 0;
|
24
|
-
ptr->ptr = NULL;
|
25
|
-
|
26
|
-
return obj;
|
27
|
-
}
|
28
|
-
|
29
|
-
static VALUE
|
30
|
-
my_malloc_init(VALUE self, VALUE size) {
|
31
|
-
struct my_malloc *ptr;
|
32
|
-
size_t requested = NUM2SIZET(size);
|
33
|
-
|
34
|
-
if (0 == requested)
|
35
|
-
rb_raise(rb_eArgError, "unable to allocate 0 bytes");
|
36
|
-
|
37
|
-
Data_Get_Struct(self, struct my_malloc, ptr);
|
38
|
-
|
39
|
-
ptr->ptr = malloc(requested);
|
40
|
-
|
41
|
-
if (NULL == ptr->ptr)
|
42
|
-
rb_raise(rb_eNoMemError, "unable to allocate %ld bytes", requested);
|
43
|
-
|
44
|
-
ptr->size = requested;
|
45
|
-
|
46
|
-
return self;
|
47
|
-
}
|
48
|
-
|
49
|
-
static VALUE
|
50
|
-
my_malloc_release(VALUE self) {
|
51
|
-
struct my_malloc *ptr;
|
52
|
-
|
53
|
-
Data_Get_Struct(self, struct my_malloc, ptr);
|
54
|
-
|
55
|
-
if (0 == ptr->size)
|
56
|
-
return self;
|
57
|
-
|
58
|
-
ptr->size = 0;
|
59
|
-
free(ptr->ptr);
|
60
|
-
|
61
|
-
return self;
|
62
|
-
}
|
63
|
-
|
64
|
-
void
|
65
|
-
Init_my_malloc(void) {
|
66
|
-
VALUE cMyMalloc;
|
67
|
-
|
68
|
-
cMyMalloc = rb_const_get(rb_cObject, rb_intern("TiffFile"));
|
69
|
-
|
70
|
-
rb_define_alloc_func(cMyMalloc, my_malloc_alloc);
|
71
|
-
rb_define_method(cMyMalloc, "initialize", my_malloc_init, 1);
|
72
|
-
rb_define_method(cMyMalloc, "free", my_malloc_release, 0);
|
73
|
-
}
|
74
|
-
|
data/ext/tifffile/tifffile.h
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
#include <ruby.h>
|