ffi-clang 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +4 -0
- data/.travis.yml +20 -9
- data/Gemfile +10 -1
- data/README.md +1 -1
- data/Rakefile +9 -9
- data/examples/docs.cpp +25 -0
- data/examples/docs.rb +31 -0
- data/ffi-clang.gemspec +1 -1
- data/lib/ffi/clang.rb +16 -13
- data/lib/ffi/clang/clang_version.rb +29 -0
- data/lib/ffi/clang/code_completion.rb +1 -1
- data/lib/ffi/clang/comment.rb +8 -4
- data/lib/ffi/clang/compilation_database.rb +1 -1
- data/lib/ffi/clang/cursor.rb +42 -15
- data/lib/ffi/clang/diagnostic.rb +6 -2
- data/lib/ffi/clang/file.rb +6 -9
- data/lib/ffi/clang/index.rb +4 -4
- data/lib/ffi/clang/lib.rb +1 -1
- data/lib/ffi/clang/lib/{utils.rb → clang_version.rb} +1 -1
- data/lib/ffi/clang/lib/code_completion.rb +2 -3
- data/lib/ffi/clang/lib/comment.rb +0 -2
- data/lib/ffi/clang/lib/compilation_database.rb +6 -9
- data/lib/ffi/clang/lib/cursor.rb +10 -18
- data/lib/ffi/clang/lib/diagnostic.rb +4 -4
- data/lib/ffi/clang/lib/file.rb +4 -6
- data/lib/ffi/clang/lib/inclusions.rb +2 -2
- data/lib/ffi/clang/lib/index.rb +0 -2
- data/lib/ffi/clang/lib/source_location.rb +6 -8
- data/lib/ffi/clang/lib/source_range.rb +1 -1
- data/lib/ffi/clang/lib/string.rb +0 -2
- data/lib/ffi/clang/lib/translation_unit.rb +2 -2
- data/lib/ffi/clang/lib/type.rb +8 -17
- data/lib/ffi/clang/source_location.rb +2 -2
- data/lib/ffi/clang/source_range.rb +16 -3
- data/lib/ffi/clang/token.rb +4 -4
- data/lib/ffi/clang/translation_unit.rb +5 -5
- data/lib/ffi/clang/type.rb +0 -14
- data/lib/ffi/clang/version.rb +2 -2
- data/spec/{clang → ffi/clang}/code_completion_spec.rb +6 -6
- data/spec/{clang → ffi/clang}/comment_spec.rb +22 -39
- data/spec/{clang → ffi/clang}/compilation_database_spec.rb +8 -10
- data/spec/{clang → ffi/clang}/cursor_spec.rb +89 -97
- data/spec/{clang → ffi/clang}/diagnostic_spec.rb +9 -10
- data/spec/{clang → ffi/clang}/file_spec.rb +3 -5
- data/spec/{fixtures → ffi/clang/fixtures}/a.c +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/canonical.c +0 -0
- data/spec/ffi/clang/fixtures/class.cpp +8 -0
- data/spec/{fixtures → ffi/clang/fixtures}/compile_commands.json +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/completion.cxx +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/docs.c +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/docs.cc +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/docs.h +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/list.c +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/location1.c +0 -0
- data/spec/ffi/clang/fixtures/simple.ast +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/simple.c +0 -0
- data/spec/{fixtures → ffi/clang/fixtures}/test.cxx +0 -0
- data/spec/{clang → ffi/clang}/index_spec.rb +17 -14
- data/spec/{clang → ffi/clang}/source_location_spec.rb +12 -14
- data/spec/{clang → ffi/clang}/source_range_spec.rb +12 -14
- data/spec/{clang → ffi/clang}/token_spec.rb +6 -8
- data/spec/{clang → ffi/clang}/translation_unit_spec.rb +28 -30
- data/spec/{clang → ffi/clang}/type_spec.rb +17 -33
- data/spec/ffi/clang/version_spec.rb +28 -0
- data/spec/spec_helper.rb +11 -37
- metadata +61 -55
- data/lib/ffi/clang/utils.rb +0 -89
- data/spec/clang/utils_spec.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3fba953ec692d348f92786e6892450d93011103
|
4
|
+
data.tar.gz: 4e1b34caa60d2d0a577471d419170f998e1d5451
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b90f7d9d97dca48869b045e76c3f1c57e6efc390a67c0a07cb95527a85c735f70f22cbf76e9a0745a3233fa9cc388c42efdb1ec0c042583c413335801f376132
|
7
|
+
data.tar.gz: ea69e1a70cb738ae85cbfd86a5de317724054926cdbc2e2bab50aa154497d53104ead7af30d7afb8e84c750f5e40952b2cde388b19f63621c48e2b975adb8239
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -5,15 +5,26 @@ before_install:
|
|
5
5
|
- export PATH=/usr/lib/llvm-${LLVM_VERSION}/bin:$PATH
|
6
6
|
matrix:
|
7
7
|
include:
|
8
|
-
|
9
|
-
- &libclang-36
|
10
|
-
addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-3.6], packages: [libclang-3.6-dev, clang-3.6]}}
|
8
|
+
- addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-3.6], packages: [libclang-3.6-dev, clang-3.6]}}
|
11
9
|
env: LLVM_VERSION=3.6
|
12
|
-
rvm: "2.
|
13
|
-
# A second build with the same configuration but using ruby 2.2.4
|
14
|
-
- <<: *libclang-36
|
15
|
-
rvm: "2.2.4"
|
16
|
-
# Other builds on other versions of LLVM, all using ruby 2.3.0
|
10
|
+
rvm: "2.4.0"
|
17
11
|
- addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-3.7], packages: [libclang-3.7-dev, clang-3.7]}}
|
18
12
|
env: LLVM_VERSION=3.7
|
19
|
-
rvm: "2.
|
13
|
+
rvm: "2.4.0"
|
14
|
+
# The default build:
|
15
|
+
- &libclang-38
|
16
|
+
addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-3.8], packages: [libclang-3.8-dev, clang-3.8]}}
|
17
|
+
env: LLVM_VERSION=3.8
|
18
|
+
rvm: "2.4.0"
|
19
|
+
# A second build with the same configuration but using ruby 2.2.4
|
20
|
+
- <<: *libclang-38
|
21
|
+
rvm: "2.3.3"
|
22
|
+
- addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-3.9], packages: [libclang-3.9-dev, clang-3.9]}}
|
23
|
+
env: LLVM_VERSION=3.9
|
24
|
+
rvm: "2.4.0"
|
25
|
+
- addons: {apt: {sources: [ubuntu-toolchain-r-test, llvm-toolchain-precise-4.0], packages: [libclang-4.0-dev, clang-4.0]}}
|
26
|
+
env: LLVM_VERSION=4.0
|
27
|
+
rvm: "2.4.0"
|
28
|
+
allow_failures:
|
29
|
+
- env: LLVM_VERSION=4.0
|
30
|
+
rvm: "2.4.0"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# FFI::Clang
|
2
2
|
|
3
|
-
A light-weight wrapper for Ruby exposing [libclang][1].
|
3
|
+
A light-weight wrapper for Ruby exposing [libclang][1]. Works for libclang v3.4+.
|
4
4
|
|
5
5
|
[![Build Status](https://secure.travis-ci.org/ioquatix/ffi-clang.svg)](http://travis-ci.org/ioquatix/ffi-clang)
|
6
6
|
[![Code Climate](https://codeclimate.com/github/ioquatix/ffi-clang.svg)](https://codeclimate.com/github/ioquatix/ffi-clang)
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
task
|
7
|
-
|
8
|
-
|
9
|
-
RSpec::Core::RakeTask.new do |t|
|
10
|
-
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
11
|
-
# Put spec opts in a file named .rspec in root
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
5
|
+
begin
|
6
|
+
require('simplecov/version')
|
7
|
+
task.rspec_opts = %w{--require simplecov} if ENV['COVERAGE']
|
8
|
+
rescue LoadError
|
9
|
+
end
|
12
10
|
end
|
11
|
+
|
12
|
+
task :default => :spec
|
data/examples/docs.cpp
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
/** A test class which does nothing.
|
3
|
+
|
4
|
+
This is used by `main`.
|
5
|
+
*/
|
6
|
+
template<typename T>
|
7
|
+
class Test {};
|
8
|
+
|
9
|
+
/// This is a specialization for integers.
|
10
|
+
template<>
|
11
|
+
class Test<int> {
|
12
|
+
public:
|
13
|
+
/// The number of times it has been incremented.
|
14
|
+
int count;
|
15
|
+
|
16
|
+
};
|
17
|
+
|
18
|
+
/// This always fails.
|
19
|
+
/// @param argc The number of items in `argv`. At least 1.
|
20
|
+
/// @param argv The command line arguments, with argv[0] being the command used to execute this program.
|
21
|
+
int main(int argc, char ** argv) {
|
22
|
+
Test<int> test;
|
23
|
+
|
24
|
+
return 1;
|
25
|
+
}
|
data/examples/docs.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
require 'ffi/clang'
|
5
|
+
|
6
|
+
index = FFI::Clang::Index.new
|
7
|
+
|
8
|
+
# clang -Xclang -ast-dump -fsyntax-only ./examples/docs.cpp
|
9
|
+
|
10
|
+
def title(declaration)
|
11
|
+
puts ["Symbol:", Rainbow(declaration.spelling).blue.bright, "Type:", Rainbow(declaration.type.spelling).green, declaration.kind.to_s].join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
ARGV.each do |path|
|
15
|
+
translation_unit = index.parse_translation_unit(path)
|
16
|
+
|
17
|
+
declarations = translation_unit.cursor.select(&:declaration?)
|
18
|
+
|
19
|
+
declarations.each do |declaration|
|
20
|
+
title declaration
|
21
|
+
|
22
|
+
if location = declaration.location
|
23
|
+
puts "Defined at #{location.file}:#{location.line}"
|
24
|
+
end
|
25
|
+
|
26
|
+
if comment = declaration.comment
|
27
|
+
# puts Rainbow(comment.inspect).gray
|
28
|
+
puts Rainbow(comment.text)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/ffi-clang.gemspec
CHANGED
@@ -21,6 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency "ffi"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
-
spec.add_development_dependency "rspec", "~> 3.
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.4.0"
|
25
25
|
spec.add_development_dependency "rake"
|
26
26
|
end
|
data/lib/ffi/clang.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
22
|
require 'ffi'
|
23
|
-
require
|
23
|
+
require 'rbconfig'
|
24
24
|
|
25
25
|
module FFI::Clang
|
26
26
|
class Error < StandardError
|
@@ -42,15 +42,18 @@ module FFI::Clang
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
# Load the shared object:
|
46
|
+
require_relative 'clang/lib'
|
47
|
+
|
48
|
+
# Wrappers around C functionality:
|
49
|
+
require_relative 'clang/clang_version'
|
50
|
+
require_relative 'clang/index'
|
51
|
+
require_relative 'clang/translation_unit'
|
52
|
+
require_relative 'clang/diagnostic'
|
53
|
+
require_relative 'clang/cursor'
|
54
|
+
require_relative 'clang/source_location'
|
55
|
+
require_relative 'clang/source_range'
|
56
|
+
require_relative 'clang/unsaved_file'
|
57
|
+
require_relative 'clang/token'
|
58
|
+
require_relative 'clang/code_completion'
|
59
|
+
require_relative 'clang/compilation_database'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'lib/clang_version'
|
22
|
+
|
23
|
+
module FFI
|
24
|
+
module Clang
|
25
|
+
def self.clang_version_string
|
26
|
+
Lib.extract_string Lib.get_clang_version
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/ffi/clang/comment.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
# Copyright, 2013, by Carlos Martín Nieto <cmn@dwim.me>
|
3
2
|
#
|
4
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -19,9 +18,9 @@
|
|
19
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
19
|
# THE SOFTWARE.
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
require_relative 'lib/cursor'
|
22
|
+
require_relative 'lib/comment'
|
23
|
+
require_relative 'source_location'
|
25
24
|
|
26
25
|
module FFI
|
27
26
|
module Clang
|
@@ -205,6 +204,7 @@ module FFI
|
|
205
204
|
def text
|
206
205
|
self.map(&:text).join("")
|
207
206
|
end
|
207
|
+
|
208
208
|
alias_method :comment, :text
|
209
209
|
|
210
210
|
def valid_index?
|
@@ -273,6 +273,10 @@ module FFI
|
|
273
273
|
def to_xml
|
274
274
|
Lib.extract_string Lib.full_comment_get_as_xml(@comment)
|
275
275
|
end
|
276
|
+
|
277
|
+
def text
|
278
|
+
self.children.collect{|child| child.text.strip}.join("\n")
|
279
|
+
end
|
276
280
|
end
|
277
281
|
end
|
278
282
|
end
|
data/lib/ffi/clang/cursor.rb
CHANGED
@@ -20,11 +20,12 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
require_relative 'lib/cursor'
|
24
|
+
require_relative 'lib/code_completion'
|
25
|
+
|
26
|
+
require_relative 'source_location'
|
27
|
+
require_relative 'comment'
|
28
|
+
require_relative 'type'
|
28
29
|
|
29
30
|
module FFI
|
30
31
|
module Clang
|
@@ -238,18 +239,10 @@ module FFI
|
|
238
239
|
Lib.get_language @cursor
|
239
240
|
end
|
240
241
|
|
241
|
-
def translation_unit
|
242
|
-
@translation_unit
|
243
|
-
end
|
244
|
-
|
245
242
|
def num_args
|
246
243
|
Lib.get_num_args @cursor
|
247
244
|
end
|
248
245
|
|
249
|
-
def variadic?
|
250
|
-
Lib.is_variadic(@cursor) != 0
|
251
|
-
end
|
252
|
-
|
253
246
|
def visit_children(&block)
|
254
247
|
adapter = Proc.new do |cxcursor, parent_cursor, unused|
|
255
248
|
block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
|
@@ -348,12 +341,46 @@ module FFI
|
|
348
341
|
Lib.cursor_get_num_arguments(@cursor)
|
349
342
|
end
|
350
343
|
|
351
|
-
attr_reader :cursor
|
352
|
-
|
353
344
|
def ==(other)
|
354
345
|
Lib.are_equal(@cursor, other.cursor) != 0
|
355
346
|
end
|
356
347
|
|
348
|
+
def find_all(*kinds)
|
349
|
+
filter do |child, parent|
|
350
|
+
kinds.include?(child.kind)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def find_first(*kinds)
|
355
|
+
find_all(*kinds).first
|
356
|
+
end
|
357
|
+
|
358
|
+
def filter
|
359
|
+
return to_enum(:select) unless block_given?
|
360
|
+
|
361
|
+
matching = []
|
362
|
+
|
363
|
+
self.visit_children do |child, parent|
|
364
|
+
if yield(child, parent)
|
365
|
+
matching << child
|
366
|
+
end
|
367
|
+
|
368
|
+
:recurse
|
369
|
+
end
|
370
|
+
|
371
|
+
return matching
|
372
|
+
end
|
373
|
+
|
374
|
+
def select
|
375
|
+
filter do |child, parent|
|
376
|
+
yield(child)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def to_a
|
381
|
+
filter.collect{|child, parent| child}
|
382
|
+
end
|
383
|
+
|
357
384
|
class PlatformAvailability < AutoPointer
|
358
385
|
def initialize(memory_pointer)
|
359
386
|
pointer = FFI::Pointer.new(memory_pointer)
|
data/lib/ffi/clang/diagnostic.rb
CHANGED
@@ -20,8 +20,8 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
require_relative 'lib/diagnostic'
|
24
|
+
require_relative 'source_range'
|
25
25
|
|
26
26
|
module FFI
|
27
27
|
module Clang
|
@@ -99,6 +99,10 @@ module FFI
|
|
99
99
|
Lib.get_diagnostic_category(self)
|
100
100
|
end
|
101
101
|
|
102
|
+
def inspect
|
103
|
+
"#{self.location}: #{self.format}"
|
104
|
+
end
|
105
|
+
|
102
106
|
private
|
103
107
|
|
104
108
|
def display_opts(opts)
|
data/lib/ffi/clang/file.rb
CHANGED
@@ -18,23 +18,20 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
|
22
|
-
require 'ffi/clang/utils'
|
21
|
+
require_relative 'lib/file'
|
23
22
|
|
24
23
|
module FFI
|
25
24
|
module Clang
|
26
25
|
class File < Pointer
|
27
26
|
attr_reader :translation_unit
|
28
27
|
|
29
|
-
def initialize(pointer,
|
28
|
+
def initialize(pointer, translation_unit)
|
30
29
|
super pointer
|
31
|
-
@translation_unit =
|
30
|
+
@translation_unit = translation_unit
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@unique_id = Lib::CXFileUniqueID.new(pointer)
|
37
|
-
end
|
32
|
+
pointer = MemoryPointer.new(Lib::CXFileUniqueID)
|
33
|
+
Lib.get_file_unique_id(self, pointer)
|
34
|
+
@unique_id = Lib::CXFileUniqueID.new(pointer)
|
38
35
|
end
|
39
36
|
|
40
37
|
def to_s
|
data/lib/ffi/clang/index.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
-
|
23
|
+
require_relative 'lib/index'
|
24
24
|
|
25
25
|
module FFI
|
26
26
|
module Clang
|
@@ -45,9 +45,9 @@ module FFI
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def create_translation_unit(ast_filename)
|
48
|
-
|
49
|
-
raise Error, "error parsing #{ast_filename.inspect}" if
|
50
|
-
TranslationUnit.new
|
48
|
+
translation_unit_pointer = Lib.create_translation_unit(self, ast_filename)
|
49
|
+
raise Error, "error parsing #{ast_filename.inspect}" if translation_unit_pointer.null?
|
50
|
+
TranslationUnit.new translation_unit_pointer, self
|
51
51
|
end
|
52
52
|
|
53
53
|
private
|