technomancy-harker 0.0.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ === 0.5.0 / 2009-03-30
2
+
3
+ * Use gem's config/database.yml for a base.
4
+ * Gemifying existing apps works now.
5
+ * Accept arguments for script/server when starting app.
6
+
1
7
  === 0.0.3 / 2009-03-26
2
8
 
3
9
  * A release!
data/Manifest.txt CHANGED
@@ -7,6 +7,9 @@ lib/harker.rb
7
7
  lib/harker/gemify.rb
8
8
  lib/harker/rails_configuration.rb
9
9
  lib/harker/server.rb
10
+ lib/harker/templates/bin.erb
11
+ lib/harker/templates/hoe.erb
12
+ lib/harker/templates/lib.erb
10
13
  test/sample/Manifest.txt
11
14
  test/sample/README.rdoc
12
15
  test/sample/Rakefile
@@ -31,8 +34,6 @@ test/sample/config/locales/en.yml
31
34
  test/sample/config/routes.rb
32
35
  test/sample/db/migrate/20090326050232_create_harks.rb
33
36
  test/sample/lib/sample_rails.rb
34
- test/sample/log/development.log
35
- test/sample/log/test.log
36
37
  test/sample/public/404.html
37
38
  test/sample/public/422.html
38
39
  test/sample/public/500.html
@@ -61,4 +62,5 @@ test/sample/test/performance/browsing_test.rb
61
62
  test/sample/test/test_helper.rb
62
63
  test/sample/test/unit/hark_test.rb
63
64
  test/sample/test/unit/helpers/harks_helper_test.rb
65
+ test/test_gemify.sh
64
66
  test/test_harker.rb
data/README.rdoc CHANGED
@@ -7,12 +7,31 @@ http://github.com/technomancy/harker
7
7
  Harker means Rails deployments via RubyGems--because a package manager
8
8
  is a terrible thing to waste.
9
9
 
10
+ == Motivation
11
+
12
+ This will mean you can use the same infrastructure you already rely on
13
+ for your dependencies to manage your application itself. It means
14
+ never having to keep a checkout of your app just for deployment. It
15
+ also becomes very easy to see what versions are installed on a given
16
+ box and run multiple instances (of the same or different versions) at
17
+ the same time on different ports.
18
+
19
+ Your app code will live in your gem home, but all the files specific
20
+ to a given instance will live in an instance directory.
21
+
22
+ In short: you've already got a package manager. Why are you handling
23
+ installation of your deployed apps with a one-off tool?
24
+
10
25
  == Setup
11
26
 
12
27
  Your Rails app will need to be modified a bit to become a gem and work
13
- with Harker. Running "harker /path/to/rails/app" will attempt to turn
14
- it into a gem that uses Hoe. It probably won't be perfect, but it's a
15
- start. See the app in test/sample/ for an example of how this works.
28
+ with Harker. But don't worry, these modifications will improve your
29
+ app and make it more awesome. Running "harker /path/to/rails/app" will
30
+ attempt to turn it into a gem that uses Hoe. You may need to perform a
31
+ bit of tweaking in order to get it to build cleanly since every app is
32
+ different--see the one in test/sample/ for an example of how this
33
+ works. In particular, be sure Manifest.txt does not include any files
34
+ that shouldn't go in the gem, such as pid or log files.
16
35
 
17
36
  You don't have to use Hoe if you want to turn your app into a gem
18
37
  manually or using another library, but it helps.
@@ -23,21 +42,24 @@ Once your app is a gem, install it locally with "rake install_gem",
23
42
  and you should be able to use the bin wrapper to generate a new
24
43
  instance:
25
44
 
26
- $ your_app init /var/myapp
45
+ $ your_app init ~/apps/your_app_3000
27
46
 
28
47
  Then edit /var/myapp/database.yml with your database settings. At that
29
48
  point you should be able to bring up your database:
30
49
 
31
- $ RAILS_ENV=production your_app migrate /var/myapp
50
+ $ your_app migrate ~/apps/your_app_3000
32
51
 
33
52
  Test it out by dropping into the console:
34
53
 
35
- $ RAILS_ENV=production your_app console /var/myapp
54
+ $ your_app console ~/apps/your_app_3000
36
55
 
37
56
  Then you can start and stop your application server via Rack:
38
57
 
39
- $ RAILS_ENV=production your_app start /var/myapp
40
- $ RAILS_ENV=production your_app stop /var/myapp
58
+ $ your_app start ~/apps/your_app_3000 --daemon
59
+ $ your_app stop ~/apps/your_app_3000
60
+
61
+ To configure the web server, create a config.ru file in your instance
62
+ directory, and Rails will pick that up with Rack.
41
63
 
42
64
  If you omit the second argument, it defaults to the current directory.
43
65
 
@@ -45,8 +67,6 @@ For deployment, simply publish your gem to a gem server (public or
45
67
  private), install it on the target server, and launch it via the bin
46
68
  wrappers.
47
69
 
48
- TODO: automate /etc/init.d scripts?
49
-
50
70
  == Requirements
51
71
 
52
72
  * rails (at least 2.3.2)
@@ -58,6 +78,12 @@ TODO: automate /etc/init.d scripts?
58
78
 
59
79
  * sudo gem install technomancy-harker --source=http://gems.github.com --source=http://gems.rubyforge.org
60
80
 
81
+ == Todo
82
+
83
+ * rake tasks for remotely installing gem
84
+ * make it easy to "rake release" to a private gem repo
85
+ * test, test, test. try it out with more rails apps!
86
+
61
87
  == License
62
88
 
63
89
  Copyright (c) 2009 Phil Hagelberg.
data/bin/harker CHANGED
@@ -6,11 +6,11 @@ begin
6
6
  gem 'hoe'
7
7
  rescue LoadError
8
8
  abort 'Hoe not found. You can continue without hoe if you gemify
9
- your app yourself; see Harker documentation for details.' # TODO: document!
9
+ your app yourself; see Harker documentation for details.'
10
10
  end
11
11
 
12
12
  if ARGV.include?('-h') or ARGV.include?('--help') or ARGV.size > 1
13
- puts "Usage: #{File.dirname($0)} [RAILS_ROOT]"
13
+ puts "Usage: #{File.basename($0)} [RAILS_ROOT]"
14
14
  puts
15
15
  puts "Attempts to turn your Rails app into a gem for deployment with harker."
16
16
  exit
data/lib/harker.rb CHANGED
@@ -1,9 +1,14 @@
1
1
  require 'fileutils'
2
2
 
3
3
  # Harker lets you deploy Rails apps via RubyGems.
4
+ #
5
+ # These commands get invoked by the bin wrapper of the rails app gem
6
+ # rather than by Harker itself.
7
+ #
4
8
  module Harker
5
- VERSION = '0.0.3'
6
- ACTIONS = %w(start stop restart init migrate console foreground)
9
+ VERSION = '0.5.0'
10
+ ACTIONS = %w(start stop restart init migrate console)
11
+ GEM_ROOT = Gem.loaded_specs[File.basename($0)].full_gem_path rescue '.'
7
12
 
8
13
  module_function
9
14
 
@@ -12,31 +17,35 @@ module Harker
12
17
  action = args.shift
13
18
 
14
19
  unless ACTIONS.include?(action)
15
- abort "Usage: #{@name} INSTANCE_DIR (#{ACTIONS.join('|')})"
20
+ abort "Usage: #{name} INSTANCE_DIR (#{ACTIONS.join('|')}).
21
+ The start command takes the same arguments as script/server."
16
22
  end
17
23
 
18
- @root = File.expand_path(args.shift || Dir.pwd)
24
+ # We need to get rid of the first arg if it's the optional
25
+ # instance directory so script/server doesn't get confused.
26
+ @root = if File.directory? args.first.to_s or action == 'init'
27
+ File.expand_path args.shift
28
+ else
29
+ Dir.pwd
30
+ end
31
+
19
32
  @name = name
20
33
 
21
- load_app unless action == 'init'
22
- self.send(action)
23
- end
34
+ unless action == 'init'
35
+ # 2.3.2 doesn't support tmp_dir config option; needs a monkeypatch.
36
+ require 'harker/rails_configuration'
37
+ require @name
38
+ end
24
39
 
25
- # Start the application server in the foreground.
26
- def foreground
27
- start(false)
40
+ self.send(action)
28
41
  end
29
42
 
30
- # Start and daemonize the application server
31
- def start(daemonize = true)
32
- # can has internal consistency plz, Rails?
33
- Rails::Rack::LogTailer::EnvironmentLog.replace(Rails.configuration.log_path)
43
+ # Start and optionally daemonize the application server
44
+ def start
34
45
  # http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2350
35
46
  # Submitted a patch to Rails, but this lets it work with 2.3.2
47
+ Rails::Rack::LogTailer::EnvironmentLog.replace(Rails.configuration.log_path)
36
48
 
37
- ARGV.replace ["--config=#{@root}/config.ru"]
38
- ARGV.push('--daemon') if daemonize
39
-
40
49
  abort "Can't start; pidfile exists at #{pidfile}." if File.exist? pidfile
41
50
  require 'harker/server'
42
51
  end
@@ -48,6 +57,7 @@ module Harker
48
57
 
49
58
  def restart
50
59
  stop
60
+ rescue SystemExit
51
61
  start
52
62
  end
53
63
 
@@ -56,28 +66,34 @@ module Harker
56
66
  FileUtils.mkdir_p(@root)
57
67
  FileUtils.mkdir_p(@root + '/log')
58
68
  FileUtils.mkdir_p(@root + '/tmp')
69
+ FileUtils.mkdir_p(@root + '/db') # In case we use sqlite.
70
+
71
+ base_db_file = File.join(GEM_ROOT, 'config', 'database.yml')
59
72
 
60
- # TODO: use the in-gem copy of database.yml as a base for this
61
73
  File.open("#{@root}/database.yml", 'w') do |fp|
62
- # TODO: be smart about environments; bleh
63
- fp.puts({ 'production' => { 'adapter' => 'sqlite3',
64
- 'database' => @root + '/db.sqlite3',
65
- 'pool' => 5, 'timeout' => 5000 }}.to_yaml)
74
+ # Need to make sure any sqlite3 DB paths are absolute.
75
+ db_config = YAML.load_file(base_db_file)
76
+ db_config.each do |env, hash|
77
+ if hash['adapter'] =~ /sqlite3?/
78
+ hash['database'] = File.join(@root, hash['database'])
79
+ end
80
+ end
81
+
82
+ fp.puts(db_config.to_yaml)
66
83
  end
67
84
 
68
- # TODO: write a default config.ru?
69
-
70
85
  puts "Initialized #{@name} instance in #{@root}..."
71
86
  puts
72
87
  puts "Configure your database by editing #{@root}/database.yml."
73
88
  puts "Optionally configure your web server via rack in #{@root}/config.ru."
74
89
  puts
75
90
  puts "Migrate your DB with: #{@name} migrate"
76
- puts "Then launch with: #{@name} start"
91
+ puts "Then launch with: #{@name} start --daemon"
77
92
  end
78
93
 
79
94
  def migrate
80
- ActiveRecord::Migrator.migrate(RAILS_ROOT + '/db/migrate',
95
+ puts "Migrating the #{RAILS_ENV} environment of #{@name}..."
96
+ ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db', 'migrate'),
81
97
  ENV["VERSION"] && ENV["VERSION"].to_i)
82
98
  end
83
99
 
@@ -89,16 +105,9 @@ module Harker
89
105
  def configure(config)
90
106
  config.database_configuration_file = File.join(@root, 'database.yml')
91
107
  config.log_path = File.join(@root, 'log', "#{RAILS_ENV}.log")
92
-
93
- # 2.3.2 doesn't support tmp_dir config option.
94
- require 'harker/rails_configuration' unless config.respond_to?(:tmp_dir=)
95
108
  config.tmp_dir = File.join(@root, '/tmp')
96
109
  end
97
110
 
98
- def load_app
99
- require @name
100
- end
101
-
102
111
  def pidfile
103
112
  File.join(@root, 'tmp', 'pids', 'server.pid')
104
113
  end
data/lib/harker/gemify.rb CHANGED
@@ -1,40 +1,44 @@
1
1
  require 'harker'
2
+ require 'fileutils'
3
+ require 'erb'
2
4
 
3
5
  module Harker
6
+ # Turn an existing Rails app into a gem.
4
7
  def self.gemify(rails_root)
5
- project_name = File.basename(rails_root)
8
+ @project_name = File.basename(rails_root)
6
9
 
7
- if File.exist?(rails_root + "/bin/#{project_name}", 'w') or
8
- File.exist?(rails_root + "/lib/#{project_name}.rb", 'w')
10
+ if File.exist?(rails_root + "/bin/#{@project_name}") or
11
+ File.exist?(rails_root + "/lib/#{@project_name}.rb")
9
12
  abort "Can't write gem files without overwriting existing ones.
10
13
  Try manually gemifying."
11
14
  end
12
15
 
13
- # TODO: can we specify the version better?
14
- hoe = "Hoe.new('#{project_name}', '1.0.0') do |p|
15
- p.extra_deps << ['rails', '~> 2.3.2']
16
- p.extra_deps << ['harker', '~> #{Harker::VERSION}']
17
- p.developer('Your Name', 'you@example.com') # FIXME!
18
- end"
19
-
20
- bin = "#!/usr/bin/env ruby
21
- require 'rubygems'
22
- require 'harker'
16
+ File.open(File.join(rails_root, '/Rakefile'), 'a') do |fp|
17
+ fp.puts template('hoe')
18
+ puts "Added hoe block to Rakefile."
19
+ end
23
20
 
24
- Harker.launch(File.basename($0), ARGV)"
21
+ FileUtils.mkdir_p(File.join(rails_root, '/bin'))
22
+ File.open(File.join(rails_root, "/bin/#{@project_name}"), 'w') do |fp|
23
+ fp.puts template('bin')
24
+ puts "Wrote bin launcher."
25
+ end
25
26
 
26
- lib = "# Allow rubygems to load this app
27
- require File.dirname(__FILE__) + '/../config/environment'"
27
+ File.open(File.join(rails_root, "/lib/#{@project_name}.rb"), 'w') do |fp|
28
+ fp.puts template('lib')
29
+ puts "Wrote lib file."
30
+ end
28
31
 
29
- File.open(rails_root + '/Rakefile', 'a') { |fp| fp.puts hoe }
30
- puts "Added hoe block to Rakefile."
31
- File.open(rails_root + "/bin/#{project_name}", 'w') { fp.puts bin }
32
- puts "Wrote bin launcher."
33
- File.open(rails_root + "/lib/#{project_name}.rb", 'w') { fp.puts lib }
34
- puts "Wrote lib file."
35
- system "cd #{rails_root}; rake check_manifest | patch"
36
- puts "Wrote manifest."
32
+ # Submitted a patch to hoe to make it ignore log files by default,
33
+ # but folks should still give it a once-over manually anyway.
34
+ system "cd #{rails_root}; touch Manifest.txt; rake check_manifest | patch"
35
+ puts "Wrote Manifest.txt."
36
+ puts "Ensure the manifest doesn't contain files you don't want in the gem."
37
+ puts "Then try running rake install_gem."
38
+ end
37
39
 
38
- puts "Done! Try running rake install_gem."
40
+ def self.template(name)
41
+ template_path = File.join File.dirname(__FILE__), 'templates', "#{name}.erb"
42
+ ERB.new(File.read(template_path)).result(binding)
39
43
  end
40
44
  end
@@ -1,4 +1,13 @@
1
- # TODO: not sure if my Rails patches cover tmp/sessions or tmp/sockets
1
+ # This monkeypatches Rails to allow tmp_dir to be configured.
2
+
3
+ # It's been submitted upstream:
4
+ # http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2379
5
+
6
+ # We can remove the Configuration monkeypatch once the above patch is
7
+ # accepted if we don't care about supporting older versions.
8
+
9
+ gem 'rails'
10
+ require 'initializer'
2
11
 
3
12
  class Rails::Configuration
4
13
  attr_accessor :tmp_dir
@@ -17,7 +26,7 @@ class Rails::Configuration
17
26
  end
18
27
 
19
28
  class Rails::Initializer
20
- def self.run(command = :process, configuration = Configuration.new)
29
+ def self.run(command = :process, configuration = Rails::Configuration.new)
21
30
  yield configuration if block_given?
22
31
  Harker.configure(configuration)
23
32
  initializer = new configuration
data/lib/harker/server.rb CHANGED
@@ -1,4 +1,11 @@
1
1
  # A patched copy of what Rails' script/server runs.
2
+
3
+ # These changes were submitted upstream to Rails:
4
+ # http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2379
5
+
6
+ # We can remove this file once that patch is accepted if we don't care
7
+ # about supporting older versions.
8
+
2
9
  # Only two changes were made, noted below by comments beginning with "Harker"
3
10
 
4
11
  require 'active_support'
@@ -7,7 +14,6 @@ require 'action_controller'
7
14
  require 'fileutils'
8
15
  require 'optparse'
9
16
 
10
- # TODO: Push Thin adapter upstream so we don't need worry about requiring it
11
17
  begin
12
18
  require_library_or_gem 'thin'
13
19
  rescue Exception
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'harker'
4
+
5
+ Harker.launch(File.basename($0), ARGV)
@@ -0,0 +1,9 @@
1
+ require 'hoe'
2
+ Hoe.new('<%= @project_name %>', '1.0.0') do |p|
3
+ p.summary = 'A Rails application.' # FIXME!
4
+ p.developer('Your Name', 'you@example.com') # FIXME!
5
+ p.extra_deps << ['rails', '~> 2.3.2']
6
+ p.extra_deps << ['harker', '~> <%= Harker::VERSION %>']
7
+ end
8
+
9
+ # TODO: remove hoe's test tasks once new hoe is released.
@@ -0,0 +1,2 @@
1
+ # Allow rubygems to load this app
2
+ require File.dirname(__FILE__) + '/../config/environment'
data/test/sample/Rakefile CHANGED
@@ -6,8 +6,6 @@ require 'rake/testtask'
6
6
  require 'rake/rdoctask'
7
7
  require 'tasks/rails'
8
8
 
9
- # TODO: Hoe and Rails' test tasks stomp on each other
10
- # TODO: specify version sanely
11
9
  Hoe.new('sample_rails', '1.0.0') do |p|
12
10
  p.readme_file = 'README.rdoc'
13
11
  p.extra_deps << ["rails", "~> 2.3.2"]
@@ -779,7 +779,7 @@ Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
779
779
  onComplete: Prototype.emptyFunction,
780
780
  onSuccess: function(transport) {
781
781
  var js = transport.responseText.strip();
782
- if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
782
+ if (!/^\[.*\]$/.test(js))
783
783
  throw('Server returned an invalid collection representation.');
784
784
  this._collection = eval(js);
785
785
  this.checkForExternalText();
@@ -0,0 +1,18 @@
1
+ #!/bin/sh
2
+
3
+ # The gemification step is tricky to test. =\
4
+
5
+ sudo gem uninstall -x dummy
6
+ rm -rf /tmp/dummy-instance
7
+ rm -rf /tmp/dummy
8
+
9
+ cd /tmp
10
+ rails dummy
11
+ cd /tmp/dummy
12
+ script/generate scaffold Dummy name:string favourite_dumb_thing:string
13
+ harker
14
+ rake install_gem
15
+ dummy init /tmp/dummy-instance
16
+ cd /tmp/dummy-instance
17
+ dummy migrate
18
+ dummy start
data/test/test_harker.rb CHANGED
@@ -1,19 +1,13 @@
1
1
  require "rubygems"
2
2
  require "minitest/unit"
3
3
  require 'fileutils'
4
+ require 'timeout'
4
5
  require 'open-uri'
5
6
 
6
7
  $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../lib/")
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/sample/lib/")
7
9
  require 'harker'
8
10
 
9
- begin
10
- ENV['RAILS_ENV'] = 'production'
11
- gem 'sample_rails'
12
- rescue LoadError
13
- abort "You need the sample_rails gem installed:
14
- $ cd #{File.dirname(__FILE__) + '/sample'} && rake install_gem"
15
- end
16
-
17
11
  class TestHarker < MiniTest::Unit::TestCase
18
12
  ROOT = "/tmp/harker-test-#{Process.pid}"
19
13
  URL = 'http://localhost:3000/harks'
@@ -26,6 +20,7 @@ class TestHarker < MiniTest::Unit::TestCase
26
20
 
27
21
  def setup
28
22
  unless File.exist?(ROOT)
23
+ Harker::GEM_ROOT.replace(File.dirname(__FILE__) + '/sample/')
29
24
  harker_action('init')
30
25
  harker_action('migrate')
31
26
  end
@@ -54,7 +49,7 @@ class TestHarker < MiniTest::Unit::TestCase
54
49
  def test_stop
55
50
  start_server_process
56
51
  assert File.exists?(ROOT + '/tmp/pids/server.pid'), "No pid found."
57
- Harker.launch('sample_rails', ['stop', ROOT])
52
+ Harker.launch('sample_rails', ['stop', ROOT]); sleep 0.1
58
53
  assert_raises(Errno::ECONNREFUSED) { open(URL).read }
59
54
  end
60
55
 
@@ -75,8 +70,11 @@ class TestHarker < MiniTest::Unit::TestCase
75
70
  end
76
71
 
77
72
  def start_server_process
78
- `cd #{File.dirname(__FILE__)}/.. ; ruby -I:lib test/sample/bin/sample_rails #{ROOT} start`
79
- loop { break if File.exist?(ROOT + '/tmp/pids/server.pid'); sleep 0.1 }
73
+ `cd #{File.dirname(__FILE__)}/.. ; ruby -I:lib:test/sample/lib test/sample/bin/sample_rails start #{ROOT}`
74
+ Timeout.timeout(5) do
75
+ loop { break if File.exist?(ROOT + '/tmp/pids/server.pid'); sleep 0.1 }
76
+ end
77
+ sleep 0.1 # Waiting for pid to exist isn't enough; it looks like.
80
78
  end
81
79
  end
82
80
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: technomancy-harker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phil Hagelberg
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-26 00:00:00 -07:00
12
+ date: 2009-03-30 00:00:00 -07:00
13
13
  default_executable: harker
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -72,6 +72,9 @@ files:
72
72
  - lib/harker/gemify.rb
73
73
  - lib/harker/rails_configuration.rb
74
74
  - lib/harker/server.rb
75
+ - lib/harker/templates/bin.erb
76
+ - lib/harker/templates/hoe.erb
77
+ - lib/harker/templates/lib.erb
75
78
  - test/sample/Manifest.txt
76
79
  - test/sample/README.rdoc
77
80
  - test/sample/Rakefile
@@ -96,8 +99,6 @@ files:
96
99
  - test/sample/config/routes.rb
97
100
  - test/sample/db/migrate/20090326050232_create_harks.rb
98
101
  - test/sample/lib/sample_rails.rb
99
- - test/sample/log/development.log
100
- - test/sample/log/test.log
101
102
  - test/sample/public/404.html
102
103
  - test/sample/public/422.html
103
104
  - test/sample/public/500.html
@@ -126,6 +127,7 @@ files:
126
127
  - test/sample/test/test_helper.rb
127
128
  - test/sample/test/unit/hark_test.rb
128
129
  - test/sample/test/unit/helpers/harks_helper_test.rb
130
+ - test/test_gemify.sh
129
131
  - test/test_harker.rb
130
132
  has_rdoc: true
131
133
  homepage: http://github.com/technomancy/harker