cody 0.9.8 → 1.0.0

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. checksums.yaml +4 -4
  2. data/.gitmodules +0 -9
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile +0 -2
  5. data/cody.gemspec +3 -3
  6. data/lib/cody.rb +4 -8
  7. data/lib/cody/aws_services.rb +1 -1
  8. data/lib/cody/aws_services/helpers.rb +20 -3
  9. data/lib/cody/cli.rb +2 -13
  10. data/lib/cody/{badge.rb → cli/badge.rb} +1 -1
  11. data/lib/cody/{base.rb → cli/base.rb} +9 -3
  12. data/lib/cody/{delete.rb → cli/delete.rb} +3 -3
  13. data/lib/cody/cli/deploy.rb +7 -0
  14. data/lib/cody/cli/help.rb +11 -0
  15. data/lib/cody/{help → cli/help}/deploy.md +0 -0
  16. data/lib/cody/{help → cli/help}/init.md +0 -0
  17. data/lib/cody/{help → cli/help}/logs.md +0 -0
  18. data/lib/cody/{help → cli/help}/start.md +0 -0
  19. data/lib/cody/{help → cli/help}/stop.md +0 -0
  20. data/lib/cody/{init.rb → cli/init.rb} +1 -2
  21. data/lib/cody/{list.rb → cli/list.rb} +7 -3
  22. data/lib/cody/cli/logs.rb +10 -0
  23. data/lib/cody/{sequence.rb → cli/sequence.rb} +3 -3
  24. data/lib/cody/{start.rb → cli/start.rb} +3 -3
  25. data/lib/cody/{status.rb → cli/status.rb} +2 -1
  26. data/lib/cody/{stop.rb → cli/stop.rb} +2 -1
  27. data/lib/cody/command.rb +11 -0
  28. data/lib/cody/core.rb +5 -5
  29. data/lib/cody/dsl/base.rb +9 -0
  30. data/lib/cody/dsl/project.rb +54 -49
  31. data/lib/cody/dsl/role.rb +11 -11
  32. data/lib/cody/dsl/schedule.rb +8 -8
  33. data/lib/cody/list/no_builds_project.rb +1 -1
  34. data/lib/cody/list/project.rb +1 -1
  35. data/lib/cody/project.rb +23 -23
  36. data/lib/cody/role.rb +20 -20
  37. data/lib/cody/schedule.rb +37 -37
  38. data/lib/cody/stack.rb +16 -71
  39. data/lib/cody/stack/base.rb +104 -0
  40. data/lib/cody/{create.rb → stack/create.rb} +2 -2
  41. data/lib/cody/{update.rb → stack/update.rb} +2 -2
  42. data/lib/cody/tailer.rb +1 -1
  43. data/lib/cody/version.rb +1 -1
  44. data/lib/template/project/buildspec.yml +1 -1
  45. data/lib/template/project/project.rb.tt +5 -19
  46. metadata +64 -70
  47. data/lib/cody/completer.rb +0 -159
  48. data/lib/cody/completer/script.rb +0 -6
  49. data/lib/cody/completer/script.sh +0 -10
  50. data/lib/cody/deploy.rb +0 -40
  51. data/lib/cody/help.rb +0 -9
  52. data/lib/cody/help/completion.md +0 -22
  53. data/lib/cody/help/completion_script.md +0 -3
  54. data/lib/cody/logs.rb +0 -14
  55. data/vendor/aws_data/CHANGELOG.md +0 -7
  56. data/vendor/aws_data/Gemfile +0 -4
  57. data/vendor/aws_data/LICENSE.txt +0 -21
  58. data/vendor/aws_data/README.md +0 -42
  59. data/vendor/aws_data/Rakefile +0 -6
  60. data/vendor/aws_data/aws_data.gemspec +0 -30
  61. data/vendor/aws_data/bin/console +0 -14
  62. data/vendor/aws_data/bin/setup +0 -8
  63. data/vendor/aws_data/lib/aws_data.rb +0 -91
  64. data/vendor/aws_data/lib/aws_data/version.rb +0 -3
  65. data/vendor/aws_data/spec/aws_data_spec.rb +0 -5
  66. data/vendor/aws_data/spec/spec_helper.rb +0 -14
  67. data/vendor/cfn-status/Gemfile +0 -4
  68. data/vendor/cfn-status/LICENSE.txt +0 -21
  69. data/vendor/cfn-status/README.md +0 -56
  70. data/vendor/cfn-status/Rakefile +0 -6
  71. data/vendor/cfn-status/bin/console +0 -14
  72. data/vendor/cfn-status/bin/setup +0 -8
  73. data/vendor/cfn-status/cfn-status.gemspec +0 -30
  74. data/vendor/cfn-status/lib/cfn/aws_service.rb +0 -56
  75. data/vendor/cfn-status/lib/cfn/status.rb +0 -220
  76. data/vendor/cfn-status/lib/cfn/status/version.rb +0 -5
  77. data/vendor/cfn-status/spec/cfn/status_spec.rb +0 -81
  78. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +0 -1080
  79. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +0 -1080
  80. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +0 -1086
  81. data/vendor/cfn-status/spec/spec_helper.rb +0 -14
  82. data/vendor/cfn_camelizer/CHANGELOG.md +0 -10
  83. data/vendor/cfn_camelizer/Gemfile +0 -4
  84. data/vendor/cfn_camelizer/LICENSE.txt +0 -21
  85. data/vendor/cfn_camelizer/README.md +0 -40
  86. data/vendor/cfn_camelizer/Rakefile +0 -6
  87. data/vendor/cfn_camelizer/bin/console +0 -14
  88. data/vendor/cfn_camelizer/bin/setup +0 -8
  89. data/vendor/cfn_camelizer/cfn_camelizer.gemspec +0 -32
  90. data/vendor/cfn_camelizer/lib/camelizer.yml +0 -33
  91. data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +0 -92
  92. data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +0 -3
  93. data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +0 -79
  94. data/vendor/cfn_camelizer/spec/spec_helper.rb +0 -14
@@ -1,5 +1,5 @@
1
- module Cody
2
- class Create < Stack
1
+ class Cody::Stack
2
+ class Create < Base
3
3
  def perform
4
4
  cfn.create_stack(
5
5
  stack_name: @stack_name,
@@ -1,5 +1,5 @@
1
- module Cody
2
- class Update < Stack
1
+ class Cody::Stack
2
+ class Update < Base
3
3
  def perform
4
4
  cfn.update_stack(
5
5
  stack_name: @stack_name,
@@ -2,7 +2,7 @@ require "aws-logs"
2
2
 
3
3
  module Cody
4
4
  class Tailer
5
- include AwsServices
5
+ include Cody::AwsServices
6
6
 
7
7
  def initialize(options, build_id)
8
8
  @options, @build_id = options, build_id
@@ -1,3 +1,3 @@
1
1
  module Cody
2
- VERSION = "0.9.8"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -5,7 +5,7 @@ version: 0.2
5
5
  phases:
6
6
  install:
7
7
  runtime-versions:
8
- ruby: 2.6
8
+ ruby: latest
9
9
  build:
10
10
  commands:
11
11
  - uptime
@@ -1,5 +1,10 @@
1
1
  # For methods, refer to the properties of the CloudFormation CodeBuild::Project https://amzn.to/2UTeNlr
2
2
  # For convenience methods, refer to the source https://github.com/tongueroo/cody/blob/master/lib/cody/dsl/project.rb
3
+ # Docs:
4
+ #
5
+ # * https://cody.run/docs/dsl/project/
6
+ # * https://cody.run/docs/docs/dsl/helpers/
7
+ #
3
8
 
4
9
  # name("example-project-name") # recommend leaving unset and codebuild will use a conventional name
5
10
  github_url("<%= project_github_url %>")
@@ -8,22 +13,3 @@ environment_variables(
8
13
  JETS_ENV: "test",
9
14
  # API_KEY: "ssm:/codebuild/demo/api_key" # Example of ssm parameter
10
15
  )
11
-
12
- # Some useful helpers:
13
- # puts "project_name #{project_name}" # IE: demo-web
14
- # puts "full_project_name #{full_project_name}" # demo-web-development
15
-
16
- # Uncomment to enable github webhook, the GitHub oauth token needs admin:repo_hook permissions
17
- # Refer to https://cody.run/docs/github_oauth/
18
- # triggers(webhook: true)
19
- # Another example:
20
- # Docs: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projecttriggers.html
21
- # {type: "EVENT", pattern: "PUSH"} is required
22
- # Also, note the extra brackets: [[]] is actually the proper format. I know weird.
23
- # triggers(
24
- # webhook: true,
25
- # filter_groups: [[{type: "HEAD_REF", pattern: "my-branch"}, {type: "EVENT", pattern: "PUSH"}]]
26
- # )
27
-
28
- # Shorthand to enable all local cache modes
29
- # local_cache(true)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cody
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.8
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-09 00:00:00.000000000 Z
11
+ date: 2020-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -94,6 +94,48 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aws_data
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: cfn-status
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: cfn_camelizer
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
97
139
  - !ruby/object:Gem::Dependency
98
140
  name: cli-format
99
141
  requirement: !ruby/object:Gem::Requirement
@@ -276,18 +318,27 @@ files:
276
318
  - lib/cody/autoloader.rb
277
319
  - lib/cody/aws_services.rb
278
320
  - lib/cody/aws_services/helpers.rb
279
- - lib/cody/badge.rb
280
- - lib/cody/base.rb
281
321
  - lib/cody/cli.rb
322
+ - lib/cody/cli/badge.rb
323
+ - lib/cody/cli/base.rb
324
+ - lib/cody/cli/delete.rb
325
+ - lib/cody/cli/deploy.rb
326
+ - lib/cody/cli/help.rb
327
+ - lib/cody/cli/help/deploy.md
328
+ - lib/cody/cli/help/init.md
329
+ - lib/cody/cli/help/logs.md
330
+ - lib/cody/cli/help/start.md
331
+ - lib/cody/cli/help/stop.md
332
+ - lib/cody/cli/init.rb
333
+ - lib/cody/cli/list.rb
334
+ - lib/cody/cli/logs.rb
335
+ - lib/cody/cli/sequence.rb
336
+ - lib/cody/cli/start.rb
337
+ - lib/cody/cli/status.rb
338
+ - lib/cody/cli/stop.rb
282
339
  - lib/cody/command.rb
283
- - lib/cody/completer.rb
284
- - lib/cody/completer/script.rb
285
- - lib/cody/completer/script.sh
286
340
  - lib/cody/core.rb
287
- - lib/cody/create.rb
288
341
  - lib/cody/default/settings.yml
289
- - lib/cody/delete.rb
290
- - lib/cody/deploy.rb
291
342
  - lib/cody/dsl/base.rb
292
343
  - lib/cody/dsl/project.rb
293
344
  - lib/cody/dsl/project/ssm.rb
@@ -295,30 +346,17 @@ files:
295
346
  - lib/cody/dsl/schedule.rb
296
347
  - lib/cody/evaluate.rb
297
348
  - lib/cody/evaluate/interface.rb
298
- - lib/cody/help.rb
299
- - lib/cody/help/completion.md
300
- - lib/cody/help/completion_script.md
301
- - lib/cody/help/deploy.md
302
- - lib/cody/help/init.md
303
- - lib/cody/help/logs.md
304
- - lib/cody/help/start.md
305
- - lib/cody/help/stop.md
306
- - lib/cody/init.rb
307
- - lib/cody/list.rb
308
349
  - lib/cody/list/no_builds_project.rb
309
350
  - lib/cody/list/project.rb
310
- - lib/cody/logs.rb
311
351
  - lib/cody/project.rb
312
352
  - lib/cody/role.rb
313
353
  - lib/cody/schedule.rb
314
- - lib/cody/sequence.rb
315
354
  - lib/cody/setting.rb
316
355
  - lib/cody/stack.rb
317
- - lib/cody/start.rb
318
- - lib/cody/status.rb
319
- - lib/cody/stop.rb
356
+ - lib/cody/stack/base.rb
357
+ - lib/cody/stack/create.rb
358
+ - lib/cody/stack/update.rb
320
359
  - lib/cody/tailer.rb
321
- - lib/cody/update.rb
322
360
  - lib/cody/variables.rb
323
361
  - lib/cody/version.rb
324
362
  - lib/template/project/buildspec.yml
@@ -330,50 +368,6 @@ files:
330
368
  - lib/template/top/variables/base.rb
331
369
  - lib/template/top/variables/development.rb
332
370
  - lib/template/top/variables/production.rb
333
- - vendor/aws_data/CHANGELOG.md
334
- - vendor/aws_data/Gemfile
335
- - vendor/aws_data/Gemfile.lock
336
- - vendor/aws_data/LICENSE.txt
337
- - vendor/aws_data/README.md
338
- - vendor/aws_data/Rakefile
339
- - vendor/aws_data/aws_data.gemspec
340
- - vendor/aws_data/bin/console
341
- - vendor/aws_data/bin/setup
342
- - vendor/aws_data/lib/aws_data.rb
343
- - vendor/aws_data/lib/aws_data/version.rb
344
- - vendor/aws_data/pkg/aws_data-0.1.0.gem
345
- - vendor/aws_data/spec/aws_data_spec.rb
346
- - vendor/aws_data/spec/spec_helper.rb
347
- - vendor/cfn-status/Gemfile
348
- - vendor/cfn-status/Gemfile.lock
349
- - vendor/cfn-status/LICENSE.txt
350
- - vendor/cfn-status/README.md
351
- - vendor/cfn-status/Rakefile
352
- - vendor/cfn-status/bin/console
353
- - vendor/cfn-status/bin/setup
354
- - vendor/cfn-status/cfn-status.gemspec
355
- - vendor/cfn-status/lib/cfn/aws_service.rb
356
- - vendor/cfn-status/lib/cfn/status.rb
357
- - vendor/cfn-status/lib/cfn/status/version.rb
358
- - vendor/cfn-status/spec/cfn/status_spec.rb
359
- - vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json
360
- - vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json
361
- - vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json
362
- - vendor/cfn-status/spec/spec_helper.rb
363
- - vendor/cfn_camelizer/CHANGELOG.md
364
- - vendor/cfn_camelizer/Gemfile
365
- - vendor/cfn_camelizer/Gemfile.lock
366
- - vendor/cfn_camelizer/LICENSE.txt
367
- - vendor/cfn_camelizer/README.md
368
- - vendor/cfn_camelizer/Rakefile
369
- - vendor/cfn_camelizer/bin/console
370
- - vendor/cfn_camelizer/bin/setup
371
- - vendor/cfn_camelizer/cfn_camelizer.gemspec
372
- - vendor/cfn_camelizer/lib/camelizer.yml
373
- - vendor/cfn_camelizer/lib/cfn_camelizer.rb
374
- - vendor/cfn_camelizer/lib/cfn_camelizer/version.rb
375
- - vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb
376
- - vendor/cfn_camelizer/spec/spec_helper.rb
377
371
  homepage: https://github.com/tongueroo/cody
378
372
  licenses:
379
373
  - MIT
@@ -1,159 +0,0 @@
1
- =begin
2
- Code Explanation:
3
-
4
- There are 3 types of things to auto-complete:
5
-
6
- 1. command: the command itself
7
- 2. parameters: command parameters.
8
- 3. options: command options
9
-
10
- Here's an example:
11
-
12
- mycli hello name --from me
13
-
14
- * command: hello
15
- * parameters: name
16
- * option: --from
17
-
18
- When command parameters are done processing, the remaining completion words will be options. We can tell that the command params are completed based on the method arity.
19
-
20
- ## Arity
21
-
22
- For example, say you had a method for a CLI command with the following form:
23
-
24
- ufo scale service count --cluster development
25
-
26
- It's equivalent ruby method:
27
-
28
- scale(service, count) = has an arity of 2
29
-
30
- So typing:
31
-
32
- ufo scale service count [TAB] # there are 3 parameters including the "scale" command according to Thor's CLI processing.
33
-
34
- So the completion should only show options, something like this:
35
-
36
- --noop --verbose --cluster
37
-
38
- ## Splat Arguments
39
-
40
- When the ruby method has a splat argument, it's arity is negative. Here are some example methods and their arities.
41
-
42
- ship(service) = 1
43
- scale(service, count) = 2
44
- ships(*services) = -1
45
- foo(example, *rest) = -2
46
-
47
- Fortunately, negative and positive arity values are processed the same way. So we take simply take the absolute value of the arity and process it the same.
48
-
49
- Here are some test cases, hit TAB after typing the command:
50
-
51
- cody completion
52
- cody completion hello
53
- cody completion hello name
54
- cody completion hello name --
55
- cody completion hello name --noop
56
-
57
- cody completion
58
- cody completion sub:goodbye
59
- cody completion sub:goodbye name
60
-
61
- ## Subcommands and Thor::Group Registered Commands
62
-
63
- Sometimes the commands are not simple thor commands but are subcommands or Thor::Group commands. A good specific example is the ufo tool.
64
-
65
- * regular command: ufo ship
66
- * subcommand: ufo docker
67
- * Thor::Group command: ufo init
68
-
69
- Auto-completion accounts for each of these type of commands.
70
- =end
71
- module Cody
72
- class Completer
73
- def initialize(command_class, *params)
74
- @params = params
75
- @current_command = @params[0]
76
- @command_class = command_class # CLI initiall
77
- end
78
-
79
- def run
80
- if subcommand?(@current_command)
81
- subcommand_class = @command_class.subcommand_classes[@current_command]
82
- @params.shift # destructive
83
- Completer.new(subcommand_class, *@params).run # recursively use subcommand
84
- return
85
- end
86
-
87
- # full command has been found!
88
- unless found?(@current_command)
89
- puts all_commands
90
- return
91
- end
92
-
93
- # will only get to here if command aws found (above)
94
- arity = @command_class.instance_method(@current_command).arity.abs
95
- if @params.size > arity or thor_group_command?
96
- puts options_completion
97
- else
98
- puts params_completion
99
- end
100
- end
101
-
102
- def subcommand?(command)
103
- @command_class.subcommands.include?(command)
104
- end
105
-
106
- # hacky way to detect that command is a registered Thor::Group command
107
- def thor_group_command?
108
- command_params(raw=true) == [[:rest, :args]]
109
- end
110
-
111
- def found?(command)
112
- public_methods = @command_class.public_instance_methods(false)
113
- command && public_methods.include?(command.to_sym)
114
- end
115
-
116
- # all top-level commands
117
- def all_commands
118
- commands = @command_class.all_commands.reject do |k,v|
119
- v.is_a?(Thor::HiddenCommand)
120
- end
121
- commands.keys
122
- end
123
-
124
- def command_params(raw=false)
125
- params = @command_class.instance_method(@current_command).parameters
126
- # Example:
127
- # >> Sub.instance_method(:goodbye).parameters
128
- # => [[:req, :name]]
129
- # >>
130
- raw ? params : params.map!(&:last)
131
- end
132
-
133
- def params_completion
134
- offset = @params.size - 1
135
- offset_params = command_params[offset..-1]
136
- command_params[offset..-1].first
137
- end
138
-
139
- def options_completion
140
- used = ARGV.select { |a| a.include?('--') } # so we can remove used options
141
-
142
- method_options = @command_class.all_commands[@current_command].options.keys
143
- class_options = @command_class.class_options.keys
144
-
145
- all_options = method_options + class_options + ['help']
146
-
147
- all_options.map! { |o| "--#{o.to_s.gsub('_','-')}" }
148
- filtered_options = all_options - used
149
- filtered_options.uniq
150
- end
151
-
152
- # Useful for debugging. Using puts messes up completion.
153
- def log(msg)
154
- File.open("/tmp/complete.log", "a") do |file|
155
- file.puts(msg)
156
- end
157
- end
158
- end
159
- end
@@ -1,6 +0,0 @@
1
- class Cody::Completer::Script
2
- def self.generate
3
- bash_script = File.expand_path("script.sh", File.dirname(__FILE__))
4
- puts "source #{bash_script}"
5
- end
6
- end
@@ -1,10 +0,0 @@
1
- _cody() {
2
- COMPREPLY=()
3
- local word="${COMP_WORDS[COMP_CWORD]}"
4
- local words=("${COMP_WORDS[@]}")
5
- unset words[0]
6
- local completion=$(cody completion ${words[@]})
7
- COMPREPLY=( $(compgen -W "$completion" -- "$word") )
8
- }
9
-
10
- complete -F _cody cody
@@ -1,40 +0,0 @@
1
- module Cody
2
- class Deploy < Stack
3
- def run
4
- handle_rollback_completed!
5
- if stack_exists?(@stack_name)
6
- Update.new(@options).run
7
- else
8
- Create.new(@options).run
9
- end
10
- end
11
-
12
- def handle_rollback_completed!
13
- @stack = find_stack(@stack_name)
14
- if @stack && rollback_complete?(@stack)
15
- puts "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
16
- cfn.delete_stack(stack_name: @stack_name)
17
- status.wait
18
- status.reset
19
- @stack = nil # at this point stack has been deleted
20
- end
21
- end
22
-
23
- def rollback_complete?(stack)
24
- stack.stack_status == 'ROLLBACK_COMPLETE'
25
- end
26
-
27
- def find_stack(stack_name)
28
- return if ENV['TEST']
29
- resp = cfn.describe_stacks(stack_name: stack_name)
30
- resp.stacks.first
31
- rescue Aws::CloudFormation::Errors::ValidationError => e
32
- # example: Stack with id demo-web does not exist
33
- if e.message =~ /Stack with/ && e.message =~ /does not exist/
34
- nil
35
- else
36
- raise
37
- end
38
- end
39
- end
40
- end