caboodle 0.2.8 → 0.2.9
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/Rakefile +3 -6
- data/VERSION +1 -1
- data/bin/caboodle +7 -1
- data/lib/caboodle/app/.gems +2 -1
- data/lib/caboodle/app/config/site.yml +1 -0
- data/lib/caboodle/app.rb +1 -1
- data/lib/caboodle/command.rb +24 -14
- data/lib/caboodle/config.rb +1 -0
- data/lib/caboodle/kit.rb +53 -19
- data/lib/caboodle/kits/standard/standard.rb +3 -3
- data/lib/caboodle/scrape.rb +5 -2
- data/lib/caboodle.rb +1 -1
- metadata +29 -75
data/Rakefile
CHANGED
@@ -6,11 +6,10 @@ begin
|
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "caboodle"
|
8
8
|
gem.summary = "Web mashups the simple way"
|
9
|
-
gem.description = "
|
9
|
+
gem.description = "Caboodle is a Rack and Sinatra-based framework for creating websites which combine information from various online services. There are Kits for many of the larger services, which provide a way to retrieve and display photos, videos, blog posts, status updates and so on. Caboodle normalises the display of all of these discrete Kits so that you can create a website which looks seamless but is made up of a variety of things from a variety of sources."
|
10
10
|
gem.email = "stef@stef.io"
|
11
11
|
gem.homepage = "http://github.com/steflewandowski/caboodle"
|
12
|
-
gem.authors = ["
|
13
|
-
gem.add_dependency "heroku", ">= 0"
|
12
|
+
gem.authors = ["Stef Lewandowski"]
|
14
13
|
gem.add_dependency "sinatra", ">=1.0"
|
15
14
|
gem.add_dependency "hashie", ">=0.2.0"
|
16
15
|
gem.add_dependency "haml", ">=3.0.12"
|
@@ -18,11 +17,9 @@ begin
|
|
18
17
|
gem.add_dependency "compass-susy-plugin", ">=0.7.0"
|
19
18
|
gem.add_dependency "sinatra-compass", ">=0.5.0"
|
20
19
|
gem.add_dependency "sinatra-advanced-routes", ">=0.5.1"
|
21
|
-
gem.add_dependency "sinatra-content-for",">=0.2.0"
|
22
|
-
gem.add_dependency "memcached",">=0.19.9"
|
23
20
|
gem.add_dependency "nokogiri",">=1.4.0"
|
24
21
|
gem.add_dependency "weary",">=0.7.2"
|
25
|
-
gem.add_dependency "sleepy",">=0.1.
|
22
|
+
gem.add_dependency "sleepy",">=0.1.4"
|
26
23
|
end
|
27
24
|
Jeweler::GemcutterTasks.new
|
28
25
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.9
|
data/bin/caboodle
CHANGED
@@ -11,4 +11,10 @@ args = ARGV.dup
|
|
11
11
|
ARGV.clear
|
12
12
|
command = args.shift.strip rescue 'help'
|
13
13
|
|
14
|
-
|
14
|
+
git_path = `which git`
|
15
|
+
if git_path.blank?
|
16
|
+
puts "Sorry - you don't appear to have git installed or in your path"
|
17
|
+
puts "Please set up git and try again: http://github.com"
|
18
|
+
else
|
19
|
+
Caboodle::Command.run(command, args)
|
20
|
+
end
|
data/lib/caboodle/app/.gems
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
caboodle
|
1
|
+
caboodle
|
2
|
+
memcached
|
data/lib/caboodle/app.rb
CHANGED
data/lib/caboodle/command.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
gem 'heroku'
|
2
|
-
require 'heroku'
|
3
|
-
require 'heroku/command'
|
4
1
|
|
5
2
|
module Caboodle
|
6
3
|
module Command
|
@@ -8,20 +5,24 @@ module Caboodle
|
|
8
5
|
def run(command, args, retries=0)
|
9
6
|
case command
|
10
7
|
when "create"
|
11
|
-
puts
|
12
|
-
|
13
|
-
puts `
|
14
|
-
puts `cd #{
|
15
|
-
|
16
|
-
puts `cd #{
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
puts "Welcome to Caboodle!"
|
9
|
+
site_name = args.first
|
10
|
+
puts `mkdir -p #{site_name}`
|
11
|
+
puts `cd #{site_name} && cp -ri #{File.expand_path(File.join(File.dirname(__FILE__), 'app'))}/* .`
|
12
|
+
puts `cd #{site_name} && cp -i #{File.expand_path(File.join(File.dirname(__FILE__), 'app'))}/.gems .`
|
13
|
+
puts `cd #{site_name} && git init`
|
14
|
+
config = File.expand_path(File.join(".",site_name,"config","site.yml"))
|
15
|
+
Caboodle::Kit.configure config
|
16
|
+
puts "Please set a few settings to get started"
|
17
|
+
Caboodle::Kit.ask_user_for_all_missing_settings
|
18
|
+
puts `cd #{site_name} && git add .`
|
19
|
+
puts `cd #{site_name} && git commit -m"initial setup"`
|
20
20
|
when /kit:add/
|
21
21
|
Caboodle::Kit.load_kit args.first.capitalize
|
22
22
|
puts "Dump config"
|
23
23
|
Caboodle::Kit.dump_config
|
24
24
|
puts "Pushing to Heroku"
|
25
|
+
puts "Please be patient - this could take some time the first time you do this"
|
25
26
|
puts `git add .`
|
26
27
|
puts `git commit -m"kit:add #{args}" -a`
|
27
28
|
puts `git push heroku master`
|
@@ -29,7 +30,12 @@ module Caboodle
|
|
29
30
|
when /kit:home/
|
30
31
|
if Caboodle::Kit.available_kits.include?(args.first.capitalize)
|
31
32
|
Caboodle::Site.home_kit = args.first.capitalize
|
33
|
+
else
|
34
|
+
puts "Sorry - that Kit isn't available. Try:"
|
35
|
+
Caboodle::Kit.available_kits.each {|kit| puts kit}
|
32
36
|
end
|
37
|
+
when /kit:list/
|
38
|
+
Caboodle::Kit.available_kits.each {|kit| puts kit}
|
33
39
|
when /kit:remove/
|
34
40
|
Caboodle::Kit.unload_kit args.first.capitalize
|
35
41
|
puts "Pushing to Heroku"
|
@@ -38,12 +44,16 @@ module Caboodle
|
|
38
44
|
puts `git push heroku master`
|
39
45
|
puts "Done!"
|
40
46
|
when "deploy"
|
47
|
+
gem 'heroku'
|
48
|
+
require 'heroku'
|
49
|
+
require 'heroku/command'
|
50
|
+
|
41
51
|
puts `git commit -m"deploy" -a`
|
42
52
|
puts `git push heroku master`
|
43
53
|
else
|
44
|
-
|
54
|
+
puts "Sorry, that command is not recognized"
|
45
55
|
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
49
|
-
end
|
59
|
+
end
|
data/lib/caboodle/config.rb
CHANGED
@@ -8,6 +8,7 @@ module Caboodle
|
|
8
8
|
Errors = []
|
9
9
|
Defaults = Hashie::Mash.new(Hashie::Mash.new(YAML.load_file(File.join(File.dirname(__FILE__), 'config','defaults.yml'))))
|
10
10
|
RequiredSettings = Hashie::Mash.new()
|
11
|
+
OptionalSettings = Hashie::Mash.new()
|
11
12
|
Layout = Hashie::Mash.new()
|
12
13
|
Site = Defaults.clone
|
13
14
|
|
data/lib/caboodle/kit.rb
CHANGED
@@ -22,11 +22,13 @@ module Caboodle
|
|
22
22
|
class << self
|
23
23
|
attr_accessor :credit_link
|
24
24
|
|
25
|
-
def configure
|
26
|
-
|
25
|
+
def configure config_path
|
26
|
+
set :config, config_path
|
27
27
|
if File.exists?(config_path)
|
28
28
|
Caboodle::Kit.load_config(config_path)
|
29
29
|
Caboodle::Kit.setup
|
30
|
+
else
|
31
|
+
puts "No such configuration file: #{config_path}"
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -54,14 +56,13 @@ module Caboodle
|
|
54
56
|
|
55
57
|
def dump_config
|
56
58
|
begin
|
57
|
-
|
58
|
-
p = File.expand_path(File.join(Caboodle::App.root,"config","site.yml"))
|
59
|
+
p = config
|
59
60
|
d = Caboodle::Site.clone
|
60
61
|
e = d.to_hash
|
61
62
|
e.delete("required_settings")
|
62
63
|
File.open(p, 'w') {|f| f.write(YAML::dump(e))}
|
63
64
|
rescue
|
64
|
-
puts "Cannot write config file"
|
65
|
+
puts "Cannot write to config file: #{p}"
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
@@ -118,25 +119,43 @@ module Caboodle
|
|
118
119
|
end
|
119
120
|
|
120
121
|
def register_kit
|
121
|
-
|
122
|
-
puts "checking #{r}"
|
123
|
-
puts "value: #{Caboodle::Site[r]}"
|
124
|
-
if Caboodle::Site[r].blank?
|
125
|
-
puts "Rack env #{ENV["RACK_ENV"]}"
|
126
|
-
unless ENV["RACK_ENV"] == "production"
|
127
|
-
puts "Please set a value for #{r}:"
|
128
|
-
v = STDIN.gets
|
129
|
-
Caboodle::Site[r] = v
|
130
|
-
Caboodle::Kit.dump_config
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
122
|
+
ask_user_for_missing_settings
|
134
123
|
Site.kits << name
|
135
124
|
Site.kits.uniq!
|
136
125
|
Caboodle::Kits << self
|
137
126
|
Caboodle::Kits
|
138
127
|
end
|
139
128
|
|
129
|
+
def ask_user r, optional=false
|
130
|
+
unless ENV["RACK_ENV"] == "production"
|
131
|
+
puts " "
|
132
|
+
opt = "Optional: " if optional
|
133
|
+
puts "#{opt}Please set a value for #{r}:"
|
134
|
+
v = STDIN.gets
|
135
|
+
Caboodle::Site[r] = v
|
136
|
+
Caboodle::Kit.dump_config
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def ask_user_for_missing_settings
|
141
|
+
required_settings.each do |r|
|
142
|
+
if Caboodle::Site[r].blank?
|
143
|
+
ask_user r
|
144
|
+
end
|
145
|
+
end
|
146
|
+
optional_settings.each do |r|
|
147
|
+
if Caboodle::Site[r].blank?
|
148
|
+
ask_user r, true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def ask_user_for_all_missing_settings
|
154
|
+
Caboodle::Kits.each do |kit|
|
155
|
+
kit.ask_user_for_missing_settings
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
140
159
|
def unregister_kit
|
141
160
|
Caboodle::Kits.delete(self)
|
142
161
|
Caboodle::Site.kits.delete(self.to_s)
|
@@ -179,6 +198,16 @@ module Caboodle
|
|
179
198
|
self.required_settings
|
180
199
|
end
|
181
200
|
|
201
|
+
def optional keys
|
202
|
+
if keys.class == Array
|
203
|
+
keys.each do |k|
|
204
|
+
self.optional_settings << k
|
205
|
+
end
|
206
|
+
else
|
207
|
+
self.optional_settings << keys
|
208
|
+
end
|
209
|
+
self.optional_settings end
|
210
|
+
|
182
211
|
def stylesheets array_of_css_files
|
183
212
|
if array_of_css_files.class == Array
|
184
213
|
array_of_css_files.each { |a| Caboodle::Stylesheets << a.to_s }
|
@@ -245,9 +274,14 @@ module Caboodle
|
|
245
274
|
end
|
246
275
|
|
247
276
|
def required_settings
|
248
|
-
|
277
|
+
RequiredSettings[self.ancestors.first.to_s.split("::").last] ||= []
|
249
278
|
RequiredSettings[self.ancestors.first.to_s.split("::").last]
|
250
279
|
end
|
280
|
+
|
281
|
+
def optional_settings
|
282
|
+
OptionalSettings[self.ancestors.first.to_s.split("::").last] ||= []
|
283
|
+
OptionalSettings[self.ancestors.first.to_s.split("::").last]
|
284
|
+
end
|
251
285
|
|
252
286
|
def available_kits
|
253
287
|
Dir.new(File.join(File.dirname(__FILE__),"kits")).entries.delete_if{|a| a[0,1]=="."}
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Caboodle
|
2
2
|
class Standard < Caboodle::Kit
|
3
|
-
required [:title, :description, :
|
4
|
-
|
3
|
+
required [:title, :description, :author]
|
4
|
+
optional [:logo_url]
|
5
5
|
if Caboodle::Site.home_kit.blank? || !(Caboodle::Kit.available_kits.include?(Caboodle::Site.home_kit)) || !(Caboodle::Kits.include?(Caboodle::Site.home_kit))
|
6
|
-
puts "
|
6
|
+
puts "Using the default home kit - you will want to run 'caboodle kit:home <kit name>' to specify your own kit"
|
7
7
|
get "/" do
|
8
8
|
haml :standard
|
9
9
|
end
|
data/lib/caboodle/scrape.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'hashie'
|
3
|
+
|
1
4
|
module Caboodle
|
2
5
|
def self.scrape url
|
3
|
-
Nokogiri::HTML(Weary.get(url).perform_sleepily.body)
|
6
|
+
::Nokogiri::HTML(Weary.get(url).perform_sleepily.body)
|
4
7
|
end
|
5
8
|
|
6
9
|
def self.mash req
|
7
|
-
Hashie::Mash.new(req.perform_sleepily.parse)
|
10
|
+
::Hashie::Mash.new(req.perform_sleepily.parse)
|
8
11
|
end
|
9
12
|
end
|
data/lib/caboodle.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
$:<<File.dirname(__FILE__)
|
2
2
|
$:<<File.join(File.dirname(__FILE__),"caboodle")
|
3
|
-
%{sinatra/base
|
3
|
+
%{sinatra/base yaml hashie haml find sinatra/base sinatra/compass sinatra/advanced_routes compass susy pp sleepy caboodle/helpers caboodle/config caboodle/kit caboodle/app caboodle/scrape}.split.each{|a| require a}
|
metadata
CHANGED
@@ -1,41 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caboodle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 9
|
10
|
+
version: 0.2.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
|
-
-
|
13
|
+
- Stef Lewandowski
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-26 00:00:00 +01:00
|
19
19
|
default_executable: caboodle
|
20
20
|
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
22
|
-
name: heroku
|
23
|
-
prerelease: false
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
33
|
-
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
21
|
- !ruby/object:Gem::Dependency
|
36
22
|
name: sinatra
|
37
23
|
prerelease: false
|
38
|
-
requirement: &
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
39
25
|
none: false
|
40
26
|
requirements:
|
41
27
|
- - ">="
|
@@ -46,11 +32,11 @@ dependencies:
|
|
46
32
|
- 0
|
47
33
|
version: "1.0"
|
48
34
|
type: :runtime
|
49
|
-
version_requirements: *
|
35
|
+
version_requirements: *id001
|
50
36
|
- !ruby/object:Gem::Dependency
|
51
37
|
name: hashie
|
52
38
|
prerelease: false
|
53
|
-
requirement: &
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
54
40
|
none: false
|
55
41
|
requirements:
|
56
42
|
- - ">="
|
@@ -62,11 +48,11 @@ dependencies:
|
|
62
48
|
- 0
|
63
49
|
version: 0.2.0
|
64
50
|
type: :runtime
|
65
|
-
version_requirements: *
|
51
|
+
version_requirements: *id002
|
66
52
|
- !ruby/object:Gem::Dependency
|
67
53
|
name: haml
|
68
54
|
prerelease: false
|
69
|
-
requirement: &
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
70
56
|
none: false
|
71
57
|
requirements:
|
72
58
|
- - ">="
|
@@ -78,11 +64,11 @@ dependencies:
|
|
78
64
|
- 12
|
79
65
|
version: 3.0.12
|
80
66
|
type: :runtime
|
81
|
-
version_requirements: *
|
67
|
+
version_requirements: *id003
|
82
68
|
- !ruby/object:Gem::Dependency
|
83
69
|
name: compass
|
84
70
|
prerelease: false
|
85
|
-
requirement: &
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
86
72
|
none: false
|
87
73
|
requirements:
|
88
74
|
- - ">="
|
@@ -94,11 +80,11 @@ dependencies:
|
|
94
80
|
- 2
|
95
81
|
version: 0.10.2
|
96
82
|
type: :runtime
|
97
|
-
version_requirements: *
|
83
|
+
version_requirements: *id004
|
98
84
|
- !ruby/object:Gem::Dependency
|
99
85
|
name: compass-susy-plugin
|
100
86
|
prerelease: false
|
101
|
-
requirement: &
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
102
88
|
none: false
|
103
89
|
requirements:
|
104
90
|
- - ">="
|
@@ -110,11 +96,11 @@ dependencies:
|
|
110
96
|
- 0
|
111
97
|
version: 0.7.0
|
112
98
|
type: :runtime
|
113
|
-
version_requirements: *
|
99
|
+
version_requirements: *id005
|
114
100
|
- !ruby/object:Gem::Dependency
|
115
101
|
name: sinatra-compass
|
116
102
|
prerelease: false
|
117
|
-
requirement: &
|
103
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
118
104
|
none: false
|
119
105
|
requirements:
|
120
106
|
- - ">="
|
@@ -126,11 +112,11 @@ dependencies:
|
|
126
112
|
- 0
|
127
113
|
version: 0.5.0
|
128
114
|
type: :runtime
|
129
|
-
version_requirements: *
|
115
|
+
version_requirements: *id006
|
130
116
|
- !ruby/object:Gem::Dependency
|
131
117
|
name: sinatra-advanced-routes
|
132
118
|
prerelease: false
|
133
|
-
requirement: &
|
119
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
134
120
|
none: false
|
135
121
|
requirements:
|
136
122
|
- - ">="
|
@@ -142,43 +128,11 @@ dependencies:
|
|
142
128
|
- 1
|
143
129
|
version: 0.5.1
|
144
130
|
type: :runtime
|
145
|
-
version_requirements: *
|
146
|
-
- !ruby/object:Gem::Dependency
|
147
|
-
name: sinatra-content-for
|
148
|
-
prerelease: false
|
149
|
-
requirement: &id009 !ruby/object:Gem::Requirement
|
150
|
-
none: false
|
151
|
-
requirements:
|
152
|
-
- - ">="
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
hash: 23
|
155
|
-
segments:
|
156
|
-
- 0
|
157
|
-
- 2
|
158
|
-
- 0
|
159
|
-
version: 0.2.0
|
160
|
-
type: :runtime
|
161
|
-
version_requirements: *id009
|
162
|
-
- !ruby/object:Gem::Dependency
|
163
|
-
name: memcached
|
164
|
-
prerelease: false
|
165
|
-
requirement: &id010 !ruby/object:Gem::Requirement
|
166
|
-
none: false
|
167
|
-
requirements:
|
168
|
-
- - ">="
|
169
|
-
- !ruby/object:Gem::Version
|
170
|
-
hash: 65
|
171
|
-
segments:
|
172
|
-
- 0
|
173
|
-
- 19
|
174
|
-
- 9
|
175
|
-
version: 0.19.9
|
176
|
-
type: :runtime
|
177
|
-
version_requirements: *id010
|
131
|
+
version_requirements: *id007
|
178
132
|
- !ruby/object:Gem::Dependency
|
179
133
|
name: nokogiri
|
180
134
|
prerelease: false
|
181
|
-
requirement: &
|
135
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
182
136
|
none: false
|
183
137
|
requirements:
|
184
138
|
- - ">="
|
@@ -190,11 +144,11 @@ dependencies:
|
|
190
144
|
- 0
|
191
145
|
version: 1.4.0
|
192
146
|
type: :runtime
|
193
|
-
version_requirements: *
|
147
|
+
version_requirements: *id008
|
194
148
|
- !ruby/object:Gem::Dependency
|
195
149
|
name: weary
|
196
150
|
prerelease: false
|
197
|
-
requirement: &
|
151
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
198
152
|
none: false
|
199
153
|
requirements:
|
200
154
|
- - ">="
|
@@ -206,24 +160,24 @@ dependencies:
|
|
206
160
|
- 2
|
207
161
|
version: 0.7.2
|
208
162
|
type: :runtime
|
209
|
-
version_requirements: *
|
163
|
+
version_requirements: *id009
|
210
164
|
- !ruby/object:Gem::Dependency
|
211
165
|
name: sleepy
|
212
166
|
prerelease: false
|
213
|
-
requirement: &
|
167
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
214
168
|
none: false
|
215
169
|
requirements:
|
216
170
|
- - ">="
|
217
171
|
- !ruby/object:Gem::Version
|
218
|
-
hash:
|
172
|
+
hash: 19
|
219
173
|
segments:
|
220
174
|
- 0
|
221
175
|
- 1
|
222
|
-
-
|
223
|
-
version: 0.1.
|
176
|
+
- 4
|
177
|
+
version: 0.1.4
|
224
178
|
type: :runtime
|
225
|
-
version_requirements: *
|
226
|
-
description:
|
179
|
+
version_requirements: *id010
|
180
|
+
description: Caboodle is a Rack and Sinatra-based framework for creating websites which combine information from various online services. There are Kits for many of the larger services, which provide a way to retrieve and display photos, videos, blog posts, status updates and so on. Caboodle normalises the display of all of these discrete Kits so that you can create a website which looks seamless but is made up of a variety of things from a variety of sources.
|
227
181
|
email: stef@stef.io
|
228
182
|
executables:
|
229
183
|
- caboodle
|