rhoconnect 3.0.5 → 3.0.6

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.
Files changed (73) hide show
  1. data/CHANGELOG.md +7 -1
  2. data/Gemfile.lock +9 -9
  3. data/README.md +4 -4
  4. data/Rakefile +41 -28
  5. data/bench/bench_runner.rb +4 -5
  6. data/bench/benchapp/Gemfile +1 -1
  7. data/bench/benchapp/Gemfile.lock +26 -27
  8. data/bench/benchapp/config.ru +4 -0
  9. data/bench/benchapp/log/passenger.3000.log +1 -0
  10. data/bench/benchapp/log/passenger.9292.log +59 -0
  11. data/bench/benchapp/settings/settings.yml +2 -0
  12. data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
  13. data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
  14. data/bench/distr_bench/distr_bench +7 -0
  15. data/bench/distr_bench/distr_bench_main +99 -0
  16. data/bench/distr_bench/run_distr_client.sh +12 -0
  17. data/bench/distr_bench/run_test_query_script.sh +50 -0
  18. data/bench/lib/bench/bench_result_processor.rb +90 -0
  19. data/bench/lib/bench/cli.rb +35 -2
  20. data/bench/lib/bench/logging.rb +2 -0
  21. data/bench/lib/bench/runner.rb +4 -2
  22. data/bench/lib/bench/session.rb +3 -1
  23. data/bench/lib/bench/statistics.rb +41 -1
  24. data/bench/lib/bench/timer.rb +7 -0
  25. data/bench/lib/bench/utils.rb +8 -0
  26. data/bench/lib/bench.rb +35 -9
  27. data/bench/lib/testdata/0-data.txt +0 -0
  28. data/bench/lib/testdata/1-data.txt +0 -0
  29. data/bench/lib/testdata/10-data.txt +15 -0
  30. data/bench/lib/testdata/2-data.txt +3 -0
  31. data/bench/lib/testdata/25-data.txt +39 -0
  32. data/bench/lib/testdata/250-data.txt +353 -0
  33. data/bench/lib/testdata/3-data.txt +4 -0
  34. data/bench/lib/testdata/5-data.txt +7 -8
  35. data/bench/lib/testdata/50-data.txt +70 -0
  36. data/bench/lib/testdata/500-data.txt +711 -0
  37. data/bench/prepare_bench +45 -0
  38. data/bench/run_bench.sh +3 -3
  39. data/bench/run_blob_script.sh +1 -1
  40. data/bench/run_cud_script.sh +1 -1
  41. data/bench/run_query_md_script.sh +1 -1
  42. data/bench/run_query_only_script.sh +1 -1
  43. data/bench/run_query_script.sh +1 -1
  44. data/bench/run_test_query_script.sh +30 -0
  45. data/bench/run_test_source_script.sh +21 -0
  46. data/bench/scripts/test_query_script.rb +64 -0
  47. data/bench/scripts/test_source_script.rb +27 -0
  48. data/bin/rhoconnect-benchmark +13 -0
  49. data/doc/client-objc.txt +236 -1
  50. data/doc/client.txt +132 -0
  51. data/doc/extending-rhoconnect-server.txt +79 -0
  52. data/doc/install.txt +1 -1
  53. data/doc/java-plugin.txt +291 -0
  54. data/doc/rest-api.txt +3 -1
  55. data/installer/unix-like/create_texts.rb +73 -16
  56. data/installer/unix-like/pre_install.sh +1 -1
  57. data/installer/unix-like/rho_connect_install_constants.rb +1 -1
  58. data/installer/utils/constants.rb +2 -2
  59. data/installer/utils/nix_install_test.rb +85 -75
  60. data/installer/utils/package_upload/repos.rake +82 -2
  61. data/installer/windows/rhosync.nsi +5 -5
  62. data/lib/rhoconnect/api/application/queue_updates.rb +14 -0
  63. data/lib/rhoconnect/api/source/set_db_doc.rb +3 -1
  64. data/lib/rhoconnect/server.rb +9 -17
  65. data/lib/rhoconnect/version.rb +1 -1
  66. data/rhoconnect.gemspec +1 -1
  67. data/spec/api/admin/get_api_token_spec.rb +6 -0
  68. data/spec/api/source/set_db_doc_spec.rb +13 -0
  69. data/spec/server/server_spec.rb +27 -1
  70. data/tasks/redis.rake +2 -2
  71. metadata +73 -48
  72. data/examples/simple/dump.rdb +0 -0
  73. data/installer/utils/package_upload/repos.rb +0 -83
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/ruby
2
+ require 'rubygems'
3
+ require 'yaml'
4
+ require 'gruff'
5
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', '..','lib'))
6
+ require 'bench'
7
+
8
+ # 1) load all result YAML files
9
+ current_dir = Dir.pwd
10
+ results_dir = ARGV[0]
11
+ if results_dir.nil?
12
+ puts "Bench Result Processor: No result directory is provided - Skipping ..."
13
+ exit(1)
14
+ end
15
+ Dir.chdir results_dir
16
+ results_dir = Dir.pwd
17
+
18
+ Dir.chdir current_dir
19
+ output_dir = ARGV[1]
20
+ output_dir ||= 'images'
21
+ begin
22
+ Dir.mkdir output_dir
23
+ rescue
24
+ end
25
+ Dir.chdir output_dir
26
+ output_dir = Dir.pwd
27
+
28
+ # load meta.yaml
29
+ meta_hash = YAML.load_file("#{results_dir}/meta.yml") if File.exists?("#{results_dir}/meta.yml")
30
+ if meta_hash.nil?
31
+ puts "Bench Result Processor: No valid meta.yml file is found in the result directory - Skipping ..."
32
+ exit(1)
33
+ end
34
+
35
+ @metrics = meta_hash[:metrics]
36
+ if @metrics.nil?
37
+ puts "Bench Result Processor: No valid metrics are found in the result directory - Skipping ..."
38
+ exit(1)
39
+ end
40
+
41
+ if meta_hash[:x_keys].nil?
42
+ puts "Bench Result Processor: No valid x_keys are found in the result directory - Skipping ..."
43
+ exit(1)
44
+ end
45
+ @x_keys = meta_hash[:x_keys].keys
46
+ @x_keys = @x_keys.sort_by(&Bench.sort_natural_order)
47
+
48
+ # initialize graphs for each metric
49
+ graphs = {}
50
+ title = meta_hash[:label]
51
+ @metrics.each do |name,index|
52
+ g = Gruff::Line.new
53
+ g.title = "#{title} (#{name})"
54
+ g.labels = meta_hash[:x_keys].invert
55
+ graphs[index] = g
56
+ end
57
+
58
+ # load all result files
59
+ Dir.foreach(results_dir) do |entry|
60
+ begin
61
+ next unless entry =~ /bench.*result/
62
+
63
+ res_hash = YAML.load_file(File.join(results_dir, entry))
64
+ next if res_hash.nil? or res_hash.empty?
65
+
66
+ marker = entry.split('.').last.to_s
67
+
68
+ g_data = Array.new(@metrics.size) { Array.new }
69
+ @x_keys.each do |x_key|
70
+ results = res_hash[x_key]
71
+ results ||= Array.new(@metrics.size, 0.0)
72
+ results.each_with_index do |res, index|
73
+ g_data[index] << ("%0.4f" % res).to_f
74
+ end
75
+ end
76
+
77
+ graphs.each do |index, graph|
78
+ graph.data("#{marker}", g_data[index])
79
+ end
80
+ rescue Exception => e
81
+ puts " Benchmark processing resulted in Error : " + e.backtrace.join("\n")
82
+ throw e
83
+ end
84
+ end
85
+
86
+ # write out resulting graphs
87
+ @metrics.each do |name, index|
88
+ puts "writing #{output_dir}/#{name}.png"
89
+ graphs[index].write "#{output_dir}/#{name}.png"
90
+ end
@@ -4,12 +4,45 @@ module Bench
4
4
  class Cli < Thor
5
5
  include Logging
6
6
  desc "start path/to/bench/script", "Start performance test"
7
- def start(script,login,password='')
7
+ def start(script,login,password='',*params)
8
+ server = params[0] unless params[0].nil?
9
+ server ||= 'default'
10
+ if server != 'default'
11
+ Bench.base_url = server
12
+ end
13
+ Bench.result_filename = params[1] unless params[1].nil?
14
+ Bench.concurrency = params[2].to_i unless params[2].nil?
15
+ Bench.iterations = params[3].to_i unless params[3].nil?
16
+ Bench.datasize = params[4].to_i unless params[4].nil?
8
17
  Bench.admin_login = login
9
18
  Bench.admin_password = password
10
19
  load(script)
11
20
  Statistics.new(Bench.concurrency,Bench.iterations,
12
- Bench.total_time,Bench.sessions).process.print_stats
21
+ Bench.total_time,Bench.start_time,Bench.end_time,Bench.sessions).process.print_stats.save_results
22
+ bench_log "Bench completed..."
23
+ end
24
+ end
25
+
26
+ class DistributedCli < Thor
27
+ include Logging
28
+ desc "start path/to/bench/script", "Start performance test"
29
+ def start(script,login,password='',*params)
30
+ server = params[0] unless params[0].nil?
31
+ server ||= 'default'
32
+ if server != 'default'
33
+ Bench.base_url = server
34
+ end
35
+ Bench.sync_key = params[1] unless params[1].nil?
36
+ Bench.save_to_redis = true
37
+ Bench.processor_id = "#{Socket.gethostname}_#{Process.pid}"
38
+ Bench.concurrency = params[2].to_i unless params[2].nil?
39
+ Bench.iterations = params[3].to_i unless params[3].nil?
40
+ Bench.datasize = params[4].to_i unless params[4].nil?
41
+ Bench.admin_login = login
42
+ Bench.admin_password = password
43
+ load(script)
44
+ Statistics.new(Bench.concurrency,Bench.iterations,
45
+ Bench.total_time,Bench.start_time,Bench.end_time,Bench.sessions).process.print_stats.save_to_redis
13
46
  bench_log "Bench completed..."
14
47
  end
15
48
  end
@@ -1,5 +1,7 @@
1
1
  module Bench
2
2
  module Logging
3
+ attr_accessor :request_logging
4
+
3
5
  def log_prefix
4
6
  # FIXME: in ruby1.8: "%d" % nil => 0
5
7
  # but in ruby 1.9.2: TypeError: can't convert nil into Integer
@@ -10,7 +10,7 @@ module Bench
10
10
  end
11
11
 
12
12
  def test(concurrency,iterations,&block)
13
- total_time = time do
13
+ total_times = times do
14
14
  0.upto(concurrency - 1) do |thread_id|
15
15
  sleep rand(2)
16
16
  threads << Thread.new(block) do |t|
@@ -33,7 +33,9 @@ module Bench
33
33
  end
34
34
  end
35
35
  Bench.sessions = @sessions
36
- Bench.total_time = total_time
36
+ Bench.total_time = total_times[0]
37
+ Bench.start_time = total_times[1]
38
+ Bench.end_time = total_times[2]
37
39
  end
38
40
 
39
41
  =begin
@@ -33,7 +33,9 @@ module Bench
33
33
  result.last_response = send(verb,url,headers)
34
34
  @last_result = result
35
35
  end
36
- bench_log "#{log_prefix} #{verb.to_s.upcase.gsub(/_/,'')} #{url} #{@last_result.code} #{result.time}"
36
+ if request_logging
37
+ bench_log "#{log_prefix} #{verb.to_s.upcase.gsub(/_/,'')} #{url} #{@last_result.code} #{result.time}"
38
+ end
37
39
  rescue RestClient::Exception => e
38
40
  result.error = e
39
41
  bench_log "#{log_prefix} #{verb.to_s.upcase.gsub(/_/,'')} #{url}"
@@ -2,11 +2,13 @@ module Bench
2
2
  class Statistics
3
3
  include Logging
4
4
 
5
- def initialize(concurrency,iterations,total_time,sessions)
5
+ def initialize(concurrency,iterations,total_time,start_time,end_time,sessions)
6
6
  @sessions = sessions
7
7
  @rows = {} # row key is result.marker;
8
8
  @total_count = 0
9
9
  @total_time = total_time
10
+ @start_time = start_time
11
+ @end_time = end_time
10
12
  @concurrency,@iterations = concurrency,iterations
11
13
  end
12
14
 
@@ -16,6 +18,8 @@ module Bench
16
18
  results.each do |result|
17
19
  @rows[result.marker] ||= {}
18
20
  row = @rows[result.marker]
21
+ row[:times] ||= []
22
+ row[:times] << result.time
19
23
  row[:min] ||= 0.0
20
24
  row[:max] ||= 0.0
21
25
  row[:count] ||= 0
@@ -43,14 +47,50 @@ module Bench
43
47
  bench_log "Statistics:"
44
48
  @rows.each do |marker,row|
45
49
  bench_log "Request %-15s: min: %0.4f, max: %0.4f, avg: %0.4f, err: %d, verification err: %d" % [marker, row[:min], row[:max], average(row), row[:errors], row[:verification_errors]]
50
+ row[:times].sort!
51
+ [0.25, 0.50, 0.75, 0.9, 0.95].each do |p|
52
+ index = (p*(row[:times].size - 1) + 1).to_i
53
+ bench_log "\t#{p*100}% <= #{row[:times][index]}"
54
+ end
46
55
  end
47
56
  bench_log "State of MD : #{Bench.verify_error == 0 ? true : false}"
57
+ bench_log "Payload (#records) : #{Bench.datasize}" unless Bench.datasize.nil?
48
58
  bench_log "Concurrency : #{@concurrency}"
49
59
  bench_log "Iterations : #{@iterations}"
50
60
  bench_log "Total Count : #{@total_count}"
51
61
  bench_log "Total Time : #{@total_time}"
62
+ bench_log "Av.Time : #{average(@rows[Bench.main_marker])}" unless Bench.main_marker.nil?
52
63
  bench_log "Throughput(req/s) : #{@total_count / @total_time}"
53
64
  bench_log "Throughput(req/min): #{(@total_count / @total_time) * 60.0}"
65
+ self
66
+ end
67
+
68
+ def save_results
69
+ return self if Bench.result_filename.nil?
70
+
71
+ res_hash = YAML.load_file(Bench.result_filename) if File.exist?(Bench.result_filename)
72
+ res_hash ||= {}
73
+ res_hash[@concurrency.to_s] = [@total_count/@total_time]
74
+ res_hash[@concurrency.to_s] << average(@rows[Bench.main_marker]) unless Bench.main_marker.nil?
75
+ File.open(Bench.result_filename, 'w' ) do |file|
76
+ file.write res_hash.to_yaml unless res_hash.empty?
77
+ end
78
+ self
79
+ end
80
+
81
+ # save session times into redis doc
82
+ def save_to_redis
83
+ return self unless Bench.save_to_redis
84
+
85
+ stats = {}
86
+ throughput_data = {:start_time => @start_time.to_f,
87
+ :end_time => @end_time.to_f,
88
+ :count => @total_count}
89
+ times_data = @rows[Bench.main_marker][:times] unless Bench.main_marker.nil?
90
+ stats[Bench.processor_id] = {:payload => Bench.datasize, :times => times_data.join(',')}
91
+ stats[Bench.processor_id].merge!(throughput_data)
92
+ Bench.set_server_state("bench_statistics_data",stats,true)
93
+ self
54
94
  end
55
95
  end
56
96
  end
@@ -6,5 +6,12 @@ module Bench
6
6
  end_time = Time.now
7
7
  end_time.to_f - start.to_f
8
8
  end
9
+
10
+ def times
11
+ start = Time.now
12
+ yield
13
+ end_time = Time.now
14
+ [end_time.to_f - start.to_f, start, end_time]
15
+ end
9
16
  end
10
17
  end
@@ -2,6 +2,14 @@ module Bench
2
2
  module Utils
3
3
  include Logging
4
4
 
5
+ def sort_natural_order(nocase=false)
6
+ proc do |str|
7
+ i = true
8
+ str = str.upcase if nocase
9
+ str.gsub(/\s+/, '').split(/(\d+)/).map {|x| (i = !i) ? x.to_i : x}
10
+ end
11
+ end
12
+
5
13
  def compare(name1,s1,name2,s2)
6
14
  r1 = diff([],name1,s1,name2,s2)
7
15
  r2 = diff([],name2,s2,name1,s1)
data/bench/lib/bench.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rest_client'
2
- require 'json'
3
2
  require 'zip/zip'
4
3
  $:.unshift File.dirname(__FILE__)
5
4
  require 'bench/timer'
@@ -27,9 +26,13 @@ module Bench
27
26
 
28
27
  attr_accessor :concurrency, :iterations, :admin_login
29
28
  attr_accessor :admin_password, :user_name
30
- attr_accessor :password, :host, :base_url, :token
29
+ attr_accessor :password, :base_url, :host, :token
31
30
  attr_accessor :total_time, :sessions, :verify_error
32
- attr_accessor :adapter_name
31
+ attr_accessor :adapter_name, :datasize, :result_filename
32
+ attr_accessor :main_marker, :start_time, :end_time
33
+
34
+ # these attributes for distributed testing
35
+ attr_accessor :processor_id, :save_to_redis, :sync_key
33
36
 
34
37
  def config
35
38
  begin
@@ -41,13 +44,30 @@ module Bench
41
44
  end
42
45
  end
43
46
 
47
+ def synchronize
48
+ begin
49
+ yield self
50
+ rescue Exception => e
51
+ puts "error in synchronize: #{e.inspect}"
52
+ raise e
53
+ end
54
+ end
55
+
44
56
  def get_server_state(doc)
45
57
  token = get_token
58
+ params = {:api_token => token, :doc => doc}
46
59
  @body = RestClient.post("#{@host}/api/source/get_db_doc",
47
- {:api_token => token, :doc => doc}.to_json, :content_type => :json)
60
+ params.to_json, :content_type => :json)
48
61
  JSON.parse(@body.to_s)
49
62
  end
50
63
 
64
+ def get_server_value(doc)
65
+ token = get_token
66
+ params = {:api_token => token, :doc => doc, :data_type => 'string'}
67
+ @body = RestClient.post("#{@host}/api/source/get_db_doc",
68
+ params.to_json, :content_type => :json)
69
+ end
70
+
51
71
  def reset_app
52
72
  RestClient.post("#{@host}/api/admin/reset",{:api_token => get_token}.to_json, :content_type => :json)
53
73
  end
@@ -60,10 +80,14 @@ module Bench
60
80
  :content_type => :json)
61
81
  end
62
82
 
63
- def set_server_state(doc,data)
83
+ def set_server_state(doc,data,append=false)
64
84
  token = get_token
85
+ params = {:api_token => token, :doc => doc, :data => data, :append => append}
86
+ if data.is_a? String
87
+ params[:data_type] = 'string'
88
+ end
65
89
  RestClient.post("#{@host}/api/source/set_db_doc",
66
- {:api_token => token, :doc => doc, :data => data}.to_json, :content_type => :json)
90
+ params.to_json, :content_type => :json)
67
91
  end
68
92
 
69
93
  def reset_refresh_time(source_name,poll_interval=nil)
@@ -84,9 +108,11 @@ module Bench
84
108
  end
85
109
 
86
110
  def get_test_server(app_name = nil)
87
- app_name = 'benchapp' unless app_name
88
- load_settings(File.join(File.dirname(__FILE__),'..',app_name,'settings','settings.yml'))
89
- @base_url = $settings[:development][:syncserver].gsub(/\/$/,'')
111
+ if @base_url.nil?
112
+ app_name = 'benchapp' unless app_name
113
+ load_settings(File.join(File.dirname(__FILE__),'..',app_name,'settings','settings.yml'))
114
+ @base_url = $settings[:development][:syncserver].gsub(/\/$/,'')
115
+ end
90
116
  uri = URI.parse(@base_url)
91
117
  port = (uri.port and uri.port != 80) ? ":"+uri.port.to_s : ""
92
118
  @host = "#{uri.scheme}://#{uri.host}#{port}"
Binary file
Binary file
@@ -0,0 +1,15 @@
1
+ {"%ba6ae657fdb945dbb31a9e88901c34e3{ "
2
+ Email"collin@hotmail.com"%ec3b697c638f451f91271f15a162d4c4{ @" Mraz@
3
+ "Distribution Worker@ "
4
+ Jessy@"254-249-0520 x823@"Morar, Turner and Witting@"%ec3b697c638f451f91271f15a162d4c4@"wilfred@gmail.com"%433f0607f695480ca8fb2ed62288274b{ @"
5
+ "Technical Vice President@ " Leilani@"609.739.2116 x33454@"
6
+ "Banking Superintendent@ " Heaven@"(205)937-2087@"Williamson Inc@"%8c115ca8f13e4dabb5bdf9bd49ae09f7@"stan@gmail.com"%8714f3ee057a4f81907e23b2ae861a41{ @" Stanton@
7
+ "Chief Mechanic@ "Priscilla@"(049)684-9908@"McGlynn-Paucek@"%8714f3ee057a4f81907e23b2ae861a41@"edgar@hotmail.com"%4d9d94c8c89e45f19e6f526d0e325da8{ @"
8
+ Lesch@
9
+ "Electronics Nurse@ "
10
+ "Quality Assurance Director@ "Nia@"263-570-9397@"Braun Inc@"%fe2b4da2487e43eab2c51937867c0038@"ora.hackett@hotmail.com"%d1329cb0bda747a8a3027cde2bfb0a2c{ @" Sporer@
11
+ "Head Technologist@ "
12
+ Issac@"(604)041-1675 x977@"Stroman Inc@"%d1329cb0bda747a8a3027cde2bfb0a2c@"mozell@hotmail.com"%5d0c8ab731d3455baf098cfa4520b725{ @" Padberg@
13
+ "Administrative Mechanic@ "
14
+ Tyler@"(184)117-5343 x276@"Brown-Jacobson@"%5d0c8ab731d3455baf098cfa4520b725@"janelle@hotmail.com"%ff296946a04647d7ad8cad315a370d88{ @" Volkman@
15
+ "&Advertising Production Supervisor@ "
@@ -0,0 +1,3 @@
1
+ {"%20fe532915594c9db5433e1378df5dfb{ "
2
+ Email"solon.gottlieb@yahoo.com"%e0af7f86a53c471aacc3da73821c7b65{ @"Orn@
3
+ "Technical Clerk@ " Romaine@"1-445-379-7774@"!Nicolas, Murray and Botsford@"%e0af7f86a53c471aacc3da73821c7b65@"rickey@hotmail.com
@@ -0,0 +1,39 @@
1
+ {"%745f7eba5bdc4b5394d86704bdbb13f8{ "
2
+ Email"mya.welch@gmail.com"%b7b55988f2ba48089846d51fa29ccd3d{ @" Jacobi@
3
+ "Laboratory Clerk@ " Buford@"395-947-1236@"Abbott, Mann and Casper@"%b7b55988f2ba48089846d51fa29ccd3d@"thora_beatty@yahoo.com"%72833fead8b8438b9da511601cc2bea9{ @" Hilpert@
4
+ "Distribution Planner@ "
5
+ Cesar@"845-974-3924@"Crooks and Sons@"%72833fead8b8438b9da511601cc2bea9@"jacynthe.erdman@gmail.com"%2b9d52a78eac41be91184d5c90f1a71a{ @" Kerluke@
6
+ "Production Technologist@ "Marcellus@"462.764.4095 x0038@"!Hermann, Stanton and Stroman@"%2b9d52a78eac41be91184d5c90f1a71a@"layne@gmail.com"%0743364453504b91bb747790ac67cfaa{ @"
7
+ "Maintenance Supervisor@ " Vivian@"748-079-4465@"Weissnat LLC@"%0743364453504b91bb747790ac67cfaa@"napoleon.beier@hotmail.com"%313ff12bbdf847ff9ae46196361c6a06{ @"
8
+ Wolff@
9
+ "%Quality Assurance Superintendent@ " Judy@"1-646-220-9427@"Pagac, Kshlerin and Jast@"%313ff12bbdf847ff9ae46196361c6a06@"#constantin_lockman@hotmail.com"%719c6bda435f4402ae054e00a5488ec0{ @" Kemmer@
10
+ "Chief Supervisor@ " Mozell@"1-687-357-4506 x2642@"Becker LLC@"%719c6bda435f4402ae054e00a5488ec0@"mossie@hotmail.com"%f60acc705f774a7db82614a8379aaf89{ @" Durgan@
11
+ "#Computer Production Supervisor@ " Emma@"(807)711-1773@"O'Kon-Ernser@"%f60acc705f774a7db82614a8379aaf89@"maybelle@gmail.com"%677e0cb3e4774214891a75ce8c7d2186{ @"
12
+ Ebert@
13
+ "Medical Helper@ " Adaline@"1-829-209-7633@"
14
+ "Maintenance Mechanic@ "
15
+ Keith@"238-580-8865 x3897@"Kuphal-Kautzer@"%a18a521497ba470fbc33105a411f8086@"grover@gmail.com"%11774584e300418fa7e756ab019653f8{ @" Hane@
16
+ ",Quality Assurance Production Supervisor@ "
17
+ Zoila@"1-874-687-3044@"Morar-Schmitt@"%11774584e300418fa7e756ab019653f8@" daphney_mueller@hotmail.com"%34e7aa9a287d456f9039b319286dc5fb{ @" Douglas@
18
+ "Financial Director@ " Damian@"915.644.9796 x73099@"Glover, Hand and Lueilwitz@"%34e7aa9a287d456f9039b319286dc5fb@"luz.nicolas@yahoo.com"%579b4154f352499fbbbd94a9dbf74123{ @"
19
+ "Assistant Director@ " Yolanda@"(149)019-1565@"Kling, DuBuque and Fahey@"%579b4154f352499fbbbd94a9dbf74123@" joanie_thompson@hotmail.com"%40ec578ade8b47d7afb021ee76a9918a{ @" Lang@
20
+ " Quality Assurance Executive@ " Lula@"1-027-576-0242 x26553@"Rempel Inc@"%40ec578ade8b47d7afb021ee76a9918a@"peter@gmail.com"%1374a69e9cb44e5d8a9718afef48319e{ @"Abernathy@
21
+ "!Environmental Superintendent@ " Thelma@"681.351.3293@"%Williamson, Schmeler and Reichel@"%1374a69e9cb44e5d8a9718afef48319e@"ryann@gmail.com"%04976051884044b3898b432df5bf5d2c{ @" Douglas@
22
+ "Banking Engineer@ " Meghan@"179-501-0324@"!Schaefer, Bogisich and Bogan@"%04976051884044b3898b432df5bf5d2c@"collin_halvorson@yahoo.com"%f0f02fad738442168cca3c86e759b523{ @"Ankunding@
23
+ "Maintenance Foreman@ " Sean@"1-841-705-6222@"Runolfsdottir-Vandervort@"%f0f02fad738442168cca3c86e759b523@" lauretta_glover@hotmail.com"%76f4ec2512b646a8ac9bbd858bd97461{ @" Legros@
24
+ "Production Helper@ "
25
+ Marta@"(113)776-0880 x1162@"Cummerata Group@"%76f4ec2512b646a8ac9bbd858bd97461@"jacky_ernser@yahoo.com"%28d1f8d66d6442388d4877414365696a{ @"VonRueden@
26
+ "Electronics Clerk@ "
27
+ Fiona@"(520)711-6249 x75737@"Borer, Lemke and Schuppe@"%28d1f8d66d6442388d4877414365696a@"bennie@hotmail.com"%e7104e868fd74ef9a2863cc24459a1c9{ @" Zemlak@
28
+ "Distribution Supervisor@ " Hester@"743-122-4646 x2642@"Daugherty Group@"%e7104e868fd74ef9a2863cc24459a1c9@"shaina.jenkins@gmail.com"%0c83cd53e06b4eac8312463bae2e1663{ @"
29
+ Ortiz@
30
+ "Assistant Technician@ "
31
+ "General Recruiter@ " Danial@"1-651-973-7918 x6691@"Gaylord LLC@"%f636bcdd6af841269dd63d3d6ccc1f79@"pearl@gmail.com"%d15e38056def43d8ae7d3f233bcb6abc{ @"
32
+ Terry@
33
+ "Distribution Helper@ "
34
+ Juana@"(870)146-6842 x777@"'Schuppe, Wintheiser and Hodkiewicz@"%d15e38056def43d8ae7d3f233bcb6abc@"raheem@gmail.com"%e0a892ff16a544f4b6d510b017448386{ @"
35
+ Welch@
36
+ "Chief Buyer@ "Jay@"(544)927-7766@"Bins-Beer@"%e0a892ff16a544f4b6d510b017448386@"neal.wyman@hotmail.com"%708d263cde3d456895b554a784b15b33{ @"
37
+ Hintz@
38
+ "Production Vice President@ "
39
+ Aylin@"214-142-6776 x691@" Luettgen, Volkman and Bosco@"%708d263cde3d456895b554a784b15b33@"malika@gmail.com