whatsa 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36188353c2bbfb6f9d0c1f6a477a5fa9fe600543
4
+ data.tar.gz: 06d72756376c69c65a3a9e0c7f45cd0864428995
5
+ SHA512:
6
+ metadata.gz: 2df002badfb325346250f2237aa990a151b82b7d0e36534dd2e1337b32542892e22924dcfd2f35e715721804c5eaebb0234303cf5260d6e4645c37a95df1c85e
7
+ data.tar.gz: cbca63bef785503e51ff4e350960eacdcd9582e1fdba8c6c0005d0f3f2ade18595037515ddab29e8482ee7586dd20dfbb79e62aba25f358568c6b95207539e7d
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in whatsa.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Keegan Leitz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Whatsa
2
+
3
+ ## The basics
4
+
5
+ ### What's a Whatsa?
6
+
7
+ Whatsa is a CLI app that allows you to search a word or phrase and receive a quick summary about that subject.
8
+
9
+ ### How does it do that?
10
+
11
+ It searches your query on Wikipedia and finds the page you're most likely looking for. If you've been somewhat vague, or your search term could refer to multiple things, it will ask you to select from a disambiguation of topics. Usually, however, your term will go straight to an article. Whatsa then gives you the first paragraph of that article (usually a surprisingly decent summary).
12
+
13
+ If you're not super satisfied with that bit of information (and you need to know a little more) you can type `more` to get a better picture of that subject. If you're _still_ not satisfied, and you want to know something _specific_ about the thing you've searched, type `other`, and it will list the categories of information Wikipedia knows about the subject (its "History", "Early Life", "Uses", etc.). You can select one of those sections, if you'd like, and it will give you the first paragraph of that section, too (which you can extend similarly with another `more` command). You can make a new query with `new`, ask for help at any time with `help`, or exit the application with `exit`.
14
+
15
+ Simple?
16
+
17
+ Simple!
18
+
19
+ ## Using Whatsa
20
+
21
+ Clone this repo, `cd` to the directory, run `bundle install` (assuming you've already installed bundler), then run the `bin/Whatsa` script in a terminal. It will ask you what you'd like to learn about, and you can enter a word or phrase.
22
+
23
+ If your search term could mean multiple things, it will let you know, and you can select a choice by its name or number.
24
+
25
+ If you would like a longer explanation, type `more`.
26
+
27
+ If you would like to select a category of information about the topic, type `other`, then select a choice by its name or number.
28
+
29
+ If you'd like to search for something else, type `new`.
30
+
31
+ ## Dependencies
32
+
33
+ Requires Ruby 2.3.3 (doesn't seem to work with 2.0, at least, so see what you can get away with), the `nokogiri` gem, bundler (if you're planning on installing it the easy way), and `pry` (although it's really only in the gemspec for dev purposes).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests for this project are welcome at its [GitHub page](https://github.com/kjleitz/Whatsa). If you choose to contribute, please adhere to the [Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct/) so I don't have to go around breaking necks, running out of bubblegum, etc.
38
+
39
+ ## License
40
+
41
+ This project is open source, under the terms of the [MIT license](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "whatsa"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/whatsa ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/whatsa'
4
+
5
+ Whatsa::CLI.new.run
@@ -0,0 +1,10 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ # require 'pry'
4
+
5
+ require_relative '../lib/whatsa/version'
6
+ require_relative '../lib/whatsa/cli'
7
+ require_relative '../lib/whatsa/article'
8
+ require_relative '../lib/whatsa/section'
9
+ require_relative '../lib/whatsa/disambig'
10
+ require_relative '../lib/whatsa/scraper'
@@ -0,0 +1,66 @@
1
+ class Whatsa::Article
2
+ attr_accessor :sections
3
+ attr_reader :contents, :title
4
+
5
+ def initialize(noko_doc)
6
+ @title = noko_doc.css('h1').text
7
+ @contents = noko_doc.css('#mw-content-text').children
8
+ @sections = make_sections
9
+ end
10
+
11
+ def summary
12
+ self.sections.first.summary
13
+ end
14
+
15
+ def full_text
16
+ # name might be a little confusing: it's not really the "full text" of the
17
+ # article, it's the full text of the article summary. I'm naming it #full_text
18
+ # for duck-typing reasons
19
+ self.sections.first.full_text
20
+ end
21
+
22
+ def section_titles
23
+ self.sections.map { |s| s.title }
24
+ end
25
+
26
+ def choose_section(choice)
27
+ if choice.to_i > 0
28
+ self.sections[choice.to_i - 1]
29
+ else
30
+ get_section_by_title(title)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def get_section_by_title(title)
37
+ self.sections.find { |s| s.title.downcase == title.downcase }
38
+ end
39
+
40
+ def intro_pars
41
+ breakpoint = self.contents.to_a.index { |element| element.name == 'h2' }
42
+ pars = self.contents[0...breakpoint].css('p').map { |par| par.text }
43
+ pars.reject { |par| par == "" }
44
+ end
45
+
46
+ def make_sections
47
+ indices = section_indices
48
+ indices << -1
49
+ secs = [Whatsa::Section.new("#{self.title} - Introduction", intro_pars)]
50
+ indices.each_cons(2) do |i, j|
51
+ title = self.contents[i].text.gsub('[edit]', '').strip
52
+ par_nodes = self.contents[i...j].select { |e| e.name == 'p' && e.text != "" }
53
+ pars = par_nodes.map { |par| par.text }
54
+ secs << Whatsa::Section.new(title, pars).tap { |s| s.article = self }
55
+ end
56
+ secs
57
+ end
58
+
59
+ def section_indices
60
+ indices = []
61
+ self.contents.each_with_index do |element, i|
62
+ indices << i if element.name == 'h2'
63
+ end
64
+ indices
65
+ end
66
+ end
data/lib/whatsa/cli.rb ADDED
@@ -0,0 +1,152 @@
1
+ class Whatsa::CLI
2
+
3
+ def welcome
4
+ system('clear')
5
+ puts "Whatsa is a quick-and-dirty lookup utility, powered by Wikipedia!"
6
+ puts "-----------------------------------------------------------------"
7
+ end
8
+
9
+ def instructions
10
+ puts "Enter a word (or phrase) to get a brief summary of that subject."
11
+ puts "If you aren't satisfied, type 'more' to get a slightly longer"
12
+ puts "description, or type 'other' to get a list of specific categories"
13
+ puts "regarding that subject, which you can choose by number or name."
14
+ puts "You can type 'exit' to close the program (or 'help' to receive"
15
+ puts "these instructions again) at any time!"
16
+ end
17
+
18
+ def ask
19
+ puts "What would you like to know about?"
20
+ gets_command
21
+ end
22
+
23
+ def gets_command
24
+ input = nil
25
+ loop do
26
+ print "> "
27
+ input = gets.strip
28
+ case input
29
+ when ""
30
+ puts "Please enter a valid input."
31
+ when "exit"
32
+ exit
33
+ when "help"
34
+ instructions
35
+ when "new"
36
+ run
37
+ else
38
+ break
39
+ end
40
+ end
41
+ input
42
+ end
43
+
44
+ def word_wrap(text)
45
+ count = 0
46
+ words = text.split(/ /)
47
+ words.each_with_index do |word, index|
48
+ count += word.length + 1
49
+ if count > 80
50
+ words.insert(index, "\n")
51
+ count = 0
52
+ elsif word.index("\n")
53
+ count = word.length
54
+ end
55
+ end
56
+ words.join(" ").gsub(/^ /, "")
57
+ end
58
+
59
+ def display_dmb(dmb)
60
+ raise TypeError unless dmb.is_a?(Whatsa::Disambig)
61
+ system("clear")
62
+ stripped_title = dmb.title.gsub("(disambiguation)", "").strip
63
+ puts "Hmmm... #{stripped_title} could mean a few different things:\n"
64
+ dmb.descriptions.each_with_index do |kvp, i|
65
+ puts "#{i + 1}. #{kvp[0].to_s} (#{kvp[1]})"
66
+ end
67
+ puts "\nPlease select a choice, either by name or number."
68
+ end
69
+
70
+ def display_sections(text)
71
+ text = text.article if text.is_a?(Whatsa::Section)
72
+ system("clear")
73
+ puts "Here are some specific subjects about '#{text.title}':\n"
74
+ text.section_titles.each_with_index {|title, i| puts "#{i + 1}. #{title}"}
75
+ puts "\nPlease select a choice, either by name or number."
76
+ end
77
+
78
+ def summary_helpline
79
+ puts " _______________________________________________________________"
80
+ puts " (type 'more' for a potentially longer summary, 'other' if you'd"
81
+ puts " like to select a specific category of information on the topic,"
82
+ puts " or 'new' to find out about something else)"
83
+ end
84
+
85
+ def full_text_helpline
86
+ puts " _______________________________________________________________"
87
+ puts " (type 'other' if you'd like to select a specific category of"
88
+ puts " information on the topic, or 'new' to find out about something else)"
89
+ end
90
+
91
+ def get_dmb_choice(disambig)
92
+ display_dmb(disambig)
93
+ choice = nil
94
+ loop do
95
+ choice = gets_command
96
+ in_choices = disambig.choices.detect { |c| c.downcase == choice.downcase }
97
+ break if in_choices || choice.to_i > 0
98
+ end
99
+ disambig.choose_article(choice)
100
+ end
101
+
102
+ def summarize(text)
103
+ system("clear")
104
+ puts word_wrap(text.summary)
105
+ summary_helpline
106
+ input = gets_command
107
+ input.downcase == "more" ? full(text) : input
108
+ end
109
+
110
+ def full(text)
111
+ system("clear")
112
+ puts word_wrap(text.full_text)
113
+ full_text_helpline
114
+ gets_command
115
+ end
116
+
117
+ def categories(article)
118
+ display_sections(article)
119
+ choice = gets_command
120
+ section = article.choose_section(choice)
121
+ summarize(section)
122
+ end
123
+
124
+ def run
125
+ welcome
126
+ instructions
127
+
128
+ loop do
129
+ # get a search term
130
+ input = ask
131
+ scraper = Whatsa::Scraper.new(input)
132
+
133
+ # get an article from the search, or restart the loop if it can't be found
134
+ if scraper.not_found?
135
+ puts "Hmmm... I don't know what '#{input}' means! Try something else."
136
+ next
137
+ elsif scraper.disambig?
138
+ article = get_dmb_choice(scraper.make_disambig)
139
+ else
140
+ article = scraper.make_article
141
+ end
142
+
143
+ # summarize that article
144
+ input = summarize(article)
145
+
146
+ # the only valid input here that would go uncaught is "other", so
147
+ # keep asking until you get a caught input (logic determined by
148
+ # #gets_command, e.g. "help", "exit", "new") or "other"
149
+ loop { input = input.downcase == "other" ? categories(article) : gets_command }
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,42 @@
1
+ class Whatsa::Disambig
2
+ attr_accessor :descriptions
3
+ attr_reader :title, :items
4
+
5
+ def initialize(noko_doc)
6
+ @title = noko_doc.css('h1').text
7
+ @items = noko_doc.css('#mw-content-text li')
8
+ @descriptions = make_descriptions
9
+ end
10
+
11
+ def choices
12
+ self.descriptions.keys
13
+ end
14
+
15
+ def choose_article(choice)
16
+ if choice.to_i > 0
17
+ Whatsa::Scraper.new(choices[choice.to_i - 1]).make_article
18
+ else
19
+ Whatsa::Scraper.new(choice).make_article
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # make a hash with links and their descriptions
26
+ def make_descriptions
27
+ self.items.inject({}) do |memo, item|
28
+ unless item.css('a').empty?
29
+ key = item.css('a').first.text
30
+ toc_link = item["class"] && item["class"].match(/toc/)
31
+ dmb_link = key.match("(disambiguation)")
32
+ all_link = key.match("All pages with titles")
33
+ unless toc_link || dmb_link || all_link
34
+ desc = item.text.split("\n").first.strip
35
+ memo[key] = desc.gsub(key, "").gsub(/\A[^\w"]/, "").strip
36
+ end
37
+ end
38
+ memo
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,50 @@
1
+ class Whatsa::Scraper
2
+
3
+ WIKISEARCH = 'https://en.wikipedia.org/w/index.php?search='
4
+
5
+ attr_reader :query, :page
6
+
7
+ def initialize(term)
8
+ # only keep word chars and parens, turn everything between each 'word'
9
+ # to a single '+' and remove '+'s at the beginning and end if they're there
10
+ # @query = term.gsub(/\W+/, '+').gsub(/(\A\+|\+\z)/, '')
11
+ @query = term.gsub(/[^A-z0-9\(\)]+/, '+').gsub(/(\A\+|\+\z)/, '')
12
+
13
+ # store the page in an instance variable so we don't keep polling the site
14
+ @page = Nokogiri::HTML(open(WIKISEARCH + self.query))
15
+ end
16
+
17
+ def results_page?
18
+ !self.page.css('.searchresults').empty?
19
+ end
20
+
21
+ def not_found?
22
+ !self.page.css('.mw-search-nonefound').empty?
23
+ end
24
+
25
+ def article?
26
+ !self.page.css('#ca-nstab-main').empty? && !disambig?
27
+ end
28
+
29
+ def disambig?
30
+ !self.page.css('#disambigbox').empty?
31
+ end
32
+
33
+ def make_article
34
+ if article?
35
+ Whatsa::Article.new(self.page)
36
+ elsif results_page? && !not_found?
37
+ first_title = self.page.css('.mw-search-results li a').first.text
38
+ self.class.new(first_title).make_article
39
+ elsif disambig?
40
+ self.class.new(make_disambig.choices.first).make_article
41
+ else
42
+ nil
43
+ end
44
+ end
45
+
46
+ def make_disambig
47
+ disambig? ? Whatsa::Disambig.new(self.page) : nil
48
+ end
49
+
50
+ end
@@ -0,0 +1,24 @@
1
+ class Whatsa::Section
2
+ attr_accessor :title, :paragraphs, :article
3
+
4
+ def initialize(title, paragraphs)
5
+ @title = title
6
+ @paragraphs = paragraphs
7
+ remove_citations
8
+ end
9
+
10
+ def summary
11
+ self.paragraphs.first
12
+ end
13
+
14
+ def full_text
15
+ self.paragraphs.join("\n\n")
16
+ end
17
+
18
+ private
19
+
20
+ def remove_citations
21
+ self.paragraphs.map! { |par| par.gsub(/\[\d+\]/, "") }
22
+ end
23
+
24
+ end
@@ -0,0 +1,3 @@
1
+ module Whatsa
2
+ VERSION = "0.1.0"
3
+ end
data/lib/whatsa.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative '../config/environment'
2
+
3
+ module Whatsa
4
+ end
data/whatsa.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'whatsa/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "whatsa"
8
+ spec.version = Whatsa::VERSION
9
+ spec.authors = ["Keegan Leitz"]
10
+ spec.email = ["kjleitz@gmail.com"]
11
+
12
+ spec.summary = %q{What is that? Okay, okay, I don't need a lecture... just gimme the short 'n sweet!}
13
+ spec.description = %q{Whatsa is a CLI app that allows you to search a term or phrase and receive a quick summary about that subject. It searches your term on Wikipedia and finds the page you're most likely looking for. Whatsa then gives you the first paragraph of that article, then lists the sections on the page ("History", "Early Life", "Uses", etc.). You can select one of those sections, if you'd like, and it will give you the first paragraph of that section, too. If that's not enough for you, you can ask for more, and it will show you the full section.}
14
+ spec.homepage = "https://github.com/kjleitz/whatsa"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.13"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "nokogiri"
36
+ # spec.add_development_dependency "pry"
37
+
38
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: whatsa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Keegan Leitz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Whatsa is a CLI app that allows you to search a term or phrase and receive
56
+ a quick summary about that subject. It searches your term on Wikipedia and finds
57
+ the page you're most likely looking for. Whatsa then gives you the first paragraph
58
+ of that article, then lists the sections on the page ("History", "Early Life", "Uses",
59
+ etc.). You can select one of those sections, if you'd like, and it will give you
60
+ the first paragraph of that section, too. If that's not enough for you, you can
61
+ ask for more, and it will show you the full section.
62
+ email:
63
+ - kjleitz@gmail.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - ".gitignore"
69
+ - Gemfile
70
+ - LICENSE.md
71
+ - README.md
72
+ - Rakefile
73
+ - bin/console
74
+ - bin/setup
75
+ - bin/whatsa
76
+ - config/environment.rb
77
+ - lib/whatsa.rb
78
+ - lib/whatsa/article.rb
79
+ - lib/whatsa/cli.rb
80
+ - lib/whatsa/disambig.rb
81
+ - lib/whatsa/scraper.rb
82
+ - lib/whatsa/section.rb
83
+ - lib/whatsa/version.rb
84
+ - whatsa.gemspec
85
+ homepage: https://github.com/kjleitz/whatsa
86
+ licenses:
87
+ - MIT
88
+ metadata:
89
+ allowed_push_host: https://rubygems.org
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.6.8
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: What is that? Okay, okay, I don't need a lecture... just gimme the short
110
+ 'n sweet!
111
+ test_files: []