joshbuddy-guard 0.10.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 (70) hide show
  1. data/CHANGELOG.md +370 -0
  2. data/LICENSE +20 -0
  3. data/README.md +470 -0
  4. data/bin/fsevent_watch_guard +0 -0
  5. data/bin/guard +6 -0
  6. data/images/failed.png +0 -0
  7. data/images/pending.png +0 -0
  8. data/images/success.png +0 -0
  9. data/lib/guard.rb +463 -0
  10. data/lib/guard/cli.rb +125 -0
  11. data/lib/guard/dsl.rb +370 -0
  12. data/lib/guard/dsl_describer.rb +150 -0
  13. data/lib/guard/group.rb +37 -0
  14. data/lib/guard/guard.rb +129 -0
  15. data/lib/guard/hook.rb +118 -0
  16. data/lib/guard/interactor.rb +116 -0
  17. data/lib/guard/listener.rb +351 -0
  18. data/lib/guard/listeners/darwin.rb +60 -0
  19. data/lib/guard/listeners/linux.rb +91 -0
  20. data/lib/guard/listeners/polling.rb +55 -0
  21. data/lib/guard/listeners/windows.rb +61 -0
  22. data/lib/guard/notifier.rb +290 -0
  23. data/lib/guard/templates/Guardfile +2 -0
  24. data/lib/guard/ui.rb +193 -0
  25. data/lib/guard/version.rb +6 -0
  26. data/lib/guard/watcher.rb +114 -0
  27. data/lib/vendor/darwin/Gemfile +6 -0
  28. data/lib/vendor/darwin/Guardfile +8 -0
  29. data/lib/vendor/darwin/LICENSE +20 -0
  30. data/lib/vendor/darwin/README.rdoc +254 -0
  31. data/lib/vendor/darwin/Rakefile +21 -0
  32. data/lib/vendor/darwin/ext/extconf.rb +61 -0
  33. data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
  34. data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
  35. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
  36. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
  37. data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
  38. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  39. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  40. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
  41. data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
  42. data/lib/vendor/linux/MIT-LICENSE +20 -0
  43. data/lib/vendor/linux/README.md +66 -0
  44. data/lib/vendor/linux/Rakefile +54 -0
  45. data/lib/vendor/linux/VERSION +1 -0
  46. data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
  47. data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
  48. data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
  49. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
  50. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
  51. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
  52. data/lib/vendor/linux/rb-inotify.gemspec +53 -0
  53. data/lib/vendor/windows/Gemfile +4 -0
  54. data/lib/vendor/windows/README.md +34 -0
  55. data/lib/vendor/windows/Rakefile +18 -0
  56. data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
  57. data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
  58. data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
  59. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
  60. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
  61. data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
  62. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
  63. data/lib/vendor/windows/rb-fchange.gemspec +34 -0
  64. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  65. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  66. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
  67. data/lib/vendor/windows/spec/spec_helper.rb +21 -0
  68. data/man/guard.1 +96 -0
  69. data/man/guard.1.html +181 -0
  70. metadata +193 -0
@@ -0,0 +1,83 @@
1
+ module INotify
2
+ # Watchers monitor a single path for changes,
3
+ # specified by {INotify::Notifier#watch event flags}.
4
+ # A watcher is usually created via \{Notifier#watch}.
5
+ #
6
+ # One {Notifier} may have many {Watcher}s.
7
+ # The Notifier actually takes care of the checking for events,
8
+ # via \{Notifier#run #run} or \{Notifier#process #process}.
9
+ # The main purpose of having Watcher objects
10
+ # is to be able to disable them using \{#close}.
11
+ class Watcher
12
+ # The {Notifier} that this Watcher belongs to.
13
+ #
14
+ # @return [Notifier]
15
+ attr_reader :notifier
16
+
17
+ # The path that this Watcher is watching.
18
+ #
19
+ # @return [String]
20
+ attr_reader :path
21
+
22
+ # The {INotify::Notifier#watch flags}
23
+ # specifying the events that this Watcher is watching for,
24
+ # and potentially some options as well.
25
+ #
26
+ # @return [Array<Symbol>]
27
+ attr_reader :flags
28
+
29
+ # The id for this Watcher.
30
+ # Used to retrieve this Watcher from {Notifier#watchers}.
31
+ #
32
+ # @private
33
+ # @return [Fixnum]
34
+ attr_reader :id
35
+
36
+ # Calls this Watcher's callback with the given {Event}.
37
+ #
38
+ # @private
39
+ # @param event [Event]
40
+ def callback!(event)
41
+ @callback[event]
42
+ end
43
+
44
+ # Disables this Watcher, so that it doesn't fire any more events.
45
+ #
46
+ # @raise [SystemCallError] if the watch fails to be disabled for some reason
47
+ def close
48
+ return if Native.inotify_rm_watch(@notifier.fd, @id) == 0
49
+ raise SystemCallError.new("Failed to stop watching #{path.inspect}", FFI.errno)
50
+ end
51
+
52
+ # Creates a new {Watcher}.
53
+ #
54
+ # @private
55
+ # @see Notifier#watch
56
+ def initialize(notifier, path, *flags, &callback)
57
+ @notifier = notifier
58
+ @callback = callback || proc {}
59
+ @path = path
60
+ @flags = flags.freeze
61
+ @id = Native.inotify_add_watch(@notifier.fd, path.dup,
62
+ Native::Flags.to_mask(flags))
63
+
64
+ unless @id < 0
65
+ @notifier.watchers[@id] = self
66
+ return
67
+ end
68
+
69
+ raise SystemCallError.new(
70
+ "Failed to watch #{path.inspect}" +
71
+ case FFI.errno
72
+ when Errno::EACCES::Errno; ": read access to the given file is not permitted."
73
+ when Errno::EBADF::Errno; ": the given file descriptor is not valid."
74
+ when Errno::EFAULT::Errno; ": path points outside of the process's accessible address space."
75
+ when Errno::EINVAL::Errno; ": the given event mask contains no legal events; or fd is not an inotify file descriptor."
76
+ when Errno::ENOMEM::Errno; ": insufficient kernel memory was available."
77
+ when Errno::ENOSPC::Errno; ": The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."
78
+ else; ""
79
+ end,
80
+ FFI.errno)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rb-inotify}
8
+ s.version = "0.8.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nathan Weizenbaum"]
12
+ s.date = %q{2011-09-27}
13
+ s.description = %q{A Ruby wrapper for Linux's inotify, using FFI}
14
+ s.email = %q{nex342@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".yardopts",
20
+ "MIT-LICENSE",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/rb-inotify.rb",
25
+ "lib/rb-inotify/event.rb",
26
+ "lib/rb-inotify/native.rb",
27
+ "lib/rb-inotify/native/flags.rb",
28
+ "lib/rb-inotify/notifier.rb",
29
+ "lib/rb-inotify/watcher.rb",
30
+ "rb-inotify.gemspec"
31
+ ]
32
+ s.homepage = %q{http://github.com/nex3/rb-inotify}
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.7}
35
+ s.summary = %q{A Ruby wrapper for Linux's inotify, using FFI}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
43
+ s.add_development_dependency(%q<yard>, [">= 0.4.0"])
44
+ else
45
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
46
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
47
+ end
48
+ else
49
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
50
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
51
+ end
52
+ end
53
+
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rb-fchange.gemspec
4
+ gemspec
@@ -0,0 +1,34 @@
1
+ # rb-fchange
2
+
3
+ Code is working. But there is still a lot of work.
4
+ This is a simple wrapper over the Windows Kernel functions for monitoring the specified directory or subtree.
5
+ Tested on:
6
+
7
+ - jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6)
8
+ - ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-ingw32]
9
+ - ruby 1.9.2p180 (2011-02-18) [i386-mingw32]
10
+
11
+ Example
12
+
13
+ ```ruby
14
+ require 'rb-fchange'
15
+
16
+ notifier = FChange::Notifier.new
17
+ notifier.watch("test", :all_events, :recursive) do |event|
18
+ p Time.now.utc
19
+ end
20
+
21
+ Signal.trap('INT') do
22
+ p "Bye bye...",
23
+ notifier.stop
24
+ abort("\n")
25
+ end
26
+
27
+ notifier.run
28
+ ```
29
+
30
+ ## TODO
31
+
32
+ - add latency setting with 0.5 default
33
+ - rework interface (should more look like rb-fsevent)
34
+ - add none-ANSI path support
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
7
+
8
+ namespace(:spec) do
9
+ desc "Run all specs on multiple ruby versions (requires pik)"
10
+ task(:portability) do
11
+ %w[187 192 161].each do |version|
12
+ system("echo -----------#{version}------------")
13
+ system("pik use #{version}")
14
+ system("bundle install")
15
+ system("rake spec")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require "rb-fchange/native"
2
+ require "rb-fchange/native/flags"
3
+ require "rb-fchange/notifier"
4
+ require "rb-fchange/watcher"
5
+ require "rb-fchange/event"
6
+
7
+ # The root module of the library, which is laid out as so:
8
+ #
9
+ # * {Notifier} -- The main class, where the notifications are set up
10
+ # * {Watcher} -- A watcher for a single file or directory
11
+ # * {Event} -- An filesystem event notification
12
+ module FChange
13
+
14
+ end
@@ -0,0 +1,29 @@
1
+ module FChange
2
+ # An event caused by a change on the filesystem.
3
+ # Each {Watcher} can fire many events,
4
+ # which are passed to that watcher's callback.
5
+ class Event
6
+ # The {Watcher} that fired this event.
7
+ #
8
+ # @return [Watcher]
9
+ attr_reader :watcher
10
+
11
+ # Creates an event from a string of binary data.
12
+ # Differs from {Event.consume} in that it doesn't modify the string.
13
+ #
14
+ # @private
15
+ # @param watcher [Watcher] The {Watcher} that fired the event
16
+ def initialize(watcher)
17
+ @watcher = watcher
18
+ end
19
+
20
+ # Calls the callback of the watcher that fired this event,
21
+ # passing in the event itself.
22
+ #
23
+ # @private
24
+ def callback!
25
+ @watcher.callback!(self)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ require 'ffi'
2
+
3
+ module FChange
4
+ # This module contains the low-level foreign-function.
5
+ # It's an implementation detail, and not meant for users to deal with.
6
+ #
7
+ # @private
8
+ module Native
9
+ extend FFI::Library
10
+ ffi_lib 'kernel32'
11
+ ffi_convention :stdcall
12
+
13
+ # HANDLE FindFirstChangeNotification(
14
+ # LPCTSTR lpPathName, // directory name
15
+ # BOOL bWatchSubtree, // monitoring option
16
+ # DWORD dwNotifyFilter // filter conditions
17
+ #);
18
+ attach_function :FindFirstChangeNotificationW, [:pointer, :int, :long], :long
19
+
20
+ # HANDLE FindFirstChangeNotification(
21
+ # LPCTSTR lpPathName, // directory name
22
+ # BOOL bWatchSubtree, // monitoring option
23
+ # DWORD dwNotifyFilter // filter conditions
24
+ #);
25
+ attach_function :FindFirstChangeNotificationA, [:pointer, :int, :long], :long
26
+
27
+ # BOOL FindNextChangeNotification(
28
+ # HANDLE hChangeHandle // handle to change notification
29
+ # );
30
+ attach_function :FindNextChangeNotification, [:long], :int
31
+
32
+ # DAORD WaitForMultipleObjects(
33
+ # DWORD nCount, // number of handles in array
34
+ # CONST HANDLE *lpHandles, // object-handle array
35
+ # BOOL bWaitAll, // wait option
36
+ # DWORD dwMilliseconds // time-out interval
37
+ # );
38
+ attach_function :WaitForMultipleObjects, [:long, :pointer, :int, :long], :long
39
+
40
+ # BOOL FindCloseChangeNotification(
41
+ # HANDLE hChangeHandle
42
+ # );
43
+ attach_function :FindCloseChangeNotification, [:long], :int
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ module FChange
2
+ module Native
3
+ # A module containing all the flags to be passed to {Notifier#watch}.
4
+ # @see http://msdn.microsoft.com/en-us/library/aa364417(v=VS.85).aspx
5
+ #
6
+ # @private
7
+ module Flags
8
+
9
+ # Any file name change in the watched directory or subtree causes a change
10
+ # notification wait operation to return. Changes include renaming,
11
+ # creating, or deleting a file name.
12
+ FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001
13
+
14
+ # Any directory-name change in the watched directory or subtree causes a
15
+ # change notification wait operation to return. Changes include creating
16
+ # or deleting a directory.
17
+ FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002
18
+
19
+ # Any attribute change in the watched directory or subtree causes a change
20
+ # notification wait operation to return.
21
+ FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004
22
+
23
+ # Any file-size change in the watched directory or subtree causes a change
24
+ # notification wait operation to return. The operating system detects a
25
+ # change in file size only when the file is written to the disk.
26
+ # For operating systems that use extensive caching, detection occurs only
27
+ # when the cache is sufficiently flushed.
28
+ FILE_NOTIFY_CHANGE_SIZE = 0x00000008
29
+
30
+ # Any change to the last write-time of files in the watched directory or
31
+ # subtree causes a change notification wait operation to return.
32
+ # The operating system detects a change to the last write-time only when
33
+ # the file is written to the disk. For operating systems that use
34
+ # extensive caching, detection occurs only when the cache is sufficiently
35
+ # flushed
36
+ FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010
37
+
38
+ # Any change to the last access time of files in the watched directory or
39
+ # subtree causes a change notification wait operation to return.
40
+ FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020
41
+
42
+ # Any change to the creation time of files in the watched directory or
43
+ # subtree causes a change notification wait operation to return.
44
+ FILE_NOTIFY_CHANGE_CREATION = 0x00000040
45
+
46
+ # Any security-descriptor change in the watched directory or subtree
47
+ # causes a change notification wait operation to return.
48
+ FILE_NOTIFY_CHANGE_SECURITY = 0x00000100
49
+
50
+ FILE_NOTIFY_CHANGE_ALL_EVENTS = (
51
+ FILE_NOTIFY_CHANGE_DIR_NAME |
52
+ FILE_NOTIFY_CHANGE_FILE_NAME |
53
+ FILE_NOTIFY_CHANGE_LAST_WRITE
54
+ )
55
+
56
+ # Converts a list of flags to the bitmask that the C API expects.
57
+ #
58
+ # @param flags [Array<Symbol>]
59
+ # @return [Fixnum]
60
+ def self.to_mask(flags)
61
+ flags.map {|flag| const_get("FILE_NOTIFY_CHANGE_#{flag.to_s.upcase}")}.
62
+ inject(0) {|mask, flag| mask | flag}
63
+ end
64
+
65
+ # Converts a bitmask from the C API into a list of flags.
66
+ #
67
+ # @param mask [Fixnum]
68
+ # @return [Array<Symbol>]
69
+ def self.from_mask(mask)
70
+ constants.map {|c| c.to_s}.select do |c|
71
+ next false unless c =~ /^FILE_NOTIFY_CHANGE_/
72
+ const_get(c) & mask != 0
73
+ end.map {|c| c.sub("FILE_NOTIFY_CHANGE_", "").downcase.to_sym} - [:all_events]
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,149 @@
1
+ module FChange
2
+ # Notifier wraps a single instance of FChange.
3
+ # It's possible to have more than one instance,
4
+ # but usually unnecessary.
5
+ #
6
+ # @example
7
+ # # Create the notifier
8
+ # notifier = FChange::Notifier.new
9
+ #
10
+ # # Run this callback whenever the file path/to/foo.txt is read
11
+ # notifier.watch("path/to/foo/", :all_events) do
12
+ # puts "foo was accessed!"
13
+ # end
14
+ #
15
+ # # Nothing happens until you run the notifier!
16
+ # notifier.run
17
+ class Notifier
18
+
19
+ #
20
+ INFINITE = 0xFFFFFFFF
21
+
22
+ #
23
+ WAIT_OBJECT_0 = 0x00000000
24
+
25
+ # A hash from {Watcher} ids to the instances themselves.
26
+ #
27
+ # @private
28
+ # @return [{Fixnum => Watcher}]
29
+ attr_reader :watchers
30
+
31
+ attr_reader :dwChangeHandles
32
+ attr_reader :lp_dwChangeHandles
33
+
34
+ # Creates a new {Notifier}.
35
+ #
36
+ # @return [Notifier]
37
+ def initialize
38
+ @watchers = {}
39
+ @dwChangeHandles = []
40
+ @lp_dwChangeHandles = 0
41
+ end
42
+
43
+ # Adds a new {Watcher} to the queue.
44
+ def add_watcher(watcher)
45
+
46
+ @watchers[watcher.id] = watcher
47
+
48
+ @dwChangeHandles.push watcher.id
49
+
50
+ # Pack event handles into newly created storage area
51
+ # to be used for Win32 call
52
+ @lp_dwChangeHandles = dwChangeHandles.pack("L" * dwChangeHandles.count)
53
+
54
+ end
55
+
56
+ # Watches a file or directory for changes,
57
+ # calling the callback when there are.
58
+ # This is only activated once \{#process} or \{#run} is called.
59
+ #
60
+ # **Note that by default, this does not recursively watch subdirectories
61
+ # of the watched directory**.
62
+ # To do so, use the `:recursive` flag.
63
+ #
64
+ # `:recursive`
65
+ # : Recursively watch any subdirectories that are created.
66
+ #
67
+ # @param path [String] The path to the file or directory
68
+ # @param flags [Array<Symbol>] Which events to watch for
69
+ # @yield [event] A block that will be called
70
+ # whenever one of the specified events occur
71
+ # @yieldparam event [Event] The Event object containing information
72
+ # about the event that occured
73
+ # @return [Watcher] A Watcher set up to watch this path for these events
74
+ # @raise [SystemCallError] if the file or directory can't be watched,
75
+ # e.g. if the file isn't found, read access is denied,
76
+ # or the flags don't contain any events
77
+ def watch(path, *flags, &callback)
78
+ recursive = flags.include?(:recursive)
79
+ #:latency = 0.5
80
+ flags = flags - [:recursive]
81
+ if flags.empty?
82
+ @flags = [:all_events]
83
+ else
84
+ @flags = flags.freeze
85
+ end
86
+ Watcher.new(self, path, recursive, *@flags, &callback)
87
+ end
88
+
89
+ # Starts the notifier watching for filesystem events.
90
+ # Blocks until \{#stop} is called.
91
+ #
92
+ # @see #process
93
+ def run
94
+ @stop = false
95
+ process until @stop
96
+ end
97
+
98
+ # Stop watching for filesystem events.
99
+ # That is, if we're in a \{#run} loop,
100
+ # exit out as soon as we finish handling the events.
101
+ def stop
102
+ @stop = true
103
+ end
104
+
105
+ # Blocks until there are one or more filesystem events
106
+ # that this notifier has watchers registered for.
107
+ # Once there are events, the appropriate callbacks are called
108
+ # and this function returns.
109
+ #
110
+ # @see #run
111
+ def process
112
+ read_events.each {|event| event.callback!}
113
+ end
114
+
115
+ # Blocks until there are one or more filesystem events
116
+ # that this notifier has watchers registered for.
117
+ # Once there are events, returns their {Event} objects.
118
+ #
119
+ # @private
120
+ def read_events
121
+
122
+ # can return WAIT_TIMEOUT = 0x00000102
123
+ dwWaitStatus = Native.WaitForMultipleObjects(@dwChangeHandles.count,
124
+ @lp_dwChangeHandles, 0, 500)
125
+
126
+ events = []
127
+
128
+ # this call blocks all threads completely.
129
+ @dwChangeHandles.each_index do |index|
130
+ if dwWaitStatus == WAIT_OBJECT_0 + index
131
+
132
+ ev = Event.new(@watchers[@dwChangeHandles[index]])
133
+ events << ev
134
+
135
+ r = Native.FindNextChangeNotification(@dwChangeHandles[index])
136
+ if r == 0
137
+ raise SystemCallError.new("Failed to watch", r)
138
+ end
139
+ end
140
+ end
141
+ events
142
+ end
143
+
144
+ def close
145
+
146
+ end
147
+
148
+ end
149
+ end