extracare2of 0.2

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: d174fbafa72c46930ecc9a9b8bb6de7d1f31a935
4
+ data.tar.gz: 07364580e6775bc782038da7cdcbbaacbd184354
5
+ SHA512:
6
+ metadata.gz: 1f4dfd3c0818b0178869f2a6bb2d434d0750b2a5dff458817882d8092903e115b41c69f5793bc353c82c1645c3605e5a44e401c014b39523a894b1c3ec302665
7
+ data.tar.gz: eb25c94b7957907b398d4ed0550b88eace0b4fffd4575940c2ccfeca0170362d67d04d187f29639405e369df887264a9fe5be06dc9931a4c99b3adc6cec13187
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+ gem "mechanize"
3
+ gem "amatch"
4
+ gem "rb-appscript"
5
+ gem "highline"
6
+ gem "chronic"
7
+ gem "sqlite3"
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+
2
+ # ExtraCare Reminders
3
+
4
+ ## Synopsis
5
+
6
+ This script will send CVS ExtraCare coupon reminders to [OmniFocus][6764-001], [iCloud Reminders][6764-002], [Things for Mac][6764-003], or [DueApp][6764-004]. It includes SQLite database support for tracking previously imported coupons and will set task name, due date, start date, and a note
7
+
8
+ This script performs the following actions:
9
+
10
+ + Logs into [CVS mobile][6764-005] web
11
+ + Scans the ExtraCare page for active coupons on your card/account
12
+ + Checks coupons against the database for previously imported coupons
13
+ + Sends every new coupon to the task manager of your choice
14
+
15
+ ## Code Example
16
+
17
+ $ ruby bin/extracare2of username password
18
+ $ Looking for coupons...
19
+ $ ----
20
+ $ Title: 10% off skincare products
21
+ $ - Due Date: 8/10/2013
22
+ $ - Start Date: 8/1/2013
23
+ $ - Note: Reedemable in-store only
24
+
25
+
26
+
27
+ ## Installation
28
+
29
+ Bundle install
30
+
31
+ Edit `config/config.yml` to choose which reminder app you'd like to use.
32
+
33
+ ## Todo
34
+
35
+ + Parse ExtraBucks... I need to wait for CVS to send me some before I can figure out the right regular expression
36
+ + Handle deals that require action, i.e., activate coupon via web
37
+
38
+ _Note: This is for paper coupons only. The actual coupons are on your CVS receipts. This script merely sets reminders for you to use them._
39
+
40
+ ## Credits
41
+
42
+ This ruby script borrows some code from [ttscoff's][6764-006] [otask](http://brettterpstra.com/2011/07/02/otask-cli-for-omnifocus/) CLI OmniFocus gem.
43
+
44
+ ## License
45
+
46
+ Licensed under the [MIT License][6764-007]
47
+ [6764-001]: http://www.omnigroup.com/products/omnifocus/ "OmniFocus for Mac - The Omni Group"
48
+ [6764-002]: http://support.apple.com/kb/ht4861 "iCloud: Calendar Events, Reminders, To Dos, and Tasks behavior ..."
49
+ [6764-003]: http://culturedcode.com/things/ "Things - task management for Mac & iOS | Cultured Code"
50
+ [6764-004]: http://www.dueapp.com/ "Due: The Superfast Reminder App for iPhone & iPad"
51
+ [6764-005]: http://www.cvs.com/promo/promoLandingTemplate.jsp?promoLandingId=mobile-apps "CVS Mobile Apps - CVS pharmacy"
52
+ [6764-006]: https://github.com/ttscoff "ttscoff (Brett Terpstra) · GitHub"
53
+ [6764-007]: http://opensource.org/licenses/MIT "The MIT License (MIT) | Open Source Initiative"
data/bin/extracare2of ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require_relative '../lib/extracare2of.rb'
4
+ username = ARGV[0]
5
+ password = ARGV[1]
6
+ runner = ExtraCare2OF::Runner.new(username: username, password: password)
7
+ runner.run
data/config/config.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ :services:
3
+ :use_omnifocus: true
4
+ :use_reminders: false
5
+ :use_things: false
6
+ :use_dueapp: false
data/db/coupons.db ADDED
File without changes
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'extracare2of/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "extracare2of"
8
+ spec.version = ExtraCare2OF::VERSION
9
+ spec.authors = ["Nick Prokesch"]
10
+ spec.email = ["nick@prokes.ch"]
11
+ spec.summary = %q{send CVS ExtraCare coupon reminders to OmniFocus}
12
+ spec.description = %q{Logs into CVS account, adds coupons with due dates to OmniFocus, remembers imported coupons}
13
+ spec.homepage = "https://github.com/prokizzle/extracare2of"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.require_paths = ["lib"]
18
+ spec.bindir = 'bin'
19
+ spec.executables << 'extracare2of'
20
+
21
+ spec.add_dependency "mechanize", "~> 2.7"
22
+ spec.add_dependency "amatch", "~> 0.2"
23
+ spec.add_dependency "rb-appscript", "~> 0.6"
24
+ spec.add_dependency "highline", "~> 1.6"
25
+ spec.add_dependency "chronic", "~> 0.10"
26
+ spec.add_dependency "sqlite3", "~> 1.3"
27
+ end
@@ -0,0 +1,39 @@
1
+ module ExtraCare2OF
2
+ class Authentication
3
+ attr_reader :hash
4
+
5
+ def initialize(args)
6
+ @username = args[:username]
7
+ @password = args[:password]
8
+ @agent = Mechanize.new
9
+ @hash = Hash.new
10
+ end
11
+
12
+ def login
13
+ page = @agent.get("https://m.cvs.com/mt/www.cvs.com/account/login.jsp")
14
+ form = page.forms.first
15
+ form['/atg/userprofiling/ProfileFormHandler.value.login'] = @username
16
+ form['/atg/userprofiling/ProfileFormHandler.value.password'] = @password
17
+ page = form.submit
18
+ @page = page
19
+ sleep 3
20
+ # puts page.parser.xpath("//body").to_html
21
+ end
22
+
23
+ def request(link, request_id)
24
+ @hash[request_id] = {ready: false}
25
+ url = URI.escape(link)
26
+ @agent.read_timeout=30
27
+ temp = @agent.get(url)
28
+ # @log.debug "#{@url}"
29
+ returned_body = temp.parser.xpath("//body").to_html.to_s
30
+ @hash[request_id] = {url: url.to_s, body: returned_body, html: temp, ready: true}
31
+ {url: url.to_s, body: returned_body, html: temp, hash: request_id.to_i}
32
+ end
33
+
34
+ def logged_in?
35
+ /Welcome/.match(@page.parser.xpath("//body").to_html) == true
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,65 @@
1
+ require 'sqlite3'
2
+
3
+ module ExtraCare2OF
4
+ class Database
5
+ attr_accessor :add_user
6
+ attr_reader :add_user
7
+
8
+ def initialize(args)
9
+ @handle = args[ :username]
10
+ open
11
+ create_tables
12
+ tasks
13
+ end
14
+
15
+ def tasks
16
+ begin
17
+ # @db.execute("alter table matches add column emailed integer")
18
+ rescue
19
+ end
20
+ end
21
+
22
+ def create_tables
23
+ begin
24
+ @db.execute("CREATE TABLE coupons(
25
+ id integer,
26
+ name text,
27
+ due_date integer,
28
+ start_date text,
29
+ handle text,
30
+ PRIMARY KEY(id)
31
+ )
32
+ ")
33
+ rescue
34
+ end
35
+ end
36
+
37
+
38
+ def open
39
+ @db = SQLite3::Database.new( "./db/coupons.db" )
40
+ end
41
+
42
+ def close
43
+ @db.close
44
+ end
45
+
46
+ def add_coupon(args)
47
+
48
+ name = args[:name].to_s
49
+ due_date = args[:due_date].to_s
50
+ start_date = args[:start_date].to_s
51
+ unless coupon_exists?(name)
52
+ # begin
53
+ @db.execute("insert into coupons(name, due_date, start_date, handle) values (?,?,?,?)", name, due_date, start_date, @handle)
54
+ end
55
+ end
56
+
57
+ def coupon_exists?(name)
58
+ temp = @db.execute( "select 1 where exists(
59
+ select 1
60
+ from coupons
61
+ where name = ?
62
+ ) ", [name] ).any?
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,107 @@
1
+
2
+ module ExtraCare2OF
3
+ class Runner
4
+
5
+ def initialize(args)
6
+ @username = args[:username]
7
+ @password = args[:password]
8
+ @db = ExtraCare2OF::Database.new(username: @username)
9
+ @browser = ExtraCare2OF::Authentication.new(username: @username, password: @password)
10
+ @settings = Settings.new
11
+ @browser.login
12
+ @count = 0
13
+ # p @rewards_source
14
+ end
15
+
16
+ def async_response(url)
17
+ request_id = Time.now.to_i
18
+ @browser.request(url, request_id)
19
+ until @browser.hash[request_id][:ready]
20
+ sleep 0.1
21
+ end
22
+ @browser.hash[request_id]
23
+ end
24
+
25
+ # [fix] - rewards scanner not picking up all deals
26
+ # [todo] - add extrabucks support
27
+ def get_coupons
28
+ @rewards_source = async_response("https://m.cvs.com/mt/www.cvs.com/extracare/landing.jsp")[:body]
29
+ if $debug
30
+ puts @rewards_source
31
+ exit
32
+ end
33
+ @deals_array = Array.new
34
+ rewards = @rewards_source.scan(/<div class="un_exEntry">\n.+\>(.+)\<.div><.div.+$\n.+\>(.+)\<.div.+$\n.+\>(.+)\<.div.+$\n.+$/)
35
+ rewards.each do |deal|
36
+ name = deal[0]
37
+ due_date = deal[1]
38
+ note = deal[2]
39
+ # defer_date = deal[3]
40
+ @deals_array.push({:name => name,:due_date => parse_date(due_date), :defer_date => Time.now, :note => note})
41
+ end
42
+ @deals_array
43
+ end
44
+
45
+ def send_bucks_to_card
46
+ bucks = @rewards_source.scan(regex)
47
+ bucks.each do |buck|
48
+ link = buck.match(url)
49
+ link_page = @browser.request(link)
50
+ confirmation = @browser.request(button)
51
+ if confirmation == regex
52
+ puts "Extra Bucks sent to card"
53
+ else
54
+ puts "Error: Unable to send to card"
55
+ end
56
+ end
57
+ end
58
+
59
+ #borrowed from ttscoff's otask
60
+ def parse_date(datestring)
61
+ days = 0
62
+ if datestring =~ /^\+(\d+)$/
63
+ days = (60 * 60 * 24 * $1.to_i)
64
+ newdate = Time.now + days
65
+ else
66
+ newdate = Chronic.parse(datestring, {:context => :future, :ambiguous_time_range => 8})
67
+ end
68
+ # parsed = newdate.strftime('%D %l:%M%p').gsub(/\s+/,' ');
69
+ # return parsed =~ /1969/ ? false : parsed
70
+ return newdate
71
+ end
72
+
73
+ def process_coupon(coupon)
74
+ # puts " - Sending #{get_coupons.size} tasks to OF"
75
+ unless @db.coupon_exists?(coupon[:name])
76
+ @db.add_coupon(name: coupon[:name], due_date: coupon[:due_date], defer_date: coupon[:defer_date])
77
+ puts "----"
78
+ puts " Title: #{coupon[:name]}"
79
+ puts " - Due Date: #{coupon[:due_date]}"
80
+ puts " - Start Date: #{coupon[:defer_date]}"
81
+ puts " - Note: #{coupon[:note]}"
82
+ CreateTask::OmniFocus.new(coupon.to_hash) if @settings.use_omnifocus
83
+ CreateTask::Reminders.new(coupon.to_hash) if @settings.use_reminders
84
+ CreateTask::Things.new(coupon.to_hash) if @settings.use_things
85
+ CreateTask::DueApp.new(coupon.to_hash) if @settings.use_dueapp
86
+ # Services::Reminders.new(coupon.to_hash)
87
+ end
88
+ end
89
+
90
+
91
+ def run
92
+ puts "Looking for coupons..."
93
+ @result = get_coupons
94
+ @result.each {|coupon| process_coupon(coupon)}
95
+ if @count > 0
96
+ puts "Sent #{@count} coupons to OmniFocus"
97
+ else
98
+ puts "No new coupons found."
99
+ end
100
+ # puts "Sending extra bucks to card"
101
+ # send_bucks_to_card
102
+ # puts "Done"
103
+ # exit
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,113 @@
1
+ module CreateTask
2
+ require 'chronic'
3
+
4
+ class OmniFocus
5
+ require 'appscript'#;include Appscript
6
+
7
+
8
+ def initialize(args)
9
+ args[:due_date] = parse_date(args[:due_date]) if args[:due_date]
10
+ args[:defer_date] = parse_date(args[:defer_date]) if args[:defer_date]
11
+
12
+ of = app("OmniFocus")
13
+ @dd= of.default_document
14
+ @dd.make(:new => :inbox_task, :with_properties => args.to_hash)
15
+ end
16
+
17
+ def parse_date(datestring)
18
+ days = 0
19
+ if datestring =~ /^\+(\d+)$/
20
+ days = (60 * 60 * 24 * $1.to_i)
21
+ newdate = Time.now + days
22
+ else
23
+ newdate = Chronic.parse(datestring.to_s, {:context => :future, :ambiguous_time_range => 8})
24
+ end
25
+ # parsed = newdate.strftime('%D %l:%M%p').gsub(/\s+/,' ');
26
+ # return parsed =~ /1969/ ? false : parsed
27
+ return newdate
28
+ end
29
+
30
+
31
+
32
+ end
33
+
34
+ class Reminders
35
+ # include 'helper'
36
+ def initialize(args)
37
+ name = args[:name]
38
+ # due_date = parse_date(args[:due_date])
39
+ due_date = args[:due_date]
40
+ remind = %x{osascript <<'APPLESCRIPT'
41
+ set d_date to date "#{due_date}"
42
+ tell application "Reminders" to show (make new reminder with properties {name:"#{name}", due date:(d_date)})
43
+ APPLESCRIPT}
44
+ end
45
+
46
+ def parse_date(datestring)
47
+ days = 0
48
+ if datestring =~ /^\+(\d+)$/
49
+ days = (60 * 60 * 24 * $1.to_i)
50
+ newdate = Time.now + days
51
+ else
52
+ newdate = Chronic.parse(datestring, {:context => :future, :ambiguous_time_range => 8})
53
+ end
54
+ # parsed = newdate.strftime('%D %l:%M%p').gsub(/\s+/,' ');
55
+ # return parsed =~ /1969/ ? false : parsed
56
+ return newdate
57
+ end
58
+
59
+ end
60
+
61
+ class DueApp
62
+ # include 'helper'
63
+ def initialize(args)
64
+ name = args[:name]
65
+ # due_date = parse_date(args[:due_date])
66
+ due_date = args[:due_date]
67
+ remind =%x{osascript << 'APPLESCRIPT'
68
+ set d_date to date "#{due_date}"
69
+ set theURl to "due:///add?title=#{name}&due_date=" & d_date
70
+ tell application "Finder" to open location theURl
71
+ tell application "Due" to activate
72
+ delay 0.5 -- This delay can be tweaked for your system
73
+ tell application "Due" to activate
74
+ tell application "System Events" to key code 36
75
+ delay 1 -- This delay can be tweaked for your system
76
+ APPLESCRIPT
77
+ }
78
+
79
+ end
80
+
81
+ def parse_date(datestring)
82
+ days = 0
83
+ if datestring =~ /^\+(\d+)$/
84
+ days = (60 * 60 * 24 * $1.to_i)
85
+ newdate = Time.now + days
86
+ else
87
+ newdate = Chronic.parse(datestring, {:context => :future, :ambiguous_time_range => 8})
88
+ end
89
+ # parsed = newdate.strftime('%D %l:%M%p').gsub(/\s+/,' ');
90
+ # return parsed =~ /1969/ ? false : parsed
91
+ return newdate
92
+ end
93
+ end
94
+
95
+ class Things
96
+ def initialize(args)
97
+ name = args[:name]
98
+ due_date = args[:due_date]
99
+ notes = args[:notes]
100
+ tags = args[:tag]
101
+ remind = %x{osascript << 'APPLESCRIPT'
102
+ set d_date to date "#{due_date}"
103
+ tell application "Things"
104
+ set newToDo to make new to do with properties {name: "#{name}"}
105
+ set newToDo's notes to "#{notes}"
106
+ set newToDo's due date to d_date
107
+ set tag names of newToDo to "#{tags}"
108
+ end tell
109
+ APPLESCRIPT}
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,27 @@
1
+ module ExtraCare2OF
2
+ class Settings
3
+ attr_reader :debug, :use_omnifocus, :use_reminders, :use_things, :use_dueapp
4
+
5
+ def initialize
6
+ @filename = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "config.yml"))
7
+ unless File.exists?(@filename)
8
+ config = {services: {
9
+ :use_omnifocus => true,
10
+ :use_reminders => false,
11
+ :use_things => false,
12
+ :use_dueapp => false
13
+ }
14
+ }
15
+ File.open(@filename, "w") do |f|
16
+ f.write(config.to_yaml)
17
+ end
18
+ end
19
+ @settings = YAML.load_file(@filename)
20
+ @use_omnifocus = @settings[:services][:use_omnifocus]
21
+ @use_reminders = @settings[:services][:use_reminders]
22
+ @use_things = @settings[:services][:use_things]
23
+ @use_dueapp = @settings[:services][:use_dueapp]
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module ExtraCare2OF
2
+ ExtraCare2OF::VERSION = 0.2
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'yaml'
2
+ require 'highline/import'
3
+ require 'appscript';include Appscript
4
+ require 'amatch';include Amatch
5
+ require 'chronic'
6
+ require 'mechanize'
7
+ require 'open-uri'
8
+
9
+ module ExtraCare2OF
10
+ Dir[File.dirname(__FILE__) + '/extracare2of/*.rb'].each do |file|
11
+ require file
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: extracare2of
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ platform: ruby
6
+ authors:
7
+ - Nick Prokesch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mechanize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: amatch
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rb-appscript
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: highline
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: chronic
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.10'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ description: Logs into CVS account, adds coupons with due dates to OmniFocus, remembers
98
+ imported coupons
99
+ email:
100
+ - nick@prokes.ch
101
+ executables:
102
+ - extracare2of
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".ruby-version"
108
+ - Gemfile
109
+ - README.md
110
+ - bin/extracare2of
111
+ - config/config.yml
112
+ - db/coupons.db
113
+ - extracare2of.gemspec
114
+ - lib/ExtraCare2OF/authentication.rb
115
+ - lib/ExtraCare2OF/database.rb
116
+ - lib/ExtraCare2OF/runner.rb
117
+ - lib/ExtraCare2OF/services.rb
118
+ - lib/ExtraCare2OF/settings.rb
119
+ - lib/ExtraCare2OF/version.rb
120
+ - lib/extracare2of.rb
121
+ homepage: https://github.com/prokizzle/extracare2of
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.2.2
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: send CVS ExtraCare coupon reminders to OmniFocus
145
+ test_files: []