we_chat 0.5.15

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +26 -0
  4. data/app/assets/javascripts/we_chat/application.js +13 -0
  5. data/app/assets/stylesheets/we_chat/application.css +15 -0
  6. data/app/controllers/we_chat/application_controller.rb +4 -0
  7. data/app/helpers/we_chat/application_helper.rb +4 -0
  8. data/app/views/layouts/we_chat/application.html.erb +14 -0
  9. data/config/routes.rb +4 -0
  10. data/lib/tasks/we_chat/access_token.rake +26 -0
  11. data/lib/we_chat/access_token.rb +56 -0
  12. data/lib/we_chat/acts_as_we_chat_entity.rb +72 -0
  13. data/lib/we_chat/category.rb +19 -0
  14. data/lib/we_chat/category_property.rb +20 -0
  15. data/lib/we_chat/category_property_item.rb +17 -0
  16. data/lib/we_chat/engine.rb +5 -0
  17. data/lib/we_chat/entity/base.rb +62 -0
  18. data/lib/we_chat/entity/creator.rb +67 -0
  19. data/lib/we_chat/entity/destroyer.rb +16 -0
  20. data/lib/we_chat/entity/identity_entity.rb +21 -0
  21. data/lib/we_chat/entity/named_entity.rb +21 -0
  22. data/lib/we_chat/entity/retriever.rb +21 -0
  23. data/lib/we_chat/error.rb +105 -0
  24. data/lib/we_chat/headers.rb +15 -0
  25. data/lib/we_chat/menu.rb +36 -0
  26. data/lib/we_chat/messaging/message.rb +46 -0
  27. data/lib/we_chat/messaging/message_validator.rb +15 -0
  28. data/lib/we_chat/messaging/responder.rb +92 -0
  29. data/lib/we_chat/multipart_ext.rb +12 -0
  30. data/lib/we_chat/product.rb +119 -0
  31. data/lib/we_chat/product_attribute.rb +23 -0
  32. data/lib/we_chat/rest/api.rb +17 -0
  33. data/lib/we_chat/rest/client.rb +41 -0
  34. data/lib/we_chat/rest/media.rb +18 -0
  35. data/lib/we_chat/rest/menu.rb +21 -0
  36. data/lib/we_chat/rest/request.rb +103 -0
  37. data/lib/we_chat/rest/store.rb +172 -0
  38. data/lib/we_chat/rest/template_message.rb +14 -0
  39. data/lib/we_chat/rest/user.rb +20 -0
  40. data/lib/we_chat/rest/utils.rb +27 -0
  41. data/lib/we_chat/sku.rb +55 -0
  42. data/lib/we_chat/sku_definition.rb +21 -0
  43. data/lib/we_chat/sku_definition_item.rb +17 -0
  44. data/lib/we_chat/subscriber.rb +32 -0
  45. data/lib/we_chat/symbolizable.rb +18 -0
  46. data/lib/we_chat/version.rb +3 -0
  47. data/lib/we_chat.rb +46 -0
  48. metadata +257 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: feb8514ae121d06ffb939ed48de578fbf4772d55
4
+ data.tar.gz: 4d29334931bdf43b6e214682f09bacf7bae6551d
5
+ SHA512:
6
+ metadata.gz: 9b98760c30df6ac196d261fb0fc9be4afbe702161b52d67a159e5907fb49d38888edb71a0e4d21b13bb875ccea00158d7dd89bf017edb3c46744be8f1a2b16b8
7
+ data.tar.gz: bb7ee269809961857a7b119a9bb1f4651f052b2c39d3ccda2af38a290bd5e90adbfefc114387e476cadcff7c7f9acf172efc7fd13fd67caea370037fa90024c1
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = WeChat
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'WeChat'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/test_app/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module WeChat
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module WeChat
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>WeChat</title>
5
+ <%= stylesheet_link_tag "we_chat/application", media: "all" %>
6
+ <%= javascript_include_tag "we_chat/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ WeChat::Engine.routes.draw do
2
+ get 'referrer/register'
3
+
4
+ end
@@ -0,0 +1,26 @@
1
+ # desc "Explaining what the task does"
2
+ # task :we_chat do
3
+ # # Task goes here
4
+ # end
5
+
6
+ require 'we_chat'
7
+
8
+ namespace :we_chat do
9
+ namespace :access_token do
10
+ task :refresh => :environment do
11
+ if defined?(Rails) && (Rails.env == 'development')
12
+ Rails.logger = Logger.new(STDOUT)
13
+ end
14
+
15
+ access_token = WeChat::AccessToken.new(
16
+ WeChat::REST::Client.new,
17
+ WeChat.wechat_appid,
18
+ WeChat.wechat_secret,
19
+ WeChat.wechat_access_token_file_path
20
+ )
21
+ access_token.retrieve
22
+
23
+ Rails.logger.info "* [ACCESS_TOKEN]#{access_token.value}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,56 @@
1
+ require 'we_chat/rest/utils'
2
+ require 'we_chat/rest/request'
3
+ require 'we_chat/symbolizable'
4
+
5
+ module WeChat
6
+ class AccessToken
7
+ include WeChat::REST::Utils
8
+ include WeChat::Symbolizable
9
+
10
+ attr_reader :client, :appid, :secret, :access_token_file, :access_token_data
11
+
12
+ def initialize(client, appid, secret, access_token_file)
13
+ @client = client
14
+ @appid = appid
15
+ @secret = secret
16
+ @access_token_file = access_token_file
17
+ end
18
+
19
+ def retrieve
20
+ response = WeChat::REST::Request.new(client, :get, '/token',
21
+ params: {
22
+ grant_type: 'client_credential',
23
+ appid: appid,
24
+ secret: secret
25
+ }).perform
26
+
27
+ File.open(access_token_file, 'w') { |file| file.write(response.to_json) } if valid?(response)
28
+ return @access_token_data = response
29
+ end
30
+
31
+ def value
32
+ begin
33
+ @access_token_data ||= symbolize_keys!(JSON.parse(File.read(access_token_file)))
34
+ rescue => e
35
+ Rails.logger.debug e
36
+ retrieve
37
+ end
38
+ @access_token_data[:access_token]
39
+ end
40
+
41
+ def valid?(data)
42
+ access_token = data.nil? ? '' : data[:access_token]
43
+ !access_token.blank?
44
+ end
45
+
46
+ class << self
47
+
48
+ def get_access_token(file_path = nil)
49
+ file_path ||= WeChat.wechat_access_token_file_path
50
+ data = JSON.parse(File.read(file_path))
51
+ data["access_token"]
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,72 @@
1
+ require 'we_chat/category'
2
+ require 'we_chat/product'
3
+ require 'we_chat/sku'
4
+ require 'we_chat/sku_definition_item'
5
+ require 'we_chat/category_property_item'
6
+ require 'we_chat/product_attribute'
7
+ require 'we_chat/category_property'
8
+ require 'we_chat/sku_definition'
9
+ require 'we_chat/subscriber'
10
+ require 'we_chat/menu'
11
+
12
+ module WeChat
13
+ module ActsAsWeChatEntity
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+
18
+ end
19
+
20
+ module ClassMethods
21
+ def acts_as_we_chat_entity(entity_name, options = {})
22
+ children_options = options[:children] || {}
23
+ children_definition = {}
24
+
25
+ module_including = "WeChat::#{entity_name.to_s.camelize}".constantize
26
+ include module_including
27
+
28
+ if module_including.const_defined?(:CHILDREN)
29
+ children_definition = generate_children_definition(module_including.const_get(:CHILDREN), children_options)
30
+ end
31
+
32
+ define_children_defintion_method(children_definition)
33
+ define_entity_name_method(entity_name)
34
+ end
35
+
36
+ def generate_children_definition(module_children_definition, children_options)
37
+ children_definition = {}
38
+ module_children_definition.map do |child_key, child_data_key|
39
+ option_item = children_options[child_key]
40
+ child_klass = default_child_class(option_item, child_key)
41
+ child_method = default_child_method(option_item, child_key)
42
+ children_definition[child_key] = { klass: child_klass, method: child_method, data_key: child_data_key }
43
+ end
44
+ children_definition
45
+ end
46
+
47
+ def default_child_class(klass_option, default)
48
+ return default.to_s.camelize.constantize if klass_option.nil? || klass_option[:klass].nil?
49
+ klass_option[:klass]
50
+ end
51
+
52
+ def default_child_method(method_option, default)
53
+ return default.to_s.pluralize if method_option.nil? || method_option[:method].nil?
54
+ method_option[:method]
55
+ end
56
+
57
+ def define_entity_name_method(entity_name)
58
+ define_singleton_method(:we_chat_entity_name) do
59
+ return entity_name
60
+ end
61
+ end
62
+
63
+ def define_children_defintion_method(children_definition)
64
+ define_singleton_method(:children_definition) do
65
+ return children_definition
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ ActiveRecord::Base.send :include, WeChat::ActsAsWeChatEntity
@@ -0,0 +1,19 @@
1
+ require 'we_chat/entity/named_entity'
2
+ require 'we_chat/entity/identity_entity'
3
+
4
+ module WeChat
5
+ module Category
6
+ extend ActiveSupport::Concern
7
+
8
+ include WeChat::Entity::NamedEntity
9
+ include WeChat::Entity::IdentityEntity
10
+
11
+ included do
12
+
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require 'we_chat/entity/named_entity'
2
+ require 'we_chat/entity/identity_entity'
3
+
4
+ module WeChat
5
+ module CategoryProperty
6
+ extend ActiveSupport::Concern
7
+ include WeChat::Entity::NamedEntity
8
+ include WeChat::Entity::IdentityEntity
9
+
10
+ CHILDREN = { category_property_item: :property_value }.freeze
11
+
12
+ included do
13
+
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ require 'we_chat/entity/named_entity'
2
+ require 'we_chat/entity/identity_entity'
3
+
4
+ module WeChat
5
+ module CategoryPropertyItem
6
+ extend ActiveSupport::Concern
7
+ include WeChat::Entity::NamedEntity
8
+ include WeChat::Entity::IdentityEntity
9
+
10
+ included do
11
+ end
12
+
13
+ module ClassMethods
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module WeChat
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace WeChat
4
+ end
5
+ end
@@ -0,0 +1,62 @@
1
+ require_relative 'retriever'
2
+ require_relative 'creator'
3
+ require_relative 'destroyer'
4
+
5
+ module WeChat
6
+ module Entity
7
+ module Base
8
+ extend ActiveSupport::Concern
9
+
10
+ include Retriever
11
+ include Creator
12
+ include Destroyer
13
+
14
+ def to_we_chat_data
15
+ { id: self.we_chat_id, name: self.name }
16
+ end
17
+
18
+ def submitted_to_we_chat?
19
+ !(self.we_chat_id.nil? || self.we_chat_id.empty?)
20
+ end
21
+
22
+ def submit_to_we_chat
23
+ unless submitted_to_we_chat?
24
+ response = WeChat::REST::Client.default.send("#{self.class.we_chat_entity_name.to_s}_create".to_sym, self.to_we_chat_data)
25
+ set_we_chat_id(response)
26
+ end
27
+ end
28
+
29
+ def delete_from_we_chat
30
+ if submitted_to_we_chat?
31
+ self.class.delete_from_we_chat(self.we_chat_id)
32
+ reset_we_chat_id
33
+ end
34
+ end
35
+
36
+ def update_to_we_chat
37
+ if submitted_to_we_chat?
38
+ WeChat::REST::Client.default.send("#{self.class.we_chat_entity_name.to_s}_update".to_sym, self.to_we_chat_data)
39
+ else
40
+ submit_to_we_chat
41
+ end
42
+ end
43
+
44
+ def get_we_chat_id_from_data(data)
45
+ data[:we_chat_id]
46
+ end
47
+
48
+ def reset_we_chat_id
49
+ self.update_attributes!(we_chat_id: nil)
50
+ end
51
+
52
+ def set_we_chat_id(data)
53
+ self.update_attributes!(we_chat_id: get_we_chat_id_from_data(data))
54
+ end
55
+
56
+ module ClassMethods
57
+
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,67 @@
1
+ require 'we_chat/error'
2
+
3
+ module WeChat
4
+ module Entity
5
+ module Creator
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+
10
+ def create_by_we_chat_data(data)
11
+ instance = prepare_children(prepare_instance(data), data) unless data.nil?
12
+ instance || fail(WeChat::Error.new('Entity was created by WeChat data failed'))
13
+ end
14
+
15
+ private
16
+
17
+ def prepare_instance_data(data)
18
+ {}
19
+ end
20
+
21
+ def prepare_instance(data)
22
+ instance_data = prepare_instance_data(data)
23
+ instance = find_by_we_chat_id(instance_data[:we_chat_id])
24
+ if instance.nil?
25
+ instance = create(instance_data)
26
+ else
27
+ instance.update(instance_data)
28
+ end
29
+ instance
30
+ end
31
+
32
+ def prepare_children_data(data)
33
+ children_data = {}
34
+ children_definition.map do |key, value|
35
+ children_data[key] = prepare_one_type_of_children_data(data, key, value)
36
+ end
37
+
38
+ children_data
39
+ end
40
+
41
+ def prepare_one_type_of_children_data(data, child_type, definition)
42
+ data_key = definition[:data_key]
43
+ definition.merge(data: data[data_key])
44
+ end
45
+
46
+ def prepare_children(instance, data)
47
+ return nil if instance.nil?
48
+ children_data = prepare_children_data(data)
49
+ children_data.map do |key, value|
50
+ prepare_one_type_of_children(instance, key, value)
51
+ end
52
+ instance
53
+ end
54
+
55
+ def prepare_one_type_of_children(instance, child_type, child_data)
56
+ if child_data && child_data[:data]
57
+ child_data[:data].each do |item|
58
+ child_instance = child_data[:klass].send(:create_by_we_chat_data, item) if child_data[:klass].singleton_class.method_defined?(:create_by_we_chat_data)
59
+ instance.send(child_data[:method]) << child_instance if child_instance
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,16 @@
1
+ module WeChat
2
+ module Entity
3
+ module Destroyer
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ def delete_from_we_chat(id)
9
+ WeChat::REST::Client.default.send("#{we_chat_entity_name.to_s}_delete".to_sym, id)
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'we_chat/entity/base'
2
+
3
+ module WeChat
4
+ module Entity
5
+ module IdentityEntity
6
+ extend ActiveSupport::Concern
7
+ include WeChat::Entity::Base
8
+
9
+ module ClassMethods
10
+
11
+ def prepare_instance_data(data)
12
+ result = super(data)
13
+ result[:we_chat_id] = data[:id]
14
+ result
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'we_chat/entity/base'
2
+
3
+ module WeChat
4
+ module Entity
5
+ module NamedEntity
6
+ extend ActiveSupport::Concern
7
+ include WeChat::Entity::Base
8
+
9
+ module ClassMethods
10
+
11
+ def prepare_instance_data(data)
12
+ result = super(data)
13
+ result[:name] = data[:name]
14
+ result
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module WeChat
2
+ module Entity
3
+ module Retriever
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ def retrieve_from_we_chat(id)
9
+ response = WeChat::REST::Client.default.send("#{we_chat_entity_name.to_s}_get".to_sym, id)
10
+ create_by_we_chat(get_instance_data_from_reponse(response))
11
+ end
12
+
13
+ def get_instance_data_from_reponse(response)
14
+ response
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,105 @@
1
+ module WeChat
2
+ # Custom error class for rescuing from all WeChat errors
3
+ class Error < StandardError
4
+ # @return [Integer]
5
+ attr_reader :code
6
+
7
+ # Raised when WeChat returns a 4xx HTTP status code
8
+ ClientError = Class.new(self)
9
+
10
+ # Raised when WeChat returns the HTTP status code 400
11
+ BadRequest = Class.new(ClientError)
12
+
13
+ # Raised when WeChat returns the HTTP status code 401
14
+ Unauthorized = Class.new(ClientError)
15
+
16
+ # Raised when WeChat returns the HTTP status code 403
17
+ Forbidden = Class.new(ClientError)
18
+
19
+ # Raised when a Tweet has already been favorited
20
+ AlreadyFavorited = Class.new(Forbidden)
21
+
22
+ # Raised when a Tweet has already been retweeted
23
+ AlreadyRetweeted = Class.new(Forbidden)
24
+
25
+ # Raised when a Tweet has already been posted
26
+ DuplicateStatus = Class.new(Forbidden)
27
+
28
+ # Raised when WeChat returns the HTTP status code 404
29
+ NotFound = Class.new(ClientError)
30
+
31
+ # Raised when WeChat returns the HTTP status code 406
32
+ NotAcceptable = Class.new(ClientError)
33
+
34
+ # Raised when WeChat returns the HTTP status code 422
35
+ UnprocessableEntity = Class.new(ClientError)
36
+
37
+ # Raised when WeChat returns the HTTP status code 429
38
+ TooManyRequests = Class.new(ClientError)
39
+
40
+ # Raised when WeChat returns a 5xx HTTP status code
41
+ ServerError = Class.new(self)
42
+
43
+ # Raised when WeChat returns the HTTP status code 500
44
+ InternalServerError = Class.new(ServerError)
45
+
46
+ # Raised when WeChat returns the HTTP status code 502
47
+ BadGateway = Class.new(ServerError)
48
+
49
+ # Raised when WeChat returns the HTTP status code 503
50
+ ServiceUnavailable = Class.new(ServerError)
51
+
52
+ # Raised when WeChat returns the HTTP status code 504
53
+ GatewayTimeout = Class.new(ServerError)
54
+
55
+ ERRORS = {
56
+ 400 => WeChat::Error::BadRequest,
57
+ 401 => WeChat::Error::Unauthorized,
58
+ 403 => WeChat::Error::Forbidden,
59
+ 404 => WeChat::Error::NotFound,
60
+ 406 => WeChat::Error::NotAcceptable,
61
+ 422 => WeChat::Error::UnprocessableEntity,
62
+ 429 => WeChat::Error::TooManyRequests,
63
+ 500 => WeChat::Error::InternalServerError,
64
+ 502 => WeChat::Error::BadGateway,
65
+ 503 => WeChat::Error::ServiceUnavailable,
66
+ 504 => WeChat::Error::GatewayTimeout,
67
+ }
68
+
69
+ class << self
70
+
71
+ # Create a new error from an HTTP response
72
+ #
73
+ # @param body [String]
74
+ # @param headers [Hash]
75
+ # @return [WeChat::Error]
76
+ def from_response(body, headers)
77
+ message, code = parse_error(body)
78
+ new(message, headers, code)
79
+ end
80
+
81
+ private
82
+
83
+ def parse_error(body)
84
+ if body.nil? || body.empty?
85
+ ['', -1]
86
+ elsif body[:errcode] && body[:errcode] != 0
87
+ [body[:errmsg], body[:errcode]]
88
+ else
89
+ ['', -1]
90
+ end
91
+ end
92
+ end
93
+
94
+ # Initializes a new Error object
95
+ #
96
+ # @param message [Exception, String]
97
+ # @param rate_limit [Hash]
98
+ # @param code [Integer]
99
+ # @return [WeChat::Error]
100
+ def initialize(message = '', headers = {}, code = nil)
101
+ super(message)
102
+ @code = code
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,15 @@
1
+ module WeChat
2
+ class Headers
3
+ def initialize(client, request_method, url, options = {})
4
+ @client = client
5
+ @request_method = request_method.to_sym
6
+ @uri = Addressable::URI.parse(url)
7
+ @options = options
8
+ end
9
+
10
+ def request_headers
11
+ headers = {}
12
+ headers
13
+ end
14
+ end
15
+ end