connfu-client 0.1

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 (94) hide show
  1. data/.rspec +3 -0
  2. data/.rvmrc +2 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +120 -0
  5. data/LICENSE.txt +661 -0
  6. data/README.rdoc +398 -0
  7. data/Rakefile +38 -0
  8. data/bin/.DS_Store +0 -0
  9. data/bin/connfu-client +94 -0
  10. data/connfu-client.gemspec +41 -0
  11. data/examples/conference/application.rb +68 -0
  12. data/examples/conference/conference.rb +33 -0
  13. data/examples/conference/conference_app.rb +25 -0
  14. data/examples/conference/connfu.log +5 -0
  15. data/examples/conference/wall.rb +11 -0
  16. data/examples/provisioning/app/get.rb +29 -0
  17. data/examples/provisioning/channels/get.rb +34 -0
  18. data/examples/provisioning/rss/create.rb +28 -0
  19. data/examples/provisioning/rss/delete.rb +27 -0
  20. data/examples/provisioning/rss/get.rb +32 -0
  21. data/examples/provisioning/rss/put.rb +29 -0
  22. data/examples/provisioning/setup.rb +2 -0
  23. data/examples/provisioning/twitter/create.rb +31 -0
  24. data/examples/provisioning/twitter/delete.rb +27 -0
  25. data/examples/provisioning/twitter/get.rb +32 -0
  26. data/examples/provisioning/twitter/put.rb +29 -0
  27. data/examples/provisioning/voice/create.rb +26 -0
  28. data/examples/provisioning/voice/delete.rb +27 -0
  29. data/examples/provisioning/voice/get.rb +36 -0
  30. data/examples/provisioning/voice/phones/create.rb +26 -0
  31. data/examples/provisioning/voice/phones/delete.rb +28 -0
  32. data/examples/provisioning/voice/phones/get.rb +38 -0
  33. data/examples/provisioning/voice/put.rb +38 -0
  34. data/examples/provisioning/voice/whitelist/create.rb +26 -0
  35. data/examples/provisioning/voice/whitelist/delete.rb +27 -0
  36. data/examples/provisioning/voice/whitelist/get.rb +36 -0
  37. data/examples/provisioning/voice/whitelist/put.rb +27 -0
  38. data/lib/connfu.rb +134 -0
  39. data/lib/connfu/cli/generator.rb +71 -0
  40. data/lib/connfu/connfu_logger.rb +88 -0
  41. data/lib/connfu/connfu_message_formatter.rb +134 -0
  42. data/lib/connfu/connfu_stream.rb +182 -0
  43. data/lib/connfu/dispatcher.rb +164 -0
  44. data/lib/connfu/dsl.rb +84 -0
  45. data/lib/connfu/events.rb +32 -0
  46. data/lib/connfu/listener.rb +85 -0
  47. data/lib/connfu/listener_channel.rb +100 -0
  48. data/lib/connfu/message.rb +74 -0
  49. data/lib/connfu/provisioning.rb +12 -0
  50. data/lib/connfu/provisioning/application.rb +374 -0
  51. data/lib/connfu/provisioning/base.rb +95 -0
  52. data/lib/connfu/provisioning/channel.rb +79 -0
  53. data/lib/connfu/provisioning/phone.rb +55 -0
  54. data/lib/connfu/provisioning/rss.rb +21 -0
  55. data/lib/connfu/provisioning/twitter.rb +28 -0
  56. data/lib/connfu/provisioning/voice.rb +89 -0
  57. data/lib/connfu/provisioning/whitelist.rb +62 -0
  58. data/lib/connfu/version.rb +6 -0
  59. data/lib/rdoc/generator/template/connfu/_context.rhtml +209 -0
  60. data/lib/rdoc/generator/template/connfu/_head.rhtml +7 -0
  61. data/lib/rdoc/generator/template/connfu/class.rhtml +38 -0
  62. data/lib/rdoc/generator/template/connfu/file.rhtml +36 -0
  63. data/lib/rdoc/generator/template/connfu/index.rhtml +13 -0
  64. data/lib/rdoc/generator/template/connfu/resources/apple-touch-icon.png +0 -0
  65. data/lib/rdoc/generator/template/connfu/resources/css/github.css +129 -0
  66. data/lib/rdoc/generator/template/connfu/resources/css/main.css +339 -0
  67. data/lib/rdoc/generator/template/connfu/resources/css/panel.css +389 -0
  68. data/lib/rdoc/generator/template/connfu/resources/css/reset.css +53 -0
  69. data/lib/rdoc/generator/template/connfu/resources/favicon.ico +0 -0
  70. data/lib/rdoc/generator/template/connfu/resources/i/arrows.png +0 -0
  71. data/lib/rdoc/generator/template/connfu/resources/i/results_bg.png +0 -0
  72. data/lib/rdoc/generator/template/connfu/resources/i/tree_bg.png +0 -0
  73. data/lib/rdoc/generator/template/connfu/resources/js/highlight.pack.js +1 -0
  74. data/lib/rdoc/generator/template/connfu/resources/js/jquery-1.3.2.min.js +19 -0
  75. data/lib/rdoc/generator/template/connfu/resources/js/jquery-effect.js +593 -0
  76. data/lib/rdoc/generator/template/connfu/resources/js/main.js +20 -0
  77. data/lib/rdoc/generator/template/connfu/resources/js/searchdoc.js +628 -0
  78. data/lib/rdoc/generator/template/connfu/resources/panel/index.html +72 -0
  79. data/lib/rdoc/generator/template/connfu/se_index.rhtml +8 -0
  80. data/spec/connfu_message_formatter_spec.rb +88 -0
  81. data/spec/connfu_spec.rb +51 -0
  82. data/spec/connfu_stream_spec.rb +84 -0
  83. data/spec/dispatcher_spec.rb +227 -0
  84. data/spec/dsl_spec.rb +159 -0
  85. data/spec/listener_channel_spec.rb +130 -0
  86. data/spec/listener_spec.rb +67 -0
  87. data/spec/provisioning/application_spec.rb +47 -0
  88. data/spec/provisioning/channel_shared_examples.rb +52 -0
  89. data/spec/provisioning/channel_spec.rb +13 -0
  90. data/spec/provisioning/phone_spec.rb +88 -0
  91. data/spec/provisioning/voice_spec.rb +138 -0
  92. data/spec/provisioning_spec.rb +500 -0
  93. data/spec/spec_helper.rb +51 -0
  94. metadata +298 -0
@@ -0,0 +1,32 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 1 and
10
+ (
11
+ puts "Please include as argument the api_key"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+
17
+ channel = if ARGV.length < 1
18
+ ""
19
+ else
20
+ ARGV.shift
21
+ end
22
+
23
+
24
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
25
+
26
+ begin
27
+ puts application.get_twitter_channel(channel)
28
+ rescue Exception => ex
29
+ puts "There was an error:"
30
+ puts "Exception message: #{ex.message}"
31
+ end
32
+
@@ -0,0 +1,29 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 3 and
10
+ (
11
+ puts "Please include as argument the api_key, the channel and the new topic value to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel = ARGV.shift
17
+ topic = ARGV.shift
18
+
19
+
20
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
21
+
22
+ begin
23
+ puts application.update_voice_channel(channel, topic)
24
+
25
+ rescue Exception => ex
26
+ puts "There was an error:"
27
+ puts "Exception message: #{ex.message}"
28
+ end
29
+
@@ -0,0 +1,26 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key and the channel name to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel_name = ARGV.shift
17
+
18
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
19
+
20
+ begin
21
+ puts application.create_voice_channel(channel_name, "uk")
22
+ rescue Exception => ex
23
+ puts "There was an error: #{ex.inspect}"
24
+ puts "Exception message: #{ex.message}"
25
+ end
26
+
@@ -0,0 +1,27 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key and channel to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel = ARGV.shift
17
+
18
+
19
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
20
+
21
+ begin
22
+ puts application.delete_voice_channel(channel)
23
+ rescue Exception => ex
24
+ puts "There was an error:"
25
+ puts "Exception message: #{ex.message}"
26
+ end
27
+
@@ -0,0 +1,36 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 1 and
10
+ (
11
+ puts "Please include as argument the api_key"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+
17
+ channel = if ARGV.length < 1
18
+ ""
19
+ else
20
+ ARGV.shift
21
+ end
22
+
23
+
24
+ Connfu.log_level = Logger::DEBUG
25
+
26
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
27
+
28
+
29
+ begin
30
+ app = application.get_voice_channel(channel)
31
+ p app
32
+ rescue Exception => ex
33
+ puts "There was an error:"
34
+ puts "Exception message: #{ex.message}"
35
+ end
36
+
@@ -0,0 +1,26 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key and the channel name to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel_name = ARGV.shift
17
+
18
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
19
+
20
+ begin
21
+ puts application.add_phone(channel_name, "UK")
22
+ rescue Exception => ex
23
+ puts "There was an error: #{ex.inspect}"
24
+ puts "Exception message: #{ex.message}"
25
+ end
26
+
@@ -0,0 +1,28 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 3 and
10
+ (
11
+ puts "Please include as argument the api_key, the channel and the phone to be deleted"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel = ARGV.shift
17
+ phone = ARGV.shift
18
+
19
+
20
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
21
+
22
+ begin
23
+ puts application.delete_phone(channel, phone)
24
+ rescue Exception => ex
25
+ puts "There was an error:"
26
+ puts "Exception message: #{ex.message}"
27
+ end
28
+
@@ -0,0 +1,38 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key, the channel and optionally the phone number"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+
17
+ channel = ARGV.shift
18
+
19
+ number = if ARGV.length < 1
20
+ ""
21
+ else
22
+ ARGV.shift
23
+ end
24
+
25
+
26
+ Connfu.log_level = Logger::DEBUG
27
+
28
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
29
+
30
+
31
+ begin
32
+ phones = application.get_phones(channel, number)
33
+ p phones
34
+ rescue Exception => ex
35
+ puts "There was an error:"
36
+ puts "Exception message: #{ex.message}"
37
+ end
38
+
@@ -0,0 +1,38 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 3 and
10
+ (
11
+ puts "Please include as argument the api_key, the channel and the new topic value to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel = ARGV.shift
17
+ if ARGV.length.eql?(1)
18
+ attributes = ARGV.shift
19
+ else
20
+ if ARGV.length % 2 == 0
21
+ # create a hash using array values: odd values => key, even values => value
22
+ attributes = Hash[*ARGV]
23
+ else
24
+ puts "Invalid number of arguments"
25
+ exit
26
+ end
27
+ end
28
+
29
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
30
+
31
+ begin
32
+ puts application.update_voice_channel(channel, attributes)
33
+
34
+ rescue Exception => ex
35
+ puts "There was an error:#{ex.inspect}"
36
+ puts "Exception message: #{ex.message}"
37
+ end
38
+
@@ -0,0 +1,26 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 4 and
10
+ (
11
+ puts "Please include as argument the api_key, channel, whitelist name and whitelist number to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel_name = ARGV.shift
17
+
18
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
19
+
20
+ begin
21
+ puts application.add_whitelist(channel_name, ARGV.shift, ARGV.shift)
22
+ rescue Exception => ex
23
+ puts "There was an error:"
24
+ puts "Exception message: #{ex.inspect}"
25
+ end
26
+
@@ -0,0 +1,27 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key and channel to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel = ARGV.shift
17
+ number = ARGV.shift
18
+
19
+
20
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
21
+
22
+ begin
23
+ puts application.delete_whitelist(channel, number)
24
+ rescue Exception => ex
25
+ puts "There was an error:"
26
+ puts "Exception message: #{ex.message}"
27
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 2 and
10
+ (
11
+ puts "Please include as argument the api_key and the channel to retrieve the whitelist"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+
17
+ channel = ARGV.shift
18
+
19
+ number = if ARGV.length < 1
20
+ ""
21
+ else
22
+ ARGV.shift
23
+ end
24
+
25
+
26
+
27
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
28
+
29
+ begin
30
+ puts application.get_whitelist(channel, number)
31
+ rescue Exception => ex
32
+ puts "There was an error:"
33
+ puts "Exception message: #{ex.message}"
34
+ puts ex.backtrace
35
+ end
36
+
@@ -0,0 +1,27 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib')
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..', '..')
4
+
5
+ require 'connfu'
6
+
7
+ require 'examples/provisioning/setup'
8
+
9
+ ARGV.length < 4 and
10
+ (
11
+ puts "Please include as argument the api_key, channel, whitelist name and whitelist number to be used"
12
+ exit
13
+ )
14
+
15
+ api_key = ARGV.shift
16
+ channel_name = ARGV.shift
17
+
18
+ application = Connfu::Provisioning::Application.new(api_key, CONNFU_ENDPOINT)
19
+
20
+ begin
21
+ user = Connfu::Provisioning::WhitelistUser.new(ARGV.shift, ARGV.shift)
22
+ puts application.update_whitelist(channel_name, user)
23
+ rescue Exception => ex
24
+ puts "There was an error:"
25
+ puts "Exception message: #{ex.inspect}"
26
+ end
27
+
data/lib/connfu.rb ADDED
@@ -0,0 +1,134 @@
1
+ ##
2
+ # connFu is a platform of Telefonica delivered by Bluevia Labs.
3
+ #
4
+ # Please, check out www.connfu.com and if you need further information
5
+ # contact us at mailto:support@connfu.com
6
+
7
+ require 'connfu/connfu_logger'
8
+
9
+ module Connfu
10
+ include Connfu::ConnfuLogger
11
+
12
+ autoload :ConnfuMessageFormatter, 'connfu/connfu_message_formatter'
13
+ autoload :ConnfuStream, 'connfu/connfu_stream'
14
+ autoload :Dispatcher, 'connfu/dispatcher'
15
+ autoload :DSL, 'connfu/dsl'
16
+ autoload :Events, 'connfu/events'
17
+ autoload :Listener, 'connfu/listener'
18
+ autoload :ListenerChannel, 'connfu/listener_channel'
19
+ autoload :Provisioning, 'connfu/provisioning'
20
+
21
+
22
+ # connFu provisioning API endpoint
23
+ CONNFU_ENDPOINT = "https://api.connfu.com/v1"
24
+
25
+ # connFu HTTP streaming API endpoint
26
+ STREAM_ENDPOINT = "https://stream.connfu.com/"
27
+
28
+ class << self
29
+
30
+ # The token defines the application that is using the connFu platform.
31
+ # Get a valid one using connfu portal
32
+ attr_reader :token
33
+
34
+ # Hash that keeps information about the blocks to be executed when a new event is thrown
35
+ attr_reader :listener_channels
36
+
37
+ # Hash that keeps information about the connFu application channels
38
+ attr_reader :app_channels
39
+
40
+ # events dispatcher handler
41
+ attr_accessor :dispatcher
42
+
43
+ # events listener. It gets incoming events and forward them to the dispatcher layer
44
+ attr_accessor :listener
45
+
46
+ ##
47
+ # This method is used to start a connFu application.
48
+ # Check the examples folder to find some code snippets.
49
+ #
50
+ # ==== Parameters
51
+ #
52
+ # * +token+ valid application token got from connfu
53
+ # * +endpoint+ connFu endpoint (valid provisioning API endpoint)
54
+ # * +stream_endpoint+ connFu streaming endpoint
55
+ def application(token, endpoint = CONNFU_ENDPOINT, stream_endpoint = STREAM_ENDPOINT)
56
+ @token = token
57
+ @listener_channels = {}
58
+ @app_channels = []
59
+ @endpoint = endpoint
60
+
61
+ # set the log level to DEBUG if we are in debug mode
62
+ $DEBUG and self.log_level=Logger::DEBUG
63
+
64
+ logger.info("Starting application with token #{token}")
65
+
66
+ # stop if invalid token
67
+ stream = nil
68
+ begin
69
+ app_info = prov_client.get_info
70
+ rescue RestClient::Unauthorized => ex
71
+ logger.error("Invalid token provided")
72
+ logger.error(ex.inspect)
73
+ raise "Token is invalid"
74
+ rescue Exception => ex
75
+ logger.error("Error retrieving application info")
76
+ logger.error(ex.inspect)
77
+ raise "Token is invalid"
78
+ end
79
+
80
+ app_info.nil? and raise "Unable to find application data"
81
+
82
+ app_stream = app_info.stream_name
83
+
84
+ channels = prov_client.get_channels
85
+
86
+ # Get the interesting channel data using the channel specific method to_hash
87
+ @app_channels = channels.map { |channel| channel.to_hash }
88
+
89
+ # Duplicate voice channels to sms channels
90
+ sms = channels.select { |channel| channel.type.eql?("voice") }
91
+ sms.map!{|channel| channel.type = "sms"; channel.to_hash}
92
+
93
+ sms.each{|channel|
94
+ @app_channels << channel
95
+ }
96
+
97
+ logger.debug "The application #{app_info.name} has these channels: #{@app_channels}"
98
+
99
+ if block_given?
100
+
101
+ # Load the listening channels defined using the DSL
102
+ @listener_channels = DSL.run &Proc.new
103
+
104
+ # This Queue will be used by the listener to put events
105
+ # and by the dispatcher to handle them
106
+ events = Connfu::Events.new
107
+
108
+ # Start the dispatcher
109
+ @dispatcher = Connfu::Dispatcher.new(events, self.listener_channels, self.app_channels)
110
+ @dispatcher.start
111
+
112
+ # Start the listener
113
+ @listener = Connfu::Listener.new(events, app_stream, token, stream_endpoint)
114
+ @listener.start
115
+
116
+ @listener.join # wait for incoming events
117
+ @dispatcher.join
118
+ end
119
+
120
+ # Return the module
121
+ self
122
+ end
123
+
124
+ private
125
+
126
+ ##
127
+ # Provisioning client to retrieve application valid streams
128
+ def prov_client
129
+ # create client instance to retrieve valid streams
130
+ @prov_client ||= Connfu::Provisioning::Application.new(@token, @endpoint)
131
+ end
132
+
133
+ end
134
+ end