mongo 2.1.2 → 2.2.0.rc0

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 (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +10 -3
  5. data/Rakefile +1 -7
  6. data/lib/csasl/csasl.bundle +0 -0
  7. data/lib/mongo/auth/user/view.rb +1 -1
  8. data/lib/mongo/bulk_write.rb +7 -1
  9. data/lib/mongo/client.rb +17 -15
  10. data/lib/mongo/cluster.rb +4 -2
  11. data/lib/mongo/collection.rb +36 -2
  12. data/lib/mongo/collection/view.rb +24 -21
  13. data/lib/mongo/collection/view/aggregation.rb +5 -42
  14. data/lib/mongo/collection/view/builder.rb +20 -0
  15. data/lib/mongo/collection/view/builder/aggregation.rb +98 -0
  16. data/lib/mongo/collection/view/builder/find_command.rb +111 -0
  17. data/lib/mongo/collection/view/builder/flags.rb +62 -0
  18. data/lib/mongo/collection/view/builder/map_reduce.rb +134 -0
  19. data/lib/mongo/collection/view/builder/modifiers.rb +80 -0
  20. data/lib/mongo/collection/view/builder/op_query.rb +83 -0
  21. data/lib/mongo/collection/view/explainable.rb +15 -0
  22. data/lib/mongo/collection/view/immutable.rb +5 -12
  23. data/lib/mongo/collection/view/iterable.rb +24 -2
  24. data/lib/mongo/collection/view/map_reduce.rb +18 -27
  25. data/lib/mongo/collection/view/readable.rb +70 -112
  26. data/lib/mongo/collection/view/writable.rb +23 -7
  27. data/lib/mongo/cursor.rb +76 -25
  28. data/lib/mongo/cursor/builder.rb +18 -0
  29. data/lib/mongo/cursor/builder/get_more_command.rb +71 -0
  30. data/lib/mongo/cursor/builder/kill_cursors_command.rb +62 -0
  31. data/lib/mongo/cursor/builder/op_get_more.rb +61 -0
  32. data/lib/mongo/cursor/builder/op_kill_cursors.rb +56 -0
  33. data/lib/mongo/database.rb +2 -2
  34. data/lib/mongo/database/view.rb +9 -5
  35. data/lib/mongo/dbref.rb +3 -3
  36. data/lib/mongo/error.rb +1 -0
  37. data/lib/mongo/error/invalid_write_concern.rb +35 -0
  38. data/lib/mongo/grid/file/chunk.rb +2 -2
  39. data/lib/mongo/index/view.rb +5 -2
  40. data/lib/mongo/operation.rb +1 -0
  41. data/lib/mongo/operation/commands.rb +2 -0
  42. data/lib/mongo/operation/commands/aggregate.rb +39 -45
  43. data/lib/mongo/operation/commands/aggregate/result.rb +54 -68
  44. data/lib/mongo/operation/commands/collections_info.rb +38 -36
  45. data/lib/mongo/operation/commands/collections_info/result.rb +17 -15
  46. data/lib/mongo/operation/commands/command.rb +24 -22
  47. data/lib/mongo/operation/commands/find.rb +27 -0
  48. data/lib/mongo/operation/commands/find/result.rb +62 -0
  49. data/lib/mongo/operation/commands/get_more.rb +27 -0
  50. data/lib/mongo/operation/commands/get_more/result.rb +62 -0
  51. data/lib/mongo/operation/commands/indexes.rb +41 -39
  52. data/lib/mongo/operation/commands/list_collections.rb +25 -31
  53. data/lib/mongo/operation/commands/list_collections/result.rb +63 -81
  54. data/lib/mongo/operation/commands/list_indexes.rb +27 -35
  55. data/lib/mongo/operation/commands/list_indexes/result.rb +67 -85
  56. data/lib/mongo/operation/commands/map_reduce.rb +29 -37
  57. data/lib/mongo/operation/commands/map_reduce/result.rb +85 -88
  58. data/lib/mongo/operation/commands/parallel_scan.rb +29 -33
  59. data/lib/mongo/operation/commands/parallel_scan/result.rb +34 -42
  60. data/lib/mongo/operation/commands/user_query.rb +40 -38
  61. data/lib/mongo/operation/commands/users_info.rb +24 -29
  62. data/lib/mongo/operation/commands/users_info/result.rb +13 -11
  63. data/lib/mongo/operation/object_id_generator.rb +36 -0
  64. data/lib/mongo/operation/result.rb +30 -0
  65. data/lib/mongo/operation/specifiable.rb +35 -1
  66. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -3
  67. data/lib/mongo/operation/write/bulk/delete/result.rb +18 -25
  68. data/lib/mongo/operation/write/bulk/legacy_mergable.rb +2 -2
  69. data/lib/mongo/operation/write/command/delete.rb +3 -2
  70. data/lib/mongo/operation/write/command/insert.rb +4 -2
  71. data/lib/mongo/operation/write/command/update.rb +6 -3
  72. data/lib/mongo/operation/write/gle.rb +2 -1
  73. data/lib/mongo/operation/write/idable.rb +19 -2
  74. data/lib/mongo/options/mapper.rb +22 -0
  75. data/lib/mongo/protocol/bit_vector.rb +3 -3
  76. data/lib/mongo/protocol/delete.rb +15 -5
  77. data/lib/mongo/protocol/get_more.rb +10 -5
  78. data/lib/mongo/protocol/insert.rb +1 -6
  79. data/lib/mongo/protocol/kill_cursors.rb +14 -1
  80. data/lib/mongo/protocol/message.rb +32 -8
  81. data/lib/mongo/protocol/serializers.rb +15 -16
  82. data/lib/mongo/protocol/update.rb +35 -12
  83. data/lib/mongo/server/connectable.rb +3 -1
  84. data/lib/mongo/server/connection.rb +5 -5
  85. data/lib/mongo/server/description.rb +8 -2
  86. data/lib/mongo/server/description/features.rb +2 -1
  87. data/lib/mongo/server/monitor.rb +1 -12
  88. data/lib/mongo/server/monitor/connection.rb +30 -26
  89. data/lib/mongo/server_selector/selectable.rb +21 -4
  90. data/lib/mongo/uri.rb +2 -0
  91. data/lib/mongo/version.rb +1 -1
  92. data/lib/mongo/write_concern.rb +21 -6
  93. data/mongo.gemspec +1 -2
  94. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +13 -0
  95. data/spec/mongo/bulk_write_spec.rb +58 -0
  96. data/spec/mongo/client_spec.rb +6 -4
  97. data/spec/mongo/collection/view/builder/find_command_spec.rb +167 -0
  98. data/spec/mongo/collection/view/builder/flags_spec.rb +106 -0
  99. data/spec/mongo/collection/view/builder/modifiers_spec.rb +210 -0
  100. data/spec/mongo/collection/view/builder/op_query_spec.rb +154 -0
  101. data/spec/mongo/collection/view/explainable_spec.rb +1 -2
  102. data/spec/mongo/collection/view/immutable_spec.rb +3 -52
  103. data/spec/mongo/collection/view/map_reduce_spec.rb +12 -12
  104. data/spec/mongo/collection/view/readable_spec.rb +86 -80
  105. data/spec/mongo/collection/view_spec.rb +109 -703
  106. data/spec/mongo/collection_spec.rb +594 -11
  107. data/spec/mongo/command_monitoring_spec.rb +40 -27
  108. data/spec/mongo/cursor/builder/get_more_command_spec.rb +160 -0
  109. data/spec/mongo/cursor/builder/op_get_more_spec.rb +52 -0
  110. data/spec/mongo/cursor_spec.rb +10 -60
  111. data/spec/mongo/database_spec.rb +24 -3
  112. data/spec/mongo/dbref_spec.rb +4 -4
  113. data/spec/mongo/grid/file/chunk_spec.rb +1 -1
  114. data/spec/mongo/grid/fs_bucket_spec.rb +3 -3
  115. data/spec/mongo/index/view_spec.rb +41 -0
  116. data/spec/mongo/operation/{aggregate → commands/aggregate}/result_spec.rb +1 -1
  117. data/spec/mongo/operation/commands/aggregate_spec.rb +1 -1
  118. data/spec/mongo/operation/commands/collections_info_spec.rb +1 -1
  119. data/spec/mongo/operation/commands/command_spec.rb +1 -1
  120. data/spec/mongo/operation/commands/indexes_spec.rb +1 -1
  121. data/spec/mongo/operation/commands/map_reduce_spec.rb +1 -1
  122. data/spec/mongo/operation/write/command/delete_spec.rb +25 -0
  123. data/spec/mongo/operation/write/command/insert_spec.rb +25 -0
  124. data/spec/mongo/operation/write/command/update_spec.rb +25 -0
  125. data/spec/mongo/protocol/delete_spec.rb +4 -4
  126. data/spec/mongo/protocol/get_more_spec.rb +4 -4
  127. data/spec/mongo/protocol/insert_spec.rb +3 -3
  128. data/spec/mongo/protocol/kill_cursors_spec.rb +3 -3
  129. data/spec/mongo/protocol/query_spec.rb +7 -7
  130. data/spec/mongo/protocol/update_spec.rb +5 -5
  131. data/spec/mongo/server/description/features_spec.rb +25 -0
  132. data/spec/mongo/write_concern_spec.rb +126 -0
  133. data/spec/spec_helper.rb +9 -19
  134. data/spec/support/command_monitoring.rb +8 -0
  135. data/spec/support/command_monitoring/find.yml +53 -4
  136. data/spec/support/matchers.rb +1 -1
  137. data/spec/support/shared/protocol.rb +5 -5
  138. data/spec/support/travis.rb +1 -1
  139. metadata +43 -10
  140. metadata.gz.sig +0 -0
@@ -12,42 +12,37 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'mongo/operation/commands/users_info/result'
16
-
17
15
  module Mongo
18
16
  module Operation
17
+ module Commands
19
18
 
20
- # A MongoDB operation to get info of a particular user in a database.
21
- #
22
- # @example Create the users info operation.
23
- # Read::UsersInfo.new(:name => 'emily', :db_name => 'test-db')
24
- #
25
- # Initialization:
26
- # param [ Hash ] spec The specifications for the users info operation.
27
- #
28
- # option spec :user_name [ String ] The name of the user.
29
- # option spec :db_name [ String ] The name of the database where the user exists.
30
- # option spec :options [ Hash ] Options for the operation.
31
- #
32
- # @since 2.1.0
33
- class UsersInfo
34
- include Executable
35
- include Specifiable
36
- include Limited
19
+ # A MongoDB operation to get info of a particular user in a database.
20
+ #
21
+ # @example Create the users info operation.
22
+ # Read::UsersInfo.new(:name => 'emily', :db_name => 'test-db')
23
+ #
24
+ # Initialization:
25
+ # param [ Hash ] spec The specifications for the users info operation.
26
+ #
27
+ # option spec :user_name [ String ] The name of the user.
28
+ # option spec :db_name [ String ] The name of the database where the user exists.
29
+ # option spec :options [ Hash ] Options for the operation.
30
+ #
31
+ # @since 2.1.0
32
+ class UsersInfo < Command
37
33
 
38
- private
34
+ private
39
35
 
40
- def selector
41
- { :usersInfo => user_name }
42
- end
36
+ def selector
37
+ { :usersInfo => user_name }
38
+ end
43
39
 
44
- def query_coll
45
- Database::COMMAND
46
- end
47
-
48
- def message(context)
49
- Protocol::Query.new(db_name, query_coll, selector, options)
40
+ def message(context)
41
+ Protocol::Query.new(db_name, query_coll, selector, options)
42
+ end
50
43
  end
51
44
  end
52
45
  end
53
46
  end
47
+
48
+ require 'mongo/operation/commands/users_info/result'
@@ -14,21 +14,23 @@
14
14
 
15
15
  module Mongo
16
16
  module Operation
17
- class UsersInfo
17
+ module Commands
18
+ class UsersInfo
18
19
 
19
- # Defines custom behaviour of results when using the
20
- # usersInfo command.
21
- #
22
- # @since 2.1.0
23
- class Result < Operation::Result
24
-
25
- # The field name for the users document in a usersInfo result.
20
+ # Defines custom behaviour of results when using the
21
+ # usersInfo command.
26
22
  #
27
23
  # @since 2.1.0
28
- USERS = 'users'.freeze
24
+ class Result < Operation::Result
25
+
26
+ # The field name for the users document in a usersInfo result.
27
+ #
28
+ # @since 2.1.0
29
+ USERS = 'users'.freeze
29
30
 
30
- def documents
31
- reply.documents.first[USERS]
31
+ def documents
32
+ reply.documents.first[USERS]
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -0,0 +1,36 @@
1
+ # Copyright (C) 2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Operation
17
+
18
+ # The default generator of ids for documents.
19
+ #
20
+ # @since 2.2.0
21
+ class ObjectIdGenerator
22
+
23
+ # Generate a nwe id.
24
+ #
25
+ # @example Generate the id.
26
+ # object_id_generator.generate
27
+ #
28
+ # @return [ BSON::ObjectId ] The new id.
29
+ #
30
+ # @since 2.2.0
31
+ def generate
32
+ BSON::ObjectId.new
33
+ end
34
+ end
35
+ end
36
+ end
@@ -22,6 +22,31 @@ module Mongo
22
22
  extend Forwardable
23
23
  include Enumerable
24
24
 
25
+ # The field name for the cursor document in an aggregation.
26
+ #
27
+ # @since 2.2.0
28
+ CURSOR = 'cursor'.freeze
29
+
30
+ # The cursor id field in the cursor document.
31
+ #
32
+ # @since 2.2.0
33
+ CURSOR_ID = 'id'.freeze
34
+
35
+ # The field name for the first batch of a cursor.
36
+ #
37
+ # @since 2.2.0
38
+ FIRST_BATCH = 'firstBatch'.freeze
39
+
40
+ # The field name for the next batch of a cursor.
41
+ #
42
+ # @since 2.2.0
43
+ NEXT_BATCH = 'nextBatch'.freeze
44
+
45
+ # The namespace field in the cursor document.
46
+ #
47
+ # @since 2.2.0
48
+ NAMESPACE = 'ns'.freeze
49
+
25
50
  # The number of documents updated in the write.
26
51
  #
27
52
  # @since 2.0.0
@@ -32,6 +57,11 @@ module Mongo
32
57
  # @since 2.0.0
33
58
  OK = 'ok'.freeze
34
59
 
60
+ # The result field constant.
61
+ #
62
+ # @since 2.2.0
63
+ RESULT = 'result'.freeze
64
+
35
65
  # @return [ Array<Protocol::Reply> ] replies The wrapped wire protocol replies.
36
66
  attr_reader :replies
37
67
 
@@ -86,6 +86,11 @@ module Mongo
86
86
  # @since 2.0.0
87
87
  OPTIONS = :options.freeze
88
88
 
89
+ # The read concern option.
90
+ #
91
+ # @since 2.2.0
92
+ READ_CONCERN = :read_concern.freeze
93
+
89
94
  # The field for a selector.
90
95
  #
91
96
  # @since 2.0.0
@@ -126,6 +131,11 @@ module Mongo
126
131
  # @since 2.0.0
127
132
  READ = :read.freeze
128
133
 
134
+ # Whether to bypass document level validation.
135
+ #
136
+ # @since 2.2.0
137
+ BYPASS_DOC_VALIDATION = :bypass_document_validation.freeze
138
+
129
139
  # @return [ Hash ] spec The specification for the operation.
130
140
  attr_reader :spec
131
141
 
@@ -317,6 +327,30 @@ module Mongo
317
327
  spec[OPTIONS] || {}
318
328
  end
319
329
 
330
+ # Get the read concern from the spec.
331
+ #
332
+ # @example Get the read concern.
333
+ # specifiable.read_concern
334
+ #
335
+ # @return [ Hash ] The read concern.
336
+ #
337
+ # @since 2.2.0
338
+ def read_concern
339
+ spec[READ_CONCERN]
340
+ end
341
+
342
+ # Whether or not to bypass document level validation.
343
+ #
344
+ # @example Get the bypass_document_validation option.
345
+ # specifiable.bypass_documentation_validation.
346
+ #
347
+ # @return [ true, false ] Whether to bypass document level validation.
348
+ #
349
+ # @since 2.2.0
350
+ def bypass_document_validation
351
+ spec[BYPASS_DOC_VALIDATION]
352
+ end
353
+
320
354
  # The selector for from the specification.
321
355
  #
322
356
  # @example Get a selector specification.
@@ -396,7 +430,7 @@ module Mongo
396
430
  #
397
431
  # @since 2.0.0
398
432
  def write_concern
399
- @spec[WRITE_CONCERN] || WriteConcern.get(WriteConcern::DEFAULT)
433
+ @spec[WRITE_CONCERN]
400
434
  end
401
435
 
402
436
  # The read preference for this operation.
@@ -63,9 +63,10 @@ module Mongo
63
63
  end
64
64
 
65
65
  def gle
66
- gle_message = ( ordered? && write_concern.get_last_error.nil? ) ?
67
- Mongo::WriteConcern.get(:w => 1).get_last_error :
68
- write_concern.get_last_error
66
+ wc = write_concern || WriteConcern.get(WriteConcern::DEFAULT)
67
+ gle_message = ( ordered? && wc.get_last_error.nil? ) ?
68
+ Mongo::WriteConcern.get(Mongo::WriteConcern::DEFAULT).get_last_error :
69
+ wc.get_last_error
69
70
  if gle_message
70
71
  Protocol::Query.new(
71
72
  db_name,
@@ -18,16 +18,10 @@ module Mongo
18
18
  module Bulk
19
19
  class Delete
20
20
 
21
- # Defines custom behaviour of results when deleting.
21
+ # Defines common r_removed aggreation behaviour.
22
22
  #
23
- # @since 2.0.0
24
- class Result < Operation::Result
25
- include Mergable
26
-
27
- # The aggregate number of deleted docs reported in the replies.
28
- #
29
- # @since 2.0.0
30
- REMOVED = 'nRemoved'.freeze
23
+ # @since 2.2.0
24
+ module Aggregatable
31
25
 
32
26
  # Gets the number of documents deleted.
33
27
  #
@@ -40,32 +34,31 @@ module Mongo
40
34
  def n_removed
41
35
  return 0 unless acknowledged?
42
36
  @replies.reduce(0) do |n, reply|
43
- n += reply.documents.first[N]
37
+ n += reply.documents.first[Result::N]
44
38
  end
45
39
  end
46
40
  end
47
41
 
48
42
  # Defines custom behaviour of results when deleting.
49
- # For server versions < 2.5.5 (that don't use write commands).
50
43
  #
51
44
  # @since 2.0.0
52
- class LegacyResult < Operation::Result
53
- include LegacyMergable
45
+ class Result < Operation::Result
46
+ include Mergable
47
+ include Aggregatable
54
48
 
55
- # Gets the number of documents deleted.
56
- #
57
- # @example Get the deleted count.
58
- # result.n_removed
59
- #
60
- # @return [ Integer ] The number of documents deleted.
49
+ # The aggregate number of deleted docs reported in the replies.
61
50
  #
62
51
  # @since 2.0.0
63
- def n_removed
64
- return 0 unless acknowledged?
65
- @replies.reduce(0) do |n, reply|
66
- n += reply.documents.first[N]
67
- end
68
- end
52
+ REMOVED = 'nRemoved'.freeze
53
+ end
54
+
55
+ # Defines custom behaviour of results when deleting.
56
+ # For server versions < 2.5.5 (that don't use write commands).
57
+ #
58
+ # @since 2.0.0
59
+ class LegacyResult < Operation::Result
60
+ include LegacyMergable
61
+ include Aggregatable
69
62
  end
70
63
  end
71
64
  end
@@ -42,7 +42,7 @@ module Mongo
42
42
  'code' => reply.documents.first[Error::CODE] }
43
43
  end
44
44
  errors
45
- end
45
+ end if @replies
46
46
  end
47
47
 
48
48
  # Aggregate the write concern errors returned from this result.
@@ -71,7 +71,7 @@ module Mongo
71
71
  'code' => code } if error_string
72
72
  end
73
73
  errors
74
- end
74
+ end if @replies
75
75
  end
76
76
 
77
77
  private
@@ -43,9 +43,10 @@ module Mongo
43
43
  def selector
44
44
  { delete: coll_name,
45
45
  deletes: deletes,
46
- writeConcern: write_concern.options,
47
46
  ordered: ordered?
48
- }
47
+ }.tap do |cmd|
48
+ cmd.merge!(writeConcern: write_concern.options) if write_concern
49
+ end
49
50
  end
50
51
  end
51
52
  end
@@ -42,9 +42,11 @@ module Mongo
42
42
  def selector
43
43
  { insert: coll_name,
44
44
  documents: documents,
45
- writeConcern: write_concern.options,
46
45
  ordered: ordered?
47
- }
46
+ }.tap do |cmd|
47
+ cmd.merge!(writeConcern: write_concern.options) if write_concern
48
+ cmd.merge!(:bypassDocumentValidation => true) if bypass_document_validation
49
+ end
48
50
  end
49
51
  end
50
52
  end
@@ -31,7 +31,8 @@ module Mongo
31
31
  # :db_name => 'test',
32
32
  # :coll_name => 'test_coll',
33
33
  # :write_concern => write_concern,
34
- # :ordered => true
34
+ # :ordered => true,
35
+ # :bypass_document_validation => true
35
36
  # })
36
37
  #
37
38
  # @since 2.0.0
@@ -47,9 +48,11 @@ module Mongo
47
48
  def selector
48
49
  { update: coll_name,
49
50
  updates: updates,
50
- writeConcern: write_concern.options,
51
51
  ordered: ordered?
52
- }
52
+ }.tap do |cmd|
53
+ cmd.merge!(writeConcern: write_concern.options) if write_concern
54
+ cmd.merge!(:bypassDocumentValidation => true) if bypass_document_validation
55
+ end
53
56
  end
54
57
  end
55
58
  end
@@ -33,7 +33,8 @@ module Mongo
33
33
  end
34
34
 
35
35
  def gle
36
- if gle_message = write_concern.get_last_error
36
+ wc = write_concern || WriteConcern.get(WriteConcern::DEFAULT)
37
+ if gle_message = wc.get_last_error
37
38
  Protocol::Query.new(
38
39
  db_name,
39
40
  Database::COMMAND,
@@ -22,6 +22,23 @@ module Mongo
22
22
  # @since 2.1.0
23
23
  module Idable
24
24
 
25
+ # The option for a custom id generator.
26
+ #
27
+ # @since 2.2.0
28
+ ID_GENERATOR = :id_generator.freeze
29
+
30
+ # Get the id generator.
31
+ #
32
+ # @example Get the id generator.
33
+ # idable.id_generator
34
+ #
35
+ # @return [ IdGenerator ] The default or custom id generator.
36
+ #
37
+ # @since 2.2.0
38
+ def id_generator
39
+ @id_generator ||= (spec[ID_GENERATOR] || ObjectIdGenerator.new)
40
+ end
41
+
25
42
  private
26
43
 
27
44
  def id(doc)
@@ -35,7 +52,7 @@ module Mongo
35
52
  def ensure_ids(documents)
36
53
  @ids ||= []
37
54
  documents.collect do |doc|
38
- doc_with_id = has_id?(doc) ? doc : doc.merge(_id: BSON::ObjectId.new)
55
+ doc_with_id = has_id?(doc) ? doc : doc.merge(_id: id_generator.generate)
39
56
  @ids << id(doc_with_id)
40
57
  doc_with_id
41
58
  end
@@ -43,4 +60,4 @@ module Mongo
43
60
  end
44
61
  end
45
62
  end
46
- end
63
+ end