ucenter 0.0.3 → 0.1.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: 455a44d1c4adabc58b1e3427ab519d340edae2d2
4
- data.tar.gz: 44f6c5b7e7f0b6716fc66ec6680f70ba7173c140
3
+ metadata.gz: 39fb7334c69206eda4dc53352bc1761faa573f8d
4
+ data.tar.gz: 59c136c1cd60937283cd40c59ad738be9976ed33
5
5
  SHA512:
6
- metadata.gz: f53e7f4caa4ef1d23c28446d83e7d1e4296329d2fd30ac33f803843518a186431459c5037609dced43ea82f8922e72ee744d9f3c52a66c918f7467f6f6a28d1d
7
- data.tar.gz: ff434fc772fc413ebb1a114f0212d5a80b92179a27d5d3abebc4e6dfbddd85e966182a184647a73383110c9dffd54a023cfe42afe1912271d6275b8366a697a7
6
+ metadata.gz: 5ab39a314f899cdaf779ba25b52dda6b9ad7b71b5e56aacbc95179c60c6cda71774b20c12325cb6a31e7329a1d673a4f200f34e6924eb741b64581cc21da16b7
7
+ data.tar.gz: 35d08c5f26b5c8b27b25fdcbd4cfe2f074a1a198a045a1de15a3ae6cf0427275a1ba7d694b0e25d66d256b9b6bfa699f821841e03f04e8abef21480029cba900
@@ -1,7 +1,14 @@
1
1
  require 'ucenter/config'
2
- require 'ucenter/client'
2
+
3
3
  require 'ucenter/interface/base'
4
4
  require 'ucenter/interface/authcode'
5
5
  require 'ucenter/interface/user'
6
- require 'ucenter/interface/xml'
7
- require 'ucenter/interface/utility'
6
+ require 'ucenter/interface/app'
7
+
8
+ require 'ucenter/tools/base'
9
+ require 'ucenter/tools/url'
10
+ require 'ucenter/tools/xml'
11
+ require 'ucenter/tools/php'
12
+
13
+ require 'ucenter/client'
14
+ require 'ucenter/utility'
@@ -1,5 +1,9 @@
1
1
  module Ucenter
2
2
  class Client
3
+ def app
4
+ @app ||= Ucenter::Interface::App.new(self)
5
+ end
6
+
3
7
  def authcode
4
8
  @authcode ||= Ucenter::Interface::Authcode.new(self)
5
9
  end
@@ -7,14 +11,5 @@ module Ucenter
7
11
  def user
8
12
  @user ||= Ucenter::Interface::User.new(self)
9
13
  end
10
-
11
- def utility
12
- @utility ||= Ucenter::Interface::Utility.new(self)
13
- end
14
-
15
- def xml
16
- @xml ||= Ucenter::Interface::Xml.new(self)
17
- end
18
-
19
14
  end
20
15
  end
@@ -0,0 +1,16 @@
1
+ module Ucenter
2
+ module Interface
3
+ class App < Base
4
+ def get_apps(col = '*', where = '')
5
+ col = db_client.escape(col)
6
+ where = db_client.escape(where)
7
+ data = db_client.query("SELECT #{col} FROM #{Ucenter::Config.uc_dbtablepre}applications #{where!="" ? " WHERE #{where} " : ""}").to_a
8
+ data.each_with_index do |item,index|
9
+ item['extra'] = Ucenter::Tools::PHP.unserialize(item['extra'])
10
+ data[index] = item
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -46,6 +46,56 @@ module Ucenter
46
46
  end
47
47
  end
48
48
 
49
+ def encode string
50
+ operation = 'ENCODE'
51
+ expiry = 0
52
+ ckey_length = 4
53
+ key = md5(Ucenter::Config.uc_key)
54
+ keya = md5(key[0, 16])
55
+ keyb = md5(key[16, 16])
56
+ keyc = ckey_length > 0 ? (operation == 'DECODE' ? string[0, ckey_length] : (md5(microtime()))[-ckey_length..-1]) : ''
57
+ cryptkey = keya + md5(keya+keyc)
58
+ key_length = cryptkey.size
59
+ string = operation == 'DECODE' ? base64_url_decode(string[ckey_length..-1]) : sprintf('%010d', expiry>0 ? expiry + Time.now.to_i : 0)+ (md5(string+keyb))[0, 16] + string
60
+ string_ords = ords(string)
61
+ string_length = string_ords.size
62
+ result = ''
63
+ box = (0..255).to_a
64
+
65
+ rndkey = []
66
+
67
+ 0.upto(255) do |i|
68
+ rndkey[i] = (cryptkey[i % key_length]).ord
69
+ end
70
+
71
+ j = i = 0
72
+ while i < 256 do
73
+ j = (j + box[i] + rndkey[i]) % 256
74
+ box[i], box[j] = box[j], box[i]
75
+ i +=1
76
+ end
77
+
78
+ a = j = i = 0
79
+ while i < string_length
80
+ a = (a + 1) % 256
81
+ j = (j + box[a]) % 256
82
+ box[a], box[j] = box[j], box[a]
83
+ result += (string_ords[i] ^ (box[(box[a] + box[j]) % 256])).chr
84
+ i +=1
85
+ end
86
+
87
+ if operation == 'DECODE' then
88
+ if ( result[0,10] == '0'*10 || (result[0, 10]).to_i - Time.now.to_i > 0 ) and
89
+ result[10, 16] == (md5(result[26..-1] + keyb))[0, 16] then
90
+ return result[26..-1]
91
+ else
92
+ return ''
93
+ end
94
+ else
95
+ keyc + (Base64.encode64(result)).gsub(/=/, '')
96
+ end
97
+ end
98
+
49
99
  def microtime
50
100
  epoch_mirco = Time.now.to_f
51
101
  epoch_full = Time.now.to_i
@@ -62,6 +112,10 @@ module Ucenter
62
112
  Base64.decode64 str2
63
113
  end
64
114
 
115
+ def ords(s)
116
+ s.bytes.to_a
117
+ end
118
+
65
119
  end
66
120
  end
67
121
  end
@@ -3,6 +3,7 @@ module Ucenter
3
3
  class User < Base
4
4
 
5
5
  def get_user(username, is_uid = FALSE)
6
+ username = db_client.escape(username) unless username.nil?
6
7
  if is_uid == 1
7
8
  data = get_user_by_uid(username)
8
9
  elsif is_uid == 2
@@ -17,7 +18,7 @@ module Ucenter
17
18
 
18
19
  def check_login(username, password, is_uid = FALSE)
19
20
  user = get_user(username, is_uid)
20
- if user['username'].nil?
21
+ if user.nil? or user['username'].nil?
21
22
  return [-1,nil]
22
23
  elsif user['password'] != md5("#{md5(password)}#{user['salt']}")
23
24
  return [-2,nil]
@@ -25,6 +26,45 @@ module Ucenter
25
26
  [user['uid'],user]
26
27
  end
27
28
 
29
+ def check_username(username)
30
+ len = username.bytesize
31
+ return FALSE if len > 15 or len < 3 or !( /\s+|^c:\\con\\con|\[%,\*\"\s\<\>\&\]|\xA1\xA1|\xAC\xA3|^Guest|^\xD3\xCE\xBF\xCD|\xB9\x43\xAB\xC8/is =~ username).nil?
32
+ TRUE
33
+ end
34
+
35
+ def check_email_format(email)
36
+ email.bytesize > 6 and !(/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/ =~ email).nil?
37
+ end
38
+
39
+ def check_email_access(email)
40
+ # TODO: 验证email权限
41
+ TRUE
42
+ end
43
+
44
+ def check_email_exist(email, username = '')
45
+ username = db_client.escape(username)
46
+ email = db_client.escape(email)
47
+ sql_add = username != '' ? "AND username<>'#{username}'" : '';
48
+ db_client.query("SELECT email FROM #{Ucenter::Config.uc_dbtablepre}members WHERE email='#{email}' #{sql_add}").to_a[0]
49
+ end
50
+
51
+ def check_mergeuser(username)
52
+ username = db_client.escape(username)
53
+ db_client.query("SELECT count(*) FROM #{Ucenter::Config.uc_dbtablepre}mergemembers WHERE appid='#{Ucenter::Config.app_id}' AND username='#{username}'").to_a[0]
54
+ end
55
+
56
+ def add_user
57
+ # TODO: 注册
58
+ end
59
+
60
+ def edit_user
61
+ # TODO: 修改
62
+ end
63
+
64
+ def delete_user
65
+ # TODO: 删除
66
+ end
67
+
28
68
  protected
29
69
  def get_user_by_username(username)
30
70
  db_client.query("SELECT * FROM #{Ucenter::Config.uc_dbtablepre}members WHERE username='#{username}'").to_a[0]
@@ -0,0 +1,18 @@
1
+ module Ucenter
2
+ module Tools
3
+ # The Base class of API
4
+ class Base
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ def get(path, opts={}, &block)
10
+ request(:get, path, opts, &block)
11
+ end
12
+
13
+ def post(path, opts={}, &block)
14
+ request(:post, path, opts, &block)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,317 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2003-2009 Thomas Hurst <tom@hur.st>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ # SOFTWARE.
21
+
22
+ # PHP serialize() and unserialize() workalikes
23
+ #
24
+ # Release History:
25
+ # 1.0.0 - 2003-06-02 - First release.
26
+ # 1.0.1 - 2003-06-16 - Minor bugfixes.
27
+ # 1.0.2 - 2004-09-17 - Switch all {}'s to explicit Hash.new's.
28
+ # 1.1.0 - 2009-04-01 - Pass assoc to recursive calls (thanks to Edward Speyer).
29
+ # - Serialize Symbol like String.
30
+ # - Add testsuite.
31
+ # - Instantiate auto-generated Structs properly (thanks
32
+ # to Philip Hallstrom).
33
+ # - Unserialize arrays properly in assoc mode.
34
+ # - Add PHP session support (thanks to TJ Vanderpoel).
35
+ # - Release as tarball and gem.
36
+ #
37
+ # See http://www.php.net/serialize and http://www.php.net/unserialize for
38
+ # details on the PHP side of all this.
39
+ module Ucenter
40
+ module Tools
41
+ # string = PHP.serialize(mixed var[, bool assoc])
42
+ #
43
+ # Returns a string representing the argument in a form PHP.unserialize
44
+ # and PHP's unserialize() should both be able to load.
45
+ #
46
+ # Array, Hash, Fixnum, Float, True/FalseClass, NilClass, String and Struct
47
+ # are supported; as are objects which support the to_assoc method, which
48
+ # returns an array of the form [['attr_name', 'value']..]. Anything else
49
+ # will raise a TypeError.
50
+ #
51
+ # If 'assoc' is specified, Array's who's first element is a two value
52
+ # array will be assumed to be an associative array, and will be serialized
53
+ # as a PHP associative array rather than a multidimensional array.
54
+ class PHP
55
+ def self.serialize(var, assoc = false) # {{{
56
+ s = ''
57
+ case var
58
+ when Array
59
+ s << "a:#{var.size}:{"
60
+ if assoc and var.first.is_a?(Array) and var.first.size == 2
61
+ var.each { |k,v|
62
+ s << self.serialize(k, assoc) << self.serialize(v, assoc)
63
+ }
64
+ else
65
+ var.each_with_index { |v,i|
66
+ s << "i:#{i};#{self.serialize(v, assoc)}"
67
+ }
68
+ end
69
+
70
+ s << '}'
71
+
72
+ when Hash
73
+ s << "a:#{var.size}:{"
74
+ var.each do |k,v|
75
+ s << "#{self.serialize(k, assoc)}#{self.serialize(v, assoc)}"
76
+ end
77
+ s << '}'
78
+
79
+ when Struct
80
+ # encode as Object with same name
81
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{var.members.length}:{"
82
+ var.members.each do |member|
83
+ s << "#{self.serialize(member, assoc)}#{self.serialize(var[member], assoc)}"
84
+ end
85
+ s << '}'
86
+
87
+ when String, Symbol
88
+ s << "s:#{var.to_s.length}:\"#{var.to_s}\";"
89
+
90
+ when Fixnum # PHP doesn't have bignums
91
+ s << "i:#{var};"
92
+
93
+ when Float
94
+ s << "d:#{var};"
95
+
96
+ when NilClass
97
+ s << 'N;'
98
+
99
+ when FalseClass, TrueClass
100
+ s << "b:#{var ? 1 :0};"
101
+
102
+ else
103
+ if var.respond_to?(:to_assoc)
104
+ v = var.to_assoc
105
+ # encode as Object with same name
106
+ s << "O:#{var.class.to_s.length}:\"#{var.class.to_s.downcase}\":#{v.length}:{"
107
+ v.each do |k,v|
108
+ s << "#{self.serialize(k.to_s, assoc)}#{self.serialize(v, assoc)}"
109
+ end
110
+ s << '}'
111
+ else
112
+ raise TypeError, "Unable to serialize type #{var.class}"
113
+ end
114
+ end
115
+
116
+ s
117
+ end # }}}
118
+
119
+ # string = PHP.serialize_session(mixed var[, bool assoc])
120
+ #
121
+ # Like PHP.serialize, but only accepts a Hash or associative Array as the root
122
+ # type. The results are returned in PHP session format.
123
+ def self.serialize_session(var, assoc = false) # {{{
124
+ s = ''
125
+ case var
126
+ when Hash
127
+ var.each do |key,value|
128
+ if key.to_s =~ /\|/
129
+ raise IndexError, "Top level names may not contain pipes"
130
+ end
131
+ s << "#{key}|#{self.serialize(value, assoc)}"
132
+ end
133
+ when Array
134
+ var.each do |x|
135
+ case x
136
+ when Array
137
+ if x.size == 2
138
+ s << "#{x[0]}|#{self.serialize(x[1])}"
139
+ else
140
+ raise TypeError, "Array is not associative"
141
+ end
142
+ end
143
+ end
144
+ else
145
+ raise TypeError, "Unable to serialize sessions with top level types other than Hash and associative Array"
146
+ end
147
+ s
148
+ end # }}}
149
+
150
+ # mixed = PHP.unserialize(string serialized, [hash classmap, [bool assoc]])
151
+ #
152
+ # Returns an object containing the reconstituted data from serialized.
153
+ #
154
+ # If a PHP array (associative; like an ordered hash) is encountered, it
155
+ # scans the keys; if they're all incrementing integers counting from 0,
156
+ # it's unserialized as an Array, otherwise it's unserialized as a Hash.
157
+ # Note: this will lose ordering. To avoid this, specify assoc=true,
158
+ # and it will be unserialized as an associative array: [[key,value],...]
159
+ #
160
+ # If a serialized object is encountered, the hash 'classmap' is searched for
161
+ # the class name (as a symbol). Since PHP classnames are not case-preserving,
162
+ # this *must* be a .capitalize()d representation. The value is expected
163
+ # to be the class itself; i.e. something you could call .new on.
164
+ #
165
+ # If it's not found in 'classmap', the current constant namespace is searched,
166
+ # and failing that, a new Struct(classname) is generated, with the arguments
167
+ # for .new specified in the same order PHP provided; since PHP uses hashes
168
+ # to represent attributes, this should be the same order they're specified
169
+ # in PHP, but this is untested.
170
+ #
171
+ # each serialized attribute is sent to the new object using the respective
172
+ # {attribute}=() method; you'll get a NameError if the method doesn't exist.
173
+ #
174
+ # Array, Hash, Fixnum, Float, True/FalseClass, NilClass and String should
175
+ # be returned identically (i.e. foo == PHP.unserialize(PHP.serialize(foo))
176
+ # for these types); Struct should be too, provided it's in the namespace
177
+ # Module.const_get within unserialize() can see, or you gave it the same
178
+ # name in the Struct.new(<structname>), otherwise you should provide it in
179
+ # classmap.
180
+ #
181
+ # Note: StringIO is required for unserialize(); it's loaded as needed
182
+ def self.unserialize(string, classmap = nil, assoc = false) # {{{
183
+ if classmap == true or classmap == false
184
+ assoc = classmap
185
+ classmap = {}
186
+ end
187
+ classmap ||= {}
188
+
189
+ require 'stringio'
190
+ string = StringIO.new(string)
191
+ def string.read_until(char)
192
+ val = ''
193
+ while (c = self.read(1)) != char
194
+ val << c
195
+ end
196
+ val
197
+ end
198
+
199
+ if string.string =~ /^(\w+)\|/ # session_name|serialized_data
200
+ ret = Hash.new
201
+ loop do
202
+ if string.string[string.pos, 32] =~ /^(\w+)\|/
203
+ string.pos += $&.size
204
+ ret[$1] = self.do_unserialize(string, classmap, assoc)
205
+ else
206
+ break
207
+ end
208
+ end
209
+ ret
210
+ else
211
+ self.do_unserialize(string, classmap, assoc)
212
+ end
213
+ end
214
+
215
+ private
216
+ def self.do_unserialize(string, classmap, assoc)
217
+ val = nil
218
+ # determine a type
219
+ type = string.read(2)[0,1]
220
+ case type
221
+ when 'a' # associative array, a:length:{[index][value]...}
222
+ count = string.read_until('{').to_i
223
+ val = vals = Array.new
224
+ count.times do |i|
225
+ vals << [do_unserialize(string, classmap, assoc), do_unserialize(string, classmap, assoc)]
226
+ end
227
+ string.read(1) # skip the ending }
228
+
229
+ # now, we have an associative array, let's clean it up a bit...
230
+ # arrays have all numeric indexes, in order; otherwise we assume a hash
231
+ array = true
232
+ i = 0
233
+ vals.each do |key,value|
234
+ if key != i # wrong index -> assume hash
235
+ array = false
236
+ break
237
+ end
238
+ i += 1
239
+ end
240
+
241
+ if array
242
+ vals.collect! do |key,value|
243
+ value
244
+ end
245
+ else
246
+ if assoc
247
+ val = vals.map {|v| v }
248
+ else
249
+ val = Hash.new
250
+ vals.each do |key,value|
251
+ val[key] = value
252
+ end
253
+ end
254
+ end
255
+
256
+ when 'O' # object, O:length:"class":length:{[attribute][value]...}
257
+ # class name (lowercase in PHP, grr)
258
+ len = string.read_until(':').to_i + 3 # quotes, seperator
259
+ klass = string.read(len)[1...-2].capitalize.intern # read it, kill useless quotes
260
+
261
+ # read the attributes
262
+ attrs = []
263
+ len = string.read_until('{').to_i
264
+
265
+ len.times do
266
+ attr = (do_unserialize(string, classmap, assoc))
267
+ attrs << [attr.intern, (attr << '=').intern, do_unserialize(string, classmap, assoc)]
268
+ end
269
+ string.read(1)
270
+
271
+ val = nil
272
+ # See if we need to map to a particular object
273
+ if classmap.has_key?(klass)
274
+ val = classmap[klass].new
275
+ elsif Struct.const_defined?(klass) # Nope; see if there's a Struct
276
+ classmap[klass] = val = Struct.const_get(klass)
277
+ val = val.new
278
+ else # Nope; see if there's a Constant
279
+ begin
280
+ classmap[klass] = val = Module.const_get(klass)
281
+
282
+ val = val.new
283
+ rescue NameError # Nope; make a new Struct
284
+ classmap[klass] = Struct.new(klass.to_s, *attrs.collect { |v| v[0].to_s })
285
+ val = val.new
286
+ end
287
+ end
288
+
289
+ attrs.each do |attr,attrassign,v|
290
+ val.__send__(attrassign, v)
291
+ end
292
+
293
+ when 's' # string, s:length:"data";
294
+ len = string.read_until(':').to_i + 3 # quotes, separator
295
+ val = string.read(len)[1...-2] # read it, kill useless quotes
296
+
297
+ when 'i' # integer, i:123
298
+ val = string.read_until(';').to_i
299
+
300
+ when 'd' # double (float), d:1.23
301
+ val = string.read_until(';').to_f
302
+
303
+ when 'N' # NULL, N;
304
+ val = nil
305
+
306
+ when 'b' # bool, b:0 or 1
307
+ val = (string.read(2)[0] == ?1 ? true : false)
308
+
309
+ else
310
+ raise TypeError, "Unable to unserialize type '#{type}'"
311
+ end
312
+
313
+ val
314
+ end # }}}
315
+ end
316
+ end
317
+ end
@@ -1,6 +1,6 @@
1
1
  module Ucenter
2
- module Interface
3
- class Utility < Base
2
+ module Tools
3
+ class Url < Base
4
4
  def explain_query(query_params)
5
5
  query_params = '' if query_params === {}
6
6
  # systemname=cets&responsible=sj ==> {"systemname"=>"cets","responsible"=>"sj"}
@@ -1,5 +1,5 @@
1
1
  module Ucenter
2
- module Interface
2
+ module Tools
3
3
  class Xml < Base
4
4
  def parse body
5
5
  reader = Nokogiri::XML::Reader(body)
@@ -0,0 +1,12 @@
1
+ module Ucenter
2
+ class Utility
3
+ def url
4
+ @url ||= Ucenter::Tools::Url.new(self)
5
+ end
6
+
7
+ def xml
8
+ @xml ||= Ucenter::Tools::Xml.new(self)
9
+ end
10
+
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Ucenter
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ucenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willin Wang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-27 00:00:00.000000000 Z
11
+ date: 2014-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,11 +80,15 @@ files:
80
80
  - lib/ucenter.rb
81
81
  - lib/ucenter/client.rb
82
82
  - lib/ucenter/config.rb
83
+ - lib/ucenter/interface/app.rb
83
84
  - lib/ucenter/interface/authcode.rb
84
85
  - lib/ucenter/interface/base.rb
85
86
  - lib/ucenter/interface/user.rb
86
- - lib/ucenter/interface/utility.rb
87
- - lib/ucenter/interface/xml.rb
87
+ - lib/ucenter/tools/base.rb
88
+ - lib/ucenter/tools/php.rb
89
+ - lib/ucenter/tools/url.rb
90
+ - lib/ucenter/tools/xml.rb
91
+ - lib/ucenter/utility.rb
88
92
  - lib/ucenter/version.rb
89
93
  - ucenter.gemspec
90
94
  homepage: https://github.com/willin/ucenter