Skip to content

Commit 4776dc5

Browse files
gazconroyGary ConroyGary Conroydylantientcheu
authored
fix: Editorial changes to the CLI docs (#173)
* fix: Algolia CLI editorial update * Ignore docs directory * Update pkg/cmd/crawler/reindex/reindex.go Co-authored-by: Dylan Tientcheu <[email protected]> * fix: tests --------- Co-authored-by: Gary Conroy <[email protected]> Co-authored-by: Gary Conroy <[email protected]> Co-authored-by: Dylan Tientcheu <[email protected]>
1 parent 087b7c6 commit 4776dc5

File tree

45 files changed

+257
-253
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+257
-253
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@
1616
vendor/
1717

1818
# local build
19-
algolia
19+
algolia
20+
21+
# Ignore docs directory
22+
docs/

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ VARIATION ?= old
1414
ifeq ($(VARIATION),old)
1515
DOCS_FOLDER = docs
1616
DOCS_GENERATED_PATH = app_data/cli/commands
17-
DOCS_REPO_URL = https://github.com/algolia/doc.git
17+
DOCS_REPO_URL = git@github.com:algolia/doc.git
1818
DOCS_BRANCH = master
1919
DOCS_EXTENSION = yml
2020
else ifeq ($(VARIATION),new)

pkg/cmd/apikeys/create/create.go

+23-24
Original file line numberDiff line numberDiff line change
@@ -61,42 +61,41 @@ func NewCreateCmd(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
6161
}
6262

6363
cmd.Flags().StringSliceVar(&opts.ACL, "acl", nil, heredoc.Docf(`
64-
ACL of the API Key.
65-
66-
%[1]ssearch%[1]s: allowed to perform search operations.
67-
%[1]sbrowse%[1]s: allowed to retrieve all index data with the browse endpoint.
68-
%[1]saddObject%[1]s: allowed to add or update a records in the index.
69-
%[1]sdeleteObject%[1]s: allowed to delete an existing record.
70-
%[1]slistIndexes%[1]s: allowed to get a list of all existing indices.
71-
%[1]sdeleteIndex%[1]s: allowed to delete an index.
72-
%[1]ssettings%[1]s: allowed to read all index settings.
73-
%[1]seditSettings%[1]s: allowed to update all index settings.
74-
%[1]sanalytics%[1]s: allowed to retrieve data with the Analytics API.
75-
%[1]srecommendation%[1]s: allowed to interact with the Recommendation API.
76-
%[1]susage%[1]s: allowed to retrieve data with the Usage API.
77-
%[1]slogs%[1]s: allowed to query the logs.
78-
%[1]sseeUnretrievableAttributes%[1]s: allowed to retrieve unretrievableAttributes for all operations that return records.
64+
API key's ACL.
65+
66+
%[1]ssearch%[1]s: can perform search operations.
67+
%[1]sbrowse%[1]s: can retrieve all index data with the browse endpoint.
68+
%[1]saddObject%[1]s: can add or update records in the index.
69+
%[1]sdeleteObject%[1]s: can delete an existing record.
70+
%[1]slistIndexes%[1]s: can get a list of all indices.
71+
%[1]sdeleteIndex%[1]s: can delete an index.
72+
%[1]ssettings%[1]s: can read all index settings.
73+
%[1]seditSettings%[1]s: can update all index settings.
74+
%[1]sanalytics%[1]s: can retrieve data with the Analytics API.
75+
%[1]srecommendation%[1]s: can interact with the Recommendation API.
76+
%[1]susage%[1]s: can retrieve data with the Usage API.
77+
%[1]slogs%[1]s: can query the logs.
78+
%[1]sseeUnretrievableAttributes%[1]s: can retrieve unretrievableAttributes for all operations that return records.
7979
`, "`"))
8080

8181
cmd.Flags().StringSliceVarP(&opts.Indices, "indices", "i", nil, heredoc.Docf(`
82-
Specify the list of targeted indices.
83-
You can target all indices starting with a prefix or ending with a suffix using the %[1]s*%[1]s character.
84-
For example, %[1]sdev_*%[1]s matches all indices starting with %[1]sdev_%[1]s and %[1]s*_dev%[1]s matches all indices ending with %[1]s_dev%[1]s.
82+
Index names or patterns that this API key can access. By default, an API key can access all indices in the same application.
83+
84+
You can use leading and trailing wildcard characters (%[1]s*%[1]s).
85+
For example, %[1]sdev_*%[1]s matches all indices starting with %[1]sdev_%[1]s. %[1]s*_dev%[1]s matches all indices ending with %[1]s_dev%[1]s. %[1]s*_products_*%[1]s matches all indices containing %[1]sproducts%[1]s.
8586
`, "`"))
8687

8788
cmd.Flags().DurationVarP(&opts.Validity, "validity", "u", 0, heredoc.Doc(`
88-
How long this API key is valid, in seconds.
89-
A value of 0 means the API key doesn’t expire.`,
89+
Duration (in seconds) after which the API key expires. By default (a value of 0), API keys don't expire.`,
9090
))
9191

9292
cmd.Flags().StringSliceVarP(&opts.Referers, "referers", "r", nil, heredoc.Docf(`
9393
Specify the list of referrers that can perform an operation.
94-
You can use the %[1]s*%[1]s (asterisk) character as a wildcard to match subdomains, or all pages of a website.
94+
You can use the wildcard character (%[1]s*%[1]s) to match subdomains or entire websites.
9595
`, "`"))
9696

9797
cmd.Flags().StringVarP(&opts.Description, "description", "d", "", heredoc.Doc(`
98-
Specify a description of the API key.
99-
Used for informative purposes only. It has no impact on the functionality of the API key.`,
98+
Describe an API key to help you identify its uses.`,
10099
))
101100

102101
_ = cmd.RegisterFlagCompletionFunc("indices", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
@@ -130,7 +129,7 @@ func NewCreateCmd(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
130129
"usage": "retrieve data with the Usage API",
131130
"logs": "query the logs",
132131
"seeUnretrievableAttributes": "retrieve unretrievableAttributes for all operations that return records",
133-
}, "allowed to"))
132+
}, "can"))
134133

135134
return cmd
136135
}

pkg/cmd/apikeys/delete/delete.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func NewDeleteCmd(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
3636

3737
cmd := &cobra.Command{
3838
Use: "delete <api-key>",
39-
Short: "Delete API key",
39+
Short: "Deletes the API key",
4040
Args: validators.ExactArgs(1),
4141
Annotations: map[string]string{
4242
"acls": "admin",
@@ -58,7 +58,7 @@ func NewDeleteCmd(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
5858
},
5959
}
6060

61-
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "skip confirmation prompt")
61+
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "Skip the delete API key confirmation prompt")
6262

6363
return cmd
6464
}

pkg/cmd/apikeys/get/get.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func NewGetCmd(f *cmdutil.Factory, runF func(*GetOptions) error) *cobra.Command
3737

3838
cmd := &cobra.Command{
3939
Use: "get <api-key>",
40-
Short: "Get API key",
40+
Short: "Get the API key",
4141
Long: heredoc.Doc(`
4242
Get the details of a given API Key (ACLs, description, indexes, and other attributes).
4343
`),

pkg/cmd/apikeys/list/list.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func NewListCmd(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
4040
Annotations: map[string]string{
4141
"acls": "admin",
4242
},
43-
Short: "List API keys",
43+
Short: "Lists all API keys associated with your Algolia application, including their permissions and restrictions.",
4444
RunE: func(cmd *cobra.Command, args []string) error {
4545
if runF != nil {
4646
return runF(opts)

pkg/cmd/crawler/crawl/crawl.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func NewCrawlCmd(f *cmdutil.Factory, runF func(*CrawlOptions) error) *cobra.Comm
3939
ValidArgsFunction: cmdutil.CrawlerIDs(opts.CrawlerClient),
4040
Short: "Crawl specific URLs",
4141
Long: heredoc.Doc(`
42-
Immediately crawl the given URLs.
42+
Immediately crawl these URLs.
4343
The generated records are pushed to the live index if there's no ongoing reindex, and to the temporary index otherwise.
4444
`),
4545
Example: heredoc.Doc(`
@@ -71,9 +71,9 @@ func NewCrawlCmd(f *cmdutil.Factory, runF func(*CrawlOptions) error) *cobra.Comm
7171
_ = cmd.MarkFlagRequired("urls")
7272

7373
cmd.Flags().BoolVarP(&opts.Save, "save", "s", false, heredoc.Doc(`
74-
When true, the given URLs are added to the extraUrls list of your configuration (unless already present in startUrls or sitemaps).
75-
When false, the URLs aren't saved in the configuration.
76-
When unspecified, the URLs are added to the extraUrls list of your configuration, but only if they haven't been indexed during the last reindex, and they aren't already present in startUrls or sitemaps.
74+
When true, the URLs are added to your %[1]sextraUrls%[1]s (unless present in %[1]sstartUrls%[1]s or %[1]ssitemaps%[1]s).
75+
When false, the URLs aren't added.
76+
When unspecified, the URLs are added to your %[1]sextraUrls%[1]s (unless present in %[1]sstartUrls%[1]s or %[1]ssitemaps%[1]s or they weren't indexed during the preceding reindex).
7777
`))
7878

7979
return cmd

pkg/cmd/crawler/pause/pause.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func NewPauseCmd(f *cmdutil.Factory, runF func(*PauseOptions) error) *cobra.Comm
3535
ValidArgsFunction: cmdutil.CrawlerIDs(opts.CrawlerClient),
3636
Short: "Pause one or multiple crawlers",
3737
Long: heredoc.Doc(`
38-
Request the specified crawler to pause its execution.
38+
Pauses the specified crawler.
3939
`),
4040
Example: heredoc.Doc(`
4141
# Pause the crawler with the ID "my-crawler"

pkg/cmd/crawler/reindex/reindex.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewReindexCmd(f *cmdutil.Factory, runF func(*ReindexOptions) error) *cobra.
3333
Use: "reindex <crawler_id>...",
3434
Args: cobra.MinimumNArgs(1),
3535
ValidArgsFunction: cmdutil.CrawlerIDs(opts.CrawlerClient),
36-
Short: "Reindex one or multiple crawlers",
36+
Short: "Reindexes the specified crawlers",
3737
Long: heredoc.Doc(`
3838
Request the specified crawler to start (or restart) crawling.
3939
`),

pkg/cmd/crawler/run/run.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ func NewRunCmd(f *cmdutil.Factory, runF func(*RunOptions) error) *cobra.Command
3333
Use: "run <crawler_id>",
3434
Args: cobra.ExactArgs(1),
3535
ValidArgsFunction: cmdutil.CrawlerIDs(opts.CrawlerClient),
36-
Short: "Run a crawler",
36+
Short: "Start or resume a crawler",
3737
Long: heredoc.Doc(`
38-
Unpause the specified crawler. If a crawl was previously ongoing, it will be resumed.
39-
Otherwise, the crawler will go into the active state and wait for the next schedule.
38+
Unpause the specified crawler.
39+
Previously ongoing crawls will be resumed. Otherwise, the crawler waits for its next scheduled run.
4040
`),
4141
Example: heredoc.Doc(`
4242
# Run the crawler with the ID "my-crawler"

pkg/cmd/crawler/test/test.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,9 @@ func NewTestCmd(f *cmdutil.Factory, runF func(*TestOptions) error) *cobra.Comman
4242
Use: "test <crawler_id> --url <url> [-F <file>]",
4343
Args: cobra.ExactArgs(1),
4444
ValidArgsFunction: cmdutil.CrawlerIDs(opts.CrawlerClient),
45-
Short: "Test a URL on a crawler",
45+
Short: "Tests a URL with the crawler's configuration and shows the extracted records.",
4646
Long: heredoc.Doc(`
47-
Test an URL against the given crawler's configuration and see what will be processed.
48-
You can also override parts of the configuration to try your changes before updating the configuration.
47+
You can override parts of the configuration to test your changes before updating the configuration.
4948
`),
5049
Example: heredoc.Doc(`
5150
# Test the URL "https://www.example.com" against the crawler with the ID "my-crawler"

pkg/cmd/dictionary/entries/browse/browse.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type BrowseOptions struct {
2828
PrintFlags *cmdutil.PrintFlags
2929
}
3030

31-
// DictionaryEntry can be plural, compound or stopword entry.
31+
// DictionaryEntry can be plural, compound, or stop word entry.
3232
type DictionaryEntry struct {
3333
Type shared.EntryType
3434
Word string `json:"word,omitempty"`
@@ -63,7 +63,7 @@ func NewBrowseCmd(f *cmdutil.Factory, runF func(*BrowseOptions) error) *cobra.Co
6363
This command retrieves all entries from the specified %s dictionaries.
6464
`, cs.Bold("custom")),
6565
Example: heredoc.Doc(`
66-
# Retrieve all entries from the "stopwords" dictionary (doesn't include default stopwords)
66+
# Retrieve all entries from the "stopwords" dictionary (not including the Algolia default stop words)
6767
$ algolia dictionary entries browse stopwords
6868
6969
# Retrieve all entries from the "stopwords" and "plurals" dictionaries
@@ -72,7 +72,7 @@ func NewBrowseCmd(f *cmdutil.Factory, runF func(*BrowseOptions) error) *cobra.Co
7272
# Retrieve all entries from all dictionaries
7373
$ algolia dictionary entries browse --all
7474
75-
# Retrieve all entries from the "stopwords" dictionaries (including default stopwords)
75+
# Retrieve all entries from the "stopwords" dictionaries (including the Algolia default stop words)
7676
$ algolia dictionary entries browse stopwords --include-defaults
7777
`),
7878
RunE: func(cmd *cobra.Command, args []string) error {
@@ -120,7 +120,7 @@ func runBrowseCmd(opts *BrowseOptions) error {
120120
pageCount := 0
121121
maxPages := 1
122122

123-
// implement infinite pagination
123+
// Infinite pagination
124124
for pageCount < maxPages {
125125
res, err := client.SearchDictionaryEntries(dictionary, "", opt.HitsPerPage(1000), opt.Page(pageCount))
126126
if err != nil {
@@ -131,13 +131,13 @@ func runBrowseCmd(opts *BrowseOptions) error {
131131

132132
data, err := json.Marshal(res.Hits)
133133
if err != nil {
134-
return fmt.Errorf("cannot unmarshal dictionary entries: error while marshalling original dictionary entries: %v", err)
134+
return fmt.Errorf("can't unmarshal dictionary entries: error while marshalling original dictionary entries: %v", err)
135135
}
136136

137137
var entries []DictionaryEntry
138138
err = json.Unmarshal(data, &entries)
139139
if err != nil {
140-
return fmt.Errorf("cannot unmarshal dictionary entries: error while unmarshalling original dictionary entries: %v", err)
140+
return fmt.Errorf("can't unmarshal dictionary entries: error while unmarshalling original dictionary entries: %v", err)
141141
}
142142

143143
if len(entries) != 0 {
@@ -146,12 +146,12 @@ func runBrowseCmd(opts *BrowseOptions) error {
146146

147147
for _, entry := range entries {
148148
if opts.IncludeDefaultStopwords {
149-
// print all entries (default stopwords included)
149+
// Print all entries (inlcuding the default Algolia stop words)
150150
if err = p.Print(opts.IO, entry); err != nil {
151151
return err
152152
}
153153
} else if entry.Type == shared.CustomEntryType {
154-
// print only custom entries
154+
// Print only custom entries
155155
if err = p.Print(opts.IO, entry); err != nil {
156156
return err
157157
}
@@ -161,12 +161,12 @@ func runBrowseCmd(opts *BrowseOptions) error {
161161
pageCount++
162162
}
163163

164-
// in case no entry is found in all the dictionaries
164+
// If no entry is found in all the dictionaries
165165
if hasNoEntries {
166166
if _, err = fmt.Fprintf(opts.IO.Out, "%s No entries found.\n\n", cs.WarningIcon()); err != nil {
167167
return err
168168
}
169-
// go to the next dictionary
169+
// Go to the next dictionary
170170
break
171171
}
172172
}

pkg/cmd/dictionary/entries/clear/clear.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ func NewClearCmd(f *cmdutil.Factory, runF func(*ClearOptions) error) *cobra.Comm
9797
},
9898
}
9999

100-
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "skip confirmation prompt")
101-
cmd.Flags().BoolVarP(&opts.All, "all", "a", false, "clear all dictionaries")
100+
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "Skip the clear dictionary entry confirmation prompt")
101+
cmd.Flags().BoolVarP(&opts.All, "all", "a", false, "Clear all dictionaries")
102102

103103
return cmd
104104
}

pkg/cmd/dictionary/entries/delete/delete.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func NewDeleteCmd(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
7878
cmd.Flags().StringSliceVarP(&opts.ObjectIDs, "object-ids", "", nil, "Object IDs to delete")
7979
_ = cmd.MarkFlagRequired("object-ids")
8080

81-
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "skip confirmation prompt")
81+
cmd.Flags().BoolVarP(&confirm, "confirm", "y", false, "Skip the delete dictionary entry confirmation prompt")
8282

8383
return cmd
8484
}

pkg/cmd/dictionary/entries/entries.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
"github.com/algolia/cli/pkg/cmdutil"
1111
)
1212

13-
// NewEntriesCmd returns a new command for dictionaries' entries.
13+
// NewEntriesCmd returns a new command for dictionary entries.
1414
func NewEntriesCmd(f *cmdutil.Factory) *cobra.Command {
1515
cmd := &cobra.Command{
1616
Use: "entries",
17-
Short: "Manage your Algolia dictionaries entries",
17+
Short: "Manage your Algolia dictionary entries",
1818
}
1919

2020
cmd.AddCommand(clear.NewClearCmd(f, nil))

pkg/cmd/dictionary/entries/import/import.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ func NewImportCmd(f *cmdutil.Factory, runF func(*ImportOptions) error) *cobra.Co
6060
The file must contains one single JSON object per line (newline delimited JSON objects - ndjson format: https://ndjson.org/).
6161
`),
6262
Example: heredoc.Doc(`
63-
# Import entries from the "entries.ndjson" file to "stopwords" dictionary
63+
# Import entries from the "entries.ndjson" file to the "stopwords" dictionary
6464
$ algolia dictionary import stopwords -F entries.ndjson
6565
66-
# Import entries from the "entries.ndjson" file to "plurals" dictionary and continue importing entries even if some entries are invalid
66+
# Import entries from the "entries.ndjson" file to the "plurals" dictionary and continue importing entries even if some entries are invalid
6767
$ algolia dictionary import plurals -F entries.ndjson --continue-on-errors
6868
`),
6969
RunE: func(cmd *cobra.Command, args []string) error {

pkg/cmd/dictionary/settings/set/set.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@ func NewSetCmd(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
4141
Long: heredoc.Doc(`
4242
Set the dictionary settings.
4343
44-
For now, the only setting available is to enable/disable the standard entries for the stopwords dictionary.
44+
You can turn the standard stop words dictionary on or off.
4545
`),
4646
Example: heredoc.Doc(`
47-
# Disable standard entries for English and French
47+
# Tuen off standard entries for English and French
4848
$ algolia dictionary settings set --disable-standard-entries en,fr
4949
50-
# Enable standard entries for English and French languages
50+
# Enable standard entries for English and French
5151
$ algolia dictionary settings set --enable-standard-entries en,fr
5252
53-
# Disable standard entries for English and French languages and enable standard entries for Spanish language.
53+
# Turn off standard entries for English and French and enable standard entries for Spanish.
5454
$ algolia dictionary settings set --disable-standard-entries en,fr --enable-standard-entries es
5555
5656
# Reset standard entries to their default values
@@ -62,12 +62,12 @@ func NewSetCmd(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
6262
return cmdutil.FlagErrorf("Either --disable-standard-entries and/or --enable-standard-entries or --reset-standard-entries must be set")
6363
}
6464

65-
// Check that the user is not resetting standard entries and trying to disable or enable standard entries at the same time
65+
// Check that the user isn't resetting standard entries and trying to turn standard entries on or off at the same time
6666
if opts.ResetStandardEntries && (len(opts.DisableStandardEntries) > 0 || len(opts.EnableStandardEntries) > 0) {
6767
return cmdutil.FlagErrorf("You cannot reset standard entries and disable or enable standard entries at the same time")
6868
}
6969

70-
// Check if the user is trying to disable and enable standard entries for the same languages at the same time
70+
// Check if the user is trying to turn standard entries on or off for the same languages at the same time
7171
for _, disableLanguage := range opts.DisableStandardEntries {
7272
for _, enableLanguage := range opts.EnableStandardEntries {
7373
if disableLanguage == enableLanguage {
@@ -84,8 +84,8 @@ func NewSetCmd(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
8484
},
8585
}
8686

87-
cmd.Flags().StringSliceVarP(&opts.DisableStandardEntries, "disable-standard-entries", "d", []string{}, "Disable standard entries for the given languages")
88-
cmd.Flags().StringSliceVarP(&opts.EnableStandardEntries, "enable-standard-entries", "e", []string{}, "Enable standard entries for the given languages")
87+
cmd.Flags().StringSliceVarP(&opts.DisableStandardEntries, "disable-standard-entries", "d", []string{}, "Turn off standard entries for these languages")
88+
cmd.Flags().StringSliceVarP(&opts.EnableStandardEntries, "enable-standard-entries", "e", []string{}, "Turn on standard entries for these languages")
8989
cmd.Flags().BoolVarP(&opts.ResetStandardEntries, "reset-standard-entries", "r", false, "Reset standard entries to their default values")
9090

9191
SupportedLanguages := make(map[string]string, len(LanguagesWithStopwordsSupport))

pkg/cmd/dictionary/settings/settings.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
func NewSettingsCmd(f *cmdutil.Factory) *cobra.Command {
1313
cmd := &cobra.Command{
1414
Use: "settings",
15-
Short: "Manage your Algolia dictionaries settings",
15+
Short: "Manage your Algolia dictionary settings",
1616
}
1717

1818
cmd.AddCommand(set.NewSetCmd(f, nil))

0 commit comments

Comments
 (0)