awspec 1.2.0 → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6b179910887dad4c07a7dcb3a3964eddd1bd89a5
4
- data.tar.gz: '09e960c5431fbf85ed39531e42dee075f46e9e67'
3
+ metadata.gz: 5326ef5dcbd3e3d0c6d832875aff370eb2319aeb
4
+ data.tar.gz: 8d619b765a444302e46962d98561b85ccf405672
5
5
  SHA512:
6
- metadata.gz: 348f694481e7db4994744ffbc6ee94001f10d2132ae6762dc6f2f314e7dbb62d6e30c2e30609f833604c30bcc5d8472c0a972fd94f6d907ac3ed2815dbd6bccb
7
- data.tar.gz: 1584f796a4420efa011fdd2f297096e8872f48d473becda49b8dbfce86d896613546c28d9347ebd5b90e7cd31ce1f2d716cbc5b3e5824202b19c274657dc6087
6
+ metadata.gz: ae0828218096b5bdca15b27fa098efd163cd8264556d0f6028c25dc2765798bc1e61fcf6efb745ebdd7e7d922859928120d6bfc53f1a44f54aeab7851b03cb56
7
+ data.tar.gz: d99ca40c1655e97f5cf031ce7b2dd13dd083c309d14606f91fbea8db5dcaf4455a815311a74011f198c23d4bd0af985b59e180c9f4160658c21a359c57970fde
@@ -0,0 +1,41 @@
1
+ ### exist
2
+
3
+ ```ruby
4
+ describe nlb('my-nlb') do
5
+ it { should exist }
6
+ end
7
+ ```
8
+
9
+ ### be_active, be_provisioning, be_failed
10
+
11
+ ```ruby
12
+ describe nlb('my-nlb') do
13
+ it { should be_active }
14
+ end
15
+ ```
16
+
17
+ ### have_security_group
18
+
19
+ Note that NLBs never have security groups. The have_security_group() function always returns false. See https://forums.aws.amazon.com/thread.jspa?threadID=263245 for discussion about the security-group-less-ness of NLBs.
20
+
21
+ ```ruby
22
+ describe nlb('my-nlb') do
23
+ it { should_not have_security_group('sg-1a2b3cd4') }
24
+ end
25
+ ```
26
+
27
+ ### have_subnet
28
+
29
+ ```ruby
30
+ describe nlb('my-nlb') do
31
+ it { should have_subnet('subnet-1234a567') }
32
+ end
33
+ ```
34
+
35
+ ### belong_to_vpc
36
+
37
+ ```ruby
38
+ describe nlb('my-nlb') do
39
+ it { should belong_to_vpc('my-vpc') }
40
+ end
41
+ ```
@@ -0,0 +1,29 @@
1
+ ### exist
2
+
3
+ ```ruby
4
+ describe nlb_listener('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2') do
5
+ it { should exist }
6
+ its(:port) { should eq 80 }
7
+ its(:protocol) { should eq 'HTTP' }
8
+ end
9
+ ```
10
+
11
+ ### have_rule
12
+
13
+ ```ruby
14
+ describe nlb_listener('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2') do
15
+ it { should have_rule('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener-rule/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2/9683b2d02a6cabee') }
16
+ it do
17
+ should have_rule.priority('10')
18
+ .conditions(field: 'path-pattern', values: ['/img/*'])
19
+ .actions(target_group_arn: 'arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:123456789012:targetgroup/73e2d6bc24d8a067/73e2d6bc24d8a067', type: 'forward')
20
+ end
21
+ it do
22
+ should have_rule.priority('10')
23
+ .if(field: 'path-pattern', values: ['/img/*'])
24
+ .then(target_group_arn: 'arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:123456789012:targetgroup/73e2d6bc24d8a067/73e2d6bc24d8a067', type: 'forward')
25
+ end
26
+ it { should have_rule.conditions([{ field: 'path-pattern', values: ['/admin/*'] }, { field: 'host-header', values: ['admin.example.com'] }]) }
27
+ it { should have_rule.actions(target_group_name: 'my-nlb-target-group', type: 'forward') }
28
+ end
29
+ ```
@@ -0,0 +1,35 @@
1
+ ### exist
2
+
3
+ ```ruby
4
+ describe nlb_target_group('my-nlb-target-group') do
5
+ it { should exist }
6
+ its(:health_check_path) { should eq '/' }
7
+ its(:health_check_port) { should eq 'traffic-port' }
8
+ its(:health_check_protocol) { should eq 'HTTP' }
9
+ end
10
+ ```
11
+
12
+ ### have_ec2
13
+
14
+ ```ruby
15
+ describe nlb_target_group('my-nlb-target-group') do
16
+ it { should have_ec2('my-ec2') }
17
+ end
18
+ ```
19
+
20
+ ### belong_to_nlb
21
+
22
+ ```ruby
23
+ describe nlb_target_group('my-nlb-target-group') do
24
+ it { should belong_to_nlb('my-nlb') }
25
+ end
26
+ ```
27
+
28
+ ### belong_to_vpc
29
+
30
+ ```ruby
31
+ describe nlb_target_group('my-nlb-target-group') do
32
+ it { should belong_to_vpc('my-vpc') }
33
+ end
34
+ ```
35
+
@@ -40,6 +40,9 @@
40
40
  | [nat_gateway](#nat_gateway)
41
41
  | [network_acl](#network_acl)
42
42
  | [network_interface](#network_interface)
43
+ | [nlb](#nlb)
44
+ | [nlb_listener](#nlb_listener)
45
+ | [nlb_target_group](#nlb_target_group)
43
46
  | [rds](#rds)
44
47
  | [rds_db_cluster_parameter_group](#rds_db_cluster_parameter_group)
45
48
  | [rds_db_parameter_group](#rds_db_parameter_group)
@@ -279,6 +282,8 @@ end
279
282
  ```
280
283
 
281
284
 
285
+ ### have_nlb_target_group
286
+
282
287
  ### have_suspended_process
283
288
 
284
289
  ### have_tag
@@ -957,7 +962,7 @@ describe ecs_service('my-ecs-service') do
957
962
  end
958
963
  ```
959
964
 
960
- ### its(:service_arn), its(:service_name), its(:cluster_arn), its(:load_balancers), its(:status), its(:desired_count), its(:running_count), its(:pending_count), its(:launch_type), its(:platform_version), its(:task_definition), its(:role_arn), its(:created_at), its(:placement_constraints), its(:placement_strategy), its(:network_configuration)
965
+ ### its(:service_arn), its(:service_name), its(:cluster_arn), its(:load_balancers), its(:status), its(:desired_count), its(:running_count), its(:pending_count), its(:launch_type), its(:platform_version), its(:task_definition), its(:role_arn), its(:created_at), its(:placement_constraints), its(:placement_strategy), its(:network_configuration), its(:health_check_grace_period_seconds)
961
966
  ## <a name="ecs_task_definition">ecs_task_definition</a>
962
967
 
963
968
  ECS Task Definition resource type.
@@ -1670,7 +1675,7 @@ end
1670
1675
 
1671
1676
  This matcher does not support Amazon S3 event sources. ( [See SDK doc](http://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#list_event_source_mappings-instance_method) )
1672
1677
 
1673
- ### its(:function_name), its(:function_arn), its(:runtime), its(:role), its(:handler), its(:code_size), its(:description), its(:timeout), its(:memory_size), its(:last_modified), its(:code_sha_256), its(:version), its(:vpc_config), its(:dead_letter_config), its(:environment), its(:kms_key_arn), its(:tracing_config), its(:master_arn)
1678
+ ### its(:function_name), its(:function_arn), its(:runtime), its(:role), its(:handler), its(:code_size), its(:description), its(:timeout), its(:memory_size), its(:last_modified), its(:code_sha_256), its(:version), its(:vpc_config), its(:dead_letter_config), its(:environment), its(:kms_key_arn), its(:tracing_config), its(:master_arn), its(:revision_id)
1674
1679
  ## <a name="launch_configuration">launch_configuration</a>
1675
1680
 
1676
1681
  LaunchConfiguration resource type.
@@ -1886,6 +1891,137 @@ end
1886
1891
  ```
1887
1892
 
1888
1893
  ### its(:association), its(:availability_zone), its(:description), its(:interface_type), its(:ipv_6_addresses), its(:mac_address), its(:network_interface_id), its(:owner_id), its(:private_dns_name), its(:private_ip_address), its(:requester_id), its(:requester_managed), its(:source_dest_check), its(:status), its(:subnet_id), its(:vpc_id)
1894
+ ## <a name="nlb">nlb</a>
1895
+
1896
+ NLB resource type.
1897
+
1898
+ ### exist
1899
+
1900
+ ```ruby
1901
+ describe nlb('my-nlb') do
1902
+ it { should exist }
1903
+ end
1904
+ ```
1905
+
1906
+
1907
+ ### be_active, be_provisioning, be_failed
1908
+
1909
+ ```ruby
1910
+ describe nlb('my-nlb') do
1911
+ it { should be_active }
1912
+ end
1913
+ ```
1914
+
1915
+
1916
+ ### have_security_group
1917
+
1918
+ Note that NLBs never have security groups. The have_security_group() function always returns false. See https://forums.aws.amazon.com/thread.jspa?threadID=263245 for discussion about the security-group-less-ness of NLBs.
1919
+
1920
+ ```ruby
1921
+ describe nlb('my-nlb') do
1922
+ it { should_not have_security_group('sg-1a2b3cd4') }
1923
+ end
1924
+ ```
1925
+
1926
+
1927
+ ### have_subnet
1928
+
1929
+ ```ruby
1930
+ describe nlb('my-nlb') do
1931
+ it { should have_subnet('subnet-1234a567') }
1932
+ end
1933
+ ```
1934
+
1935
+
1936
+ ### belong_to_vpc
1937
+
1938
+ ```ruby
1939
+ describe nlb('my-nlb') do
1940
+ it { should belong_to_vpc('my-vpc') }
1941
+ end
1942
+ ```
1943
+
1944
+ ### its(:load_balancer_arn), its(:dns_name), its(:canonical_hosted_zone_id), its(:created_time), its(:load_balancer_name), its(:scheme), its(:vpc_id), its(:type), its(:security_groups), its(:ip_address_type)
1945
+ ## <a name="nlb_listener">nlb_listener</a>
1946
+
1947
+ NlbListener resource type.
1948
+
1949
+ ### exist
1950
+
1951
+ ```ruby
1952
+ describe nlb_listener('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2') do
1953
+ it { should exist }
1954
+ its(:port) { should eq 80 }
1955
+ its(:protocol) { should eq 'HTTP' }
1956
+ end
1957
+ ```
1958
+
1959
+
1960
+ ### have_rule
1961
+
1962
+ ```ruby
1963
+ describe nlb_listener('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2') do
1964
+ it { should have_rule('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener-rule/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2/9683b2d02a6cabee') }
1965
+ it do
1966
+ should have_rule.priority('10')
1967
+ .conditions(field: 'path-pattern', values: ['/img/*'])
1968
+ .actions(target_group_arn: 'arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:123456789012:targetgroup/73e2d6bc24d8a067/73e2d6bc24d8a067', type: 'forward')
1969
+ end
1970
+ it do
1971
+ should have_rule.priority('10')
1972
+ .if(field: 'path-pattern', values: ['/img/*'])
1973
+ .then(target_group_arn: 'arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:123456789012:targetgroup/73e2d6bc24d8a067/73e2d6bc24d8a067', type: 'forward')
1974
+ end
1975
+ it { should have_rule.conditions([{ field: 'path-pattern', values: ['/admin/*'] }, { field: 'host-header', values: ['admin.example.com'] }]) }
1976
+ it { should have_rule.actions(target_group_name: 'my-nlb-target-group', type: 'forward') }
1977
+ end
1978
+ ```
1979
+
1980
+ ### its(:listener_arn), its(:load_balancer_arn), its(:port), its(:protocol), its(:certificates), its(:ssl_policy)
1981
+ ## <a name="nlb_target_group">nlb_target_group</a>
1982
+
1983
+ NlbTargetGroup resource type.
1984
+
1985
+ ### exist
1986
+
1987
+ ```ruby
1988
+ describe nlb_target_group('my-nlb-target-group') do
1989
+ it { should exist }
1990
+ its(:health_check_path) { should eq '/' }
1991
+ its(:health_check_port) { should eq 'traffic-port' }
1992
+ its(:health_check_protocol) { should eq 'HTTP' }
1993
+ end
1994
+ ```
1995
+
1996
+
1997
+ ### have_ec2
1998
+
1999
+ ```ruby
2000
+ describe nlb_target_group('my-nlb-target-group') do
2001
+ it { should have_ec2('my-ec2') }
2002
+ end
2003
+ ```
2004
+
2005
+
2006
+ ### belong_to_nlb
2007
+
2008
+ ```ruby
2009
+ describe nlb_target_group('my-nlb-target-group') do
2010
+ it { should belong_to_nlb('my-nlb') }
2011
+ end
2012
+ ```
2013
+
2014
+
2015
+ ### belong_to_vpc
2016
+
2017
+ ```ruby
2018
+ describe nlb_target_group('my-nlb-target-group') do
2019
+ it { should belong_to_vpc('my-vpc') }
2020
+ end
2021
+ ```
2022
+
2023
+
2024
+ ### its(:target_group_arn), its(:target_group_name), its(:protocol), its(:port), its(:vpc_id), its(:health_check_protocol), its(:health_check_port), its(:health_check_interval_seconds), its(:health_check_timeout_seconds), its(:healthy_threshold_count), its(:unhealthy_threshold_count), its(:health_check_path), its(:load_balancer_arns), its(:target_type)
1889
2025
  ## <a name="rds">rds</a>
1890
2026
 
1891
2027
  RDS resource type.
@@ -1974,7 +2110,7 @@ end
1974
2110
  ```
1975
2111
 
1976
2112
 
1977
- ### its(:vpc_id), its(:db_instance_identifier), its(:db_instance_class), its(:engine), its(:db_instance_status), its(:master_username), its(:db_name), its(:endpoint), its(:allocated_storage), its(:instance_create_time), its(:preferred_backup_window), its(:backup_retention_period), its(:db_security_groups), its(:availability_zone), its(:preferred_maintenance_window), its(:pending_modified_values), its(:latest_restorable_time), its(:multi_az), its(:engine_version), its(:auto_minor_version_upgrade), its(:read_replica_source_db_instance_identifier), its(:read_replica_db_instance_identifiers), its(:read_replica_db_cluster_identifiers), its(:license_model), its(:iops), its(:character_set_name), its(:secondary_availability_zone), its(:publicly_accessible), its(:status_infos), its(:storage_type), its(:tde_credential_arn), its(:db_instance_port), its(:db_cluster_identifier), its(:storage_encrypted), its(:kms_key_id), its(:dbi_resource_id), its(:ca_certificate_identifier), its(:domain_memberships), its(:copy_tags_to_snapshot), its(:monitoring_interval), its(:enhanced_monitoring_resource_arn), its(:monitoring_role_arn), its(:promotion_tier), its(:db_instance_arn), its(:timezone), its(:iam_database_authentication_enabled), its(:performance_insights_enabled), its(:performance_insights_kms_key_id)
2113
+ ### its(:vpc_id), its(:db_instance_identifier), its(:db_instance_class), its(:engine), its(:db_instance_status), its(:master_username), its(:db_name), its(:endpoint), its(:allocated_storage), its(:instance_create_time), its(:preferred_backup_window), its(:backup_retention_period), its(:db_security_groups), its(:availability_zone), its(:preferred_maintenance_window), its(:pending_modified_values), its(:latest_restorable_time), its(:multi_az), its(:engine_version), its(:auto_minor_version_upgrade), its(:read_replica_source_db_instance_identifier), its(:read_replica_db_instance_identifiers), its(:read_replica_db_cluster_identifiers), its(:license_model), its(:iops), its(:character_set_name), its(:secondary_availability_zone), its(:publicly_accessible), its(:status_infos), its(:storage_type), its(:tde_credential_arn), its(:db_instance_port), its(:db_cluster_identifier), its(:storage_encrypted), its(:kms_key_id), its(:dbi_resource_id), its(:ca_certificate_identifier), its(:domain_memberships), its(:copy_tags_to_snapshot), its(:monitoring_interval), its(:enhanced_monitoring_resource_arn), its(:monitoring_role_arn), its(:promotion_tier), its(:db_instance_arn), its(:timezone), its(:iam_database_authentication_enabled), its(:performance_insights_enabled), its(:performance_insights_kms_key_id), its(:enabled_cloudwatch_logs_exports)
1978
2114
  ### :unlock: Advanced use
1979
2115
 
1980
2116
  `rds` can use `Aws::RDS::DBInstance` resource (see http://docs.aws.amazon.com/sdkforruby/api/Aws/RDS/DBInstance.html).
@@ -8,7 +8,7 @@ module Awspec
8
8
  class_option :secrets_path
9
9
 
10
10
  types = %w(
11
- vpc ec2 rds security_group elb network_acl route_table subnet nat_gateway network_interface alb
11
+ vpc ec2 rds security_group elb network_acl route_table subnet nat_gateway network_interface alb nlb
12
12
  internet_gateway
13
13
  )
14
14
 
@@ -36,6 +36,18 @@ module Awspec
36
36
  end
37
37
  end
38
38
 
39
+ types = %w(
40
+ rds_db_parameter_group rds_db_cluster_parameter_group
41
+ )
42
+
43
+ types.each do |type|
44
+ desc type + ' [paramater_name]', "Generate #{type} spec from paramater name."
45
+ define_method type do |_paramater_name|
46
+ Awsecrets.load(profile: options[:profile], region: options[:region], secrets_path: options[:secrets_path])
47
+ eval "puts Awspec::Generator::Spec::#{type.camelize}.new.generate_by_paramater_group(_paramater_name)"
48
+ end
49
+ end
50
+
39
51
  types_for_generate_all = %w(
40
52
  cloudwatch_alarm cloudwatch_event directconnect ebs efs
41
53
  elasticsearch iam_group iam_policy iam_role iam_user kms lambda
@@ -25,9 +25,12 @@ require 'awspec/generator/spec/iam_role'
25
25
  require 'awspec/generator/spec/acm'
26
26
  require 'awspec/generator/spec/cloudwatch_logs'
27
27
  require 'awspec/generator/spec/alb'
28
+ require 'awspec/generator/spec/nlb'
28
29
  require 'awspec/generator/spec/internet_gateway'
29
30
  require 'awspec/generator/spec/elasticsearch'
30
31
  require 'awspec/generator/spec/eip'
32
+ require 'awspec/generator/spec/rds_db_parameter_group'
33
+ require 'awspec/generator/spec/rds_db_cluster_parameter_group'
31
34
 
32
35
  # Doc
33
36
  require 'awspec/generator/doc/type'
@@ -0,0 +1,20 @@
1
+ module Awspec::Generator
2
+ module Doc
3
+ module Type
4
+ class Nlb < Base
5
+ def initialize
6
+ super
7
+ @type_name = 'NLB'
8
+ @type = Awspec::Type::Nlb.new('my-nlb')
9
+ @ret = @type.resource_via_client
10
+ @matchers = [
11
+ Awspec::Type::Nlb::STATES.map { |state| 'be_' + state }.join(', '),
12
+ 'belong_to_vpc'
13
+ ]
14
+ @ignore_matchers = Awspec::Type::Nlb::STATES.map { |state| 'be_' + state }
15
+ @describes = []
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module Awspec::Generator
2
+ module Doc
3
+ module Type
4
+ class NlbListener < Base
5
+ # rubocop:disable Metrics/LineLength
6
+ def initialize
7
+ super
8
+ @type_name = 'NlbListener'
9
+ @type = Awspec::Type::NlbListener.new('arn:aws:elasticloadbalancing:ap-northeast-1:1234567890:listener/app/my-nlb/1aa1bb1cc1ddee11/f2f7dc8efc522ab2')
10
+ @ret = @type.resource_via_client
11
+ @matchers = []
12
+ @ignore_matchers = []
13
+ @describes = []
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module Awspec::Generator
2
+ module Doc
3
+ module Type
4
+ class NlbTargetGroup < Base
5
+ def initialize
6
+ super
7
+ @type_name = 'NlbTargetGroup'
8
+ @type = Awspec::Type::NlbTargetGroup.new('my-nlb-target-group')
9
+ @ret = @type.resource_via_client
10
+ @matchers = %w(belong_to_nlb belong_to_vpc)
11
+ @ignore_matchers = []
12
+ @describes = []
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ module Awspec::Generator
2
+ module Spec
3
+ class Nlb
4
+ include Awspec::Helper::Finder
5
+ def generate_by_vpc_id(vpc_id)
6
+ describes = %w(
7
+ load_balancer_name
8
+ )
9
+ vpc = find_vpc(vpc_id)
10
+ raise 'Not Found VPC' unless vpc
11
+ @vpc_id = vpc[:vpc_id]
12
+ @vpc_tag_name = vpc.tag_name
13
+ nlbs = select_nlb_by_vpc_id(@vpc_id)
14
+
15
+ specs = nlbs.map do |nlb|
16
+ content = ERB.new(nlb_spec_template, nil, '-').result(binding).gsub(/^\n/, '')
17
+ end
18
+ specs.join("\n")
19
+ end
20
+
21
+ def nlb_spec_template
22
+ template = <<-'EOF'
23
+ describe nlb('<%= nlb.load_balancer_name %>') do
24
+ it { should exist }
25
+ its(:load_balancer_arn) { should eq '<%= nlb.load_balancer_arn %>' }
26
+ its(:dns_name) { should eq '<%= nlb.dns_name %>' }
27
+ its(:load_balancer_name) { should eq '<%= nlb.load_balancer_name %>' }
28
+ its(:scheme) { should eq '<%= nlb.scheme %>' }
29
+ its(:vpc_id) { should eq '<%= nlb.vpc_id %>' }
30
+ its(:type) { should eq '<%= nlb.type %>' }
31
+ its(:ip_address_type) { should eq '<%= nlb.ip_address_type %>' }
32
+ end
33
+ EOF
34
+ template
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module Awspec::Generator
2
+ module Spec
3
+ class RdsDbClusterParameterGroup
4
+ include Awspec::Helper::Finder
5
+ def generate_by_paramater_group(paramater_group)
6
+ @paramater_group = paramater_group
7
+ res = select_all_rds_db_cluster_parameters(@paramater_group)
8
+ ERB.new(db_cluster_parameter_group_template, nil, '-').result(binding).gsub(/^\n/, '')
9
+ end
10
+
11
+ def db_cluster_parameter_group_template
12
+ template = <<-'EOF'
13
+ describe rds_db_cluster_parameter_group('<%= @paramater_group %>') do
14
+ <% res.each do |key, value| %>
15
+ its('<%= key %>') { should eq '<%= value %>' }
16
+ <% end %>
17
+ end
18
+ EOF
19
+ template
20
+ end
21
+ end
22
+ end
23
+ end