logstash-input-meetup 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d707708edea17fc04c18423a1fb419cc26ee166303252bbbef55c3253ac04cc5
4
- data.tar.gz: 04f228ac0f73111fc473501d4c9fe882df071187dfc749a42148acae11ff6adf
3
+ metadata.gz: 85492b95be62dcfc91d477af8bc8f69b1b925c47e6823163901f57b545adc8c8
4
+ data.tar.gz: f35a4f5dd80b76d9fcd9b7ef26411c812796efc31ffec2fb3b80ce26d6ca6747
5
5
  SHA512:
6
- metadata.gz: b00911ff5dc51e0acfb3d77938d32564dc858bdffd48924f18e6833ec0aef35c4536c14c433a0313a8c1d7875c5e3296a1fae83de7bd324d670f7ccb5405b046
7
- data.tar.gz: 4acbf1de52e8b3237a6fdae87aadb1c9d254c31946b32fb34553431b32cd0136b1673cca211bd47e0a5f89d579a607c59914d99620ce1b6ddbd102fdc10986fa
6
+ metadata.gz: d82de4e2e417fa910095ed0103da0fc9cdb91f92faf6ff34dfd6a60631357ffd5ba63aef20d8e46a6d4d0acad53047bc29539882e1a16eecf2929002a4172126
7
+ data.tar.gz: a30cf11209dccdc9abc577a8cfd08cf3aa318f0566e8a00af1ad6c521f4b411d8e89bafc9c18534b2150d380e2ad6fc5a0eb08fdb193967a6378766bcd2c7aba
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 3.0.4
2
+ - Fix syntax errors (tylerjl) [#11](https://github.com/logstash-plugins/logstash-input-meetup/pull/11)
3
+ - Minor logging and validation updates
4
+
1
5
  ## 3.0.3
2
6
  - Update gemspec summary
3
7
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012–2016 Elasticsearch <http://www.elastic.co>
1
+ Copyright (c) 2012-2018 Elasticsearch <http://www.elastic.co>
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ class LogStash::Inputs::Meetup < LogStash::Inputs::Base
25
25
  config :interval, :validate => :number, :required => true
26
26
 
27
27
  # Meetup Key
28
- config :meetupkey, :validate => :string, :required => true
28
+ config :meetupkey, :validate => :password, :required => true
29
29
 
30
30
  # Event Status'
31
31
  config :eventstatus, :validate => :string, :default => "upcoming,past"
@@ -35,20 +35,21 @@ class LogStash::Inputs::Meetup < LogStash::Inputs::Base
35
35
  require "faraday"
36
36
  # group_id
37
37
  if groupid
38
- addon = "group_id=#{ @groupid }"
39
- # group_urlname
38
+ addon = "group_id=#{ @groupid }"
39
+ # group_urlname
40
40
  elsif urlname
41
- addon = "group_urlname=#{ @urlname }"
42
- # venue_id
41
+ addon = "group_urlname=#{ @urlname }"
42
+ # venue_id
43
43
  elsif venueid
44
- addon = "venue_id=#{ @venueid }"
44
+ addon = "venue_id=#{ @venueid }"
45
45
  else
46
- # None Selected, raise an error
47
- addon = ""
46
+ # None Selected, raise an error
47
+ raise "Configuration error! - Must have one of `urlname`, `venue_id`, or `group_id` defined"
48
+ addon = ""
48
49
  end
49
- @url = "https://api.meetup.com/2/events.json?key=#{ @meetupkey }&status=#{ @eventstatus }&#{ addon }"
50
- @logger.info("Registering meetup Input", :url => @url, :interval => @interval)
51
- end # def register
50
+ @url = "https://api.meetup.com/2/events.json?key=#{ @meetupkey.value }&status=#{ @eventstatus }&#{ addon }"
51
+ @logger.info("Registering meetup Input", :url => @url.gsub(@meetupkey.value, "xxxx"), :interval => @interval)
52
+ end # def register
52
53
 
53
54
  public
54
55
  def run(queue)
@@ -58,10 +59,12 @@ class LogStash::Inputs::Meetup < LogStash::Inputs::Base
58
59
 
59
60
  # Pull down the RSS feed using FTW so we can make use of future cache functions
60
61
  response = Faraday.get @url
62
+ logger.error("Error call meetup API: " + response.body) unless response.status.eql?(200)
61
63
  begin
62
64
  result = LogStash::Json.load(response.body)
63
- rescue LogStash::Json::ParserError
64
- # silently ignore json parsing errors
65
+ rescue LogStash::Json::ParserError => e
66
+ # ignore json parsing errors
67
+ logger.debug("Error parsing Json", :message => e.message, :backtrace => e.backtrace)
65
68
  end
66
69
 
67
70
  result["results"].each do |rawevent|
@@ -71,8 +74,8 @@ class LogStash::Inputs::Meetup < LogStash::Inputs::Base
71
74
  event.set('time', LogStash::Timestamp.at(event.get('time') / 1000, (event.get('time') % 1000) * 1000))
72
75
  event.set('[group][created]', LogStash::Timestamp.at(event.get('group][created]') / 1000, (event.get('group][created]') % 1000) * 1000))
73
76
  event.set('updated', LogStash::Timestamp.at(event.get('updated') / 1000, (event.get('updated') % 1000) * 1000))
74
- event.set('[venue][lonlat]', [event.get('[venue][lon]'), event.get('[venue][lat]') if rawevent.has_key?('venue'))
75
- event.set('[group][lonlat]', [event.get('[group][group_lon]',event'[group][group_lat]') if rawevent.has_key?('group'))
77
+ event.set('[venue][lonlat]', [event.get('[venue][lon]'), event.get('[venue][lat]')]) if rawevent.has_key?('venue')
78
+ event.set('[group][lonlat]', [event.get('[group][group_lon]'), event.get('[group][group_lat]')]) if rawevent.has_key?('group')
76
79
  decorate(event)
77
80
  queue << event
78
81
  end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-meetup'
4
- s.version = '3.0.3'
4
+ s.version = '3.0.4'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Captures the output of command line tools as an event"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -21,7 +21,10 @@ Gem::Specification.new do |s|
21
21
 
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", "~> 2.0"
24
+ s.add_runtime_dependency 'logstash-codec-plain'
25
+ s.add_runtime_dependency 'faraday'
24
26
 
25
27
  s.add_development_dependency 'logstash-devutils'
28
+ s.add_development_dependency 'webmock'
26
29
  end
27
30
 
@@ -0,0 +1,103 @@
1
+ {
2
+ "results": [
3
+ {
4
+ "utc_offset": -18000000,
5
+ "venue": {
6
+ "country": "us",
7
+ "localized_country_name": "USA",
8
+ "city": "Durham",
9
+ "address_1": "4613 University Drive – Bldg 450",
10
+ "name": "BCBSNC ",
11
+ "lon": -78.966064,
12
+ "id": 25003187,
13
+ "state": "NC",
14
+ "lat": 35.955414,
15
+ "repinned": false
16
+ },
17
+ "headcount": 0,
18
+ "visibility": "public",
19
+ "waitlist_count": 0,
20
+ "created": 1484960943000,
21
+ "rating": {
22
+ "count": 7,
23
+ "average": 3.859999895095825
24
+ },
25
+ "maybe_rsvp_count": 0,
26
+ "description": "<p><b>Join us for our inaugural meetup on Thursday, February 16. Doors will open at 4pm and we'll start talks around 4:30pm. </b></p> <p><br/><b>Thank you to BCBSNC for hosting us! IBM will be presenting.</b></p> <p>--------</p> <p><b>Kibana Globalization</b></p> <p><br/>Adding globalization support to Kibana is a crucial capability which is necessary in all visualization dashboards. This talk will present the design, the road map of delivered and any pending parts, as well as the integration points for stakeholders. It is an exciting journey not to be missed in the growth of Kibana and the Elastic Stack.</p> <p><br/><b>Shikha</b> is a Senior Technical Staff Member (STSM) and a Master Inventor at IBM. She is a lead Connect to Cloud architect where she brings her expertise in architecture, design, leadership towards collaboratively creating innovative pragmatic solutions that leads to enabling Hybrid solution for the clients.</p> <p>\n\nShikha has won awards in innovation and technical achievement. She enjoys leadership role focussed on making things happen and shipping. Shikha is a strong open source advocate focused on building simple tools.<br/>She has worked with several clients across multiple industries including heath, insurance and finance. She has co-presented with client and BPs at conferences has also been invited as guest speaker at customer conferences</p> <p>Shikha lives in Cary, NC with her husband and two son who manage to take up most of her 'free' time.<br/>You can find her on<br/>Twitter: <a href=\"https://twitter.com/shikhasthoughts\"><a href=\"https://twitter.com/shikhasthoughts\" class=\"linkified\">https://twitter.com/shikhasthoughts</a></a><br/>LinkedIn: <a href=\"https://www.linkedin.com/pub/shikha-srivastava/5/9/64\"><a href=\"https://www.linkedin.com/pub/shikha-srivastava/5/9/64\" class=\"linkified\">https://www.linkedin.com/pub/shikha-srivastava/5/9/64</a></a></p> <p><b>IBM Bluemix platform logging with the Elastic Stack</b></p> <p>IBM Bluemix platform logs to Elastic Stacks. Learn about the flexibility of our logging solutions. We'll also share insights to challenges of offering platform logging in multi-tenant environments.</p> <p>Bluemix platform automatically collects many platform logs- no user configuration necessary. We'll talk about and demo how we do this offering a Log Search experience with the ELK stack. We'll cover scale challenges in the cloud and how we are addressing them today. </p> <p><b>Charlie</b> is a Senior Offering Manager at IBM. He is currently Offering lead for Bluemix Log, Monitoring, and Access Trail services. He passionately brings these collective experiences together drawling on his background, including: logging, analytics, and IT service management offerings. </p> <p>Charlie lives in Cary, NC with his wife and son. You can find him on:<br/>Twitter: <a href=\"https://twitter.com/CharlieComiskey\"><a href=\"https://twitter.com/CharlieComiskey\" class=\"linkified\">https://twitter.com/CharlieComiskey</a></a><br/>LinkedIn: <a href=\"http://www.linkedin.com/in/charlie-c\">www.linkedin.com/in/charlie-c </a></p> <p><br/>--------</p> <p><br/><b>I'm new to Elasticsearch. Will this event be good for me?</b></p> <p>Totally. No matter if you are a novice or an old pro, there’s something for everyone at SEARCH.</p> <p><b>What is Elasticsearch?</b></p> <p>The world is swimming in data. For years we have been simply overwhelmed by the quantity of data flowing through and produced by our systems. Existing technology has focused on how to store and structure warehouses full of data. That’s all well and good—until you actually need to make decisions in real time informed by that data.</p> <p>Elasticsearch is a real-time distributed search and analytics engine. It allows you to explore your data at a speed and at a scale never before possible. It is used for full-text search, structured search, analytics, and all three in combination:</p> <p>Wikipedia uses Elasticsearch to provide full-text search with highlighted search snippets, and search-as-you-type and did-you-mean suggestions.The Guardian uses Elasticsearch to combine visitor logs with social -network data to provide real-time feedback to its editors about the public’s response to new articles.Stack Overflow combines full-text search with geolocation queries and uses more-like-this to find related questions and answers.Netflix uses it for personalized recommendation and search millions of videos.GitHub uses Elasticsearch to query 130 billion lines of code.</p> <p><b>Can I bring a friend?</b></p> <p>Sure... Everyone is welcome! Just make sure you register for all attendees you plan to bring with you before Tuesday, 02/14/17.</p> <p><b>Will there be food?</b></p> <p>Yes! We will have a yummy selection of pizzas and beverages to help keep your energy and focus on the great technology content and networking opportunity.</p> <p><b>What are my transport/parking options getting to the event?</b></p> <p>Parking is available in the open surface parking lot across from building 450. </p> <p>Take I-40 to exit 270. Turn onto US 15/501(Durham-Chapel Hill Blvd.) headed toward Durham. Follow Durham-Chapel Hill Blvd. past Garrett Road. Stay in right two lanes and bear right to US 15/501 North. Immediately stay in right lane and bear right onto Martin Luther King, Jr. Pkwy. Turn right at the first traffic light onto University Drive. Turn left at the second light which is University Place. Building 450 will be the 2nd turn off on your right. </p> <p><b>Where can I contact the organizer with any questions?</b></p> <p>Please contact Nitin Kadam with any questions: <a href=\"mailto:[masked]\">[masked]</a></p> <p>If you're interested in speaking at a future meetup, email us at [masked]. </p>",
27
+ "how_to_find_us": "450 Auditorium: CR-450-1870/1880/1890 (1st floor) You will need to sign in at the security guest in the main lobby when entering building 450.",
28
+ "event_url": "https://www.meetup.com/Elastic-Triangle-User-Group/events/237083007/",
29
+ "yes_rsvp_count": 92,
30
+ "name": "Inaugural Elastic Triangle meetup",
31
+ "id": "237083007",
32
+ "time": 1487278800000,
33
+ "updated": 1492650351000,
34
+ "group": {
35
+ "join_mode": "open",
36
+ "created": 1484762789000,
37
+ "name": "Elastic Triangle User Group",
38
+ "group_lon": -78.9000015258789,
39
+ "id": 21979256,
40
+ "urlname": "Elastic-Triangle-User-Group",
41
+ "group_lat": 36,
42
+ "who": "Elastic Fantastics"
43
+ },
44
+ "status": "past"
45
+ },
46
+ {
47
+ "utc_offset": -14400000,
48
+ "venue": {
49
+ "country": "us",
50
+ "localized_country_name": "USA",
51
+ "city": "Durham",
52
+ "address_1": "4613 University Drive – Bldg 450",
53
+ "name": "BCBSNC ",
54
+ "lon": -78.966064,
55
+ "id": 25003187,
56
+ "state": "NC",
57
+ "lat": 35.955414,
58
+ "repinned": false
59
+ },
60
+ "headcount": 0,
61
+ "visibility": "public",
62
+ "waitlist_count": 0,
63
+ "created": 1492246911000,
64
+ "rating": {
65
+ "count": 2,
66
+ "average": 5
67
+ },
68
+ "maybe_rsvp_count": 0,
69
+ "description": "<p><b>Agenda:</b></p> <p>• 5:30 PM - <b>Pizza and Networking</b></p> <p>• 6:00-6:45 PM - <b>Talk#1: Gather 'round and hear the story of Painless!</b></p> <p>• 6:45-7:30 PM - <b>Talk#2: Learn how Bitly uses ElasticSearch</b></p> <p>• 7:30 PM - <b>Open Discussion</b></p> <p><b>We have a great inaugural meetup back in February and we are excited to be hosting our second meetup for the Elastic Triangle user group on Thursday, April 27.  </b></p> <p><b>Talk#1: Gather 'round and hear the story of Painless!</b></p> <p>Back in the pre-5.0 dark ages, Elasticsearch lacked a secure scripting language. And the people were sad! But our hero Painless came in 5.0, the shining new default, careful, quick, and kind. Ever watchful of its whitelist and loop counters, Painless protects Elasticsearch from malign mandate, inadvertent or iniquitous.</p> <p>Gather and hear of Painless' guiding principles, see the features they represent, and, time permitting, discuss Painless' future.</p> <p><b>Nik Everett</b> is an Elasticsearch Engineer based in North Carolina. Before joining Elastic, Nik worked for the Wikimedia Foundation building on site search for Wikipedia with Elasticsearch.</p> <p><b>Talk#2: Learn how Bitly uses ElasticSearch</b></p> <p>Learn how Bitly uses ElasticSearch to power not just standard search and retrieval of your shortened URLs, but also how we use the aggregations' feature of ElasticSearch to provide up-to-date analytic information on how engaged your target audience is with your content, across the internet at large. We’ll dive into how Bitly uses custom schemas to enable search, and into the details of how Bitly constructs aggregate queries for counting and categorizing. </p> <p><br/><b>Peter Herndon</b> is a Senior Application Engineer at Bitly, where he helps keep links short and smart. Working primarily on back-end systems, he uses an awful lot of open source software and occasionally contributes a bit of working code. Prior to joining Bitly, he worked briefly in the New York startup world, and for a much longer time at Memorial Sloan-Kettering Cancer Center as a developer and systems administrator. His main passion is designing and building distributed systems, and his main extracurricular hobby is learning and teaching martial arts.</p>",
70
+ "event_url": "https://www.meetup.com/Elastic-Triangle-User-Group/events/239230863/",
71
+ "yes_rsvp_count": 44,
72
+ "name": "Painless: Elasticsearch's new scripting language & Learn how Bitly uses Elastic",
73
+ "id": "239230863",
74
+ "time": 1493328600000,
75
+ "updated": 1493382683000,
76
+ "group": {
77
+ "join_mode": "open",
78
+ "created": 1484762789000,
79
+ "name": "Elastic Triangle User Group",
80
+ "group_lon": -78.9000015258789,
81
+ "id": 21979256,
82
+ "urlname": "Elastic-Triangle-User-Group",
83
+ "group_lat": 36,
84
+ "who": "Elastic Fantastics"
85
+ },
86
+ "status": "past"
87
+ }
88
+ ],
89
+ "meta": {
90
+ "next": "",
91
+ "method": "Events",
92
+ "total_count": 2,
93
+ "link": "https://api.meetup.com/2/events.json",
94
+ "count": 2,
95
+ "description": "Access Meetup events using a group, member, or event id. Events in private groups are available only to authenticated members of those groups. To search events by topic or location, see [Open Events](/meetup_api/docs/2/open_events).",
96
+ "lon": "",
97
+ "title": "Meetup Events v2",
98
+ "url": "https://api.meetup.com/2/events.json?offset=0&format=json&limited_events=False&group_id=21979256&page=200&fields=&key=551f79233a251a351215671b7a60&order=time&status=upcoming%2Cpast&desc=false",
99
+ "id": "",
100
+ "updated": 1493382683000,
101
+ "lat": ""
102
+ }
103
+ }
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../spec_helper'
4
+
5
+ describe LogStash::Inputs::Meetup do
6
+ before do
7
+ WebMock.disable_net_connect! allow_localhost: true
8
+ end
9
+
10
+ after do
11
+ WebMock.allow_net_connect!
12
+ end
13
+
14
+ let(:meetupkey) { SecureRandom.hex 14 }
15
+ let(:groupid) { (1..2).map { rand(10_000_000) }.join(',') }
16
+ let(:config) do
17
+ {
18
+ 'meetupkey' => meetupkey,
19
+ 'groupid' => groupid,
20
+ 'interval' => 1
21
+ }
22
+ end
23
+ let(:subject) { described_class.new(config) }
24
+ let(:queue) { Queue.new }
25
+
26
+ it 'fetches JSON from the Meetup API' do
27
+ api = 'https://api.meetup.com/2/events.json'
28
+ url = "#{api}?group_id=#{groupid}&key=#{meetupkey}&status=upcoming,past"
29
+
30
+ stub_request(:get, url).to_return(body: fixture('meetup-response.json'))
31
+
32
+ subject.register
33
+ Thread.new { subject.run(queue) }
34
+ sleep 0.01 while queue.size.zero?
35
+
36
+ expect(a_request(:get, url)).to have_been_made.at_least_once
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ require 'logstash/devutils/rspec/spec_helper'
2
+ require 'logstash/inputs/meetup'
3
+ require 'logstash/codecs/plain'
4
+ require 'webmock/rspec'
5
+
6
+ # JSON fixture helper
7
+ module MeetupFixtures
8
+ def fixture(filename)
9
+ File.read(File.expand_path(File.join('spec', 'fixtures', filename)))
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |c|
14
+ c.include MeetupFixtures
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-meetup
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-07 00:00:00.000000000 Z
11
+ date: 2018-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: logstash-codec-plain
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: faraday
48
+ prerelease: false
49
+ type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  requirement: !ruby/object:Gem::Requirement
29
57
  requirements:
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: webmock
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  description: This gem is a Logstash plugin required to be installed on top of the
42
84
  Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
43
85
  gem is not a stand-alone program
@@ -55,7 +97,9 @@ files:
55
97
  - docs/index.asciidoc
56
98
  - lib/logstash/inputs/meetup.rb
57
99
  - logstash-input-meetup.gemspec
58
- - spec/inputs/meetup_spec.rb
100
+ - spec/fixtures/meetup-response.json
101
+ - spec/logstash/inputs/meetup_spec.rb
102
+ - spec/spec_helper.rb
59
103
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
60
104
  licenses:
61
105
  - Apache License (2.0)
@@ -78,9 +122,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
122
  version: '0'
79
123
  requirements: []
80
124
  rubyforge_project:
81
- rubygems_version: 2.6.11
125
+ rubygems_version: 2.6.13
82
126
  signing_key:
83
127
  specification_version: 4
84
128
  summary: Captures the output of command line tools as an event
85
129
  test_files:
86
- - spec/inputs/meetup_spec.rb
130
+ - spec/fixtures/meetup-response.json
131
+ - spec/logstash/inputs/meetup_spec.rb
132
+ - spec/spec_helper.rb
@@ -1 +0,0 @@
1
- # Empty