sec_query 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/Gemfile.lock +30 -0
- data/README.md +133 -0
- data/Rakefile +1 -0
- data/lib/.DS_Store +0 -0
- data/lib/sec_query/.DS_Store +0 -0
- data/lib/sec_query/entity.rb +305 -0
- data/lib/sec_query/filing.rb +45 -0
- data/lib/sec_query/relationship.rb +63 -0
- data/lib/sec_query/transaction.rb +89 -0
- data/lib/sec_query/version.rb +3 -0
- data/lib/sec_query.rb +11 -0
- data/pkg/sec_query-0.0.1.gem +0 -0
- data/sec_query.gemspec +26 -0
- data/spec/sec_query_spec.rb +65 -0
- data/spec/spec_helper.rb +1 -0
- metadata +126 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sec_query (0.0.1)
|
5
|
+
hpricot
|
6
|
+
rest-client
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
hpricot (0.8.4)
|
13
|
+
mime-types (1.17.2)
|
14
|
+
rest-client (1.6.7)
|
15
|
+
mime-types (>= 1.16)
|
16
|
+
rspec (2.7.0)
|
17
|
+
rspec-core (~> 2.7.0)
|
18
|
+
rspec-expectations (~> 2.7.0)
|
19
|
+
rspec-mocks (~> 2.7.0)
|
20
|
+
rspec-core (2.7.1)
|
21
|
+
rspec-expectations (2.7.0)
|
22
|
+
diff-lcs (~> 1.1.2)
|
23
|
+
rspec-mocks (2.7.0)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
rspec
|
30
|
+
sec_query!
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# sec_query
|
2
|
+
|
3
|
+
A ruby gem for searching and retrieving data from the Security and Exchange Commission's Edgar web system.
|
4
|
+
|
5
|
+
Look-up an Entity - person or company - by Central Index Key (CIK), stock symbol, company name or person (by first and last name).
|
6
|
+
|
7
|
+
Additionally retrieve some, or all, Relationships, Transactions and Filings as recorded by the SEC.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
To install the 'sec_query' Ruby Gem run the following command at the terminal prompt.
|
12
|
+
|
13
|
+
`gem install sec_query`
|
14
|
+
|
15
|
+
For an example of what type of information 'sec_query' can retrieve, run the following command:
|
16
|
+
|
17
|
+
`bundle exec rspec spec`
|
18
|
+
|
19
|
+
If running 'sec_query' from the command prompt in irb:
|
20
|
+
|
21
|
+
`irb -rubygems`
|
22
|
+
|
23
|
+
`require "sec_query"`
|
24
|
+
|
25
|
+
`include SecQuery`
|
26
|
+
|
27
|
+
## Functionality
|
28
|
+
|
29
|
+
### FIND COMPANY:
|
30
|
+
|
31
|
+
#### By Stock Symbol:
|
32
|
+
|
33
|
+
`SecQuery::Entity.find("appl")`
|
34
|
+
|
35
|
+
Or:
|
36
|
+
|
37
|
+
`SecQuery::Entity.find({:symbol=> "aapl"})`
|
38
|
+
|
39
|
+
#### By Name:
|
40
|
+
|
41
|
+
`SecQuery::Entity.find("Apple, Inc.")`
|
42
|
+
|
43
|
+
Or:
|
44
|
+
|
45
|
+
`SecQuery::Entity.find({:name=> "Apple, Inc."})`
|
46
|
+
|
47
|
+
#### By Central Index Key, CIK:
|
48
|
+
|
49
|
+
`SecQuery::Entity.find( "0000320193")`
|
50
|
+
|
51
|
+
Or:
|
52
|
+
|
53
|
+
`SecQuery::Entity.find({:cik=> "0000320193"})`
|
54
|
+
|
55
|
+
#### FIND PERSON:
|
56
|
+
|
57
|
+
By First, Middle and Last Name.
|
58
|
+
|
59
|
+
`SecQuery::Entity.find({:first=> "Steve", :middle=> "P", :last=> "Jobs"})`
|
60
|
+
|
61
|
+
Middle initial or name is optional, but helps when there are multiple results for First and Last Name.
|
62
|
+
|
63
|
+
### RELATIONSHIPS, TRANSACTIONS, FILINGS
|
64
|
+
|
65
|
+
To return everything - All Relationships, Transactions and Filings - that the SEC Edgar system has stored on a company or person, do any of the following commands (They all do the same thing.):
|
66
|
+
|
67
|
+
`SecQuery::Entity.find("AAPL", true)`
|
68
|
+
|
69
|
+
`SecQuery::Entity.find("AAPL", true, true, true)`
|
70
|
+
|
71
|
+
`SecQuery::Entity.find("AAPL", {:relationships=> true, :transactions=> true, :filings=>true})`
|
72
|
+
|
73
|
+
`SecQuery::Entity.find("AAPL", :relationships=> true, :transactions=> true, :filings=>true)`
|
74
|
+
|
75
|
+
`SecQuery::Entity.find("AAPL", :relationships=> true, :transactions=> {:start=> 0, :count=> 80}, :filings=>{:start=> 0, :count=> 80})`
|
76
|
+
|
77
|
+
You may also limit either the transactions or filings by adding the :limit to the transaction or filing arguements.
|
78
|
+
|
79
|
+
For example,
|
80
|
+
|
81
|
+
`SecQuery::Entity.find("AAPL", :relationships=> true, :transactions=> {:start=> 0, :count=>20, :limit=> 20}, :filings=>{:start=> 0, :count=> 20, :limit=> 20})`
|
82
|
+
|
83
|
+
The above query will only return the last 20 transactions and filings. This is helpful when querying companies that may have thousands or tens of thousands of transactions or filings.
|
84
|
+
|
85
|
+
### Entity.log(entity)
|
86
|
+
|
87
|
+
For doing terminal queries, there is a log function that formats and prints the entity data to your terminal window.
|
88
|
+
|
89
|
+
`entity = SecQuery::Entity.find("AAPL", true)`
|
90
|
+
|
91
|
+
`SecQuery::Entity.log(entity)`
|
92
|
+
|
93
|
+
|
94
|
+
## Classes
|
95
|
+
|
96
|
+
This gem contains four classes - Entity, Relationship, Transaction and Filing. Each Class contains the listed fields. (Everything I could parse out of the query results.)
|
97
|
+
|
98
|
+
* Entity
|
99
|
+
|
100
|
+
`:first, :middle, :last, :name, :symbol, :cik, :url, :type, :sic, :location, :state_of_inc, :formerly, :mailing_address, :business_address, :relationships, :transactions, :filings`
|
101
|
+
|
102
|
+
* Relationship
|
103
|
+
|
104
|
+
`:name, :position, :date, :cik`
|
105
|
+
|
106
|
+
* Transaction
|
107
|
+
|
108
|
+
`:filing_number, :code, :date, :reporting_owner, :form, :type, :modes, :shares, :price, :owned, :number, :owner_cik, :security_name, :deemed, :exercise, :nature, :derivative, :underlying_1, :exercised, :underlying_2, :expires, :underlying_3`
|
109
|
+
|
110
|
+
* Filing
|
111
|
+
|
112
|
+
`:cik, :title, :summary, :link, :term, :date, :file_id`
|
113
|
+
|
114
|
+
## To Whom It May Concern at the SEC
|
115
|
+
|
116
|
+
Over the last decade, I have gotten to know Edgar quite extensively and I have grown quite fond of it and the information it contains. So it is with my upmost respect that I make the following suggestions:
|
117
|
+
|
118
|
+
* Edgar is in dire need of a proper, published RESTful API.
|
119
|
+
* Edgar needs to be able to return XML or JSON for any API query.
|
120
|
+
* Edgar's search engine is atrocious; Rigid to the point of being almost unusable.
|
121
|
+
* Edgar only goes back as far as 1993, and in most cases, only provides extensive information after 2000.
|
122
|
+
|
123
|
+
It is my humble opinion that these four issues are limiting the effectiveness of Edgar and the SEC in general. The information the SEC contains is vitally important to National Security and the stability of the American Economy and the World. It is time to make all information available and accessible.
|
124
|
+
|
125
|
+
## License
|
126
|
+
|
127
|
+
Copyright (c) 2011 Ty Rauber
|
128
|
+
|
129
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
130
|
+
|
131
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
132
|
+
|
133
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,305 @@
|
|
1
|
+
module SecQuery
|
2
|
+
class Entity
|
3
|
+
|
4
|
+
attr_accessor :first, :middle, :last, :name, :symbol, :cik, :url, :type, :sic, :location, :state_of_inc, :formerly, :mailing_address, :business_address, :relationships, :transactions, :filings
|
5
|
+
|
6
|
+
def initialize(entity)
|
7
|
+
@first = entity[:first]
|
8
|
+
@middle = entity[:middle]
|
9
|
+
@last = entity[:last]
|
10
|
+
@name = entity[:name]
|
11
|
+
@sic = entity[:sic]
|
12
|
+
@url = entity[:url]
|
13
|
+
@location = entity[:location]
|
14
|
+
@state_of_inc = entity[:state_of_inc]
|
15
|
+
@formerly = entity[:formerly]
|
16
|
+
@symbol = entity[:symbol]
|
17
|
+
@cik = entity[:cik]
|
18
|
+
@type =entity[:type]
|
19
|
+
@mailing_address = entity[:mailing_address]
|
20
|
+
@business_address = entity[:business_address]
|
21
|
+
@relationships = entity[:relationships]
|
22
|
+
@transactions = entity[:transactions]
|
23
|
+
@filings = entity[:filings]
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def self.find(entity_args, *options)
|
28
|
+
|
29
|
+
temp = {}
|
30
|
+
temp[:url] = Entity.url(entity_args)
|
31
|
+
temp[:cik] = Entity.cik(temp[:url], entity_args)
|
32
|
+
|
33
|
+
if !temp[:cik]; return false; end
|
34
|
+
|
35
|
+
### Get Document and Entity Type
|
36
|
+
doc = Entity.document(temp[:cik])
|
37
|
+
temp = Entity.parse_document(temp, doc)
|
38
|
+
|
39
|
+
### Get Additional Arguments and Query Additional Details
|
40
|
+
if !options.empty?;
|
41
|
+
temp[:transactions]=[]
|
42
|
+
temp[:filings] =[]
|
43
|
+
options = Entity.options(temp, options);
|
44
|
+
temp = Entity.details(temp, options);
|
45
|
+
end
|
46
|
+
|
47
|
+
### Return entity Object
|
48
|
+
@entity = Entity.new(temp)
|
49
|
+
|
50
|
+
return @entity
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def self.query(url)
|
56
|
+
RestClient.get(url){ |response, request, result, &block|
|
57
|
+
case response.code
|
58
|
+
when 200
|
59
|
+
return response
|
60
|
+
else
|
61
|
+
response.return!(request, result, &block)
|
62
|
+
end
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def self.url(args)
|
68
|
+
if args.is_a?(Hash)
|
69
|
+
if args[:symbol] != nil
|
70
|
+
string = "CIK="+args[:symbol]
|
71
|
+
elsif args[:cik] != nil
|
72
|
+
string = "CIK="+args[:cik]
|
73
|
+
elsif args[:first] != nil and args[:last]
|
74
|
+
string = "company="+args[:last]+" "+args[:first]
|
75
|
+
elsif args[:name] != nil
|
76
|
+
string = "company="+args[:name].gsub(/[(,?!\''"":.)]/, '')
|
77
|
+
end
|
78
|
+
elsif args.is_a?(String)
|
79
|
+
begin Float(args)
|
80
|
+
string = "CIK="+args
|
81
|
+
rescue
|
82
|
+
if args.length <= 4
|
83
|
+
string = "CIK="+args
|
84
|
+
else
|
85
|
+
string = "company="+args.gsub(/[(,?!\''"":.)]/, '')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
string = string.to_s.gsub(" ", "+")
|
90
|
+
url = "http://www.sec.gov/cgi-bin/browse-edgar?"+string+"&action=getcompany"
|
91
|
+
return url
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.cik(url, entity)
|
95
|
+
response = Entity.query(url+"&output=atom")
|
96
|
+
doc = Hpricot::XML(response)
|
97
|
+
data = doc.search(:title)[0];
|
98
|
+
if data.inner_text == "EDGAR Search Results"
|
99
|
+
tbl = doc.search("//span[@class='companyMatch']")
|
100
|
+
if tbl && tbl.innerHTML != ""
|
101
|
+
tbl = tbl[0].parent.search("table")[0].search("tr")
|
102
|
+
for tr in tbl
|
103
|
+
td = tr.search("td")
|
104
|
+
if td[1] != nil && entity[:middle] != nil && td[1].innerHTML.downcase == (entity[:last]+" "+entity[:first]+" "+entity[:middle]).downcase or td[1] != nil && td[1].innerHTML.downcase == (entity[:last]+" "+entity[:first]).downcase
|
105
|
+
cik = td[0].search("a").innerHTML
|
106
|
+
return cik;
|
107
|
+
end
|
108
|
+
end
|
109
|
+
else
|
110
|
+
return false;
|
111
|
+
end
|
112
|
+
else
|
113
|
+
cik = data.inner_text.scan(/\(([^)]+)\)/).to_s
|
114
|
+
return cik
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.document(cik)
|
119
|
+
url ="http://www.sec.gov/cgi-bin/own-disp?action=getissuer&CIK="+cik
|
120
|
+
response = query(url)
|
121
|
+
doc = Hpricot(response)
|
122
|
+
text = "Ownership Reports from:"
|
123
|
+
type = "issuer"
|
124
|
+
entity = doc.search("//table").search("//td").search("b[text()*='"+text+"']")
|
125
|
+
if entity.empty?
|
126
|
+
url= "http://www.sec.gov/cgi-bin/own-disp?action=getowner&CIK="+cik
|
127
|
+
response = query(url)
|
128
|
+
doc = Hpricot(response)
|
129
|
+
text = "Ownership Reports for entitys:"
|
130
|
+
type = "owner"
|
131
|
+
entity = doc.search("//table").search("//td").search("b[text()*='"+text+"']")
|
132
|
+
end
|
133
|
+
return [doc, type]
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.parse_document(temp, doc)
|
138
|
+
|
139
|
+
temp[:type] = doc[1]
|
140
|
+
info = Entity.info(doc[0])
|
141
|
+
temp[:name] = info[:name]
|
142
|
+
temp[:location] = info[:location]
|
143
|
+
temp[:sic] = info[:sic]
|
144
|
+
temp[:state_of_inc] = info[:state_of_inc]
|
145
|
+
temp[:formerly] = info[:formerly]
|
146
|
+
|
147
|
+
### Get Mailing Address
|
148
|
+
temp[:mailing_address] = Entity.mailing_address(doc[0])
|
149
|
+
|
150
|
+
### Get Business Address
|
151
|
+
temp[:business_address] = Entity.business_address(doc[0])
|
152
|
+
|
153
|
+
return temp;
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.info(doc)
|
157
|
+
info={}
|
158
|
+
lines = doc.search("//td[@bgcolor='#E6E6E6']")[0].parent.parent.search("//tr")
|
159
|
+
td = lines[0].search("//td//b").innerHTML
|
160
|
+
info[:name] = td.gsub(td.scan(/\(([^)]+)\)/).to_s, "").gsub("()", "").gsub("\n", "")
|
161
|
+
lines = lines[1].search("//table")[0].search("//tr//td")
|
162
|
+
if lines[0].search("a")[0] != nil
|
163
|
+
info[:sic] = lines[0].search("a")[0].innerHTML
|
164
|
+
end
|
165
|
+
if lines[0].search("a")[1] != nil
|
166
|
+
info[:location] = lines[0].search("a")[1].innerHTML
|
167
|
+
end
|
168
|
+
|
169
|
+
if lines[0].search("b")[0] != nil and lines[0].search("b")[0].innerHTML.squeeze(" ") != " "
|
170
|
+
info[:state_of_inc] = lines[0].search("b")[0].innerHTML
|
171
|
+
end
|
172
|
+
if lines[1] != nil and lines[1].search("font")
|
173
|
+
info[:formerly] = lines[1].search("font").innerHTML.gsub("formerly: ", "").gsub("<br />", "").gsub("\n", "; ")
|
174
|
+
end
|
175
|
+
return info
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
def self.business_address(doc)
|
180
|
+
addie = doc.search("//table").search("//td").search("b[text()*='Business Address']")
|
181
|
+
if !addie.empty?;
|
182
|
+
business_address = addie[0].parent.innerHTML.gsub('<b class="blue">Business Address</b>', '').gsub('<br />', ' ');
|
183
|
+
return business_address
|
184
|
+
else
|
185
|
+
return false;
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.mailing_address(doc)
|
190
|
+
addie = doc.search("//table").search("//td").search("b[text()*='Mailing Address']")
|
191
|
+
if !addie.empty?;
|
192
|
+
mailing_address = addie[0].parent.innerHTML.gsub('<b class="blue">Mailing Address</b>', '').gsub('<br />', ' ');
|
193
|
+
return mailing_address
|
194
|
+
else
|
195
|
+
return false;
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def self.options(temp, options)
|
201
|
+
|
202
|
+
args={}
|
203
|
+
if options.is_a?(Array) && options.length == 1 && options[0] == true;
|
204
|
+
args[:relationships] = true;
|
205
|
+
args[:transactions]= true;
|
206
|
+
args[:filings] = true;
|
207
|
+
elsif options.is_a?(Array) && options.length > 1
|
208
|
+
args[:relationships] = options[0];
|
209
|
+
args[:transactions]= options[1];
|
210
|
+
args[:filings] = options[2];
|
211
|
+
elsif options[0].is_a?(Hash)
|
212
|
+
args[:relationships] = options[0][:relationships];
|
213
|
+
args[:transactions]= options[0][:transactions];
|
214
|
+
args[:filings] = options[0][:filings];
|
215
|
+
end
|
216
|
+
return args;
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.details(temp, options)
|
220
|
+
|
221
|
+
## Get Relationships for entity
|
222
|
+
if options[:relationships] == true
|
223
|
+
relationships = Relationship.find(temp)
|
224
|
+
temp[:relationships] =relationships
|
225
|
+
end
|
226
|
+
|
227
|
+
## Get Transactions for entity
|
228
|
+
if options[:transactions] != nil and options[:transactions].is_a?(Hash)
|
229
|
+
temp = Transaction.find(temp, options[:transactions][:start], options[:transactions][:count], options[:transactions][:limit])
|
230
|
+
elsif options[:transactions] != nil && options[:transactions] == true
|
231
|
+
temp = Transaction.find(temp, nil, nil, nil)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
## Get Filings for entity
|
236
|
+
|
237
|
+
if options[:filings] != nil and options[:filings].is_a?(Hash)
|
238
|
+
temp = Filing.find(temp, options[:filings][:start], options[:filings][:count], options[:filings][:limit])
|
239
|
+
elsif options[:filings] != nil and options[:filings] == true
|
240
|
+
temp = Filing.find(temp, nil, nil, nil)
|
241
|
+
end
|
242
|
+
|
243
|
+
return temp;
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
def self.log(entity)
|
248
|
+
|
249
|
+
if entity != false
|
250
|
+
puts "\n\t# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\n\n"
|
251
|
+
puts "\t"+entity.name
|
252
|
+
puts "\t("+entity.cik+")"
|
253
|
+
if entity.formerly && entity.formerly != ""
|
254
|
+
puts "\tFormerly: "+entity.formerly
|
255
|
+
end
|
256
|
+
if entity.sic
|
257
|
+
puts "\tSIC = "+entity.sic
|
258
|
+
end
|
259
|
+
if entity.location
|
260
|
+
puts "\tLocation: "+entity.location+", "
|
261
|
+
end
|
262
|
+
if entity.state_of_inc
|
263
|
+
puts "\tState of Incorporation: "+entity.state_of_inc
|
264
|
+
end
|
265
|
+
if entity.mailing_address
|
266
|
+
puts "\tMailing Address:\t"+ entity.mailing_address.inspect.gsub('\n', ' ').squeeze(" ")
|
267
|
+
end
|
268
|
+
|
269
|
+
if entity.business_address
|
270
|
+
puts "\tBusiness Address:\t"+ entity.business_address.inspect.gsub('\n', ' ').squeeze(" ")
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
if !entity.relationships
|
275
|
+
puts "\n\tRELATIONSHIPS:\t0 Total"
|
276
|
+
else
|
277
|
+
puts "\n\tRELATIONSHIPS:\t"+ entity.relationships.count.to_s+" Total"
|
278
|
+
printf("\t%-40s %-15s %-30s %-10s\n\n","Entity", "CIK", "Position", "Date")
|
279
|
+
for relationship in entity.relationships
|
280
|
+
printf("\t%-40s %-15s %-30s %-10s\n",relationship.name, relationship.cik, relationship.position, relationship.date)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
if entity.transactions
|
284
|
+
puts "\n\tTRANSACTIONS:\t"+ entity.transactions.count.to_s+" Total"
|
285
|
+
printf("\t%-20s %-10s %-5s %-10s %-10s %-10s %-15s %-10s\n\n","Owner", "CIK", "Modes", "Type","Shares","Price","Owned","Date")
|
286
|
+
for transaction in entity.transactions
|
287
|
+
printf("\t%-20s %-10s %-5s %-10s%-10s %-10s %-15s %-10s\n", transaction.reporting_owner,transaction.owner_cik,transaction.modes, transaction.type,transaction.shares,transaction.price,transaction.owned,transaction.date)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
if entity.filings
|
291
|
+
puts "\n\tFILINGS:\t"+ entity.filings.count.to_s+" Total"
|
292
|
+
printf("\t%-10s %-30s %-20s\n\n","Type", "File ID", "Date")
|
293
|
+
for filing in entity.filings
|
294
|
+
printf("\t%-10s %-30s %-20s\n",filing.term, filing.file_id, filing.date)
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
puts "\t"+entity.url+"\n\n"
|
299
|
+
else
|
300
|
+
return "No Entity found."
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SecQuery
|
2
|
+
class Filing
|
3
|
+
attr_accessor :cik, :title, :summary, :link, :term, :date, :file_id
|
4
|
+
def initialize(filing)
|
5
|
+
@cik = filing[:cik]
|
6
|
+
@title = filing[:title]
|
7
|
+
@summary = filing[:summary]
|
8
|
+
@link = filing[:link]
|
9
|
+
@term = filing[:term]
|
10
|
+
@date = filing[:date]
|
11
|
+
@file_id = filing[:file_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def self.find(entity, start, count, limit)
|
16
|
+
|
17
|
+
if start == nil; start = 0; end
|
18
|
+
if count == nil; count = 80; end
|
19
|
+
url ="http://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK="+entity[:cik]+"&output=atom&count="+count.to_s+"&start="+start.to_s
|
20
|
+
response = Entity.query(url)
|
21
|
+
doc = Hpricot::XML(response)
|
22
|
+
entries = doc.search(:entry);
|
23
|
+
query_more = false;
|
24
|
+
for entry in entries
|
25
|
+
query_more = true;
|
26
|
+
filing={}
|
27
|
+
filing[:cik] = entity[:cik]
|
28
|
+
filing[:title] = (entry/:title).innerHTML
|
29
|
+
filing[:summary] = (entry/:summary).innerHTML
|
30
|
+
filing[:link] = (entry/:link)[0].get_attribute("href")
|
31
|
+
filing[:term] = (entry/:category)[0].get_attribute("term")
|
32
|
+
filing[:date] = (entry/:updated).innerHTML
|
33
|
+
filing[:file_id] = (entry/:id).innerHTML.split("=").last
|
34
|
+
|
35
|
+
entity[:filings] << Filing.new(filing)
|
36
|
+
end
|
37
|
+
if query_more and limit == nil || query_more and !limit
|
38
|
+
Filing.find(entity, start+count, count, limit);
|
39
|
+
else
|
40
|
+
return entity
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SecQuery
|
2
|
+
class Relationship
|
3
|
+
|
4
|
+
## Relationships are Owner / Issuer Relationships between Entities, forged by Transactions.
|
5
|
+
|
6
|
+
attr_accessor :name, :position, :date, :cik
|
7
|
+
def initialize(relationship)
|
8
|
+
@cik = relationship[:cik];
|
9
|
+
@name = relationship[:name];
|
10
|
+
@position = relationship[:position];
|
11
|
+
date = relationship[:date].split("-")
|
12
|
+
@date = Time.utc(date[0],date[1],date[2].to_i)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def self.find(entity)
|
17
|
+
@relationships =[]
|
18
|
+
|
19
|
+
if entity[:doc] != nil
|
20
|
+
doc = entity[:doc]
|
21
|
+
elsif entity[:cik] != nil
|
22
|
+
doc = Entity.document(entity[:cik])[0]
|
23
|
+
end
|
24
|
+
|
25
|
+
type = "Ownership Reports for Issuers:"
|
26
|
+
lines = doc.search("//table").search("//td").search("b[text()*='"+type+"']")
|
27
|
+
if lines.empty?
|
28
|
+
type = "Ownership Reports from:"
|
29
|
+
lines = doc.search("//table").search("//td").search("b[text()*='"+type+"']");
|
30
|
+
end
|
31
|
+
if !lines.empty?
|
32
|
+
relationship = {}
|
33
|
+
lines= lines[0].parent.search("//table")[0].search("//tr")
|
34
|
+
for line in lines
|
35
|
+
link = line.search("//a")[0]
|
36
|
+
if link.innerHTML != "Owner" and link.innerHTML != "Issuer"
|
37
|
+
relationship[:name] = link.innerHTML;
|
38
|
+
relationship[:cik] = line.search("//td")[1].search("//a").innerHTML
|
39
|
+
relationship[:date] = position = line.search("//td")[2].innerHTML
|
40
|
+
relationship[:position] = line.search("//td")[3].innerHTML
|
41
|
+
@relationship = Relationship.new(relationship)
|
42
|
+
@relationships << @relationship
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return @relationships
|
47
|
+
else
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
def self.print(relationships)
|
52
|
+
if relationships
|
53
|
+
puts "\n\t"+relationships[1]+"\n"
|
54
|
+
printf("\t%-30s %-10s %-40s %-10s\n\n","Entity", "CIK", "Position", "Date")
|
55
|
+
for relationship in issuer[:relationships]
|
56
|
+
printf("\t%-30s %-10s %-40s %-10s\n",relationship.name, relationship.cik, relationship.position, relationship.date)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
puts "No relationships"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module SecQuery
|
2
|
+
class Transaction
|
3
|
+
|
4
|
+
attr_accessor :filing_number, :code, :date, :reporting_owner, :form, :type, :modes, :shares, :price, :owned, :number, :owner_cik, :security_name, :deemed, :exercise, :nature, :derivative, :underlying_1, :exercised, :underlying_2, :expires, :underlying_3
|
5
|
+
|
6
|
+
def initialize(transaction)
|
7
|
+
@filing_number = transaction[:form].split("/")[-2][0..19]
|
8
|
+
@code = transaction[:code]
|
9
|
+
if transaction[:date] != nil and transaction[:date] != "-"
|
10
|
+
date = transaction[:date].split("-")
|
11
|
+
@date = Time.utc(date[0],date[1],date[2])
|
12
|
+
end
|
13
|
+
@reporting_owner = transaction[:reporting_owner]
|
14
|
+
@form = transaction[:form]
|
15
|
+
@type = transaction[:type]
|
16
|
+
@modes = transaction[:modes]
|
17
|
+
@shares = transaction[:shares].to_f
|
18
|
+
@price = transaction[:price].gsub("$", "").to_f
|
19
|
+
@owned = transaction[:owned].to_f
|
20
|
+
@number = transaction[:number].to_i
|
21
|
+
@owner_cik = transaction[:owner_cik]
|
22
|
+
@security_name = transaction[:security_name]
|
23
|
+
@deemed = transaction[:deemed]
|
24
|
+
@exercise = transaction[:exercise]
|
25
|
+
@nature = transaction[:nature]
|
26
|
+
@derivative = transaction[:derivative]
|
27
|
+
@underlying_1 = transaction[:underlying_1].to_f
|
28
|
+
@exercised = transaction[:exercised]
|
29
|
+
@underlying_2 = transaction[:underlying_2].to_f
|
30
|
+
if transaction[:expires] != nil;
|
31
|
+
expires = transaction[:expires].split("-")
|
32
|
+
@expires = Time.utc(expires[0],expires[1],expires[2].to_i)
|
33
|
+
end
|
34
|
+
@underlying_3 = transaction[:underlying_3].to_f
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.find(entity, start, count, limit)
|
38
|
+
|
39
|
+
if start == nil; start = 0; end
|
40
|
+
if count == nil; count = 80; end
|
41
|
+
url = "http://www.sec.gov/cgi-bin/own-disp?action=get"+entity[:type]+"&CIK="+entity[:cik]+"&start="+start.to_s+"&count="+count.to_s
|
42
|
+
response = Entity.query(url)
|
43
|
+
doc = Hpricot(response)
|
44
|
+
trans = doc.search("//td[@width='40%']")[0].parent.parent.search("//tr")
|
45
|
+
i= start;
|
46
|
+
query_more = false;
|
47
|
+
for tran in trans
|
48
|
+
td = tran.search("//td")
|
49
|
+
if td[2] != nil and td[1].innerHTML != "Exercise"
|
50
|
+
query_more = true;
|
51
|
+
if !td[0].empty?
|
52
|
+
transaction={}
|
53
|
+
transaction[:code] = td[0].innerHTML;
|
54
|
+
transaction[:date] = td[1].innerHTML;
|
55
|
+
transaction[:reporting_owner] = td[2].innerHTML;
|
56
|
+
transaction[:form] = td[3].innerHTML;
|
57
|
+
transaction[:type] = td[4].innerHTML;
|
58
|
+
transaction[:modes] = td[5].innerHTML;
|
59
|
+
transaction[:shares] = td[6].innerHTML;
|
60
|
+
transaction[:price] = td[7].innerHTML;
|
61
|
+
transaction[:owned] = td[8].innerHTML;
|
62
|
+
transaction[:number] = td[9].innerHTML;
|
63
|
+
transaction[:owner_cik] = td[10].innerHTML;
|
64
|
+
transaction[:security_name] = td[11].innerHTML;
|
65
|
+
transaction[:deemed] = td[12].innerHTML;
|
66
|
+
if trans[i+1]; n_td = trans[i+1].search("//td"); end
|
67
|
+
if n_td != nil and n_td.count ==7 and n_td[0].innerHTML.empty?
|
68
|
+
transaction[:exercise] = n_td[1].innerHTML;
|
69
|
+
transaction[:nature] = n_td[2].innerHTML;
|
70
|
+
transaction[:derivative] = n_td[3].innerHTML;
|
71
|
+
transaction[:underlying_1] = n_td[4].innerHTML;
|
72
|
+
transaction[:exercised] = n_td[5].innerHTML;
|
73
|
+
transaction[:underlying_2] = n_td[6].innerHTML;
|
74
|
+
transaction[:expires] = n_td[7].innerHTML;
|
75
|
+
transaction[:underlying_3] =n_td[8].innerHTML;
|
76
|
+
end
|
77
|
+
entity[:transactions] << Transaction.new(transaction)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
i=i+1
|
81
|
+
end
|
82
|
+
if query_more and limit == nil || query_more and !limit
|
83
|
+
Transaction.find(entity, start+count, count, limit);
|
84
|
+
else
|
85
|
+
return entity
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/sec_query.rb
ADDED
Binary file
|
data/sec_query.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sec_query/version"
|
4
|
+
require "sec_query"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "sec_query"
|
8
|
+
s.version = SecQuery::VERSION
|
9
|
+
s.authors = ["Ty Rauber"]
|
10
|
+
s.email = ["tyrauber@mac.com"]
|
11
|
+
s.homepage = "https://github.com/tyrauber/sec_query"
|
12
|
+
s.summary = "A ruby gem for querying the United States Securities and Exchange Commission Edgar System."
|
13
|
+
s.description = "Search for company or person, by name, symbol or Central Index Key (CIK), and retrieve relationships, transactions and filings."
|
14
|
+
|
15
|
+
s.rubyforge_project = "sec_query"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
s.add_development_dependency "rspec"
|
24
|
+
s.add_runtime_dependency "rest-client"
|
25
|
+
s.add_runtime_dependency "hpricot"
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
#cfr_directors = ["Carla A. Hills", "Robert E. Rubin", "Richard E. Salomon", "Richard N. Haass", "John P. Abizaid", "Peter Ackerman", "Fouad Ajami", "Madeleine K. Albright", "Alan S. Blinder", "Mary Boies", "David G. Bradley", "Tom Brokaw", "Sylvia Mathews Burwell", "Kenneth M. Duberstein", "Martin S. Feldstein", "Stephen Friedman","Ann M. Fudge", "Pamela Gann", "Thomas H. Glocer", "J. Tomilson Hill","Donna J. Hrinak", "Alberto Ibargüen", "Shirley Ann Jackson", "Henry R. Kravis", "Jami Miscik", "Joseph S. Nye", "James W. Owens", "Eduardo J. Padrón", "Colin L. Powell", "Penny Pritzker", "David M. Rubenstein", "George Rupp", "Frederick W. Smith", "Christine Todd Whitman", "Fareed Zakaria", "Leslie H. Gelb", "Maurice R. Greenberg", "Peter G. Peterson","David Rockefeller"]
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
cfr_directors = [
|
7
|
+
{:middle=>"A", :first=>"Carla", :last=>"Hills", :cik_id=> "0001194913"},
|
8
|
+
{:middle=>"E", :first=>"Robert", :last=>"Rubin", :cik_id=> "0001225178"},
|
9
|
+
{:middle=>"E", :first=>"Richard", :last=>"Salomon", :cik_id => "0001217109"},
|
10
|
+
{:middle=>"N", :first=>"Richard", :last=>"Haass", :cik_id => "0001123553"},
|
11
|
+
{:middle=>"P", :first=>"John", :last=>"Abizaid", :cik_id => "0001425152"},
|
12
|
+
{:first=>"Peter", :last=>"Ackerman", :cik_id => "0001111564"},
|
13
|
+
{:first=>"Fouad", :last=>"Ajami"},
|
14
|
+
{:middle=>"K", :first=>"Madeleine", :last=>"Albright"},
|
15
|
+
{:middle=>"S", :first=>"Alan", :last=>"Blinder"},
|
16
|
+
{:first=>"Mary", :last=>"Boies", :cik_id => "0001291933"},
|
17
|
+
{:middle=>"G", :first=>"David", :last=>"Bradley", :cik_id=> "0001106734"},
|
18
|
+
{:first=>"Tom", :last=>"Brokaw"},
|
19
|
+
{:first=>"Sylvia", :last=>"Burwell"},
|
20
|
+
{:middle=>"M", :first=>"Kenneth", :last=>"Duberstein", :cik_id=> "0001179625"},
|
21
|
+
{:middle=>"S", :first=>"Martin", :last=>"Feldstein", :cik_id=> "0001236596"},
|
22
|
+
{:first=>"Stephen", :last=>"Friedman", :cik_id=> "0001029607"},
|
23
|
+
{:middle=>"M", :first=>"Ann", :last=>"Fudge", :cik_id=> "0001198098"},
|
24
|
+
{:first=>"Pamela", :last=>"Gann"},
|
25
|
+
{:middle=>"H", :first=>"Thomas", :last=>"Glocer", :cik_id=> "0001140799"},
|
26
|
+
{:middle=>"J", :first=>"J.", :last=>"Hill"},
|
27
|
+
{:middle=>"J", :first=>"Donna", :last=>"Hrinak", :cik_id=> "0001296811"},
|
28
|
+
{:first=>"Alberto", :last=>"Ibarguen", :cik_id=> "0001339732"},
|
29
|
+
{:first=>"Shirley", :last=>"Jackson", :cik_id=> "0001168019"},
|
30
|
+
{:middle=>"R", :first=>"Henry", :last=>"Kravis", :cik_id=> "0001081714"},
|
31
|
+
{:first=>"Jami", :last=>"Miscik"},
|
32
|
+
{:middle=>"S", :first=>"Joseph", :last=>"Nye", :cik_id=> "0001299821"},
|
33
|
+
{:middle=>"W", :first=>"James", :last=>"Owens", :cik_id=> "0001443909"},
|
34
|
+
{:middle=>"J", :first=>"Eduardo", :last=>"Padron"},
|
35
|
+
{:middle=>"L", :first=>"Colin", :last=>"Powell"},
|
36
|
+
{:first=>"Penny", :last=>"Pritzker", :cik_id=> "0001087398"},
|
37
|
+
{:middle=>"M", :first=>"David", :last=>"Rubenstein"},
|
38
|
+
{:first=>"George", :last=>"Rupp"},
|
39
|
+
{:middle=>"W", :first=>"Frederick", :last=>"Smith", :cik_id=> "0001033677"},
|
40
|
+
{:first=>"Christine", :last=>"Whitman", :cik_id=> "0001271384"},
|
41
|
+
{:first=>"Fareed", :last=>"Zakaria"},
|
42
|
+
{:middle=>"H", :first=>"Leslie", :last=>"Gelb", :cik_id=> "0001240500"},
|
43
|
+
{:middle=>"R", :first=>"Maurice", :last=>"Greenberg", :cik_id=> "0001236599"},
|
44
|
+
{:middle=>"G", :first=>"Peter", :last=>"Peterson", :cik_id=> "0001070843"},
|
45
|
+
{:first=>"David", :last=>"Rockefeller", :cik_id=> "0001204357"}
|
46
|
+
]
|
47
|
+
|
48
|
+
include SecQuery
|
49
|
+
|
50
|
+
describe SecQuery::Entity do
|
51
|
+
puts "\n\nCOUNCIL ON FOREIGN RELATIONS' DIRECTORS\nAs perceived by the Security and Exchange Commission Edgar System:\n"
|
52
|
+
for t in cfr_directors
|
53
|
+
entity = SecQuery::Entity.find(t, true)
|
54
|
+
# entity = SecQuery::Entity.find(t, true, {:start => 0, :count => 20, :limit => 20}, {:start => 0, :count => 20, :limit => 20})
|
55
|
+
if entity != false
|
56
|
+
Entity.log(entity)
|
57
|
+
it t[:cik].to_s+" is company "+entity.name.to_s do
|
58
|
+
if t[:cik] != nil
|
59
|
+
entity.cik.should eql(t[:cik_id])
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "sec_query"
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sec_query
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ty Rauber
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-12-02 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
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: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rest-client
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: hpricot
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description: Search for company or person, by name, symbol or Central Index Key (CIK), and retrieve relationships, transactions and filings.
|
64
|
+
email:
|
65
|
+
- tyrauber@mac.com
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- Gemfile
|
74
|
+
- Gemfile.lock
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- lib/.DS_Store
|
78
|
+
- lib/sec_query.rb
|
79
|
+
- lib/sec_query/.DS_Store
|
80
|
+
- lib/sec_query/entity.rb
|
81
|
+
- lib/sec_query/filing.rb
|
82
|
+
- lib/sec_query/relationship.rb
|
83
|
+
- lib/sec_query/transaction.rb
|
84
|
+
- lib/sec_query/version.rb
|
85
|
+
- pkg/sec_query-0.0.1.gem
|
86
|
+
- sec_query-1.0.0.gem
|
87
|
+
- sec_query.gemspec
|
88
|
+
- spec/sec_query_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
has_rdoc: true
|
91
|
+
homepage: https://github.com/tyrauber/sec_query
|
92
|
+
licenses: []
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project: sec_query
|
120
|
+
rubygems_version: 1.5.3
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: A ruby gem for querying the United States Securities and Exchange Commission Edgar System.
|
124
|
+
test_files:
|
125
|
+
- spec/sec_query_spec.rb
|
126
|
+
- spec/spec_helper.rb
|