ronin-code-asm 1.0.0.beta1 → 1.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -0
  3. data/.yardopts +1 -1
  4. data/README.md +2 -1
  5. data/gemspec.yml +2 -2
  6. data/lib/ronin/code/asm/archs/amd64.rb +2 -2
  7. data/lib/ronin/code/asm/archs/x86.rb +2 -2
  8. data/lib/ronin/code/asm/archs.rb +1 -1
  9. data/lib/ronin/code/asm/config.rb +1 -1
  10. data/lib/ronin/code/asm/immediate_operand.rb +1 -1
  11. data/lib/ronin/code/asm/instruction.rb +1 -1
  12. data/lib/ronin/code/asm/memory_operand.rb +1 -1
  13. data/lib/ronin/code/asm/os/freebsd.rb +1 -1
  14. data/lib/ronin/code/asm/os/linux.rb +1 -1
  15. data/lib/ronin/code/asm/os/os.rb +1 -1
  16. data/lib/ronin/code/asm/os.rb +1 -1
  17. data/lib/ronin/code/asm/program.rb +6 -6
  18. data/lib/ronin/code/asm/register.rb +2 -2
  19. data/lib/ronin/code/asm/shellcode.rb +1 -1
  20. data/lib/ronin/code/asm/syntax/att.rb +1 -1
  21. data/lib/ronin/code/asm/syntax/common.rb +1 -1
  22. data/lib/ronin/code/asm/syntax/intel.rb +1 -1
  23. data/lib/ronin/code/asm/syntax.rb +1 -1
  24. data/lib/ronin/code/asm/version.rb +2 -2
  25. data/lib/ronin/code/asm.rb +1 -1
  26. data/ronin-code-asm.gemspec +2 -1
  27. metadata +5 -30
  28. data/spec/asm_spec.rb +0 -14
  29. data/spec/config_spec.rb +0 -10
  30. data/spec/immediate_operand_spec.rb +0 -79
  31. data/spec/instruction_spec.rb +0 -62
  32. data/spec/memory_operand_spec.rb +0 -80
  33. data/spec/os_spec.rb +0 -68
  34. data/spec/program_spec.rb +0 -439
  35. data/spec/register_spec.rb +0 -112
  36. data/spec/shellcode_spec.rb +0 -58
  37. data/spec/spec_helper.rb +0 -7
  38. data/spec/syntax/att_spec.rb +0 -181
  39. data/spec/syntax/common_spec.rb +0 -42
  40. data/spec/syntax/intel_spec.rb +0 -174
@@ -1,80 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'ronin/code/asm/memory_operand'
4
- require 'ronin/code/asm/register'
5
-
6
- describe Ronin::Code::ASM::MemoryOperand do
7
- let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
8
-
9
- describe "#initialize" do
10
- it { expect(subject.base).to be_nil }
11
- it { expect(subject.offset).to eq(0) }
12
- it { expect(subject.index).to be_nil }
13
- it { expect(subject.scale).to eq(1) }
14
-
15
- it "must only accept nil and a Register for base" do
16
- expect {
17
- described_class.new(Object.new)
18
- }.to raise_error(TypeError)
19
- end
20
-
21
- it "must only accept Integers for offset" do
22
- expect {
23
- described_class.new(register,2.0)
24
- }.to raise_error(TypeError)
25
- end
26
-
27
- it "must only accept nil and a Register for index" do
28
- expect {
29
- described_class.new(register,0,Object.new)
30
- }.to raise_error(TypeError)
31
- end
32
-
33
- it "must only accept Integers for offset" do
34
- expect {
35
- described_class.new(register,0,nil,2.0)
36
- }.to raise_error(TypeError)
37
- end
38
-
39
- end
40
-
41
- describe "#+" do
42
- let(:operand) { described_class.new(register,4,register,2) }
43
-
44
- subject { operand + 4 }
45
-
46
- it "must add to offset" do
47
- expect(subject.offset).to eq(8)
48
- end
49
-
50
- it "must not change base, index or scale" do
51
- expect(subject.base).to eq(operand.base)
52
- expect(subject.index).to eq(operand.index)
53
- expect(subject.scale).to eq(operand.scale)
54
- end
55
- end
56
-
57
- describe "#-" do
58
- let(:operand) { described_class.new(register,4,register,2) }
59
-
60
- subject { operand - 2 }
61
-
62
- it "must subtract from offset" do
63
- expect(subject.offset).to eq(2)
64
- end
65
-
66
- it "must not change base, index or scale" do
67
- expect(subject.base).to eq(operand.base)
68
- expect(subject.index).to eq(operand.index)
69
- expect(subject.scale).to eq(operand.scale)
70
- end
71
- end
72
-
73
- describe "#width" do
74
- subject { described_class.new(register,10) }
75
-
76
- it "must return the width of base" do
77
- expect(subject.width).to eq(register.width)
78
- end
79
- end
80
- end
data/spec/os_spec.rb DELETED
@@ -1,68 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/code/asm/os'
3
-
4
- describe Ronin::Code::ASM::OS do
5
- describe "SYSCALLS" do
6
- subject { described_class::SYSCALLS }
7
-
8
- let(:data_dir) { Ronin::Code::ASM::Config::DATA_DIR }
9
-
10
- it { expect(subject).to be_kind_of(Hash) }
11
-
12
- it "must load syscalls for :freebsd and :amd64" do
13
- expect(subject[:freebsd][:amd64]).to eq(
14
- YAML.load_file(
15
- File.join(data_dir,'os','freebsd','amd64','syscalls.yml')
16
- )
17
- )
18
- end
19
-
20
- it "must load syscalls for :freebsd and :x86" do
21
- expect(subject[:freebsd][:amd64]).to eq(
22
- YAML.load_file(
23
- File.join(data_dir,'os','freebsd','x86','syscalls.yml')
24
- )
25
- )
26
- end
27
-
28
- it "must load syscalls for :linux and :amd64" do
29
- expect(subject[:linux][:amd64]).to eq(
30
- YAML.load_file(
31
- File.join(data_dir,'os','linux','amd64','syscalls.yml')
32
- )
33
- )
34
- end
35
-
36
- it "must load syscalls for :linux and :x86" do
37
- expect(subject[:linux][:x86]).to eq(
38
- YAML.load_file(
39
- File.join(data_dir,'os','linux','x86','syscalls.yml')
40
- )
41
- )
42
- end
43
- end
44
-
45
- describe ".[]" do
46
- context "when given :linux" do
47
- it "must return #{described_class}::Linux" do
48
- expect(subject[:linux]).to be(described_class::Linux)
49
- end
50
- end
51
-
52
- context "when given :freebsd" do
53
- it "must return #{described_class}::FreeBSD" do
54
- expect(subject[:freebsd]).to be(described_class::FreeBSD)
55
- end
56
- end
57
-
58
- context "when given an unknown Symbol" do
59
- let(:name) { :foo }
60
-
61
- it do
62
- expect {
63
- subject[name]
64
- }.to raise_error(ArgumentError,"unknown OS name: #{name.inspect}")
65
- end
66
- end
67
- end
68
- end
data/spec/program_spec.rb DELETED
@@ -1,439 +0,0 @@
1
- require 'spec_helper'
2
- require 'ronin/code/asm/program'
3
-
4
- describe Ronin::Code::ASM::Program do
5
- describe "#arch" do
6
- it "must default to :x86" do
7
- expect(subject.arch).to eq(:x86)
8
- end
9
- end
10
-
11
- context "when :arch is :x86" do
12
- subject { described_class.new(arch: :x86) }
13
-
14
- it { expect(subject.word_size).to eq(4) }
15
-
16
- describe "#stask_base" do
17
- it "must be ebp" do
18
- expect(subject.stack_base.name).to eq(:ebp)
19
- end
20
- end
21
-
22
- describe "#stask_pointer" do
23
- it "must be esp" do
24
- expect(subject.stack_pointer.name).to eq(:esp)
25
- end
26
- end
27
-
28
- describe "#stack_push" do
29
- let(:value) { 0xff }
30
-
31
- before { subject.stack_push(value) }
32
-
33
- it "must add a 'push' instruction with a value" do
34
- expect(subject.instructions[-1].name).to eq(:push)
35
- expect(subject.instructions[-1].operands[0].value).to eq(value)
36
- end
37
- end
38
-
39
- describe "#stack_pop" do
40
- let(:register) { subject.register(:eax) }
41
-
42
- before { subject.stack_pop(register) }
43
-
44
- it "must add a 'pop' instruction with a register" do
45
- expect(subject.instructions[-1].name).to eq(:pop)
46
- expect(subject.instructions[-1].operands[0]).to eq(register)
47
- end
48
- end
49
-
50
- describe "#register_clear" do
51
- let(:name) { :eax }
52
-
53
- before { subject.register_clear(name) }
54
-
55
- it "must add a 'xor' instruction with a registers" do
56
- expect(subject.instructions[-1].name).to eq(:xor)
57
- expect(subject.instructions[-1].operands[0].name).to eq(name)
58
- expect(subject.instructions[-1].operands[1].name).to eq(name)
59
- end
60
- end
61
-
62
- describe "#register_set" do
63
- let(:name) { :eax }
64
- let(:value) { 0xff }
65
-
66
- before { subject.register_set(name,value) }
67
-
68
- it "must add a 'xor' instruction with a registers" do
69
- expect(subject.instructions[-1].name).to eq(:mov)
70
- expect(subject.instructions[-1].operands[0].value).to eq(value)
71
- expect(subject.instructions[-1].operands[1].name).to eq(name)
72
- end
73
- end
74
-
75
- describe "#register_save" do
76
- let(:name) { :eax }
77
-
78
- before { subject.register_save(name) }
79
-
80
- it "must add a 'xor' instruction with a registers" do
81
- expect(subject.instructions[-1].name).to eq(:push)
82
- expect(subject.instructions[-1].operands[0].name).to eq(name)
83
- end
84
- end
85
-
86
- describe "#register_save" do
87
- let(:name) { :eax }
88
-
89
- before { subject.register_load(name) }
90
-
91
- it "must add a 'xor' instruction with a registers" do
92
- expect(subject.instructions[-1].name).to eq(:pop)
93
- expect(subject.instructions[-1].operands[0].name).to eq(name)
94
- end
95
- end
96
-
97
- describe "#interrupt" do
98
- let(:number) { 0x0a }
99
-
100
- before { subject.interrupt(number) }
101
-
102
- it "must add an 'int' instruction with the interrupt number" do
103
- expect(subject.instructions[-1].name).to eq(:int)
104
- expect(subject.instructions[-1].operands[0].value).to eq(number)
105
- end
106
- end
107
-
108
- describe "#syscall" do
109
- before { subject.syscall }
110
-
111
- it "must add an 'int 0x80' instruction" do
112
- expect(subject.instructions[-1].name).to eq(:int)
113
- expect(subject.instructions[-1].operands[0].value).to eq(0x80)
114
- end
115
- end
116
-
117
- context "when :os is :linux" do
118
- subject { described_class.new(arch: :x86, os: :linux) }
119
-
120
- it { expect(subject.syscalls).to_not be_empty }
121
- end
122
-
123
- context "when :os is :freebsd" do
124
- subject { described_class.new(arch: :x86, os: :freebsd) }
125
-
126
- it { expect(subject.syscalls).to_not be_empty }
127
- end
128
- end
129
-
130
- context "when :arch is :amd64" do
131
- subject { described_class.new(arch: :amd64) }
132
-
133
- it { expect(subject.word_size).to eq(8) }
134
-
135
- describe "#syscall" do
136
- before { subject.syscall }
137
-
138
- it "must add a 'syscall' instruction" do
139
- expect(subject.instructions[-1].name).to eq(:syscall)
140
- end
141
- end
142
-
143
- context "when :os is :linux" do
144
- subject { described_class.new(arch: :amd64, os: :linux) }
145
-
146
- it { expect(subject.syscalls).to_not be_empty }
147
- end
148
-
149
- context "when :os is :freebsd" do
150
- subject { described_class.new(arch: :amd64, os: :freebsd) }
151
-
152
- it { expect(subject.syscalls).to_not be_empty }
153
- end
154
- end
155
-
156
- describe "#register?" do
157
- it "must return true for existing registers" do
158
- expect(subject.register?(:eax)).to be(true)
159
- end
160
-
161
- it "must return false for unknown registers" do
162
- expect(subject.register?(:foo)).to be(false)
163
- end
164
- end
165
-
166
- describe "#register" do
167
- it "must return a Register" do
168
- expect(subject.register(:eax)).to be_kind_of(Ronin::Code::ASM::Register)
169
- end
170
-
171
- it "must allocate the register" do
172
- subject.register(:ebx)
173
-
174
- expect(subject.allocated_registers).to include(:ebx)
175
- end
176
-
177
- context "when given an unknown register name" do
178
- it "must raise an ArgumentError" do
179
- expect {
180
- subject.register(:foo)
181
- }.to raise_error(ArgumentError)
182
- end
183
- end
184
- end
185
-
186
- describe "#instruction" do
187
- it "must return an Instruction" do
188
- expect(subject.instruction(:hlt)).to be_kind_of(Ronin::Code::ASM::Instruction)
189
- end
190
-
191
- it "must append the new Instruction" do
192
- subject.instruction(:push, 1)
193
-
194
- expect(subject.instructions.last.name).to eq(:push)
195
- end
196
- end
197
-
198
- describe "#byte" do
199
- it "must return a ImmedateOperand" do
200
- expect(subject.byte(1)).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
201
- end
202
-
203
- it "must have width of 1" do
204
- expect(subject.byte(1).width).to eq(1)
205
- end
206
-
207
- context "when given a MemoryOperand" do
208
- let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
209
- let(:memory_operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
210
-
211
- it "must return a MemoryOperand" do
212
- expect(subject.byte(memory_operand)).to be_kind_of(
213
- Ronin::Code::ASM::MemoryOperand
214
- )
215
- end
216
-
217
- it "must have a width of 1" do
218
- expect(subject.byte(memory_operand).width).to eq(1)
219
- end
220
- end
221
- end
222
-
223
- describe "#word" do
224
- it "must return a Ronin::Code::ASM::ImmediateOperand" do
225
- expect(subject.word(1)).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
226
- end
227
-
228
- it "must have width of 2" do
229
- expect(subject.word(1).width).to eq(2)
230
- end
231
-
232
- context "when given a MemoryOperand" do
233
- let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
234
- let(:memory_operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
235
-
236
- it "must return a MemoryOperand" do
237
- expect(subject.word(memory_operand)).to be_kind_of(
238
- Ronin::Code::ASM::MemoryOperand
239
- )
240
- end
241
-
242
- it "must have a width of 2" do
243
- expect(subject.word(memory_operand).width).to eq(2)
244
- end
245
- end
246
- end
247
-
248
- describe "#dword" do
249
- it "must return a Ronin::Code::ASM::ImmediateOperand" do
250
- expect(subject.dword(1)).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
251
- end
252
-
253
- it "must have width of 4" do
254
- expect(subject.dword(1).width).to eq(4)
255
- end
256
-
257
- context "when given a MemoryOperand" do
258
- let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
259
- let(:memory_operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
260
-
261
- it "must return a MemoryOperand" do
262
- expect(subject.dword(memory_operand)).to be_kind_of(
263
- Ronin::Code::ASM::MemoryOperand
264
- )
265
- end
266
-
267
- it "must have a width of 4" do
268
- expect(subject.dword(memory_operand).width).to eq(4)
269
- end
270
- end
271
- end
272
-
273
- describe "#qword" do
274
- it "must return a Ronin::Code::ASM::ImmediateOperand" do
275
- expect(subject.qword(1)).to be_kind_of(Ronin::Code::ASM::ImmediateOperand)
276
- end
277
-
278
- it "must have width of 8" do
279
- expect(subject.qword(1).width).to eq(8)
280
- end
281
-
282
- context "when given a MemoryOperand" do
283
- let(:register) { Ronin::Code::ASM::Register.new(:eax, 4) }
284
- let(:memory_operand) { Ronin::Code::ASM::MemoryOperand.new(register) }
285
-
286
- it "must return a MemoryOperand" do
287
- expect(subject.qword(memory_operand)).to be_kind_of(
288
- Ronin::Code::ASM::MemoryOperand
289
- )
290
- end
291
-
292
- it "must have a width of 8" do
293
- expect(subject.qword(memory_operand).width).to eq(8)
294
- end
295
- end
296
- end
297
-
298
- describe "#label" do
299
- let(:name) { :_start }
300
-
301
- it "must return the label name" do
302
- label = subject.label(name) { }
303
-
304
- expect(label).to eq(name)
305
- end
306
-
307
- it "must add the label to the instructions" do
308
- subject.label(name) { }
309
-
310
- expect(subject.instructions.last).to eq(name)
311
- end
312
-
313
- it "must accept a block" do
314
- subject.label(name) { push 2 }
315
-
316
- expect(subject.instructions[-1].name).to eq(:push)
317
- expect(subject.instructions[-2]).to eq(name)
318
- end
319
- end
320
-
321
- describe "#method_missing" do
322
- context "when called without a block" do
323
- it "must add a new instruction" do
324
- subject.pop
325
-
326
- expect(subject.instructions[-1].name).to eq(:pop)
327
- end
328
- end
329
-
330
- context "when called with one argument and a block" do
331
- it "must add a new label" do
332
- subject._loop { mov eax, ebx }
333
-
334
- expect(subject.instructions[-2]).to eq(:_loop)
335
- expect(subject.instructions[-1].name).to eq(:mov)
336
- end
337
- end
338
- end
339
-
340
- describe "#to_asm" do
341
- subject do
342
- described_class.new do
343
- push eax
344
- push ebx
345
- push ecx
346
-
347
- mov ebx, eax
348
- mov ebx, eax+0
349
- mov ebx, eax+4
350
- mov ebx, eax+esi
351
- mov ebx, eax+(esi*4)
352
- mov ebx, eax+(esi*4)+10
353
- end
354
- end
355
-
356
- it "must convert the program to Intel syntax" do
357
- expect(subject.to_asm).to eq([
358
- "BITS 32",
359
- "section .text",
360
- "_start:",
361
- "\tpush\teax",
362
- "\tpush\tebx",
363
- "\tpush\tecx",
364
- "\tmov\tebx,\teax",
365
- "\tmov\tebx,\t[eax]",
366
- "\tmov\tebx,\t[eax+0x4]",
367
- "\tmov\tebx,\t[eax+esi]",
368
- "\tmov\tebx,\t[eax+esi*0x4]",
369
- "\tmov\tebx,\t[eax+esi*0x4+0xa]",
370
- ""
371
- ].join($/))
372
- end
373
-
374
- context "when given :att" do
375
- it "must convert the program to ATT syntax" do
376
- expect(subject.to_asm(:att)).to eq([
377
- ".code32",
378
- ".text",
379
- "_start:",
380
- "\tpushl\t%eax",
381
- "\tpushl\t%ebx",
382
- "\tpushl\t%ecx",
383
- "\tmovl\t%eax,\t%ebx",
384
- "\tmovl\t(%eax),\t%ebx",
385
- "\tmovl\t0x4(%eax),\t%ebx",
386
- "\tmovl\t(%eax,%esi),\t%ebx",
387
- "\tmovl\t(%eax,%esi,4),\t%ebx",
388
- "\tmovl\t0xa(%eax,%esi,4),\t%ebx",
389
- ""
390
- ].join($/))
391
- end
392
- end
393
- end
394
-
395
- describe "#assemble", integration: true do
396
- subject do
397
- described_class.new do
398
- push eax
399
- push ebx
400
- push ecx
401
-
402
- mov ebx, eax
403
- mov ebx, eax+0
404
- mov ebx, eax+4
405
- mov ebx, eax+esi
406
- mov ebx, eax+(esi*4)
407
- mov ebx, eax+(esi*4)+10
408
- end
409
- end
410
-
411
- let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
412
-
413
- before { subject.assemble(output) }
414
-
415
- it "must write to the output file" do
416
- expect(File.size(output)).to be > 0
417
- end
418
-
419
- context "when syntax: :intel is given" do
420
- let(:output) { Tempfile.new(['ronin-asm', '.o']).path }
421
-
422
- before { subject.assemble(output, syntax: :intel) }
423
-
424
- it "must write to the output file" do
425
- expect(File.size(output)).to be > 0
426
- end
427
- end
428
-
429
- context "when syntax is unknown" do
430
- let(:syntax) { :foo }
431
-
432
- it do
433
- expect {
434
- subject.assemble(output, syntax: syntax)
435
- }.to raise_error(ArgumentError,"unknown ASM syntax: #{syntax.inspect}")
436
- end
437
- end
438
- end
439
- end
@@ -1,112 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'ronin/code/asm/register'
4
-
5
- describe Ronin::Code::ASM::Register do
6
- let(:register) { described_class.new(:eax, 4) }
7
-
8
- subject { register }
9
-
10
- describe "#+" do
11
- context "when given an Ronin::Code::ASM::MemoryOperand" do
12
- let(:operand) do
13
- Ronin::Code::ASM::MemoryOperand.new(nil,10,register,2)
14
- end
15
-
16
- subject { register + operand }
17
-
18
- it { expect(subject).to be_kind_of(Ronin::Code::ASM::MemoryOperand) }
19
-
20
- it "must set the base" do
21
- expect(subject.base).to eq(register)
22
- end
23
-
24
- it "must preserve the offset, index and scale" do
25
- expect(subject.offset).to eq(operand.offset)
26
- expect(subject.index).to eq(operand.index)
27
- expect(subject.scale).to eq(operand.scale)
28
- end
29
- end
30
-
31
- context "when given a Register" do
32
- subject { register + register }
33
-
34
- it { expect(subject).to be_kind_of(Ronin::Code::ASM::MemoryOperand) }
35
-
36
- it "must set the base" do
37
- expect(subject.base).to eq(register)
38
- end
39
-
40
- it { expect(subject.offset).to eq(0) }
41
-
42
- it "must set the index" do
43
- expect(subject.index).to eq(register)
44
- end
45
- end
46
-
47
- context "when given an Integer" do
48
- let(:offset) { 10 }
49
-
50
- subject { register + offset }
51
-
52
- it { expect(subject).to be_kind_of(Ronin::Code::ASM::MemoryOperand) }
53
-
54
- it "must set the base" do
55
- expect(subject.base).to eq(register)
56
- end
57
-
58
- it "must set the offset" do
59
- expect(subject.offset).to eq(offset)
60
- end
61
- end
62
-
63
- context "otherwise" do
64
- it "must raise a TypeError" do
65
- expect {
66
- register + Object.new
67
- }.to raise_error(TypeError)
68
- end
69
- end
70
- end
71
-
72
- describe "#-" do
73
- let(:offset) { 10 }
74
-
75
- subject { register - offset }
76
-
77
- it { expect(subject).to be_kind_of(Ronin::Code::ASM::MemoryOperand) }
78
-
79
- it "must set the base" do
80
- expect(subject.base).to eq(register)
81
- end
82
-
83
- it "must set a negative offset" do
84
- expect(subject.offset).to eq(-offset)
85
- end
86
- end
87
-
88
- describe "#*" do
89
- let(:scale) { 2 }
90
-
91
- subject { register * scale }
92
-
93
- it { expect(subject).to be_kind_of(Ronin::Code::ASM::MemoryOperand) }
94
-
95
- it { expect(subject.base).to be_nil }
96
- it { expect(subject.offset).to eq(0) }
97
-
98
- it "must set the index" do
99
- expect(subject.index).to eq(register)
100
- end
101
-
102
- it "must set the scale" do
103
- expect(subject.scale).to eq(scale)
104
- end
105
- end
106
-
107
- describe "#to_s" do
108
- it "must return the register name" do
109
- expect(subject.to_s).to eq(subject.name.to_s)
110
- end
111
- end
112
- end