things-client 0.1.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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +114 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/lib/appscript/reference.rb +9 -0
- data/lib/things/app.rb +30 -0
- data/lib/things/area.rb +12 -0
- data/lib/things/collections/todo.rb +42 -0
- data/lib/things/list.rb +18 -0
- data/lib/things/project.rb +12 -0
- data/lib/things/reference/base.rb +14 -0
- data/lib/things/reference/inheritance.rb +29 -0
- data/lib/things/reference/record.rb +121 -0
- data/lib/things/status.rb +8 -0
- data/lib/things/tag.rb +12 -0
- data/lib/things/todo.rb +18 -0
- data/lib/things.rb +28 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/things/app_spec.rb +43 -0
- data/spec/things/area_spec.rb +153 -0
- data/spec/things/collections/todo_spec.rb +54 -0
- data/spec/things/project_spec.rb +153 -0
- data/spec/things/tag_spec.rb +153 -0
- data/spec/things/todo_spec.rb +160 -0
- data/spec/things_spec.rb +15 -0
- data/things.gemspec +68 -0
- metadata +110 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Marcin Bunsch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
= Things
|
2
|
+
|
3
|
+
Things is a Ruby API for the popular GTD app Things, available on the Mac.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Currently, because this is an alpha version and it's too early for a release, installation must be done manually, like this:
|
8
|
+
|
9
|
+
git clone http://github.com/marcinbunsch/things
|
10
|
+
cd things
|
11
|
+
rake check_dependencies:runtime
|
12
|
+
rake build
|
13
|
+
sudo gem install pkg/things-0.0.1.gem
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
=== Application
|
18
|
+
|
19
|
+
The Application can be accessed at all times by calling Things::App. It has a few useful methods which will be described below. If you want Things to gain focus and move to the front of the window stack, you can call the Things::App.activate method.
|
20
|
+
|
21
|
+
=== Todos
|
22
|
+
|
23
|
+
Todos are accessed via the Things::Todo class.
|
24
|
+
|
25
|
+
==== Create
|
26
|
+
|
27
|
+
If you want to create a new Todo, you simple create a new instance of the Things::Todo class, supplying the parameters:
|
28
|
+
|
29
|
+
Things::Todo.new(:name => 'Take out the garbage')
|
30
|
+
|
31
|
+
When you're ready to send it to Things, simply call the save method on the instance:
|
32
|
+
|
33
|
+
todo = Things::Todo.new(:name => 'Take out the garbage')
|
34
|
+
todo.save # the Todo will appear in the Inbox
|
35
|
+
|
36
|
+
If you want to send the Todo to Things during the instantiation process, simply call create:
|
37
|
+
|
38
|
+
Things::Todo.create(:name => 'Take out the garbage') # the Todo will appear in the Inbox
|
39
|
+
|
40
|
+
==== Read
|
41
|
+
|
42
|
+
===== Collections
|
43
|
+
|
44
|
+
If you want to fetch a list of todos, there is a set of collections you can use.
|
45
|
+
|
46
|
+
The largest one is the collection of all Todos. You fetch it by calling:
|
47
|
+
|
48
|
+
Things::App.todos
|
49
|
+
|
50
|
+
It will return an array of Things::Todo instances.
|
51
|
+
|
52
|
+
If you only want the active (so non-finished) Todos, you can fetch a collection by calling:
|
53
|
+
|
54
|
+
Things::App.todos.active
|
55
|
+
|
56
|
+
It will return an array of Things::Todo instances.
|
57
|
+
|
58
|
+
As the gem will grow, more methods will follow.
|
59
|
+
|
60
|
+
===== Single Todos
|
61
|
+
|
62
|
+
Things::Todo has a few useful methods if you want to fetch a single Todo.
|
63
|
+
|
64
|
+
The smartest is the Things::Todo.find method, which will accept either a name or an id.
|
65
|
+
|
66
|
+
Things::Todo.find('Take out the garbage') # => #<Things::Todo:0x115dd84>
|
67
|
+
Things::Todo.find('11111111-1111-1111-1111-111111111111') # => #<Things::Todo:0x115dd84>
|
68
|
+
|
69
|
+
If you want a more targeted approach, you can use Things::Todo.find_by_name or Things::Todo.find_by_id
|
70
|
+
|
71
|
+
==== Update
|
72
|
+
|
73
|
+
To update a Todo, you need to fetch it, change the desired properties and save it. The following example illustrates this:
|
74
|
+
|
75
|
+
todo = Things::Todo.find('Take out the garbage') # => #<Things::Todo:0x115dd84>
|
76
|
+
todo.name = 'Take out the garbage and old boxes'
|
77
|
+
todo.save
|
78
|
+
|
79
|
+
When you open up a Things window, you'll notice that the name has changed.
|
80
|
+
|
81
|
+
==== Delete
|
82
|
+
|
83
|
+
To delete a todo, simply call the delete method. The Todo will bo moved to Trash.
|
84
|
+
|
85
|
+
todo = Things::Todo.find('Take out the garbage') # => #<Things::Todo:0x115dd84>
|
86
|
+
todo.delete
|
87
|
+
|
88
|
+
== Roadmap
|
89
|
+
|
90
|
+
Currently Todos are fully supported, which is the core functionality of Todos, but leaves a lot of room for improvement. The first step is to create a unified API for handling AppleScript objects which behave in a similar way.
|
91
|
+
|
92
|
+
Planned features:
|
93
|
+
|
94
|
+
* Support for Projects
|
95
|
+
* Support for Areas
|
96
|
+
* Support for Tags
|
97
|
+
* Support for Scheduled Todos
|
98
|
+
|
99
|
+
== Contribution
|
100
|
+
|
101
|
+
You're more than welcome to fork and improve this gem. Usual rules:
|
102
|
+
|
103
|
+
* Fork the project.
|
104
|
+
* Make your feature addition or bug fix.
|
105
|
+
* Add tests for it. This is important so I don't break it in a
|
106
|
+
future version unintentionally.
|
107
|
+
* Commit, do not mess with rakefile, version, or history.
|
108
|
+
(if you want to have your own version, that is fine but
|
109
|
+
bump version in a commit by itself I can ignore when I pull)
|
110
|
+
* Send me a pull request.
|
111
|
+
|
112
|
+
== Copyright
|
113
|
+
|
114
|
+
Copyright (c) 2010 Marcin Bunsch. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "things-client"
|
8
|
+
gem.summary = %Q{A Ruby client for Things' Applescript API. Things is a GTD app for OS X.}
|
9
|
+
gem.email = "marcin@applicake.com"
|
10
|
+
gem.homepage = "http://github.com/marcinbunsch/things"
|
11
|
+
gem.authors = ["Marcin Bunsch"]
|
12
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
13
|
+
gem.add_dependency "rb-appscript", ">=0.5.3"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'spec/rake/spectask'
|
21
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
22
|
+
spec.libs << 'lib' << 'spec'
|
23
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
24
|
+
end
|
25
|
+
|
26
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
27
|
+
spec.libs << 'lib' << 'spec'
|
28
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
29
|
+
spec.rcov = true
|
30
|
+
end
|
31
|
+
|
32
|
+
task :spec => :check_dependencies
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
require 'rake/rdoctask'
|
37
|
+
Rake::RDocTask.new do |rdoc|
|
38
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
39
|
+
|
40
|
+
rdoc.rdoc_dir = 'rdoc'
|
41
|
+
rdoc.title = "things-client #{version}"
|
42
|
+
rdoc.rdoc_files.include('README*')
|
43
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/things/app.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Things
|
2
|
+
class App < Reference::Base
|
3
|
+
extend Appscript
|
4
|
+
# get the singleton Application instance
|
5
|
+
def self.instance
|
6
|
+
reference ||= app('Things')
|
7
|
+
end
|
8
|
+
|
9
|
+
# refresh the Application instance
|
10
|
+
def self.instance!
|
11
|
+
reference = app('Things')
|
12
|
+
end
|
13
|
+
|
14
|
+
# get a collection of Lists
|
15
|
+
def self.lists
|
16
|
+
List
|
17
|
+
end
|
18
|
+
|
19
|
+
# get a collection of Todos
|
20
|
+
def self.todos
|
21
|
+
Collections::Todo
|
22
|
+
end
|
23
|
+
|
24
|
+
# activate the app and bring it to front
|
25
|
+
def self.activate
|
26
|
+
instance!.activate
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/things/area.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Things
|
2
|
+
module Collections
|
3
|
+
class Todo
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Returns an Appscript Reference to the entire collection of todos
|
8
|
+
def reference
|
9
|
+
Things::App.instance.todos
|
10
|
+
end
|
11
|
+
|
12
|
+
# these are references and should be stored somewhere else...
|
13
|
+
Things::List::DEFAULTS.each do |list|
|
14
|
+
class_eval <<-"eval"
|
15
|
+
def #{list}
|
16
|
+
Things::App.lists.#{list}.todos
|
17
|
+
end
|
18
|
+
eval
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an array of Things::Todo objects
|
22
|
+
def all
|
23
|
+
reference.get.collect { |todo| Things::Todo.build(todo) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get all not completed Todos
|
27
|
+
# Note this returns an array of Todos, not references
|
28
|
+
# TODO: find a better way of filtering references
|
29
|
+
def active
|
30
|
+
result = (reference.get - Things::List.trash.todos.get).collect do |todo|
|
31
|
+
Things::Todo.build(todo) if todo.completion_date.get.to_s == 'missing_value'
|
32
|
+
end
|
33
|
+
result.compact
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/things/list.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Things
|
2
|
+
class List
|
3
|
+
DEFAULTS = [:inbox, :today, :next, :scheduled, :someday, :projects, :logbook, :trash]
|
4
|
+
class << self
|
5
|
+
def all
|
6
|
+
Things::App.instance.lists
|
7
|
+
end
|
8
|
+
|
9
|
+
DEFAULTS.each do |list|
|
10
|
+
class_eval <<-"eval"
|
11
|
+
def #{list}
|
12
|
+
all['#{list.to_s.capitalize}']
|
13
|
+
end
|
14
|
+
eval
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Things
|
2
|
+
# Things::Reference
|
3
|
+
module Reference
|
4
|
+
|
5
|
+
module Inheritance
|
6
|
+
|
7
|
+
def inheritable_attributes(*args)
|
8
|
+
@inheritable_attributes ||= [:inheritable_attributes]
|
9
|
+
@inheritable_attributes += args
|
10
|
+
args.each do |arg|
|
11
|
+
class_eval %(
|
12
|
+
class << self; attr_accessor :#{arg} end
|
13
|
+
)
|
14
|
+
end
|
15
|
+
@inheritable_attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def inherited(subclass)
|
19
|
+
@inheritable_attributes.each do |inheritable_attribute|
|
20
|
+
instance_var = "@#{inheritable_attribute}"
|
21
|
+
subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Things
|
2
|
+
# Things::Reference
|
3
|
+
module Reference
|
4
|
+
|
5
|
+
class Record < Base
|
6
|
+
|
7
|
+
extend Inheritance
|
8
|
+
|
9
|
+
inheritable_attributes :_properties, :identifier, :collection
|
10
|
+
|
11
|
+
def self.identifier(name = nil)
|
12
|
+
name ? @identifier = name : @identifier
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.collection(name = nil)
|
16
|
+
name ? @collection = name : @collection
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.properties(*args)
|
20
|
+
@_properties = [] if !@_properties
|
21
|
+
if args
|
22
|
+
@_properties += args
|
23
|
+
@_properties.each do |property|
|
24
|
+
attr_writer(property) if !instance_methods.include?(property.to_s)
|
25
|
+
if !instance_methods.include?(property.to_s )
|
26
|
+
class_eval <<-"eval"
|
27
|
+
def #{property}
|
28
|
+
if !@#{property}
|
29
|
+
fetched = @reference.#{property}.get rescue nil
|
30
|
+
@#{property} = fetched if fetched and fetched != :missing_value
|
31
|
+
else
|
32
|
+
@#{property}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
eval
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
# :id_ is always present
|
41
|
+
properties :id_
|
42
|
+
|
43
|
+
def initialize(props = {})
|
44
|
+
props.each_pair do |property, value|
|
45
|
+
self.send("#{property}=", value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns whether the instance if new or has already been saved
|
50
|
+
def new?
|
51
|
+
id_.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Save a Todo
|
55
|
+
#
|
56
|
+
# If a todo is new, it will be created. If not, it will be updated
|
57
|
+
def save
|
58
|
+
if new?
|
59
|
+
properties = {}
|
60
|
+
(self.class.properties - [:id_]).each do |property|
|
61
|
+
properties[property] = self.send(property) if self.send(property)
|
62
|
+
end
|
63
|
+
self.reference = Things::App.instance.make(:new => self.class.identifier, :with_properties => properties)
|
64
|
+
else
|
65
|
+
(self.class.properties - [:id_]).each do |property|
|
66
|
+
self.reference.send(property).set(self.send(property)) if self.send(property)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Delete a object
|
73
|
+
#
|
74
|
+
# This places the object in the trash
|
75
|
+
def delete
|
76
|
+
Things::App.instance.delete(self.reference) rescue false
|
77
|
+
end
|
78
|
+
|
79
|
+
# create a new object based on that supplied properties and saves it
|
80
|
+
def self.create(props)
|
81
|
+
new(props).save
|
82
|
+
end
|
83
|
+
|
84
|
+
# build a new instance and link it to the supplied reference
|
85
|
+
#
|
86
|
+
# Returns a object associated with a reference
|
87
|
+
def self.build(reference)
|
88
|
+
todo = self.new
|
89
|
+
todo.reference = reference
|
90
|
+
todo
|
91
|
+
end
|
92
|
+
|
93
|
+
# find a todo by a name or id
|
94
|
+
#
|
95
|
+
# Returns a Things::Todo object associated with a reference
|
96
|
+
def self.find(name_or_id)
|
97
|
+
find_by_name(name_or_id) || find_by_id(name_or_id)
|
98
|
+
end
|
99
|
+
|
100
|
+
# find a todo by a name
|
101
|
+
#
|
102
|
+
# Returns a Things::Todo object associated with a reference
|
103
|
+
def self.find_by_name(name)
|
104
|
+
reference = Things::App.instance.send(self.collection)[name].get rescue nil
|
105
|
+
build(reference) if reference
|
106
|
+
end
|
107
|
+
|
108
|
+
# find a todo by a id
|
109
|
+
# Returns a Things::Todo object associated with a reference
|
110
|
+
def self.find_by_id(id)
|
111
|
+
finder = Appscript.its.id_.eq(id)
|
112
|
+
reference = Things::App.instance.send(self.collection)[finder].get rescue nil
|
113
|
+
reference = reference.first if reference.is_a?(Array)
|
114
|
+
build(reference) if reference
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/lib/things/tag.rb
ADDED
data/lib/things/todo.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Things
|
2
|
+
# Things::Todo
|
3
|
+
class Todo < Reference::Record
|
4
|
+
|
5
|
+
properties :name, :notes, :completion_date
|
6
|
+
# identifier is required for creation
|
7
|
+
identifier :to_do
|
8
|
+
# collection is used for findings
|
9
|
+
collection :todos
|
10
|
+
|
11
|
+
# Move a todo to a different list <br />
|
12
|
+
# Moving to Trash will delete the todo
|
13
|
+
def move(list)
|
14
|
+
Things::App.instance.move(reference, { :to => list })
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/things.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'appscript'
|
2
|
+
require "#{File.dirname(__FILE__)}/appscript/reference"
|
3
|
+
#
|
4
|
+
# Things is a client for the Mac OS X GTD app Things
|
5
|
+
#
|
6
|
+
# It uses AppleScript to gain access to the Things scripting API
|
7
|
+
#
|
8
|
+
module Things
|
9
|
+
autoload :App, File.dirname(__FILE__) + '/things/app'
|
10
|
+
autoload :Todo, File.dirname(__FILE__) + '/things/todo'
|
11
|
+
autoload :List, File.dirname(__FILE__) + '/things/list'
|
12
|
+
autoload :Status, File.dirname(__FILE__) + '/things/status'
|
13
|
+
autoload :Area, File.dirname(__FILE__) + '/things/area'
|
14
|
+
autoload :Project, File.dirname(__FILE__) + '/things/project'
|
15
|
+
autoload :Tag, File.dirname(__FILE__) + '/things/tag'
|
16
|
+
|
17
|
+
module Collections
|
18
|
+
autoload :Todo, File.dirname(__FILE__) + '/things/collections/todo'
|
19
|
+
end
|
20
|
+
|
21
|
+
module Reference
|
22
|
+
autoload :Base, File.dirname(__FILE__) + '/things/reference/base'
|
23
|
+
autoload :Inheritance, File.dirname(__FILE__) + '/things/reference/inheritance'
|
24
|
+
autoload :Record, File.dirname(__FILE__) + '/things/reference/record'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Things::App" do
|
4
|
+
|
5
|
+
describe '#instance' do
|
6
|
+
|
7
|
+
it 'should return an instance of the Things app' do
|
8
|
+
Things::App.instance.class.should == Appscript::Application
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#activate' do
|
14
|
+
|
15
|
+
it 'should start the app if it is not running' do
|
16
|
+
|
17
|
+
# close if running
|
18
|
+
#Things::App.instance!.quit if `ps x | grep Things`.include?('Things.app')
|
19
|
+
#{}`ps x | grep Things`.should_not match('Things.app')
|
20
|
+
#Things::App.instance!.activate
|
21
|
+
#{}`ps x | grep Things`.should match('Things.app')
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#lists' do
|
27
|
+
|
28
|
+
it "should return Things::Collections::List" do
|
29
|
+
Things::App.lists.should == Things::List
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#todos' do
|
35
|
+
|
36
|
+
it "should return Things::Collections::Todo" do
|
37
|
+
Things::App.todos.should == Things::Collections::Todo
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|