aws_sdk_iot/operation/create_job/
builders.rs

1// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
2pub use crate::operation::create_job::_create_job_output::CreateJobOutputBuilder;
3
4pub use crate::operation::create_job::_create_job_input::CreateJobInputBuilder;
5
6impl crate::operation::create_job::builders::CreateJobInputBuilder {
7    /// Sends a request with this input using the given client.
8    pub async fn send_with(
9        self,
10        client: &crate::Client,
11    ) -> ::std::result::Result<
12        crate::operation::create_job::CreateJobOutput,
13        ::aws_smithy_runtime_api::client::result::SdkError<
14            crate::operation::create_job::CreateJobError,
15            ::aws_smithy_runtime_api::client::orchestrator::HttpResponse,
16        >,
17    > {
18        let mut fluent_builder = client.create_job();
19        fluent_builder.inner = self;
20        fluent_builder.send().await
21    }
22}
23/// Fluent builder constructing a request to `CreateJob`.
24///
25/// <p>Creates a job.</p>
26/// <p>Requires permission to access the <a href="https://docs.aws.amazon.com/service-authorization/latest/reference/list_awsiot.html#awsiot-actions-as-permissions">CreateJob</a> action.</p>
27#[derive(::std::clone::Clone, ::std::fmt::Debug)]
28pub struct CreateJobFluentBuilder {
29    handle: ::std::sync::Arc<crate::client::Handle>,
30    inner: crate::operation::create_job::builders::CreateJobInputBuilder,
31    config_override: ::std::option::Option<crate::config::Builder>,
32}
33impl crate::client::customize::internal::CustomizableSend<crate::operation::create_job::CreateJobOutput, crate::operation::create_job::CreateJobError>
34    for CreateJobFluentBuilder
35{
36    fn send(
37        self,
38        config_override: crate::config::Builder,
39    ) -> crate::client::customize::internal::BoxFuture<
40        crate::client::customize::internal::SendResult<crate::operation::create_job::CreateJobOutput, crate::operation::create_job::CreateJobError>,
41    > {
42        ::std::boxed::Box::pin(async move { self.config_override(config_override).send().await })
43    }
44}
45impl CreateJobFluentBuilder {
46    /// Creates a new `CreateJobFluentBuilder`.
47    pub(crate) fn new(handle: ::std::sync::Arc<crate::client::Handle>) -> Self {
48        Self {
49            handle,
50            inner: ::std::default::Default::default(),
51            config_override: ::std::option::Option::None,
52        }
53    }
54    /// Access the CreateJob as a reference.
55    pub fn as_input(&self) -> &crate::operation::create_job::builders::CreateJobInputBuilder {
56        &self.inner
57    }
58    /// Sends the request and returns the response.
59    ///
60    /// If an error occurs, an `SdkError` will be returned with additional details that
61    /// can be matched against.
62    ///
63    /// By default, any retryable failures will be retried twice. Retry behavior
64    /// is configurable with the [RetryConfig](aws_smithy_types::retry::RetryConfig), which can be
65    /// set when configuring the client.
66    pub async fn send(
67        self,
68    ) -> ::std::result::Result<
69        crate::operation::create_job::CreateJobOutput,
70        ::aws_smithy_runtime_api::client::result::SdkError<
71            crate::operation::create_job::CreateJobError,
72            ::aws_smithy_runtime_api::client::orchestrator::HttpResponse,
73        >,
74    > {
75        let input = self
76            .inner
77            .build()
78            .map_err(::aws_smithy_runtime_api::client::result::SdkError::construction_failure)?;
79        let runtime_plugins = crate::operation::create_job::CreateJob::operation_runtime_plugins(
80            self.handle.runtime_plugins.clone(),
81            &self.handle.conf,
82            self.config_override,
83        );
84        crate::operation::create_job::CreateJob::orchestrate(&runtime_plugins, input).await
85    }
86
87    /// Consumes this builder, creating a customizable operation that can be modified before being sent.
88    pub fn customize(
89        self,
90    ) -> crate::client::customize::CustomizableOperation<
91        crate::operation::create_job::CreateJobOutput,
92        crate::operation::create_job::CreateJobError,
93        Self,
94    > {
95        crate::client::customize::CustomizableOperation::new(self)
96    }
97    pub(crate) fn config_override(mut self, config_override: impl ::std::convert::Into<crate::config::Builder>) -> Self {
98        self.set_config_override(::std::option::Option::Some(config_override.into()));
99        self
100    }
101
102    pub(crate) fn set_config_override(&mut self, config_override: ::std::option::Option<crate::config::Builder>) -> &mut Self {
103        self.config_override = config_override;
104        self
105    }
106    /// <p>A job identifier which must be unique for your account. We recommend using a UUID. Alpha-numeric characters, "-" and "_" are valid for use here.</p>
107    pub fn job_id(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
108        self.inner = self.inner.job_id(input.into());
109        self
110    }
111    /// <p>A job identifier which must be unique for your account. We recommend using a UUID. Alpha-numeric characters, "-" and "_" are valid for use here.</p>
112    pub fn set_job_id(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
113        self.inner = self.inner.set_job_id(input);
114        self
115    }
116    /// <p>A job identifier which must be unique for your account. We recommend using a UUID. Alpha-numeric characters, "-" and "_" are valid for use here.</p>
117    pub fn get_job_id(&self) -> &::std::option::Option<::std::string::String> {
118        self.inner.get_job_id()
119    }
120    ///
121    /// Appends an item to `targets`.
122    ///
123    /// To override the contents of this collection use [`set_targets`](Self::set_targets).
124    ///
125    /// <p>A list of things and thing groups to which the job should be sent.</p>
126    pub fn targets(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
127        self.inner = self.inner.targets(input.into());
128        self
129    }
130    /// <p>A list of things and thing groups to which the job should be sent.</p>
131    pub fn set_targets(mut self, input: ::std::option::Option<::std::vec::Vec<::std::string::String>>) -> Self {
132        self.inner = self.inner.set_targets(input);
133        self
134    }
135    /// <p>A list of things and thing groups to which the job should be sent.</p>
136    pub fn get_targets(&self) -> &::std::option::Option<::std::vec::Vec<::std::string::String>> {
137        self.inner.get_targets()
138    }
139    /// <p>An S3 link, or S3 object URL, to the job document. The link is an Amazon S3 object URL and is required if you don't specify a value for <code>document</code>.</p>
140    /// <p>For example, <code>--document-source https://s3.<i>region-code</i>.amazonaws.com/example-firmware/device-firmware.1.0</code></p>
141    /// <p>For more information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html">Methods for accessing a bucket</a>.</p>
142    pub fn document_source(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
143        self.inner = self.inner.document_source(input.into());
144        self
145    }
146    /// <p>An S3 link, or S3 object URL, to the job document. The link is an Amazon S3 object URL and is required if you don't specify a value for <code>document</code>.</p>
147    /// <p>For example, <code>--document-source https://s3.<i>region-code</i>.amazonaws.com/example-firmware/device-firmware.1.0</code></p>
148    /// <p>For more information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html">Methods for accessing a bucket</a>.</p>
149    pub fn set_document_source(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
150        self.inner = self.inner.set_document_source(input);
151        self
152    }
153    /// <p>An S3 link, or S3 object URL, to the job document. The link is an Amazon S3 object URL and is required if you don't specify a value for <code>document</code>.</p>
154    /// <p>For example, <code>--document-source https://s3.<i>region-code</i>.amazonaws.com/example-firmware/device-firmware.1.0</code></p>
155    /// <p>For more information, see <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html">Methods for accessing a bucket</a>.</p>
156    pub fn get_document_source(&self) -> &::std::option::Option<::std::string::String> {
157        self.inner.get_document_source()
158    }
159    /// <p>The job document. Required if you don't specify a value for <code>documentSource</code>.</p>
160    pub fn document(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
161        self.inner = self.inner.document(input.into());
162        self
163    }
164    /// <p>The job document. Required if you don't specify a value for <code>documentSource</code>.</p>
165    pub fn set_document(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
166        self.inner = self.inner.set_document(input);
167        self
168    }
169    /// <p>The job document. Required if you don't specify a value for <code>documentSource</code>.</p>
170    pub fn get_document(&self) -> &::std::option::Option<::std::string::String> {
171        self.inner.get_document()
172    }
173    /// <p>A short text description of the job.</p>
174    pub fn description(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
175        self.inner = self.inner.description(input.into());
176        self
177    }
178    /// <p>A short text description of the job.</p>
179    pub fn set_description(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
180        self.inner = self.inner.set_description(input);
181        self
182    }
183    /// <p>A short text description of the job.</p>
184    pub fn get_description(&self) -> &::std::option::Option<::std::string::String> {
185        self.inner.get_description()
186    }
187    /// <p>Configuration information for pre-signed S3 URLs.</p>
188    pub fn presigned_url_config(mut self, input: crate::types::PresignedUrlConfig) -> Self {
189        self.inner = self.inner.presigned_url_config(input);
190        self
191    }
192    /// <p>Configuration information for pre-signed S3 URLs.</p>
193    pub fn set_presigned_url_config(mut self, input: ::std::option::Option<crate::types::PresignedUrlConfig>) -> Self {
194        self.inner = self.inner.set_presigned_url_config(input);
195        self
196    }
197    /// <p>Configuration information for pre-signed S3 URLs.</p>
198    pub fn get_presigned_url_config(&self) -> &::std::option::Option<crate::types::PresignedUrlConfig> {
199        self.inner.get_presigned_url_config()
200    }
201    /// <p>Specifies whether the job will continue to run (CONTINUOUS), or will be complete after all those things specified as targets have completed the job (SNAPSHOT). If continuous, the job may also be run on a thing when a change is detected in a target. For example, a job will run on a thing when the thing is added to a target group, even after the job was completed by all things originally in the group.</p><note>
202    /// <p>We recommend that you use continuous jobs instead of snapshot jobs for dynamic thing group targets. By using continuous jobs, devices that join the group receive the job execution even after the job has been created.</p>
203    /// </note>
204    pub fn target_selection(mut self, input: crate::types::TargetSelection) -> Self {
205        self.inner = self.inner.target_selection(input);
206        self
207    }
208    /// <p>Specifies whether the job will continue to run (CONTINUOUS), or will be complete after all those things specified as targets have completed the job (SNAPSHOT). If continuous, the job may also be run on a thing when a change is detected in a target. For example, a job will run on a thing when the thing is added to a target group, even after the job was completed by all things originally in the group.</p><note>
209    /// <p>We recommend that you use continuous jobs instead of snapshot jobs for dynamic thing group targets. By using continuous jobs, devices that join the group receive the job execution even after the job has been created.</p>
210    /// </note>
211    pub fn set_target_selection(mut self, input: ::std::option::Option<crate::types::TargetSelection>) -> Self {
212        self.inner = self.inner.set_target_selection(input);
213        self
214    }
215    /// <p>Specifies whether the job will continue to run (CONTINUOUS), or will be complete after all those things specified as targets have completed the job (SNAPSHOT). If continuous, the job may also be run on a thing when a change is detected in a target. For example, a job will run on a thing when the thing is added to a target group, even after the job was completed by all things originally in the group.</p><note>
216    /// <p>We recommend that you use continuous jobs instead of snapshot jobs for dynamic thing group targets. By using continuous jobs, devices that join the group receive the job execution even after the job has been created.</p>
217    /// </note>
218    pub fn get_target_selection(&self) -> &::std::option::Option<crate::types::TargetSelection> {
219        self.inner.get_target_selection()
220    }
221    /// <p>Allows you to create a staged rollout of the job.</p>
222    pub fn job_executions_rollout_config(mut self, input: crate::types::JobExecutionsRolloutConfig) -> Self {
223        self.inner = self.inner.job_executions_rollout_config(input);
224        self
225    }
226    /// <p>Allows you to create a staged rollout of the job.</p>
227    pub fn set_job_executions_rollout_config(mut self, input: ::std::option::Option<crate::types::JobExecutionsRolloutConfig>) -> Self {
228        self.inner = self.inner.set_job_executions_rollout_config(input);
229        self
230    }
231    /// <p>Allows you to create a staged rollout of the job.</p>
232    pub fn get_job_executions_rollout_config(&self) -> &::std::option::Option<crate::types::JobExecutionsRolloutConfig> {
233        self.inner.get_job_executions_rollout_config()
234    }
235    /// <p>Allows you to create the criteria to abort a job.</p>
236    pub fn abort_config(mut self, input: crate::types::AbortConfig) -> Self {
237        self.inner = self.inner.abort_config(input);
238        self
239    }
240    /// <p>Allows you to create the criteria to abort a job.</p>
241    pub fn set_abort_config(mut self, input: ::std::option::Option<crate::types::AbortConfig>) -> Self {
242        self.inner = self.inner.set_abort_config(input);
243        self
244    }
245    /// <p>Allows you to create the criteria to abort a job.</p>
246    pub fn get_abort_config(&self) -> &::std::option::Option<crate::types::AbortConfig> {
247        self.inner.get_abort_config()
248    }
249    /// <p>Specifies the amount of time each device has to finish its execution of the job. The timer is started when the job execution status is set to <code>IN_PROGRESS</code>. If the job execution status is not set to another terminal state before the time expires, it will be automatically set to <code>TIMED_OUT</code>.</p>
250    pub fn timeout_config(mut self, input: crate::types::TimeoutConfig) -> Self {
251        self.inner = self.inner.timeout_config(input);
252        self
253    }
254    /// <p>Specifies the amount of time each device has to finish its execution of the job. The timer is started when the job execution status is set to <code>IN_PROGRESS</code>. If the job execution status is not set to another terminal state before the time expires, it will be automatically set to <code>TIMED_OUT</code>.</p>
255    pub fn set_timeout_config(mut self, input: ::std::option::Option<crate::types::TimeoutConfig>) -> Self {
256        self.inner = self.inner.set_timeout_config(input);
257        self
258    }
259    /// <p>Specifies the amount of time each device has to finish its execution of the job. The timer is started when the job execution status is set to <code>IN_PROGRESS</code>. If the job execution status is not set to another terminal state before the time expires, it will be automatically set to <code>TIMED_OUT</code>.</p>
260    pub fn get_timeout_config(&self) -> &::std::option::Option<crate::types::TimeoutConfig> {
261        self.inner.get_timeout_config()
262    }
263    ///
264    /// Appends an item to `tags`.
265    ///
266    /// To override the contents of this collection use [`set_tags`](Self::set_tags).
267    ///
268    /// <p>Metadata which can be used to manage the job.</p>
269    pub fn tags(mut self, input: crate::types::Tag) -> Self {
270        self.inner = self.inner.tags(input);
271        self
272    }
273    /// <p>Metadata which can be used to manage the job.</p>
274    pub fn set_tags(mut self, input: ::std::option::Option<::std::vec::Vec<crate::types::Tag>>) -> Self {
275        self.inner = self.inner.set_tags(input);
276        self
277    }
278    /// <p>Metadata which can be used to manage the job.</p>
279    pub fn get_tags(&self) -> &::std::option::Option<::std::vec::Vec<crate::types::Tag>> {
280        self.inner.get_tags()
281    }
282    /// <p>The namespace used to indicate that a job is a customer-managed job.</p>
283    /// <p>When you specify a value for this parameter, Amazon Web Services IoT Core sends jobs notifications to MQTT topics that contain the value in the following format.</p>
284    /// <p><code>$aws/things/<i>THING_NAME</i>/jobs/<i>JOB_ID</i>/notify-namespace-<i>NAMESPACE_ID</i>/</code></p><note>
285    /// <p>The <code>namespaceId</code> feature is only supported by IoT Greengrass at this time. For more information, see <a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/setting-up.html">Setting up IoT Greengrass core devices.</a></p>
286    /// </note>
287    pub fn namespace_id(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
288        self.inner = self.inner.namespace_id(input.into());
289        self
290    }
291    /// <p>The namespace used to indicate that a job is a customer-managed job.</p>
292    /// <p>When you specify a value for this parameter, Amazon Web Services IoT Core sends jobs notifications to MQTT topics that contain the value in the following format.</p>
293    /// <p><code>$aws/things/<i>THING_NAME</i>/jobs/<i>JOB_ID</i>/notify-namespace-<i>NAMESPACE_ID</i>/</code></p><note>
294    /// <p>The <code>namespaceId</code> feature is only supported by IoT Greengrass at this time. For more information, see <a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/setting-up.html">Setting up IoT Greengrass core devices.</a></p>
295    /// </note>
296    pub fn set_namespace_id(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
297        self.inner = self.inner.set_namespace_id(input);
298        self
299    }
300    /// <p>The namespace used to indicate that a job is a customer-managed job.</p>
301    /// <p>When you specify a value for this parameter, Amazon Web Services IoT Core sends jobs notifications to MQTT topics that contain the value in the following format.</p>
302    /// <p><code>$aws/things/<i>THING_NAME</i>/jobs/<i>JOB_ID</i>/notify-namespace-<i>NAMESPACE_ID</i>/</code></p><note>
303    /// <p>The <code>namespaceId</code> feature is only supported by IoT Greengrass at this time. For more information, see <a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/setting-up.html">Setting up IoT Greengrass core devices.</a></p>
304    /// </note>
305    pub fn get_namespace_id(&self) -> &::std::option::Option<::std::string::String> {
306        self.inner.get_namespace_id()
307    }
308    /// <p>The ARN of the job template used to create the job.</p>
309    pub fn job_template_arn(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
310        self.inner = self.inner.job_template_arn(input.into());
311        self
312    }
313    /// <p>The ARN of the job template used to create the job.</p>
314    pub fn set_job_template_arn(mut self, input: ::std::option::Option<::std::string::String>) -> Self {
315        self.inner = self.inner.set_job_template_arn(input);
316        self
317    }
318    /// <p>The ARN of the job template used to create the job.</p>
319    pub fn get_job_template_arn(&self) -> &::std::option::Option<::std::string::String> {
320        self.inner.get_job_template_arn()
321    }
322    /// <p>Allows you to create the criteria to retry a job.</p>
323    pub fn job_executions_retry_config(mut self, input: crate::types::JobExecutionsRetryConfig) -> Self {
324        self.inner = self.inner.job_executions_retry_config(input);
325        self
326    }
327    /// <p>Allows you to create the criteria to retry a job.</p>
328    pub fn set_job_executions_retry_config(mut self, input: ::std::option::Option<crate::types::JobExecutionsRetryConfig>) -> Self {
329        self.inner = self.inner.set_job_executions_retry_config(input);
330        self
331    }
332    /// <p>Allows you to create the criteria to retry a job.</p>
333    pub fn get_job_executions_retry_config(&self) -> &::std::option::Option<crate::types::JobExecutionsRetryConfig> {
334        self.inner.get_job_executions_retry_config()
335    }
336    ///
337    /// Adds a key-value pair to `documentParameters`.
338    ///
339    /// To override the contents of this collection use [`set_document_parameters`](Self::set_document_parameters).
340    ///
341    /// <p>Parameters of an Amazon Web Services managed template that you can specify to create the job document.</p><note>
342    /// <p><code>documentParameters</code> can only be used when creating jobs from Amazon Web Services managed templates. This parameter can't be used with custom job templates or to create jobs from them.</p>
343    /// </note>
344    pub fn document_parameters(
345        mut self,
346        k: impl ::std::convert::Into<::std::string::String>,
347        v: impl ::std::convert::Into<::std::string::String>,
348    ) -> Self {
349        self.inner = self.inner.document_parameters(k.into(), v.into());
350        self
351    }
352    /// <p>Parameters of an Amazon Web Services managed template that you can specify to create the job document.</p><note>
353    /// <p><code>documentParameters</code> can only be used when creating jobs from Amazon Web Services managed templates. This parameter can't be used with custom job templates or to create jobs from them.</p>
354    /// </note>
355    pub fn set_document_parameters(
356        mut self,
357        input: ::std::option::Option<::std::collections::HashMap<::std::string::String, ::std::string::String>>,
358    ) -> Self {
359        self.inner = self.inner.set_document_parameters(input);
360        self
361    }
362    /// <p>Parameters of an Amazon Web Services managed template that you can specify to create the job document.</p><note>
363    /// <p><code>documentParameters</code> can only be used when creating jobs from Amazon Web Services managed templates. This parameter can't be used with custom job templates or to create jobs from them.</p>
364    /// </note>
365    pub fn get_document_parameters(&self) -> &::std::option::Option<::std::collections::HashMap<::std::string::String, ::std::string::String>> {
366        self.inner.get_document_parameters()
367    }
368    /// <p>The configuration that allows you to schedule a job for a future date and time in addition to specifying the end behavior for each job execution.</p>
369    pub fn scheduling_config(mut self, input: crate::types::SchedulingConfig) -> Self {
370        self.inner = self.inner.scheduling_config(input);
371        self
372    }
373    /// <p>The configuration that allows you to schedule a job for a future date and time in addition to specifying the end behavior for each job execution.</p>
374    pub fn set_scheduling_config(mut self, input: ::std::option::Option<crate::types::SchedulingConfig>) -> Self {
375        self.inner = self.inner.set_scheduling_config(input);
376        self
377    }
378    /// <p>The configuration that allows you to schedule a job for a future date and time in addition to specifying the end behavior for each job execution.</p>
379    pub fn get_scheduling_config(&self) -> &::std::option::Option<crate::types::SchedulingConfig> {
380        self.inner.get_scheduling_config()
381    }
382    ///
383    /// Appends an item to `destinationPackageVersions`.
384    ///
385    /// To override the contents of this collection use [`set_destination_package_versions`](Self::set_destination_package_versions).
386    ///
387    /// <p>The package version Amazon Resource Names (ARNs) that are installed on the device when the job successfully completes. The package version must be in either the Published or Deprecated state when the job deploys. For more information, see <a href="https://docs.aws.amazon.com/iot/latest/developerguide/preparing-to-use-software-package-catalog.html#package-version-lifecycle">Package version lifecycle</a>.</p>
388    /// <p><b>Note:</b>The following Length Constraints relates to a single ARN. Up to 25 package version ARNs are allowed.</p>
389    pub fn destination_package_versions(mut self, input: impl ::std::convert::Into<::std::string::String>) -> Self {
390        self.inner = self.inner.destination_package_versions(input.into());
391        self
392    }
393    /// <p>The package version Amazon Resource Names (ARNs) that are installed on the device when the job successfully completes. The package version must be in either the Published or Deprecated state when the job deploys. For more information, see <a href="https://docs.aws.amazon.com/iot/latest/developerguide/preparing-to-use-software-package-catalog.html#package-version-lifecycle">Package version lifecycle</a>.</p>
394    /// <p><b>Note:</b>The following Length Constraints relates to a single ARN. Up to 25 package version ARNs are allowed.</p>
395    pub fn set_destination_package_versions(mut self, input: ::std::option::Option<::std::vec::Vec<::std::string::String>>) -> Self {
396        self.inner = self.inner.set_destination_package_versions(input);
397        self
398    }
399    /// <p>The package version Amazon Resource Names (ARNs) that are installed on the device when the job successfully completes. The package version must be in either the Published or Deprecated state when the job deploys. For more information, see <a href="https://docs.aws.amazon.com/iot/latest/developerguide/preparing-to-use-software-package-catalog.html#package-version-lifecycle">Package version lifecycle</a>.</p>
400    /// <p><b>Note:</b>The following Length Constraints relates to a single ARN. Up to 25 package version ARNs are allowed.</p>
401    pub fn get_destination_package_versions(&self) -> &::std::option::Option<::std::vec::Vec<::std::string::String>> {
402        self.inner.get_destination_package_versions()
403    }
404}