ipfabric_netbox 4.2.1b2__py3-none-any.whl → 4.2.2__py3-none-any.whl

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.

Potentially problematic release.


This version of ipfabric_netbox might be problematic. Click here for more details.

@@ -6,7 +6,7 @@ class NetboxIPFabricConfig(PluginConfig):
6
6
  name = "ipfabric_netbox"
7
7
  verbose_name = "NetBox IP Fabric SoT Plugin"
8
8
  description = "Sync IP Fabric into NetBox"
9
- version = "4.2.1b2"
9
+ version = "4.2.2"
10
10
  base_url = "ipfabric"
11
11
  min_version = "4.2.4"
12
12
 
@@ -1 +1,2 @@
1
+ from .nested_serializers import * # noqa: F401, F403
1
2
  from .serializers import * # noqa: F401, F403
@@ -0,0 +1,78 @@
1
+ from drf_spectacular.types import OpenApiTypes
2
+ from drf_spectacular.utils import extend_schema_field
3
+ from netbox.api.fields import ContentTypeField
4
+ from netbox.api.serializers import NetBoxModelSerializer
5
+ from netbox.api.serializers import WritableNestedSerializer
6
+ from rest_framework import serializers
7
+
8
+ from ipfabric_netbox.models import IPFabricSnapshot
9
+ from ipfabric_netbox.models import IPFabricSource
10
+ from ipfabric_netbox.models import IPFabricSync
11
+ from ipfabric_netbox.models import IPFabricTransformMap
12
+
13
+
14
+ __all__ = (
15
+ "NestedIPFabricSourceSerializer",
16
+ "NestedIPFabricSnapshotSerializer",
17
+ "NestedIPFabricTransformMapSerializer",
18
+ "NestedIPFabricSyncSerializer",
19
+ )
20
+
21
+
22
+ class NestedIPFabricSourceSerializer(WritableNestedSerializer):
23
+ url = serializers.URLField()
24
+
25
+ class Meta:
26
+ model = IPFabricSource
27
+ fields = ["id", "url", "display", "name", "type"]
28
+
29
+
30
+ class NestedIPFabricSnapshotSerializer(NetBoxModelSerializer):
31
+ source = NestedIPFabricSourceSerializer(read_only=True)
32
+ display = serializers.SerializerMethodField(read_only=True)
33
+
34
+ class Meta:
35
+ model = IPFabricSnapshot
36
+ fields = [
37
+ "id",
38
+ "name",
39
+ "source",
40
+ "snapshot_id",
41
+ "status",
42
+ "date",
43
+ "display",
44
+ "sites",
45
+ ]
46
+
47
+ @extend_schema_field(OpenApiTypes.STR)
48
+ def get_display(self, obj):
49
+ return f"{obj.name} ({obj.snapshot_id})"
50
+
51
+
52
+ class NestedIPFabricSyncSerializer(NetBoxModelSerializer):
53
+ snapshot_data = NestedIPFabricSnapshotSerializer(read_only=True)
54
+
55
+ class Meta:
56
+ model = IPFabricSync
57
+ fields = [
58
+ "id",
59
+ "name",
60
+ "display",
61
+ "snapshot_data",
62
+ "type",
63
+ "status",
64
+ "parameters",
65
+ "last_synced",
66
+ ]
67
+
68
+
69
+ class NestedIPFabricTransformMapSerializer(NetBoxModelSerializer):
70
+ target_model = ContentTypeField(read_only=True)
71
+
72
+ class Meta:
73
+ model = IPFabricTransformMap
74
+ fields = [
75
+ "id",
76
+ "source_model",
77
+ "target_model",
78
+ ]
@@ -1,19 +1,19 @@
1
1
  from core.choices import DataSourceStatusChoices
2
- from django.contrib.contenttypes.models import ContentType
3
2
  from netbox.api.fields import ChoiceField
4
3
  from netbox.api.fields import ContentTypeField
5
- from netbox.api.fields import RelatedObjectCountField
6
- from netbox.api.serializers import NestedGroupModelSerializer
4
+ from netbox.api.serializers import NetBoxModelSerializer
7
5
  from netbox_branching.api.serializers import BranchSerializer
8
6
  from rest_framework import serializers
9
7
 
8
+ from .nested_serializers import NestedIPFabricSnapshotSerializer
9
+ from .nested_serializers import NestedIPFabricSourceSerializer
10
+ from .nested_serializers import NestedIPFabricSyncSerializer
11
+ from .nested_serializers import NestedIPFabricTransformMapSerializer
10
12
  from ipfabric_netbox.models import IPFabricIngestion
11
13
  from ipfabric_netbox.models import IPFabricIngestionIssue
12
14
  from ipfabric_netbox.models import IPFabricRelationshipField
13
- from ipfabric_netbox.models import IPFabricRelationshipFieldSourceModels
14
15
  from ipfabric_netbox.models import IPFabricSnapshot
15
16
  from ipfabric_netbox.models import IPFabricSource
16
- from ipfabric_netbox.models import IPFabricSupportedSyncModels
17
17
  from ipfabric_netbox.models import IPFabricSync
18
18
  from ipfabric_netbox.models import IPFabricTransformField
19
19
  from ipfabric_netbox.models import IPFabricTransformMap
@@ -32,201 +32,129 @@ __all__ = (
32
32
  )
33
33
 
34
34
 
35
- class IPFabricTransformMapGroupSerializer(NestedGroupModelSerializer):
36
- transform_maps_count = RelatedObjectCountField("transform_maps")
35
+ class IPFabricSyncSerializer(NetBoxModelSerializer):
36
+ snapshot_data = NestedIPFabricSnapshotSerializer(read_only=True)
37
37
 
38
38
  class Meta:
39
- model = IPFabricTransformMapGroup
40
- fields = (
39
+ model = IPFabricSync
40
+ fields = [
41
41
  "id",
42
42
  "name",
43
- "description",
44
- "transform_maps_count",
43
+ "display",
44
+ "snapshot_data",
45
+ "type",
46
+ "status",
47
+ "parameters",
48
+ "last_synced",
45
49
  "created",
46
50
  "last_updated",
47
- )
48
- brief_fields = (
49
- "id",
50
- "name",
51
- "description",
52
- )
51
+ ]
53
52
 
54
53
 
55
- class IPFabricTransformMapSerializer(NestedGroupModelSerializer):
56
- group = IPFabricTransformMapGroupSerializer(
57
- nested=True, required=False, allow_null=True
58
- )
59
- target_model = ContentTypeField(
60
- queryset=ContentType.objects.filter(IPFabricSupportedSyncModels)
61
- )
54
+ class IPFabricSnapshotSerializer(NetBoxModelSerializer):
55
+ source = NestedIPFabricSourceSerializer()
56
+ data = serializers.JSONField()
57
+ date = serializers.DateTimeField()
58
+ last_updated = serializers.DateTimeField()
62
59
 
63
60
  class Meta:
64
- model = IPFabricTransformMap
65
- fields = (
61
+ model = IPFabricSnapshot
62
+ fields = [
66
63
  "id",
67
64
  "name",
68
- "group",
69
- "source_model",
70
- "target_model",
65
+ "source",
66
+ "snapshot_id",
67
+ "status",
68
+ "date",
69
+ "display",
70
+ "sites",
71
+ "data",
71
72
  "created",
72
73
  "last_updated",
73
- )
74
- brief_fields = (
75
- "id",
76
- "name",
77
- "group",
78
- "source_model",
79
- "target_model",
80
- )
74
+ ]
81
75
 
76
+ extra_kwargs = {
77
+ "raw_data": {"write_only": True},
78
+ }
82
79
 
83
- class IPFabricTransformFieldSerializer(NestedGroupModelSerializer):
84
- transform_map = IPFabricTransformMapSerializer(nested=True)
85
-
86
- class Meta:
87
- model = IPFabricTransformField
88
- fields = (
89
- "id",
90
- "transform_map",
91
- "source_field",
92
- "target_field",
93
- "coalesce",
94
- "template",
95
- )
96
80
 
97
-
98
- class IPFabricRelationshipFieldSerializer(NestedGroupModelSerializer):
99
- transform_map = IPFabricTransformMapSerializer(nested=True)
100
- source_model = ContentTypeField(
101
- queryset=ContentType.objects.filter(IPFabricRelationshipFieldSourceModels)
102
- )
81
+ class IPFabricRelationshipFieldSerializer(NetBoxModelSerializer):
82
+ transform_map = NestedIPFabricTransformMapSerializer(read_only=True)
83
+ source_model = ContentTypeField(read_only=True)
103
84
 
104
85
  class Meta:
105
86
  model = IPFabricRelationshipField
106
- fields = (
87
+ fields = [
107
88
  "id",
108
89
  "transform_map",
109
90
  "source_model",
110
91
  "target_field",
111
92
  "coalesce",
112
93
  "template",
113
- )
94
+ ]
114
95
 
115
96
 
116
- class IPFabricSourceSerializer(NestedGroupModelSerializer):
117
- status = ChoiceField(choices=DataSourceStatusChoices, read_only=True)
118
- url = serializers.URLField()
119
-
97
+ class IPFabricTransformMapGroupSerializer(NetBoxModelSerializer):
120
98
  class Meta:
121
- model = IPFabricSource
122
- fields = (
123
- "id",
124
- "url",
125
- "display",
99
+ model = IPFabricTransformMapGroup
100
+ fields = [
126
101
  "name",
127
- "type",
128
- "status",
129
- "last_synced",
130
102
  "description",
131
- "comments",
132
- "parameters",
103
+ "transform_maps",
133
104
  "created",
134
105
  "last_updated",
135
- )
136
- brief_fields = (
137
- "display",
138
- "id",
139
- "name",
140
- "status",
141
- "type",
142
- "url",
143
- )
106
+ ]
144
107
 
145
108
 
146
- class IPFabricSnapshotSerializer(NestedGroupModelSerializer):
147
- source = IPFabricSourceSerializer(nested=True, read_only=True)
148
- data = serializers.JSONField()
149
- display = serializers.CharField(source="__str__", read_only=True)
109
+ class IPFabricTransformMapSerializer(NetBoxModelSerializer):
110
+ target_model = ContentTypeField(read_only=True)
150
111
 
151
112
  class Meta:
152
- model = IPFabricSnapshot
153
- fields = (
113
+ model = IPFabricTransformMap
114
+ fields = [
154
115
  "id",
155
- "display",
156
- "name",
157
- "source",
158
- "snapshot_id",
159
- "status",
160
- "data",
161
- "date",
116
+ "source_model",
117
+ "target_model",
162
118
  "created",
163
119
  "last_updated",
164
- )
165
- brief_fields = (
166
- "display",
167
- "id",
168
- "name",
169
- "source",
170
- "snapshot_id",
171
- "status",
172
- "data",
173
- "date",
174
- )
120
+ ]
175
121
 
176
122
 
177
- class IPFabricSyncSerializer(NestedGroupModelSerializer):
178
- snapshot_data = IPFabricSnapshotSerializer(nested=True)
123
+ class IPFabricTransformFieldSerializer(NetBoxModelSerializer):
124
+ transform_map = NestedIPFabricTransformMapSerializer(read_only=True)
179
125
 
180
126
  class Meta:
181
- model = IPFabricSync
182
- fields = (
183
- "id",
184
- "name",
185
- "snapshot_data",
186
- "status",
187
- "parameters",
188
- "auto_merge",
189
- "last_synced",
190
- "scheduled",
191
- "interval",
192
- "user",
193
- )
194
- brief_fields = (
195
- "auto_merge",
127
+ model = IPFabricTransformField
128
+ fields = [
196
129
  "id",
197
- "last_synced",
198
- "name",
199
- "parameters",
200
- "status",
201
- )
130
+ "transform_map",
131
+ "source_field",
132
+ "target_field",
133
+ "coalesce",
134
+ "template",
135
+ ]
202
136
 
203
137
 
204
- class IPFabricIngestionSerializer(NestedGroupModelSerializer):
138
+ class IPFabricIngestionSerializer(NetBoxModelSerializer):
205
139
  branch = BranchSerializer(read_only=True)
206
- sync = IPFabricSyncSerializer(nested=True)
140
+ sync = NestedIPFabricSyncSerializer(read_only=True)
207
141
 
208
142
  class Meta:
209
143
  model = IPFabricIngestion
210
- fields = (
211
- "id",
212
- "name",
213
- "branch",
214
- "sync",
215
- )
216
- brief_fields = (
144
+ fields = [
217
145
  "id",
218
146
  "name",
219
147
  "branch",
220
148
  "sync",
221
- )
149
+ ]
222
150
 
223
151
 
224
- class IPFabricIngestionIssueSerializer(NestedGroupModelSerializer):
225
- ingestion = IPFabricIngestionSerializer(nested=True)
152
+ class IPFabricIngestionIssueSerializer(NetBoxModelSerializer):
153
+ ingestion = IPFabricIngestionSerializer(read_only=True)
226
154
 
227
155
  class Meta:
228
156
  model = IPFabricIngestionIssue
229
- fields = (
157
+ fields = [
230
158
  "id",
231
159
  "ingestion",
232
160
  "timestamp",
@@ -236,11 +164,26 @@ class IPFabricIngestionIssueSerializer(NestedGroupModelSerializer):
236
164
  "coalesce_fields",
237
165
  "defaults",
238
166
  "exception",
239
- )
240
- brief_fields = (
241
- "exception",
167
+ ]
168
+
169
+
170
+ class IPFabricSourceSerializer(NetBoxModelSerializer):
171
+ status = ChoiceField(choices=DataSourceStatusChoices)
172
+ url = serializers.URLField()
173
+
174
+ class Meta:
175
+ model = IPFabricSource
176
+ fields = [
242
177
  "id",
243
- "ingestion",
244
- "message",
245
- "model",
246
- )
178
+ "url",
179
+ "display",
180
+ "name",
181
+ "type",
182
+ "status",
183
+ "last_synced",
184
+ "description",
185
+ "comments",
186
+ "parameters",
187
+ "created",
188
+ "last_updated",
189
+ ]
@@ -3,11 +3,11 @@ from netbox.api.routers import NetBoxRouter
3
3
 
4
4
  from ipfabric_netbox.api.views import IPFabricIngestionIssueViewSet
5
5
  from ipfabric_netbox.api.views import IPFabricIngestionViewSet
6
- from ipfabric_netbox.api.views import IPFabricRelationshipFieldViewSet
6
+ from ipfabric_netbox.api.views import IPFabricRelationshipFieldiewSet
7
7
  from ipfabric_netbox.api.views import IPFabricSnapshotViewSet
8
8
  from ipfabric_netbox.api.views import IPFabricSourceViewSet
9
9
  from ipfabric_netbox.api.views import IPFabricSyncViewSet
10
- from ipfabric_netbox.api.views import IPFabricTransformFieldViewSet
10
+ from ipfabric_netbox.api.views import IPFabricTransformFieldiewSet
11
11
  from ipfabric_netbox.api.views import IPFabricTransformMapGroupViewSet
12
12
  from ipfabric_netbox.api.views import IPFabricTransformMapViewSet
13
13
 
@@ -20,6 +20,6 @@ router.register("transform-map", IPFabricTransformMapViewSet)
20
20
  router.register("sync", IPFabricSyncViewSet)
21
21
  router.register("ingestion", IPFabricIngestionViewSet)
22
22
  router.register("ingestion-issues", IPFabricIngestionIssueViewSet)
23
- router.register("transform-field", IPFabricTransformFieldViewSet)
24
- router.register("relationship-field", IPFabricRelationshipFieldViewSet)
23
+ router.register("transform-field", IPFabricTransformFieldiewSet)
24
+ router.register("relationship-field", IPFabricRelationshipFieldiewSet)
25
25
  urlpatterns = router.urls
@@ -14,7 +14,6 @@ from .serializers import IPFabricSyncSerializer
14
14
  from .serializers import IPFabricTransformFieldSerializer
15
15
  from .serializers import IPFabricTransformMapGroupSerializer
16
16
  from .serializers import IPFabricTransformMapSerializer
17
- from ipfabric_netbox.filtersets import IPFabricRelationshipFieldFilterSet
18
17
  from ipfabric_netbox.filtersets import IPFabricSnapshotFilterSet
19
18
  from ipfabric_netbox.filtersets import IPFabricSourceFilterSet
20
19
  from ipfabric_netbox.filtersets import IPFabricTransformFieldFilterSet
@@ -30,29 +29,29 @@ from ipfabric_netbox.models import IPFabricTransformMap
30
29
  from ipfabric_netbox.models import IPFabricTransformMapGroup
31
30
 
32
31
 
33
- class IPFabricTransformMapGroupViewSet(NetBoxModelViewSet):
32
+ class IPFabricTransformMapGroupViewSet(NetBoxReadOnlyModelViewSet):
34
33
  queryset = IPFabricTransformMapGroup.objects.all()
35
34
  serializer_class = IPFabricTransformMapGroupSerializer
36
35
 
37
36
 
38
- class IPFabricTransformMapViewSet(NetBoxModelViewSet):
37
+ class IPFabricTransformMapViewSet(NetBoxReadOnlyModelViewSet):
39
38
  queryset = IPFabricTransformMap.objects.all()
40
39
  serializer_class = IPFabricTransformMapSerializer
41
40
 
42
41
 
43
- class IPFabricTransformFieldViewSet(NetBoxModelViewSet):
42
+ class IPFabricTransformFieldiewSet(NetBoxReadOnlyModelViewSet):
44
43
  queryset = IPFabricTransformField.objects.all()
45
44
  serializer_class = IPFabricTransformFieldSerializer
46
45
  filterset_class = IPFabricTransformFieldFilterSet
47
46
 
48
47
 
49
- class IPFabricRelationshipFieldViewSet(NetBoxModelViewSet):
48
+ class IPFabricRelationshipFieldiewSet(NetBoxReadOnlyModelViewSet):
50
49
  queryset = IPFabricRelationshipField.objects.all()
51
50
  serializer_class = IPFabricRelationshipFieldSerializer
52
- filterset_class = IPFabricRelationshipFieldFilterSet
51
+ filterset_class = IPFabricTransformFieldFilterSet
53
52
 
54
53
 
55
- class IPFabricSyncViewSet(NetBoxModelViewSet):
54
+ class IPFabricSyncViewSet(NetBoxReadOnlyModelViewSet):
56
55
  queryset = IPFabricSync.objects.all()
57
56
  serializer_class = IPFabricSyncSerializer
58
57
 
@@ -67,7 +66,7 @@ class IPFabricIngestionIssueViewSet(NetBoxReadOnlyModelViewSet):
67
66
  serializer_class = IPFabricIngestionIssueSerializer
68
67
 
69
68
 
70
- class IPFabricSnapshotViewSet(NetBoxReadOnlyModelViewSet):
69
+ class IPFabricSnapshotViewSet(NetBoxModelViewSet):
71
70
  queryset = IPFabricSnapshot.objects.all()
72
71
  serializer_class = IPFabricSnapshotSerializer
73
72
  filterset_class = IPFabricSnapshotFilterSet
@@ -80,21 +79,24 @@ class IPFabricSnapshotViewSet(NetBoxReadOnlyModelViewSet):
80
79
  raw_data._raw_delete(raw_data.db)
81
80
  return Response({"status": "success"})
82
81
  elif request.method == "PATCH":
83
- with transaction.atomic():
84
- IPFabricData.objects.bulk_create(
85
- [
86
- IPFabricData(snapshot_data=snapshot, data=item["data"])
87
- for item in request.data["data"]
88
- ],
89
- batch_size=5000,
90
- )
82
+ transaction.set_autocommit(False)
83
+ IPFabricData.objects.bulk_create(
84
+ [
85
+ IPFabricData(
86
+ snapshot_data=snapshot, data=item["data"], type=item["type"]
87
+ )
88
+ for item in request.data["data"]
89
+ ],
90
+ batch_size=5000,
91
+ )
92
+ transaction.commit()
91
93
  return Response({"status": "success"})
92
94
 
93
95
  @action(detail=True, methods=["get"], url_path="sites")
94
96
  def sites(self, request, pk):
95
97
  q = request.GET.get("q", None)
96
98
  snapshot = IPFabricSnapshot.objects.get(pk=pk)
97
- new_sites = {"count": 0, "results": []}
99
+ new_sites = {"results": []}
98
100
  if snapshot.data:
99
101
  sites = snapshot.data.get("sites", None)
100
102
  num = 0
@@ -110,7 +112,6 @@ class IPFabricSnapshotViewSet(NetBoxReadOnlyModelViewSet):
110
112
  {"display": site, "name": site, "id": site}
111
113
  )
112
114
  num += 1
113
- new_sites["count"] = num
114
115
  return Response(new_sites)
115
116
  else:
116
117
  return Response([])
@@ -198,6 +198,18 @@ class IPFabricSnapshotStatusModelChoices(ChoiceSet):
198
198
  ]
199
199
 
200
200
 
201
+ class IPFabricSyncTypeChoices(ChoiceSet):
202
+ ALL = "all"
203
+ DCIM = "dcim"
204
+ IPAM = "ipam"
205
+
206
+ CHOICES = (
207
+ (ALL, _("All"), "gray"),
208
+ (DCIM, _("DCIM"), "blue"),
209
+ (IPAM, _("IPAM"), "blue"),
210
+ )
211
+
212
+
201
213
  class IPFabricSourceTypeChoices(ChoiceSet):
202
214
  LOCAL = "local"
203
215
  REMOTE = "remote"
@@ -11,11 +11,9 @@ from netbox_branching.models import ChangeDiff
11
11
  from .models import IPFabricData
12
12
  from .models import IPFabricIngestion
13
13
  from .models import IPFabricIngestionIssue
14
- from .models import IPFabricRelationshipField
15
14
  from .models import IPFabricSnapshot
16
15
  from .models import IPFabricSource
17
16
  from .models import IPFabricSync
18
- from .models import IPFabricTransformField
19
17
  from .models import IPFabricTransformMap
20
18
  from .models import IPFabricTransformMapGroup
21
19
 
@@ -74,12 +72,14 @@ class IPFabricDataFilterSet(BaseFilterSet):
74
72
 
75
73
  class Meta:
76
74
  model = IPFabricData
77
- fields = ["snapshot_data"]
75
+ fields = ["snapshot_data", "type"]
78
76
 
79
77
  def search(self, queryset, name, value):
80
78
  if not value.strip():
81
79
  return queryset
82
- return queryset.filter(Q(snapshot_data__icontains=value))
80
+ return queryset.filter(
81
+ Q(snapshot_data__icontains=value) | Q(type__icontains=value)
82
+ )
83
83
 
84
84
 
85
85
  class IPFabricSnapshotFilterSet(ChangeLoggedModelFilterSet):
@@ -193,66 +193,3 @@ class IPFabricTransformFieldFilterSet(BaseFilterSet):
193
193
  transform_map = django_filters.ModelMultipleChoiceFilter(
194
194
  queryset=IPFabricTransformMap.objects.all(), label=_("Transform Map")
195
195
  )
196
-
197
- class Meta:
198
- model = IPFabricTransformField
199
- fields = (
200
- "id",
201
- "transform_map",
202
- "source_field",
203
- "target_field",
204
- "coalesce",
205
- "template",
206
- )
207
-
208
-
209
- class IPFabricRelationshipFieldFilterSet(BaseFilterSet):
210
- transform_map = django_filters.ModelMultipleChoiceFilter(
211
- queryset=IPFabricTransformMap.objects.all(), label=_("Transform Map")
212
- )
213
-
214
- class Meta:
215
- model = IPFabricRelationshipField
216
- fields = (
217
- "id",
218
- "transform_map",
219
- "source_model",
220
- "target_field",
221
- "coalesce",
222
- "template",
223
- )
224
-
225
-
226
- class IPFabricSyncFilterSet(ChangeLoggedModelFilterSet):
227
- q = django_filters.CharFilter(method="search")
228
- snapshot_data_id = django_filters.ModelMultipleChoiceFilter(
229
- queryset=IPFabricSnapshot.objects.all(),
230
- label=_("Snapshot (ID)"),
231
- )
232
- snapshot_data = django_filters.ModelMultipleChoiceFilter(
233
- field_name="snapshot_data__name",
234
- queryset=IPFabricSnapshot.objects.all(),
235
- to_field_name="name",
236
- label=_("Snapshot (name)"),
237
- )
238
-
239
- class Meta:
240
- model = IPFabricSync
241
- fields = (
242
- "id",
243
- "name",
244
- "snapshot_data",
245
- "snapshot_data_id",
246
- "status",
247
- "auto_merge",
248
- "last_synced",
249
- "scheduled",
250
- "interval",
251
- )
252
-
253
- def search(self, queryset, name, value):
254
- if not value.strip():
255
- return queryset
256
- return queryset.filter(
257
- Q(name__icontains=value) | Q(snapshot_data__name__icontains=value)
258
- )