puppet-debugger 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.gitlab-ci.yml +30 -13
- data/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +11 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +9 -0
- data/DEVELOPMENT.md +6 -1
- data/Gemfile +14 -12
- data/Plugin_development.md +304 -0
- data/README.md +4 -7
- data/Rakefile +6 -5
- data/bin/pdb +1 -0
- data/lib/awesome_print/ext/awesome_puppet.rb +1 -0
- data/lib/plugins/puppet-debugger/input_responders/benchmark.rb +40 -0
- data/lib/plugins/puppet-debugger/input_responders/classes.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/classification.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/commands.rb +95 -0
- data/lib/plugins/puppet-debugger/input_responders/datatypes.rb +17 -0
- data/lib/plugins/puppet-debugger/input_responders/environment.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/exit.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/facterdb_filter.rb +16 -0
- data/lib/plugins/puppet-debugger/input_responders/facts.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/functions.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/help.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/krt.rb +14 -0
- data/lib/{puppet-debugger/support → plugins/puppet-debugger/input_responders}/play.rb +37 -26
- data/lib/plugins/puppet-debugger/input_responders/reset.rb +21 -0
- data/lib/plugins/puppet-debugger/input_responders/resources.rb +22 -0
- data/lib/plugins/puppet-debugger/input_responders/set.rb +55 -0
- data/lib/plugins/puppet-debugger/input_responders/types.rb +35 -0
- data/lib/plugins/puppet-debugger/input_responders/vars.rb +18 -0
- data/lib/plugins/puppet-debugger/input_responders/whereami.rb +29 -0
- data/lib/puppet-debugger.rb +12 -1
- data/lib/puppet-debugger/cli.rb +38 -22
- data/lib/puppet-debugger/code/code_file.rb +16 -15
- data/lib/puppet-debugger/code/code_range.rb +1 -0
- data/lib/puppet-debugger/code/loc.rb +1 -0
- data/lib/puppet-debugger/debugger_code.rb +1 -0
- data/lib/puppet-debugger/hooks.rb +174 -0
- data/lib/puppet-debugger/input_responder_plugin.rb +45 -0
- data/lib/puppet-debugger/plugin_test_helper.rb +44 -0
- data/lib/puppet-debugger/support.rb +13 -9
- data/lib/puppet-debugger/support/compiler.rb +1 -0
- data/lib/puppet-debugger/support/environment.rb +2 -0
- data/lib/puppet-debugger/support/errors.rb +9 -0
- data/lib/puppet-debugger/support/facts.rb +2 -1
- data/lib/puppet-debugger/support/functions.rb +3 -1
- data/lib/puppet-debugger/support/loader.rb +2 -0
- data/lib/puppet-debugger/support/node.rb +1 -0
- data/lib/puppet-debugger/support/scope.rb +1 -0
- data/lib/puppet/application/debugger.rb +1 -0
- data/lib/version.rb +2 -1
- data/puppet-debugger.gemspec +20 -15
- data/run_container_test.sh +1 -1
- data/spec/environment_spec.rb +2 -1
- data/spec/facts_spec.rb +1 -0
- data/spec/hooks_spec.rb +341 -0
- data/spec/input_responder_plugin_spec.rb +45 -0
- data/spec/input_responders/help_spec.rb +17 -0
- data/spec/input_responders/krt_spec.rb +12 -0
- data/spec/input_responders/play_spec.rb +160 -0
- data/spec/pdb_spec.rb +1 -0
- data/spec/puppet/application/debugger_spec.rb +1 -2
- data/spec/puppet_debugger_spec.rb +49 -88
- data/spec/remote_node_spec.rb +3 -2
- data/spec/spec_helper.rb +7 -0
- data/spec/support_spec.rb +5 -116
- data/test_matrix.rb +2 -0
- metadata +65 -12
- data/Gemfile.lock +0 -95
- data/lib/puppet-debugger/support/input_responders.rb +0 -191
data/README.md
CHANGED
@@ -23,16 +23,10 @@
|
|
23
23
|
- [Setting the puppet log level](#setting-the-puppet-log-level)
|
24
24
|
- [Remote nodes](#remote-nodes)
|
25
25
|
- [Setup](#setup)
|
26
|
-
- [Usage](#usage-1)
|
27
|
-
- [Command line:](#command-line)
|
28
|
-
- [From repl session:](#from-repl-session)
|
29
|
-
- [Auto Complete](#auto-complete)
|
30
|
-
- [Playback support](#playback-support)
|
31
|
-
- [Troubleshooting](#troubleshooting)
|
32
|
-
- [Copyright](#copyright)
|
33
26
|
|
34
27
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
35
28
|
[![Gem Version](https://badge.fury.io/rb/puppet-debugger.svg)](https://badge.fury.io/rb/puppet-debugger)
|
29
|
+
|
36
30
|
# puppet-debugger
|
37
31
|
|
38
32
|
A interactive command line tool for evaluating and debugging the puppet language.
|
@@ -273,6 +267,9 @@ https://www.puppet-debugger.com/play?content=vars
|
|
273
267
|
Please note the web based debugger only contains a minimal amount of puppet modules. So its likely
|
274
268
|
that your code may not work if using third party modules. This may change in the future though.
|
275
269
|
|
270
|
+
## Development
|
271
|
+
* [Plugin Development Guide](Plugin_development.md)
|
272
|
+
|
276
273
|
## Troubleshooting
|
277
274
|
Please file an issue so we can track bugs.
|
278
275
|
|
data/Rakefile
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rubygems'
|
4
5
|
require 'bundler'
|
5
|
-
require
|
6
|
-
require
|
6
|
+
require 'bundler/gem_tasks'
|
7
|
+
require 'rake/testtask'
|
7
8
|
|
8
9
|
begin
|
9
10
|
Bundler.setup(:default, :development, :test)
|
10
11
|
rescue Bundler::BundlerError => e
|
11
12
|
$stderr.puts e.message
|
12
|
-
$stderr.puts
|
13
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
13
14
|
exit e.status_code
|
14
15
|
end
|
15
16
|
require 'rake'
|
@@ -20,11 +21,11 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
20
21
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
21
22
|
end
|
22
23
|
|
23
|
-
task :
|
24
|
+
task default: :spec
|
24
25
|
|
25
26
|
require 'rdoc/task'
|
26
27
|
Rake::RDocTask.new do |rdoc|
|
27
|
-
version = File.exist?('VERSION') ? File.read('VERSION') :
|
28
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ''
|
28
29
|
rdoc.rdoc_dir = 'rdoc'
|
29
30
|
rdoc.title = "puppet-debugger #{version}"
|
30
31
|
rdoc.rdoc_files.include('README*')
|
data/bin/pdb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'puppet-debugger/input_responder_plugin'
|
3
|
+
module PuppetDebugger
|
4
|
+
module InputResponders
|
5
|
+
class Benchmark < InputResponderPlugin
|
6
|
+
COMMAND_WORDS = %w(benchmark bm)
|
7
|
+
SUMMARY = 'Benchmark your Puppet code.'
|
8
|
+
COMMAND_GROUP = :tools
|
9
|
+
|
10
|
+
def run(args = [])
|
11
|
+
if args.count > 0
|
12
|
+
enable(false)
|
13
|
+
out = debugger.handle_input(args.first)
|
14
|
+
disable
|
15
|
+
out
|
16
|
+
else
|
17
|
+
status = debugger.bench ? disable : enable(true)
|
18
|
+
"Benchmark Mode #{status}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def disable
|
25
|
+
debugger.bench = false
|
26
|
+
debugger.extra_prompt = ''
|
27
|
+
'Off'
|
28
|
+
end
|
29
|
+
|
30
|
+
def enable(show_status = false)
|
31
|
+
debugger.bench = true
|
32
|
+
if show_status
|
33
|
+
debugger.extra_prompt = 'BM'
|
34
|
+
'On'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Classes < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(classes)
|
6
|
+
SUMMARY = 'List all the classes current in the catalog.'
|
7
|
+
COMMAND_GROUP = :scope
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
debugger.scope.compiler.catalog.classes.ai
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Classification < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(classification)
|
6
|
+
SUMMARY = 'Show the classification details of the node.'
|
7
|
+
COMMAND_GROUP = :node
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
debugger.node.classes.ai
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Commands < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(commands)
|
6
|
+
SUMMARY = 'List all available commands, aka. this screen'
|
7
|
+
COMMAND_GROUP = :help
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
commands_list
|
11
|
+
end
|
12
|
+
|
13
|
+
def commands_list
|
14
|
+
unless @commands_list
|
15
|
+
@commands_list = ''
|
16
|
+
command_groups.sort.each do |command_group|
|
17
|
+
group_name = command_group[0].to_s.capitalize.bold
|
18
|
+
commands = command_group[1]
|
19
|
+
@commands_list += ' ' + group_name + "\n"
|
20
|
+
commands.sort.each do |command|
|
21
|
+
command_name = command[0]
|
22
|
+
command_description = command[1]
|
23
|
+
@commands_list += format(" %-20s %s\n", command_name, command_description)
|
24
|
+
end
|
25
|
+
@commands_list += "\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@commands_list
|
29
|
+
end
|
30
|
+
|
31
|
+
def command_groups
|
32
|
+
unless @command_groups
|
33
|
+
@command_groups = {}
|
34
|
+
self.class.command_output.each do | item|
|
35
|
+
if @command_groups[item[:group]]
|
36
|
+
@command_groups[item[:group]].merge!({ item[:words].first => item[:summary] })
|
37
|
+
else
|
38
|
+
@command_groups[item[:group]] = { item[:words].first => item[:summary] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@command_groups
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.command_list_regex
|
46
|
+
out = command_list.map {|n| "^#{n}"}.join('|')
|
47
|
+
%r(#{out})
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.command_list
|
51
|
+
command_output.map{|f| f[:words] }.flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.command_output
|
55
|
+
plugins.map(&:details)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.plugins
|
59
|
+
begin
|
60
|
+
debug_plugins = Pluginator.find('puppet-debugger')
|
61
|
+
debug_plugins["input_responders"]
|
62
|
+
rescue NoMethodError => e
|
63
|
+
raise PuppetDebugger::Exception::InvalidCommand.new(message: "Unsupported gem version. Please update with: gem update --system")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param name [String] - the name of the command that is associated with a plugin
|
68
|
+
# @return [PuppetDebugger::InputResponders::InputResponderPlugin]
|
69
|
+
def self.plugin_from_command(name)
|
70
|
+
p = plugins.find {|p| p::COMMAND_WORDS.include?(name)}
|
71
|
+
raise PuppetDebugger::Exception::InvalidCommand.new(message: "invalid command #{command}") unless p
|
72
|
+
p
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module Pluginator
|
80
|
+
# a helper for handling name / file / class conversions
|
81
|
+
module NameConverter
|
82
|
+
private
|
83
|
+
# full_name => class
|
84
|
+
def name2class(name)
|
85
|
+
klass = Kernel
|
86
|
+
name.to_s.split(%r{/}).each do |part|
|
87
|
+
klass = klass.const_get(
|
88
|
+
part.capitalize.gsub(/[_-](.)/) { |match| match[1].upcase }
|
89
|
+
)
|
90
|
+
end
|
91
|
+
klass
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Datatypes < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(datatypes)
|
6
|
+
SUMMARY = 'List all the datatypes available in the environment.'
|
7
|
+
COMMAND_GROUP = :environment
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
types = debugger.all_data_types
|
11
|
+
return types.sort.ai if types.instance_of?(Array)
|
12
|
+
types
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Environment < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(environment)
|
6
|
+
SUMMARY = 'Show the current environment name'
|
7
|
+
COMMAND_GROUP = :context
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
"Puppet Environment: #{debugger.puppet_env_name}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Exit < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(exit)
|
6
|
+
SUMMARY = 'Quit Puppet Debugger.'
|
7
|
+
COMMAND_GROUP = :help
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
exit 0
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class FacterdbFilter < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(facterdb_filter ff)
|
6
|
+
SUMMARY = 'Set the facterdb filter'
|
7
|
+
COMMAND_GROUP = :node
|
8
|
+
|
9
|
+
# displays the facterdb filter
|
10
|
+
# @param [Array] - args is not used
|
11
|
+
def run(args = [])
|
12
|
+
debugger.dynamic_facterdb_filter.ai
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Facts < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(facts)
|
6
|
+
SUMMARY = 'List all the facts associated with the node.'
|
7
|
+
COMMAND_GROUP = :node
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
variables = debugger.node.facts.values
|
11
|
+
variables.ai(sort_keys: true, indent: -1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Functions < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(functions)
|
6
|
+
SUMMARY = 'List all the functions available in the environment.'
|
7
|
+
COMMAND_GROUP = :environment
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
filter = args.first || ''
|
11
|
+
function_map.keys.sort.grep(/^#{Regexp.escape(filter)}/)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Help < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(help)
|
6
|
+
SUMMARY = 'Show the help screen with version information.'
|
7
|
+
COMMAND_GROUP = :help
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
PuppetDebugger::Cli.print_repl_desc
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
|
+
module PuppetDebugger
|
3
|
+
module InputResponders
|
4
|
+
class Krt < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(krt)
|
6
|
+
SUMMARY = 'List all the known resource types.'
|
7
|
+
COMMAND_GROUP = :scope
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
debugger.known_resource_types.ai(sort_keys: true, indent: -1)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,7 +1,18 @@
|
|
1
|
-
|
1
|
+
require 'puppet-debugger/input_responder_plugin'
|
2
2
|
module PuppetDebugger
|
3
|
-
module
|
4
|
-
|
3
|
+
module InputResponders
|
4
|
+
class Play < InputResponderPlugin
|
5
|
+
COMMAND_WORDS = %w(play)
|
6
|
+
SUMMARY = 'Playback a file or URL as input.'
|
7
|
+
COMMAND_GROUP = :editing
|
8
|
+
|
9
|
+
def run(args = [])
|
10
|
+
config = {}
|
11
|
+
config[:play] = args.first
|
12
|
+
play_back(config)
|
13
|
+
nil # we don't want to return anything
|
14
|
+
end
|
15
|
+
|
5
16
|
def play_back(config = {})
|
6
17
|
if config[:play]
|
7
18
|
if config[:play] =~ /^http/
|
@@ -9,7 +20,7 @@ module PuppetDebugger
|
|
9
20
|
elsif File.exist? config[:play]
|
10
21
|
play_back_string(File.read(config[:play]))
|
11
22
|
else config[:play]
|
12
|
-
|
23
|
+
debugger.out_buffer.puts "puppet-debugger can't play #{config[:play]}'"
|
13
24
|
end
|
14
25
|
end
|
15
26
|
end
|
@@ -18,23 +29,23 @@ module PuppetDebugger
|
|
18
29
|
require 'uri'
|
19
30
|
url_data = URI(url)
|
20
31
|
case url_data.host
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
url
|
29
|
-
when /^gitlab.com/
|
30
|
-
if url_data.path =~ /snippets/
|
31
|
-
url += '/raw' unless url_data.path =~ /raw/
|
32
|
+
when /^gist\.github*/
|
33
|
+
url = url += '.txt' unless url_data.path =~ /raw/
|
34
|
+
url
|
35
|
+
when /^github.com/
|
36
|
+
url.gsub('blob', 'raw') if url_data.path =~ /blob/
|
37
|
+
when /^gist.github.com/
|
38
|
+
url = url += '.txt' unless url_data.path =~ /raw/
|
32
39
|
url
|
40
|
+
when /^gitlab.com/
|
41
|
+
if url_data.path =~ /snippets/
|
42
|
+
url += '/raw' unless url_data.path =~ /raw/
|
43
|
+
url
|
44
|
+
else
|
45
|
+
url.gsub('blob', 'raw')
|
46
|
+
end
|
33
47
|
else
|
34
|
-
url
|
35
|
-
end
|
36
|
-
else
|
37
|
-
url
|
48
|
+
url
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
@@ -54,18 +65,18 @@ module PuppetDebugger
|
|
54
65
|
end
|
55
66
|
|
56
67
|
# plays back the string to the output stream
|
57
|
-
#
|
68
|
+
# echos the input and the produced output
|
58
69
|
def play_back_string(str)
|
59
70
|
full_buffer = ''
|
60
71
|
str.split("\n").each do |buf|
|
61
72
|
begin
|
62
73
|
full_buffer += buf
|
63
74
|
# unless this is puppet code, otherwise skip repl keywords
|
64
|
-
if
|
65
|
-
out_buffer.write('>> ')
|
75
|
+
if PuppetDebugger::InputResponders::Commands.command_list_regex.match(buf)
|
76
|
+
debugger.out_buffer.write('>> ')
|
66
77
|
else
|
67
|
-
parser.parse_string(full_buffer)
|
68
|
-
out_buffer.write('>> ')
|
78
|
+
debugger.parser.parse_string(full_buffer)
|
79
|
+
debugger.out_buffer.write('>> ')
|
69
80
|
end
|
70
81
|
rescue Puppet::ParseErrorWithIssue => e
|
71
82
|
if multiline_input?(e)
|
@@ -73,8 +84,8 @@ module PuppetDebugger
|
|
73
84
|
next
|
74
85
|
end
|
75
86
|
end
|
76
|
-
out_buffer.puts(full_buffer)
|
77
|
-
handle_input(full_buffer)
|
87
|
+
debugger.out_buffer.puts(full_buffer)
|
88
|
+
debugger.handle_input(full_buffer)
|
78
89
|
full_buffer = ''
|
79
90
|
end
|
80
91
|
end
|