time_tap 0.2.0 → 0.4.0.pre

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 (42) hide show
  1. data/.gitignore +5 -37
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +3 -21
  5. data/README.md +104 -41
  6. data/Rakefile +1 -30
  7. data/bin/timetap +25 -26
  8. data/lib/time_tap.rb +126 -52
  9. data/lib/time_tap/backend.rb +9 -0
  10. data/lib/time_tap/backend/file_system.rb +36 -0
  11. data/lib/time_tap/config.yml.example +32 -0
  12. data/lib/time_tap/editor.rb +9 -0
  13. data/lib/time_tap/editor/sublime_text2.rb +15 -0
  14. data/lib/time_tap/editor/text_mate.rb +22 -0
  15. data/lib/time_tap/editor/text_mate2.rb +15 -0
  16. data/lib/time_tap/editor/xcode.rb +24 -0
  17. data/lib/time_tap/project.rb +136 -116
  18. data/lib/time_tap/server.rb +20 -20
  19. data/lib/time_tap/version.rb +3 -0
  20. data/lib/time_tap/views/project.haml +5 -3
  21. data/lib/time_tap/views/project_day.haml +1 -0
  22. data/lib/time_tap/watcher.rb +46 -43
  23. data/log/.git-keep +1 -0
  24. data/spec/lib/time_tap/project_spec.rb +12 -0
  25. data/spec/spec_helper.rb +3 -1
  26. data/spec/time_tap/backend_spec.rb +12 -0
  27. data/spec/time_tap/project_spec.rb +13 -0
  28. data/spec/time_tap/watcher_spec.rb +14 -0
  29. data/spec/time_tap_spec.rb +6 -4
  30. data/time_tap.gemspec +26 -108
  31. data/vendor/SublimeText2/.gitignore +1 -0
  32. data/vendor/SublimeText2/README.md +27 -0
  33. data/vendor/SublimeText2/TimeTap.py +10 -0
  34. data/vendor/TextMate2/TimeTap.tmbundle/Commands/Record current file.tmCommand +33 -0
  35. data/vendor/TextMate2/TimeTap.tmbundle/info.plist +16 -0
  36. data/vendor/TimeTap.tmbundle/Commands/Record current file.tmCommand +36 -0
  37. data/vendor/TimeTap.tmbundle/info.plist +18 -0
  38. metadata +161 -260
  39. data/Gemfile.lock +0 -48
  40. data/VERSION +0 -1
  41. data/config.yaml +0 -8
  42. data/lib/time_tap/editors.rb +0 -23
data/.gitignore CHANGED
@@ -1,42 +1,10 @@
1
- # rcov generated
2
1
  coverage
3
-
4
- # rdoc generated
5
2
  rdoc
6
-
7
- # yard generated
8
3
  doc
9
4
  .yardoc
10
-
11
- # bundler
5
+ pkg/*
6
+ *.gem
12
7
  .bundle
13
-
14
- # jeweler generated
15
- pkg
16
-
17
- # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
18
- #
19
- # * Create a file at ~/.gitignore
20
- # * Include files you want ignored
21
- # * Run: git config --global core.excludesfile ~/.gitignore
22
- #
23
- # After doing this, these files will be ignored in all your git projects,
24
- # saving you from having to 'pollute' every project you touch with them
25
- #
26
- # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
27
- #
28
- # For MacOS:
29
- #
30
- #.DS_Store
31
- #
32
- # For TextMate
33
- #*.tmproj
34
- #tmtags
35
- #
36
- # For emacs:
37
- #*~
38
- #\#*
39
- #.\#*
40
- #
41
- # For vim:
42
- #*.swp
8
+ .sass*
9
+ /Gemfile.lock
10
+ /log/*.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3
data/Gemfile CHANGED
@@ -1,22 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
- gem 'activesupport', '~> 2.3.8'
4
- gem 'actionpack', '~> 2.3.8'
5
- gem 'i18n', '~> 0.3.5'
6
- gem 'haml'
7
- gem 'rb-appscript'
8
- gem 'sinatra'
9
-
10
- # Add dependencies required to use your gem here.
11
- # Example:
12
- # gem "activesupport", ">= 2.3.5"
13
-
14
- # Add dependencies to develop your gem here.
15
- # Include everything needed to run rake, tests, features, etc.
16
- group :development do
17
- gem "rspec", ">= 2.0.0.beta.19"
18
- gem "yard", "~> 0.6.0"
19
- gem "bundler", "~> 1.0.0"
20
- gem "jeweler", "~> 1.5.0.pre3"
21
- gem "rcov", ">= 0"
22
- end
3
+ # Specify your gem's dependencies in time_tap.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -2,80 +2,122 @@
2
2
 
3
3
  TimeTap helps you track the time you spend coding on each project while in TextMate.
4
4
 
5
- Once it's launched you don't have to bother anymore starting/stopping timers or
5
+ Once it's launched you don't have to bother anymore starting/stopping timers or
6
6
  inventing some arbitrary amount of time to fill your fancy time tracker.
7
7
 
8
8
  <img src="http://f.cl.ly/items/17025fecf7189518cf07/timetap-project-list.png"/>
9
9
  <img src="http://f.cl.ly/items/7b96ad2f7b49a95fdfd0/timetap-project-page.png"/>
10
10
 
11
11
 
12
- ## How does it work
13
12
 
14
- TimeTap keeps an eye on (tracks) the modification time of the frontmost file
15
- and tells you how much time you spent on each project.
13
+ ## Installing
16
14
 
17
- If you stop coding for a while while squeezing your brains TimeTap understands.
18
- TimeTap will consider "coding time" pauses to up to 30 minutes between to saves
15
+ gem install time_tap
16
+
17
+ timetap --install
18
+
19
+ … and visit [localhost:1111](http://localhost:1111/)
20
+
21
+ ### Installing from source
22
+
23
+ - Get the codez: `git clone git://github.com/elia/timetap.git`
24
+ - Run `bundle exec bin/timetap --install`
25
+
26
+
27
+
28
+
29
+ ## How it works
30
+
31
+ TimeTap keeps an eye on the modification time of the frontmost file in TextMate
32
+ and tells you how much time you spent on each project.
33
+
34
+ If you stop coding for a while while squeezing your brains TimeTap understands.
35
+ TimeTap will consider "coding time" pauses to up to 30 minutes between to saves
19
36
  in the same project.
20
37
 
21
- Technically it saves a timestamp+path of the frontmost file in TextMate every
38
+ Technically it saves a timestamp+path of the frontmost file in TextMate every
22
39
  30 seconds, then it digests all this information in a nice Sinatra webapp.
23
40
 
24
41
  The server will respond on http://0.0.0.0:1111/.
25
42
 
26
43
 
27
- ## Instructions
44
+ ### Assumptions
45
+
46
+ * You code on TextMate.
47
+ * You save often (like me), at least every 30 minutes.
48
+ * You keep your code organized (I use ~/Code as main code folder).
49
+
50
+
51
+ ## Editors
52
+
53
+ TimeTap works with TextMate, TextMate2 and SublimeText2.
54
+ For TM2 and ST2 you need to install specific bundles (in the `vendor/` folder).
55
+
56
+ ### TextMate
57
+
58
+ Need to do nothing, thanks to `rb-appscript` :)
59
+
60
+
61
+ ### TextMate 2
62
+
63
+ You need to install the bundle in [`vendor/SublimeText2`](https://github.com/elia/timetap/tree/master/vendor/TextMate2)
64
+
65
+
66
+ ### SublimeText
67
+
68
+ You need to install the package in [`vendor/SublimeText2`](https://github.com/elia/timetap/tree/master/vendor/SublimeText2)
69
+
70
+
71
+
72
+ ## Configuring
28
73
 
29
- Run `ruby -Ilib bin/timetap` or run
30
- `rake launcher && launchctl load ~/Library/LaunchAgents`
31
- to add a plist for OSX's launchd and have it launched automatically at login.
74
+ TimeTap uses a config file to control where projects are kept, etc. the path is:
32
75
 
33
- ## Setting up config file
76
+ ~/.timetap.config
34
77
 
35
- timetap uses a config file to control where projects are kept, etc. Put this config file in `~/.tap_config`.
78
+ Which can look like this:
36
79
 
37
- cp config.yaml ~/.tap_config
80
+ ```yaml
81
+ port: 1111
82
+ # the port on localhost for the web interface
38
83
 
39
- ### Keys Explained
84
+ # These are used to identify project root folders
85
+ code_folders:
86
+ - ~/Code/MyCompany
87
+ - ~/Code
40
88
 
41
- root - where the timetap logs should be saved. Recommended value: ~
42
- code - where all you project live, in a flat hierachy.
43
- nested_project_layers - see below, on nested projects. Default is 1
44
-
89
+ # It's highly recomended to use 1.9.3
90
+ ruby: /Users/elia/.rvm/bin/ruby-1.9.3-p286
91
+ ```
45
92
 
46
- Nested Projects allows you to keep your projects inside a hierarchy, instead of the original assumption of timetap (which is that all projects are flat).
47
93
 
48
- For example, you could keep your directory structure might look like:
94
+
95
+ ### About "nested project layers"
96
+
97
+ TimeTap assumes you keep your projects inside a specific folder, like this:
98
+
99
+ ~/Code/
100
+ tap/
101
+ tik_tak/
102
+ tk-win/
103
+ AcmeCorp/
104
+ website/
105
+ intranet/
106
+
107
+ But if you keep your projects grouped in subfolders like this:
49
108
 
50
109
  ~/Code/
51
110
  Clients/
52
111
  AcmeCorp/
53
112
  website/
54
- intranet
113
+ intranet/
55
114
  BetaCorp/
56
115
  skunkworks/
57
116
  OpenSource/
58
117
  project_one/
59
118
  timetap/
60
119
 
61
- A `nested_project_layers` setting of 2 (in your `.tap_config` file) would mean we track "AcmeCorp", "BetaCorp", and everything under OpenSource, as their own projects
62
-
63
- ## Assumptions
64
-
65
- * You code on TextMate.
66
- * You save often (like me), at least every 30 minutes.
67
- * You keep your code organized (I use ~/Code as main code folder).
68
-
69
-
70
- ## TODO
71
-
72
- - support other text editors, or at least make it easy to do so
73
- - (r)spec it!
74
- - make it more configurable
75
- - gemify (with jeweler)
76
- - flatten encoding quick-fixes with proper solutions (eat and spit only utf8)
77
- - integration with external (online) time tracking tools
78
- - export to csv (?)
120
+ then, the `nested_project_layers` key tells TimeTap how deep to look for project names inside a hierarchy (in the example a value of 2 will catch `AcmeCorp`, `BetaCorp`, `project_one` and `timetap`).
79
121
 
80
122
 
81
123
  ## How to Contribute
@@ -91,6 +133,27 @@ Use it, love it, then...
91
133
  * Send me a pull request. Bonus points for topic branches.
92
134
 
93
135
 
136
+ ### TODO
137
+
138
+ - <strike>make it more configurable</strike>
139
+ - <strike>gemify (with jeweler)</strike>
140
+ - <strike>support other text editors, or at least make it easy to do so</strike>
141
+ - (r)spec it!
142
+ - flatten encoding quick-fixes with proper solutions (eat and spit only utf8)
143
+ - integration with external (online) time tracking tools
144
+
145
+
146
+ ## Credits
147
+
148
+ - Ryan Wilcox [@rwilcox](https://github.com/rwilcox)
149
+
150
+
151
+ ## Related Projects
152
+
153
+ - [Watch Tower](https://github.com/TechnoGate/watch_tower)
154
+ - [Vim TimeTap](https://github.com/rainerborene/vim-timetap)
155
+
156
+
94
157
  ## Copyright
95
158
 
96
- Copyright (c) 2009 Elia Schito. See LICENSE for details.
159
+ Copyright © 2009-2012 Elia Schito. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,34 +1,5 @@
1
- require 'rubygems'
2
1
  require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
- Jeweler::Tasks.new do |gem|
14
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
- gem.name = "time_tap"
16
- gem.summary = %Q{Unobtrusive time tracking for TextMate}
17
- gem.description = %Q{TimeTap helps you track the time you spend coding on each project while in TextMate.}
18
- gem.email = "perlelia@gmail.com"
19
- gem.homepage = "http://github.com/elia/timetap"
20
- gem.authors = ["Elia Schito"]
21
- # Include your dependencies below. Runtime dependencies are required when using your gem,
22
- # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
23
- # spec.add_runtime_dependency 'jabber4r', '> 0.1'
24
- # spec.add_development_dependency 'rspec', '> 1.2.3'
25
- gem.add_development_dependency "rspec", ">= 2.0.0.beta.19"
26
- gem.add_development_dependency "yard", "~> 0.6.0"
27
- gem.add_development_dependency "bundler", "~> 1.0.0"
28
- gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
29
- gem.add_development_dependency "rcov", ">= 0"
30
- end
31
- Jeweler::RubygemsDotOrgTasks.new
2
+ Bundler::GemHelper.install_tasks
32
3
 
33
4
  require 'rspec/core'
34
5
  require 'rspec/core/rake_task'
data/bin/timetap CHANGED
@@ -4,52 +4,51 @@
4
4
  require 'time_tap'
5
5
 
6
6
 
7
- require 'yaml'
8
- user_config = File.expand_path("~/.tap_config")
9
- config_file = File.expand_path('../../config.yaml', __FILE__)
10
-
11
- options = YAML.load_file(config_file)
12
- options.merge! YAML.load_file(user_config) if File.exist?(user_config)
13
- TimeTap.config = options
14
-
7
+ TimeTap.load_user_config!
15
8
 
16
9
  require 'optparse'
17
10
  OptionParser.new do |opts|
18
11
  opts.banner = "Usage: #{$0} [options]"
19
12
 
20
- opts.on("-f", "--foreground", "Run in foreground.") do
21
- TimeTap.config[:foreground] = true
13
+ opts.on("-f", "--foreground", "Run in foreground (default).") do
14
+ TimeTap.config[:background] = false
15
+ end
16
+
17
+ opts.on("-b", "--background", "Run in background.") do
18
+ TimeTap.config[:background] = true
22
19
  end
23
-
24
- opts.on("-p", "--port PORT", "Use specified port for server. (default #{options['port']})") do |value|
20
+
21
+ opts.on("-p", "--port PORT", "Use specified port for server. (default #{TimeTap.config['port']})") do |value|
25
22
  TimeTap.config[:port] = value
26
23
  end
27
-
28
- opts.on("--install", "Launch automatically at login.") do
29
- TimeTap.install!
30
- puts "\nInstalled. Now run:\n launchctl load ~/Library/LaunchAgents\n\n"
31
- exit
24
+
25
+ opts.on("-l", "--log-level LEVEL", "Use specified port for server. (default #{TimeTap.config['port']})") do |value|
26
+ TimeTap.config[:log_level] = value
32
27
  end
33
-
34
- opts.on("--reload", "Reload login launch agent.") do
35
- puts 'Reloading...'
36
- TimeTap.reload!
28
+
29
+ opts.on("-i", "--install", "Sets TimeTap to be launched automatically at login, and boots it.") do
30
+ TimeTap.install_launcher!
31
+ TimeTap.install_config!
32
+ TimeTap.reload_launcher!
33
+ # TimeTap::reload_launcher! uses `exec` so it never gets here
37
34
  exit
38
35
  end
39
36
  end.parse!
40
37
 
41
-
42
- unless TimeTap.config[:foreground]
38
+ TimeTap.config[:foreground] = !TimeTap.config[:background]
39
+ if TimeTap.config[:background]
43
40
  require 'time_tap/daemon'
44
-
41
+
45
42
  pid = fork {
46
43
  # Try to replace "ruby" with "TimeTap" in the command string (for "ps -A" & co.)
47
44
  $0 = 'TimeTap'
48
-
45
+
49
46
  Process.daemon(true)
50
47
  TimeTap.start
51
48
  }
52
49
  else
53
- puts "going foreground"
50
+ TimeTap.logger = Logger.new($stdout)
51
+ TimeTap.logger.level = Logger.const_get(TimeTap.config[:log_level].upcase) if TimeTap.config[:log_level]
52
+ TimeTap.logger.info '[TimeTap] Going foreground...'
54
53
  TimeTap.start
55
54
  end
data/lib/time_tap.rb CHANGED
@@ -1,81 +1,123 @@
1
- #!/usr/bin/env ruby
2
- # encoding: utf-8
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'logger'
3
3
 
4
+ module TimeTap
5
+ @config = {
6
+ :root => "~",
7
+ # root is where the logs will be saved
4
8
 
5
- require 'rubygems'
6
- gem 'activesupport', '~> 2.3.8'
7
- gem 'actionpack', '~> 2.3.8'
8
- gem 'i18n', '~> 0.3.5'
9
- gem 'haml'
10
- gem 'rb-appscript'
11
- gem 'sinatra'
9
+ # code is where all your projects live
10
+ :code_folders => %w[
11
+ ~/Code
12
+ ~/Developer
13
+ ~/Development
14
+ ~/src
15
+ ~/code
16
+ ~/rails
17
+ ~/Desktop
18
+ ~
19
+ ],
12
20
 
21
+ :nested_project_layers => 1,
22
+ # see below about nested projects
13
23
 
14
- module TimeTap
24
+ :port => 1111,
25
+ # the port on localhost for the web interface
26
+
27
+ :ruby => '/usr/bin/ruby',
28
+ # the ruby you want to use
29
+
30
+ :backend => :file_system,
31
+ :backend_options => { :file_name => '~/.timetap.history' },
32
+ :editor => :text_mate,
33
+ :log_file => '~/.timetap.log'
34
+ }.with_indifferent_access
15
35
  attr_accessor :config
16
-
36
+
37
+
38
+ @logger = Logger.new($stdout)
39
+ attr_accessor :logger
40
+
41
+
17
42
  extend self
18
-
19
-
43
+
44
+
20
45
  # CONFIGURATION
21
46
 
22
47
  # Are we on 1.9?
23
48
  # FIXME: this is wrong! :)
24
49
  RUBY19 = RUBY_VERSION.to_f >= 1.9
25
-
50
+
26
51
  def config= options = {}
27
52
  require 'active_support'
28
-
53
+
29
54
  # CONFIG
30
55
  @config = HashWithIndifferentAccess.new(options)
31
56
  @config[:root] = File.expand_path(config[:root])
32
57
  @config[:port] = config[:port].to_i
33
58
  end
34
-
35
-
59
+
60
+
61
+
62
+ # BACKEND
63
+
64
+ def backend
65
+ require 'time_tap/backend'
66
+ @backend = Backend.load config[:backend], config[:backend_options]
67
+ end
68
+
69
+ def editor
70
+ require 'time_tap/editor'
71
+ @backend = Editor.load config[:editor], config[:editor_options]
72
+ end
73
+
74
+
75
+ # START
76
+
36
77
  def start options = {}
37
78
  # REQUIREMENTS
38
-
79
+
39
80
  require 'yaml'
40
- require 'active_support'
41
81
  require 'time_tap/project'
42
- require 'time_tap/editors'
43
82
  require 'time_tap/watcher'
44
83
  require 'time_tap/server'
45
-
46
-
47
-
84
+
85
+ logger.info "[TimeTap] config: #{config.to_yaml}"
48
86
  # SIGNAL HANDLING
49
-
50
- Signal.trap("INT") {exit}
51
- Signal.trap("TERM") {exit}
52
-
53
-
87
+
88
+ Signal.trap('INT') {exit}
89
+ Signal.trap('TERM') {exit}
90
+
91
+
54
92
  # WEB SERVER
55
-
93
+
56
94
  Thread.abort_on_exception = true
57
-
95
+
58
96
  @server = Thread.new {
59
97
  Signal.trap("INT") {exit}
60
98
  Signal.trap("TERM") {exit}
61
-
99
+
62
100
  Server.run! :host => 'localhost', :port => TimeTap.config[:port]
63
101
  exit
64
102
  }
65
-
66
-
103
+
104
+
67
105
  # WATCHER
68
-
69
- include Editors
70
- Watcher.keep_watching(TextMate)
106
+
107
+ watcher = Watcher.new(editor, backend)
108
+ watcher.keep_watching
71
109
  end
72
-
110
+
111
+
73
112
  # Add a plist for OSX's launchd and have *TimeTap* launched automatically at login.
74
- def install!
113
+ def install_launcher!
114
+ puts 'Installing launcher...'
115
+
75
116
  load_plist_info!
76
117
  ruby = config[:ruby] || "/usr/bin/ruby"
77
118
  include_dir = '-I'+File.expand_path('../../lib', __FILE__)
78
119
  launcher = File.expand_path('../../bin/timetap', __FILE__)
120
+ working_directory = File.expand_path('../../', __FILE__)
79
121
 
80
122
  puts "\nCreating launchd plist in\n #{plist_path}"
81
123
 
@@ -88,17 +130,25 @@ module TimeTap
88
130
  <key>Label</key>
89
131
  <string>com.eliaesocietas.TimeTap</string>
90
132
 
91
- <key>Program</key>
92
- <string>#{ruby}</string>
93
-
94
133
  <key>ProgramArguments</key>
95
134
  <array>
96
135
  <string>#{ruby}</string>
97
136
  <string>#{include_dir}</string>
137
+ <string>-S</string>
138
+ <string>bundle</string>
139
+ <string>exec</string>
98
140
  <string>#{launcher}</string>
99
141
  <string>-f</string>
100
142
  </array>
101
143
 
144
+
145
+ <key>WorkingDirectory</key>
146
+ <string>#{working_directory}</string>
147
+ <key>StandardErrorPath</key>
148
+ <string>/usr/local/var/log/timetap.log</string>
149
+ <key>StandardOutPath</key>
150
+ <string>/usr/local/var/log/timetap.log</string>
151
+
102
152
  <key>OnDemand</key>
103
153
  <false/>
104
154
 
@@ -109,20 +159,44 @@ module TimeTap
109
159
  PLIST
110
160
  end
111
161
  end
112
-
113
- def reload!
162
+
163
+ def reload_launcher!
164
+ puts 'Reloading system launcher...'
165
+
114
166
  load_plist_info!
115
167
  command = "launchctl unload #{plist_path}; launchctl load #{plist_path}"
116
168
  exec command
117
169
  end
118
-
119
- private
120
-
121
- attr_reader :plist_path, :plist_name
122
-
123
- def load_plist_info!
124
- @plist_name ||= "com.eliaesocietas.TimeTap.plist"
125
- @plist_path ||= File.expand_path("~/Library/LaunchAgents/#{plist_name}")
170
+
171
+ def load_user_config!
172
+ require 'yaml'
173
+ TimeTap.config.merge! YAML.load_file(user_config) if File.exist?(user_config)
174
+ end
175
+
176
+ def user_config
177
+ @user_config ||= File.expand_path('~/.timetap.config')
178
+ end
179
+
180
+ def install_config!
181
+ puts 'Checking config...'
182
+ unless File.exist? user_config
183
+ require 'fileutils'
184
+ example_config = File.expand_path('../time_tap/config.yml.example', __FILE__)
185
+ FileUtils.copy example_config, user_config
186
+ puts "Added default config to #{user_config}"
126
187
  end
127
-
188
+ end
189
+
190
+
191
+
192
+
193
+ private
194
+
195
+ attr_reader :plist_path, :plist_name
196
+
197
+ def load_plist_info!
198
+ @plist_name ||= "com.eliaesocietas.TimeTap.plist"
199
+ @plist_path ||= File.expand_path("~/Library/LaunchAgents/#{plist_name}")
200
+ end
201
+
128
202
  end