tml 4.3.12 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eedcd1e0845ace035f6e6b15b8a91e6376f78a8f
4
- data.tar.gz: 9f20b2e4fb6022af375b506f0d829289916533c9
3
+ metadata.gz: 219ec288ae06a6e1f41055d5a43911f912a9a60b
4
+ data.tar.gz: af5bb4eb638a821d605611fe3dfdb0eb3bfd1ef1
5
5
  SHA512:
6
- metadata.gz: b1e8412ce5d6beeadbbaf8ed073352cca9d55f437280c4c13b5e17a8d8a93d7c92da25ee6336bc8295f29ce25a09b5157917a6b9d5143efefd811b397aba17ba
7
- data.tar.gz: 06642e956d2dddbeff5cbc2a9d5e2bc8e4118e96e7667a20f3295da84ebfc612c0ca56e8645ca9c1009e2af65d91061068a2a9c9e91d7e4c4e08938d519bbdc3
6
+ metadata.gz: 284ba13aed6ef6aff3a8b016edf77d8e9e844e587fd80e4d8029e8fe2904552f7c5d75b91e31ea7173ab0bdcae24f8ffc6f3e19396d632322f566e120b5e3b85
7
+ data.tar.gz: a53fe934ba88ef001c8ab23c8f8ac14344397f5240d0ffb330bf5ac8d6967a02943c97505bea742ca0ea3d7b6a8bd023863eb29a40639b8e44d41e4f9d2c2656
@@ -33,15 +33,13 @@
33
33
  require 'faraday'
34
34
 
35
35
  class Tml::Api::Client < Tml::Base
36
+ CDN_HOST = 'https://cdn.translationexchange.com'
36
37
  API_HOST = 'https://api.translationexchange.com'
37
38
  API_PATH = '/v1'
38
39
 
39
40
  attributes :application
40
41
 
41
- def access_token
42
- Tml.config.application[:token] || Tml.config.application[:access_token]
43
- end
44
-
42
+ # get results from api
45
43
  def results(path, params = {}, opts = {})
46
44
  get(path, params, opts)['results']
47
45
  end
@@ -78,14 +76,61 @@ class Tml::Api::Client < Tml::Base
78
76
  end
79
77
  end
80
78
 
81
- def api(path, params = {}, opts = {})
82
- if Tml.session.inline_mode?
83
- return process_response(execute_request(path, params, opts), opts)
79
+ def verify_cache_version
80
+ return if Tml.cache.version and Tml.cache.version != 'undefined'
81
+
82
+ current_version = Tml.cache.fetch_version
83
+ if current_version == 'undefined'
84
+ Tml.cache.store_version(execute_request('applications/current/version', {}, {:raw => true}))
85
+ else
86
+ Tml.cache.version = current_version
87
+ end
88
+ Tml.logger.info("Version: #{Tml.cache.version}")
89
+ end
90
+
91
+ def cdn_connection
92
+ @cdn_connection ||= Faraday.new(:url => CDN_HOST) do |faraday|
93
+ faraday.request(:url_encoded) # form-encode POST params
94
+ faraday.adapter(Faraday.default_adapter) # make requests with Net::HTTP
95
+ end
96
+ end
97
+
98
+ def get_from_cdn(key, params = {}, opts = {})
99
+ return nil if Tml.cache.version == 'undefined' || Tml.cache.version.to_s == '0'
100
+
101
+ response = nil
102
+ cdn_path = "#{Tml.config.access_token}/#{Tml.cache.version}/#{key}.json"
103
+ trace_api_call(cdn_path, params, opts) do
104
+ begin
105
+ response = cdn_connection.get(cdn_path, params)
106
+ rescue Exception => ex
107
+ Tml.logger.error("Failed to execute request: #{ex.message[0..255]}")
108
+ return nil
109
+ end
84
110
  end
111
+ return if response.status >= 500 and response.status < 600
112
+ return if response.body.nil? or response.body == '' or response.body.match(/xml/)
85
113
 
86
- if opts[:method] == :get and opts[:cache_key]
114
+ begin
115
+ data = JSON.parse(response.body)
116
+ rescue Exception => ex
117
+ return nil
118
+ end
119
+
120
+ data
121
+ end
122
+
123
+ def api(path, params = {}, opts = {})
124
+ # inline mode should always bypass API calls
125
+ # get request uses local cache, then CDN, the API
126
+ if opts[:method] == :get and opts[:cache_key] and Tml.cache.enabled? and not Tml.session.inline_mode?
127
+ verify_cache_version
87
128
  data = Tml.cache.fetch(opts[:cache_key]) do
88
- Tml.cache.read_only? ? nil : execute_request(path, params, opts)
129
+ if Tml.cache.read_only?
130
+ nil
131
+ else
132
+ get_from_cdn(opts[:cache_key]) || execute_request(path, params, opts)
133
+ end
89
134
  end
90
135
  process_response(data, opts)
91
136
  else
@@ -125,7 +170,7 @@ class Tml::Api::Client < Tml::Base
125
170
 
126
171
  # oauth path is separate from versioned APIs
127
172
  path = prepare_api_path(path)
128
- params = params.merge(:access_token => access_token) unless path.index('oauth')
173
+ params = params.merge(:access_token => Tml.config.access_token) unless path.index('oauth')
129
174
 
130
175
  if opts[:method] == :post
131
176
  params = params.merge(:api_key => application.key)
@@ -155,6 +200,7 @@ class Tml::Api::Client < Tml::Base
155
200
  end
156
201
 
157
202
  return if response.body.nil? or response.body == ''
203
+ return response.body if opts[:raw]
158
204
 
159
205
  begin
160
206
  data = JSON.parse(response.body)
@@ -206,7 +252,7 @@ class Tml::Api::Client < Tml::Base
206
252
  #end
207
253
 
208
254
  if opts[:method] == :post
209
- Tml.logger.debug("post: [#{path}] #{params.inspect}")
255
+ Tml.logger.debug("post: [#{path}]")
210
256
  else
211
257
  Tml.logger.debug("get: #{path}?#{to_query(params)}")
212
258
  end
@@ -137,7 +137,7 @@ class Tml::Application < Tml::Base
137
137
  end
138
138
 
139
139
  def register_missing_key(source_key, tkey)
140
- return if Tml.cache.read_only? and not Tml.session.inline_mode?
140
+ return if Tml.cache.enabled? and not Tml.session.inline_mode?
141
141
 
142
142
  @missing_keys_by_sources ||= {}
143
143
  @missing_keys_by_sources[source_key] ||= {}
@@ -32,7 +32,7 @@
32
32
 
33
33
  module Tml
34
34
 
35
- CACHE_VERSION_KEY = '__tml_version__'
35
+ CACHE_VERSION_KEY = 'current_version'
36
36
 
37
37
  def self.memory
38
38
  @memory ||= Tml::CacheAdapters::Memory.new
@@ -52,92 +52,105 @@ module Tml
52
52
 
53
53
  class Cache
54
54
 
55
+ # Returns current cache version
55
56
  def version
56
- Tml.config.cache[:version] ||= 1
57
-
58
- @version ||= begin
59
- v = fetch(CACHE_VERSION_KEY) do
60
- {'version' => Tml.config.cache[:version]}
61
- end
62
- v['version']
63
- end
64
-
65
- @version ||= Tml.config.cache[:version]
66
-
67
- if Tml.config.cache[:version] > @version
68
- update_version(Tml.config.cache[:version])
69
- @version = Tml.config.cache[:version]
70
- end
71
-
72
57
  @version
73
58
  end
74
59
 
75
- def update_version(new_version)
76
- store(CACHE_VERSION_KEY, {'version' => new_version}, :ttl => 0)
60
+ # sets the current version
61
+ def version=(new_version)
62
+ @version = new_version
77
63
  end
78
64
 
79
- def upgrade_version
80
- update_version((version || Tml.config.cache[:version] || 0).to_i + 1)
65
+ # resets current version
66
+ def reset_version
81
67
  @version = nil
82
68
  end
83
69
 
84
- def reset_version
85
- @version = nil
70
+ # upgrade current version
71
+ def upgrade_version
72
+ store(CACHE_VERSION_KEY, {'version' => 'undefined'})
73
+ reset_version
86
74
  end
87
75
 
88
- def enabled?
89
- Tml.config.cache[:enabled]
76
+ # fetches the version from the cache
77
+ def fetch_version
78
+ @version ||= begin
79
+ v = fetch(CACHE_VERSION_KEY) do
80
+ {'version' => Tml.config.cache[:version] || 'undefined'}
81
+ end
82
+ v.is_a?(Hash) ? v['version'] : v
83
+ end
90
84
  end
91
85
 
92
- def cached_by_source?
93
- true
86
+ # stores the current version back in cache
87
+ def store_version(new_version)
88
+ @version = new_version
89
+ store(CACHE_VERSION_KEY, {'version' => new_version})
94
90
  end
95
91
 
96
- def read_only?
97
- false
92
+ # checks if Tml is enabled
93
+ def enabled?
94
+ Tml.config.cache_enabled?
98
95
  end
99
96
 
100
- def segmented?
101
- true
97
+ # by default all cache is read/write
98
+ # cache like files based should be set to read only
99
+ def read_only?
100
+ false
102
101
  end
103
102
 
103
+ # name of the cache adapter
104
104
  def cache_name
105
105
  self.class.name.split('::').last
106
106
  end
107
107
 
108
+ # logs information messages
108
109
  def info(msg)
109
110
  Tml.logger.info("#{cache_name} - #{msg}")
110
111
  end
111
112
 
113
+ # logs a warning
112
114
  def warn(msg)
113
115
  Tml.logger.warn("#{cache_name} - #{msg}")
114
116
  end
115
117
 
118
+ # namespace of each cache key
119
+ def namespace
120
+ return '#' if Tml.config.disabled?
121
+ Tml.config.cache[:namespace] || Tml.config.access_token[0..5]
122
+ end
123
+
124
+ # versioned name of cache key
116
125
  def versioned_key(key, opts = {})
117
- return key if CACHE_VERSION_KEY == key
118
- "tml_rc_v#{version}_#{key}"
126
+ "tml_#{namespace}#{CACHE_VERSION_KEY == key ? '' : "_v#{version}"}_#{key}"
119
127
  end
120
128
 
129
+ # fetches key from cache
121
130
  def fetch(key, opts = {})
122
131
  return nil unless block_given?
123
132
  yield
124
133
  end
125
134
 
135
+ # stores key in cache
126
136
  def store(key, data, opts = {})
127
137
  # do nothing
128
138
  end
129
139
 
140
+ # deletes key from cache
130
141
  def delete(key, opts = {})
131
142
  # do nothing
132
143
  end
133
144
 
145
+ # checks if the key exists
134
146
  def exist?(key, opts = {})
135
147
  false
136
148
  end
137
149
 
150
+ # clears cache
138
151
  def clear(opts = {})
139
152
  # do nothing
140
153
  end
141
154
 
142
155
  end
143
- end
156
+ end
@@ -48,11 +48,6 @@ class Tml::CacheAdapters::File < Tml::Cache
48
48
  'file'
49
49
  end
50
50
 
51
- def segmented?
52
- return true if Tml.config.cache[:segmented].nil?
53
- Tml.config.cache[:segmented]
54
- end
55
-
56
51
  def fetch(key, opts = {})
57
52
  if self.class.cache[key]
58
53
  info("Memory hit: #{key}")
@@ -71,10 +71,11 @@ class Tml::CacheAdapters::Memcache < Tml::Cache
71
71
 
72
72
  def store(key, data, opts = {})
73
73
  info("Cache store: #{key}")
74
- ttl = opts[:ttl] || Tml.config.cache[:timeout]
74
+ ttl = opts[:ttl] || Tml.config.cache[:timeout] || 0
75
75
  @cache.set(versioned_key(key, opts), data, ttl)
76
76
  data
77
77
  rescue Exception => ex
78
+ pp ex
78
79
  warn("Failed to store data: #{key}")
79
80
  data
80
81
  end
@@ -61,7 +61,7 @@ class Tml::CacheAdapters::Redis < Tml::Cache
61
61
  def fetch(key, opts = {})
62
62
  data = @cache.get(versioned_key(key, opts))
63
63
  if data
64
- info("Cache hit: #{key}")
64
+ info("Cache hit: #{key} #{data}")
65
65
 
66
66
  begin
67
67
  return JSON.parse(data)
@@ -78,7 +78,7 @@ module Tml
78
78
  attr_accessor :enabled, :default_locale, :default_level, :format, :application, :context_rules, :logger, :cache, :default_tokens, :localization
79
79
 
80
80
  # Used by Rails and Sinatra extensions
81
- attr_accessor :current_locale_method, :current_user_method, :translator_options
81
+ attr_accessor :current_locale_method, :current_user_method, :translator_options, :i18n_backend
82
82
 
83
83
  # Used for IRB only
84
84
  attr_accessor :submit_missing_keys_realtime
@@ -166,11 +166,7 @@ module Tml
166
166
  }
167
167
 
168
168
  @cache = {
169
- :enabled => false,
170
- :host => 'localhost:11211',
171
- :adapter => 'memcache',
172
- :version => 1,
173
- :timeout => 3600
169
+ :enabled => false
174
170
  }
175
171
 
176
172
  @default_tokens = {
@@ -343,6 +339,10 @@ module Tml
343
339
  @default_application ||= Tml::Application.new(:host => Tml::Api::Client::API_HOST)
344
340
  end
345
341
 
342
+ def access_token
343
+ @application[:token] || @application[:access_token] || ''
344
+ end
345
+
346
346
  #########################################################
347
347
  ## Decorations
348
348
  #########################################################
@@ -50,7 +50,11 @@ class Tml::Decorators::Html < Tml::Decorators::Base
50
50
  # return translated_label unless Tml.session.current_translator.feature_enabled?(:show_locked_keys)
51
51
  classes << 'tml_locked'
52
52
  elsif translation_language == translation_key.language
53
- classes << 'tml_not_translated'
53
+ if options[:pending]
54
+ classes << 'tml_pending'
55
+ else
56
+ classes << 'tml_not_translated'
57
+ end
54
58
  elsif translation_language == target_language
55
59
  classes << 'tml_translated'
56
60
  else
@@ -155,16 +155,14 @@ class Tml::Language < Tml::Base
155
155
 
156
156
  source_key = current_source(options)
157
157
 
158
- if Tml.cache.segmented? or Tml.session.inline_mode?
159
- source = application.source(source_key, locale)
160
- cached_translations = source.cached_translations(locale, translation_key.key)
161
- else
162
- cached_translations = application.fetch_translations(locale)[translation_key.key]
163
- end
158
+ source = application.source(source_key, locale)
159
+ cached_translations = source.cached_translations(locale, translation_key.key)
164
160
 
165
161
  if cached_translations
166
162
  translation_key.set_translations(locale, cached_translations)
167
163
  else
164
+ params[:options] ||= {}
165
+ params[:options][:pending] = true
168
166
  application.register_missing_key(source_key, translation_key)
169
167
  end
170
168
 
@@ -58,50 +58,44 @@ module Tml
58
58
  class Logger < ::Logger
59
59
  attr_accessor :external_logger
60
60
 
61
- def info(message)
62
- if external_logger
63
- return external_logger.info(format_message(Logger::Severity::INFO, Time.new, nil, message))
64
- end
61
+ def log_to_console(msg)
62
+ return unless Tml.config.logger[:console]
63
+ puts msg
64
+ end
65
65
 
66
+ def info(message)
67
+ log_to_console(message)
68
+ return external_logger.info(format_message(Logger::Severity::INFO, Time.new, nil, message)) if external_logger
66
69
  super
67
70
  end
68
71
 
69
72
  def debug(message)
70
- if external_logger
71
- return external_logger.debug(format_message(Logger::Severity::DEBUG, Time.new, nil, message))
72
- end
73
-
73
+ log_to_console(message)
74
+ return external_logger.debug(format_message(Logger::Severity::DEBUG, Time.new, nil, message)) if external_logger
74
75
  super
75
76
  end
76
77
 
77
78
  def warn(message)
78
- if external_logger
79
- return external_logger.warn(format_message(Logger::Severity::WARN, Time.new, nil, message))
80
- end
81
-
79
+ log_to_console(message)
80
+ return external_logger.warn(format_message(Logger::Severity::WARN, Time.new, nil, message)) if external_logger
82
81
  super
83
82
  end
84
83
 
85
84
  def error(message)
86
- if external_logger
87
- return external_logger.error(format_message(Logger::Severity::ERROR, Time.new, nil, message))
88
- end
89
-
85
+ log_to_console(message)
86
+ return external_logger.error(format_message(Logger::Severity::ERROR, Time.new, nil, message)) if external_logger
90
87
  super
91
88
  end
92
89
 
93
90
  def fatal(message)
94
- if external_logger
95
- return external_logger.fatal(format_message(Logger::Severity::FATAL, Time.new, nil, message))
96
- end
97
-
91
+ log_to_console(message)
92
+ return external_logger.fatal(format_message(Logger::Severity::FATAL, Time.new, nil, message)) if external_logger
98
93
  super
99
94
  end
100
95
 
101
96
  def format_message(severity, timestamp, progname, msg)
102
- return "" unless Tml.config.logger[:enabled]
103
- # TODO: check for severity/level
104
- "[#{timestamp.strftime("%D %T")}]: tml: #{' ' * stack.size}#{msg}\n"
97
+ return '' unless Tml.config.logger[:enabled]
98
+ "[#{timestamp.strftime('%D %T')}]: tml: #{' ' * stack.size}#{msg}\n"
105
99
  end
106
100
 
107
101
  def add(severity, message = nil, progname = nil, &block)
@@ -41,7 +41,7 @@ module Tml
41
41
  :current_source, :current_component, :block_options, :cookie_params, :access_token, :tools_enabled
42
42
 
43
43
  def cookie_name
44
- "trex_#{self.application.key}"
44
+ "trex_#{Tml.config.access_token[0..19]}_translationexchange"
45
45
  end
46
46
 
47
47
  def init(opts = {})
@@ -51,10 +51,6 @@ module Tml
51
51
 
52
52
  Tml.cache.reset_version
53
53
 
54
- self.application = Tml::Application.new(:host => host).fetch
55
-
56
- # Tml.logger.info(self.cookie_params.inspect)
57
-
58
54
  self.cookie_params = begin
59
55
  if opts[:cookies] and opts[:cookies][cookie_name]
60
56
  begin
@@ -70,6 +66,8 @@ module Tml
70
66
  end
71
67
  end
72
68
 
69
+ # Tml.logger.info(self.cookie_params.inspect)
70
+
73
71
  self.tools_enabled = opts[:tools_enabled]
74
72
  self.current_user = opts[:user]
75
73
  self.current_source = opts[:source] || 'index'
@@ -80,6 +78,8 @@ module Tml
80
78
  self.current_translator = Tml::Translator.new(self.cookie_params['translator'])
81
79
  end
82
80
 
81
+ self.application = Tml::Application.new(:host => host).fetch
82
+
83
83
  # if inline mode don't use any app cache
84
84
  if inline_mode?
85
85
  self.application = self.application.dup
@@ -76,6 +76,8 @@ class Tml::Source < Tml::Base
76
76
  {:cache_key => Tml::Source.cache_key(locale, self.source)}
77
77
  )
78
78
 
79
+ return self unless results
80
+
79
81
  results.each do |key, data|
80
82
  translations_data = data.is_a?(Hash) ? data['translations'] : data
81
83
  self.translations[locale][key] = translations_data.collect do |t|
@@ -30,5 +30,5 @@
30
30
  #++
31
31
 
32
32
  module Tml
33
- VERSION = '4.3.12'
33
+ VERSION = '4.4.1'
34
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tml
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.12
4
+ version: 4.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Berkovich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-26 00:00:00.000000000 Z
11
+ date: 2015-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -54,7 +54,6 @@ files:
54
54
  - lib/tml/application.rb
55
55
  - lib/tml/base.rb
56
56
  - lib/tml/cache.rb
57
- - lib/tml/cache_adapters/cdn.rb
58
57
  - lib/tml/cache_adapters/file.rb
59
58
  - lib/tml/cache_adapters/memcache.rb
60
59
  - lib/tml/cache_adapters/redis.rb
@@ -1,101 +0,0 @@
1
- # encoding: UTF-8
2
- #--
3
- # Copyright (c) 2015 Translation Exchange, Inc
4
- #
5
- # _______ _ _ _ ______ _
6
- # |__ __| | | | | (_) | ____| | |
7
- # | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
8
- # | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
9
- # | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
10
- # |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
11
- # __/ |
12
- # |___/
13
- # Permission is hereby granted, free of charge, to any person obtaining
14
- # a copy of this software and associated documentation files (the
15
- # "Software"), to deal in the Software without restriction, including
16
- # without limitation the rights to use, copy, modify, merge, publish,
17
- # distribute, sublicense, and/or sell copies of the Software, and to
18
- # permit persons to whom the Software is furnished to do so, subject to
19
- # the following conditions:
20
- #
21
- # The above copyright notice and this permission notice shall be
22
- # included in all copies or substantial portions of the Software.
23
- #
24
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
- #++
32
-
33
- class Tml::CacheAdapters::Cdn < Tml::Cache
34
-
35
- def self.cache
36
- @cache ||= {}
37
- end
38
-
39
- def self.cache_path
40
- "#{Tml.config.cache[:base_url]}/#{Tml.config.cache[:version]}"
41
- end
42
-
43
- def self.cdn_path(key)
44
- File.join(cache_path, "#{key}.json")
45
- end
46
-
47
- def cache_name
48
- 'cdn'
49
- end
50
-
51
- def segmented?
52
- return true if Tml.config.cache[:segmented].nil?
53
- Tml.config.cache[:segmented]
54
- end
55
-
56
- def fetch(key, opts = {})
57
- if self.class.cache[key]
58
- info("Memory hit: #{key}")
59
- return self.class.cache[key]
60
- end
61
-
62
- path = self.class.cdn_path(key)
63
-
64
-
65
- # load data from cdn
66
-
67
-
68
- if File.exists?(path)
69
- info("Cache hit: #{key}")
70
- self.class.cache[key] = JSON.parse(File.read(path))
71
- return self.class.cache[key]
72
- end
73
-
74
- info("Cache miss: #{key}")
75
-
76
- return nil unless block_given?
77
-
78
- yield
79
- end
80
-
81
- def store(key, data, opts = {})
82
- warn('This is a readonly cache')
83
- end
84
-
85
- def delete(key, opts = {})
86
- warn('This is a readonly cache')
87
- end
88
-
89
- def exist?(key, opts = {})
90
- File.exists?(self.class.file_path(key))
91
- end
92
-
93
- def clear(opts = {})
94
- warn('This is a readonly cache')
95
- end
96
-
97
- def read_only?
98
- true
99
- end
100
-
101
- end