weft-sdk 0.6.2 → 0.9.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 +4 -4
- data/docs/APIKeysApi.md +1 -2
- data/docs/AccountApi.md +6 -5
- data/docs/AccountDetails.md +10 -13
- data/docs/ApiKey.md +0 -1
- data/docs/ApiKeyCreated.md +0 -1
- data/docs/ApiKeyCreatedResponse.md +0 -1
- data/docs/ApiKeyListResponse.md +0 -1
- data/docs/AuthApi.md +6 -7
- data/docs/AuthResponse.md +0 -1
- data/docs/AuthResponseData.md +0 -1
- data/docs/BalanceApi.md +1 -2
- data/docs/BalanceResponse.md +3 -4
- data/docs/ConfirmRequest.md +0 -1
- data/docs/CreateApiKeyRequest.md +0 -1
- data/docs/DefaultApi.md +0 -1
- data/docs/EnrolledResource.md +43 -0
- data/docs/Error.md +0 -1
- data/docs/ErrorResponse.md +0 -1
- data/docs/Fetch403Response.md +48 -0
- data/docs/FetchApi.md +10 -7
- data/docs/FetchBalanceSnapshot.md +5 -2
- data/docs/FetchErrorResponse.md +0 -1
- data/docs/FetchRequest.md +0 -1
- data/docs/FetchRequestBody.md +0 -1
- data/docs/FetchResponse.md +6 -3
- data/docs/InsufficientScopeResponse.md +21 -0
- data/docs/MeApiKey.md +25 -0
- data/docs/MeApiKeyCreator.md +21 -0
- data/docs/MeResponse.md +1 -2
- data/docs/MeResponseData.md +78 -0
- data/docs/Merchant.md +0 -1
- data/docs/MessageResponse.md +0 -1
- data/docs/MessageResponseData.md +0 -1
- data/docs/Pagination.md +0 -1
- data/docs/PasswordResetRequest.md +0 -1
- data/docs/PasswordUpdateRequest.md +0 -1
- data/docs/Payment.md +0 -3
- data/docs/PaymentListResponse.md +0 -1
- data/docs/PaymentResponse.md +0 -1
- data/docs/PaymentsApi.md +0 -1
- data/docs/PrincipalWallet.md +19 -0
- data/docs/PromoBalance.md +0 -1
- data/docs/Purchase.md +43 -0
- data/docs/PurchaseArtifact.md +23 -0
- data/docs/PurchaseListResponse.md +19 -0
- data/docs/PurchaseResponse.md +17 -0
- data/docs/PurchasesApi.md +148 -0
- data/docs/ResendConfirmationRequest.md +0 -1
- data/docs/ResourceEnrollmentRequest.md +23 -0
- data/docs/ResourceEnrollmentResponse.md +17 -0
- data/docs/ResourceStats.md +29 -0
- data/docs/ResourcesApi.md +71 -0
- data/docs/SearchApi.md +2 -3
- data/docs/SearchCapabilityRef.md +19 -0
- data/docs/SearchEndpointCall.md +23 -0
- data/docs/SearchEndpointHit.md +41 -0
- data/docs/SearchEndpointPrice.md +25 -0
- data/docs/SearchErrorResponse.md +0 -1
- data/docs/SearchFilterSpec.md +23 -0
- data/docs/SearchPaymentOffer.md +31 -0
- data/docs/SearchPriceAtomicFilter.md +25 -0
- data/docs/SearchPriceUsdFilter.md +25 -0
- data/docs/SearchProtocolFilter.md +19 -0
- data/docs/SearchProviderRef.md +21 -0
- data/docs/SearchRequest.md +3 -4
- data/docs/SearchResourceTypeFilter.md +19 -0
- data/docs/SearchResponse.md +35 -8
- data/docs/SearchResponseWarningsInner.md +23 -0
- data/docs/SearchResult.md +8 -21
- data/docs/SignInRequest.md +0 -1
- data/docs/SignUpRequest.md +0 -1
- data/docs/SpendingPolicy.md +0 -1
- data/docs/User.md +0 -1
- data/docs/UserPrincipal.md +33 -0
- data/docs/Wallet.md +5 -2
- data/lib/weft/generated/api/account_api.rb +6 -4
- data/lib/weft/generated/api/api_keys_api.rb +4 -4
- data/lib/weft/generated/api/auth_api.rb +14 -14
- data/lib/weft/generated/api/balance_api.rb +4 -4
- data/lib/weft/generated/api/default_api.rb +2 -2
- data/lib/weft/generated/api/fetch_api.rb +22 -6
- data/lib/weft/generated/api/payments_api.rb +2 -2
- data/lib/weft/generated/api/purchases_api.rb +150 -0
- data/lib/weft/generated/api/resources_api.rb +90 -0
- data/lib/weft/generated/api/search_api.rb +6 -6
- data/lib/weft/generated/api_client.rb +2 -2
- data/lib/weft/generated/api_error.rb +2 -2
- data/lib/weft/generated/api_model_base.rb +2 -2
- data/lib/weft/generated/configuration.rb +2 -2
- data/lib/weft/generated/models/account_details.rb +94 -85
- data/lib/weft/generated/models/api_key.rb +2 -2
- data/lib/weft/generated/models/api_key_created.rb +2 -2
- data/lib/weft/generated/models/api_key_created_response.rb +2 -2
- data/lib/weft/generated/models/api_key_list_response.rb +2 -2
- data/lib/weft/generated/models/auth_response.rb +2 -2
- data/lib/weft/generated/models/auth_response_data.rb +2 -2
- data/lib/weft/generated/models/balance_response.rb +5 -5
- data/lib/weft/generated/models/confirm_request.rb +2 -2
- data/lib/weft/generated/models/create_api_key_request.rb +2 -2
- data/lib/weft/generated/models/enrolled_resource.rb +474 -0
- data/lib/weft/generated/models/error.rb +3 -3
- data/lib/weft/generated/models/error_response.rb +3 -3
- data/lib/weft/generated/models/fetch403_response.rb +104 -0
- data/lib/weft/generated/models/fetch_balance_snapshot.rb +59 -4
- data/lib/weft/generated/models/fetch_error_response.rb +5 -5
- data/lib/weft/generated/models/fetch_request.rb +5 -5
- data/lib/weft/generated/models/fetch_request_body.rb +2 -2
- data/lib/weft/generated/models/fetch_response.rb +85 -7
- data/lib/weft/generated/models/insufficient_scope_response.rb +242 -0
- data/lib/weft/generated/models/{search_skill.rb → me_api_key.rb} +50 -92
- data/lib/weft/generated/models/me_api_key_creator.rb +200 -0
- data/lib/weft/generated/models/me_response.rb +3 -3
- data/lib/weft/generated/models/me_response_data.rb +55 -0
- data/lib/weft/generated/models/merchant.rb +2 -2
- data/lib/weft/generated/models/message_response.rb +2 -2
- data/lib/weft/generated/models/message_response_data.rb +2 -2
- data/lib/weft/generated/models/pagination.rb +2 -2
- data/lib/weft/generated/models/password_reset_request.rb +2 -2
- data/lib/weft/generated/models/password_update_request.rb +2 -2
- data/lib/weft/generated/models/payment.rb +3 -12
- data/lib/weft/generated/models/payment_list_response.rb +2 -2
- data/lib/weft/generated/models/payment_response.rb +2 -2
- data/lib/weft/generated/models/principal_wallet.rb +190 -0
- data/lib/weft/generated/models/promo_balance.rb +3 -3
- data/lib/weft/generated/models/purchase.rb +427 -0
- data/lib/weft/generated/models/purchase_artifact.rb +237 -0
- data/lib/weft/generated/models/purchase_list_response.rb +192 -0
- data/lib/weft/generated/models/purchase_response.rb +164 -0
- data/lib/weft/generated/models/resend_confirmation_request.rb +2 -2
- data/lib/weft/generated/models/{search_agent_card.rb → resource_enrollment_request.rb} +59 -75
- data/lib/weft/generated/models/resource_enrollment_response.rb +164 -0
- data/lib/weft/generated/models/resource_stats.rb +323 -0
- data/lib/weft/generated/models/{search_skill_endpoint.rb → search_capability_ref.rb} +18 -19
- data/lib/weft/generated/models/search_endpoint_call.rb +179 -0
- data/lib/weft/generated/models/search_endpoint_hit.rb +296 -0
- data/lib/weft/generated/models/search_endpoint_price.rb +223 -0
- data/lib/weft/generated/models/search_error_response.rb +5 -5
- data/lib/weft/generated/models/search_filter_spec.rb +175 -0
- data/lib/weft/generated/models/{search_pricing.rb → search_payment_offer.rb} +64 -67
- data/lib/weft/generated/models/search_price_atomic_filter.rb +284 -0
- data/lib/weft/generated/models/search_price_usd_filter.rb +294 -0
- data/lib/weft/generated/models/search_protocol_filter.rb +200 -0
- data/lib/weft/generated/models/{search_endpoints.rb → search_provider_ref.rb} +26 -36
- data/lib/weft/generated/models/search_request.rb +36 -27
- data/lib/weft/generated/models/search_resource_type_filter.rb +200 -0
- data/lib/weft/generated/models/search_response.rb +366 -30
- data/lib/weft/generated/models/search_response_warnings_inner.rb +210 -0
- data/lib/weft/generated/models/search_result.rb +68 -220
- data/lib/weft/generated/models/sign_in_request.rb +2 -2
- data/lib/weft/generated/models/sign_up_request.rb +2 -2
- data/lib/weft/generated/models/spending_policy.rb +2 -2
- data/lib/weft/generated/models/user.rb +2 -2
- data/lib/weft/generated/models/user_principal.rb +370 -0
- data/lib/weft/generated/models/wallet.rb +58 -4
- data/lib/weft/generated/version.rb +3 -3
- data/lib/weft/generated.rb +10 -4
- data/lib/weft/sdk.rb +1 -1
- metadata +75 -17
- data/docs/SearchAgentCard.md +0 -34
- data/docs/SearchEndpoints.md +0 -24
- data/docs/SearchFilters.md +0 -26
- data/docs/SearchPricing.md +0 -24
- data/docs/SearchRanking.md +0 -26
- data/docs/SearchSkill.md +0 -36
- data/docs/SearchSkillEndpoint.md +0 -20
- data/lib/weft/generated/models/search_filters.rb +0 -277
- data/lib/weft/generated/models/search_ranking.rb +0 -277
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#Weft API
|
|
3
3
|
|
|
4
|
-
#The Weft API is the buyer-runtime surface that powers the `weft` CLI, the hosted MCP server (`weft.network/mcp`), and any third-party agent that wants to discover and pay for paid resources on Weft. v1 covers five buyer concerns: 1. Account onboarding (`/api/v1/auth/*`, `/api/v1/me`) 2. CLI authentication (`/api/v1/api_keys`) 3. Wallet visibility (`/api/v1/balance`) 4. Discovery (`/api/v1/search`) 5. Paid execution (`/api/v1/fetch`) 6. Purchase history (`/api/v1/
|
|
4
|
+
#The Weft API is the buyer-runtime surface that powers the `weft` CLI, the hosted MCP server (`weft.network/mcp`), and any third-party agent that wants to discover and pay for paid resources on Weft. v1 covers five buyer concerns: 1. Account onboarding (`/api/v1/auth/*`, `/api/v1/me`) 2. CLI authentication (`/api/v1/api_keys`) 3. Wallet visibility (`/api/v1/balance`) 4. Discovery (`/api/v1/search`) 5. Paid execution (`/api/v1/fetch`) 6. Purchase history (`/api/v1/purchases`) Seller-side concerns (agent management, payout analytics, webhook delivery, the public storefront for `data_api` resources) live in the dashboard and are intentionally not documented here. They will be split out into a separate, dashboard-scoped spec when they need to be SDK-consumable. All errors share the envelope defined by `ErrorResponse`, except the buyer-runtime endpoints (`/search`, `/fetch`) which use bespoke envelopes carrying additional context — see `SearchErrorResponse` and `FetchErrorResponse`.
|
|
5
5
|
|
|
6
|
-
The version of the OpenAPI document: 0.
|
|
6
|
+
The version of the OpenAPI document: 0.9.0
|
|
7
7
|
|
|
8
8
|
Generated by: https://openapi-generator.tech
|
|
9
9
|
Generator version: 7.19.0
|
|
@@ -14,29 +14,104 @@ require 'date'
|
|
|
14
14
|
require 'time'
|
|
15
15
|
|
|
16
16
|
module Weft
|
|
17
|
-
#
|
|
17
|
+
# The weft-search-platform `POST /v1/search` response envelope. The mock backend emits the same shape and adds `_mock: true`.
|
|
18
18
|
class SearchResponse < ApiModelBase
|
|
19
|
-
|
|
19
|
+
# Opaque trace id for the served query, matching the platform `query_trace_id` — and the `search_id` that re-reads it. Deliberately the same id rather than a second handle: one serve, one name.
|
|
20
|
+
attr_accessor :query_trace_id
|
|
21
|
+
|
|
22
|
+
attr_accessor :query
|
|
23
|
+
|
|
24
|
+
# Which view this response carries, echoing the requested format. `json` populates `results` and leaves `markdown` null; `markdown` populates `markdown` and leaves `results` empty. Exactly one is populated per response, never both — returning both eagerly would double the payload.
|
|
25
|
+
attr_accessor :format
|
|
26
|
+
|
|
27
|
+
# The flat comparison table, when `format` is `markdown`; null otherwise. Rendered deterministically from the same stored result the `json` view returns, so the two views of one search can never disagree.
|
|
28
|
+
attr_accessor :markdown
|
|
29
|
+
|
|
30
|
+
# How many `(Provider + Capability)` results the search produced. Read THIS, not `results.length`, for the count: on a `markdown` response `results` is empty by design, so `result_count > 0` with an empty `results` is a rendered table while `result_count == 0` is a genuine zero-result.
|
|
31
|
+
attr_accessor :result_count
|
|
32
|
+
|
|
33
|
+
# `live` for a fresh serve; `snapshot` for an immutable replay of a completed search. A re-read is a snapshot and says so — read it with `as_of` and `stale`.
|
|
34
|
+
attr_accessor :served_from
|
|
35
|
+
|
|
36
|
+
# When the results were produced. Now on a `live` serve; on a `snapshot` the ORIGINAL serve time, because a replay returns exactly what was paid for, not current truth.
|
|
37
|
+
attr_accessor :as_of
|
|
38
|
+
|
|
39
|
+
# Whether the active search index has changed since these results were produced. `true` does not mean the results are wrong — it means they are a snapshot of an index that has since moved. Always `false` on a `live` serve.
|
|
40
|
+
attr_accessor :stale
|
|
41
|
+
|
|
42
|
+
# How payment works across the catalog, stated once for the whole response rather than repeated in every endpoint's usage instructions.
|
|
43
|
+
attr_accessor :payment_note
|
|
20
44
|
|
|
21
|
-
#
|
|
22
|
-
attr_accessor :
|
|
45
|
+
# The `FilterSpec` actually applied to recall, echoed back so the caller sees exactly what constrained the results. In the current contract this is the caller's `filters` verbatim (empty object when none were sent).
|
|
46
|
+
attr_accessor :applied_filters
|
|
23
47
|
|
|
24
|
-
#
|
|
25
|
-
attr_accessor :
|
|
48
|
+
# Origin of `applied_filters`; always `CALLER`.
|
|
49
|
+
attr_accessor :decomposition_source
|
|
26
50
|
|
|
27
|
-
|
|
28
|
-
|
|
51
|
+
attr_accessor :embedder_model
|
|
52
|
+
|
|
53
|
+
attr_accessor :candidates_considered
|
|
54
|
+
|
|
55
|
+
attr_accessor :warnings
|
|
56
|
+
|
|
57
|
+
# Calibrated confidence in this result set — read this instead of thresholding a raw similarity score. `strong`: the top match is confidently on-intent, proceed. `weak`: above the relevance floor but inside the band where plausible-but-wrong matches live, verify the result before paying. `none`: nothing cleared the floor — `results` is empty and `reason` / `suggestion` say why. Results below the floor are never returned as near-misses.
|
|
58
|
+
attr_accessor :match_quality
|
|
59
|
+
|
|
60
|
+
# Machine-readable cause of an empty result set, non-null exactly when `match_quality` is `none`. `below_relevance_floor`: candidates ranked but the best scored under the floor. `filter_collapsed_pool`: a caller filter cut the pool before ranking and nothing relevant survived — relax the filter. `no_catalog_coverage`: recall returned no candidates at all on an unfiltered query. `unsupported_filter_value`: a CATEGORICAL filter value (`type` / `protocol`) matches zero stored values, so it could never have matched — categorical only, since a continuous bound like `price` that matches nothing is reported as `filter_collapsed_pool` instead (the bound needs raising, the dimension is not unsupported). `index_unavailable`: no active index — an operational fault, paired with the `EMPTY_INDEX` warning.
|
|
61
|
+
attr_accessor :reason
|
|
62
|
+
|
|
63
|
+
# Human/agent-readable explanation of `reason`, carrying the concrete numbers behind it (pool sizes, the best discarded score against the floor, the values actually stored for a filter). Non-null exactly when `reason` is.
|
|
64
|
+
attr_accessor :suggestion
|
|
65
|
+
|
|
66
|
+
# Ranked `(Provider + Capability)` results; empty when the index is empty or nothing cleared the relevance floor. Results BELOW the floor are never returned — an empty list plus a `reason` is the honest answer, not a list of near-misses in the same shape as a genuine match.
|
|
67
|
+
attr_accessor :results
|
|
29
68
|
|
|
30
69
|
# Present and `true` only when served by the mock backend.
|
|
31
70
|
attr_accessor :_mock
|
|
32
71
|
|
|
72
|
+
class EnumAttributeValidator
|
|
73
|
+
attr_reader :datatype
|
|
74
|
+
attr_reader :allowable_values
|
|
75
|
+
|
|
76
|
+
def initialize(datatype, allowable_values)
|
|
77
|
+
@allowable_values = allowable_values.map do |value|
|
|
78
|
+
case datatype.to_s
|
|
79
|
+
when /Integer/i
|
|
80
|
+
value.to_i
|
|
81
|
+
when /Float/i
|
|
82
|
+
value.to_f
|
|
83
|
+
else
|
|
84
|
+
value
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def valid?(value)
|
|
90
|
+
!value || allowable_values.include?(value)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
33
94
|
# Attribute mapping from ruby-style variable name to JSON key.
|
|
34
95
|
def self.attribute_map
|
|
35
96
|
{
|
|
97
|
+
:'query_trace_id' => :'query_trace_id',
|
|
98
|
+
:'query' => :'query',
|
|
99
|
+
:'format' => :'format',
|
|
100
|
+
:'markdown' => :'markdown',
|
|
101
|
+
:'result_count' => :'result_count',
|
|
102
|
+
:'served_from' => :'served_from',
|
|
103
|
+
:'as_of' => :'as_of',
|
|
104
|
+
:'stale' => :'stale',
|
|
105
|
+
:'payment_note' => :'payment_note',
|
|
106
|
+
:'applied_filters' => :'applied_filters',
|
|
107
|
+
:'decomposition_source' => :'decomposition_source',
|
|
108
|
+
:'embedder_model' => :'embedder_model',
|
|
109
|
+
:'candidates_considered' => :'candidates_considered',
|
|
110
|
+
:'warnings' => :'warnings',
|
|
111
|
+
:'match_quality' => :'match_quality',
|
|
112
|
+
:'reason' => :'reason',
|
|
113
|
+
:'suggestion' => :'suggestion',
|
|
36
114
|
:'results' => :'results',
|
|
37
|
-
:'paid_usd' => :'paid_usd',
|
|
38
|
-
:'tx_hash' => :'tx_hash',
|
|
39
|
-
:'artifact_id' => :'artifact_id',
|
|
40
115
|
:'_mock' => :'_mock'
|
|
41
116
|
}
|
|
42
117
|
end
|
|
@@ -54,10 +129,24 @@ module Weft
|
|
|
54
129
|
# Attribute type mapping.
|
|
55
130
|
def self.openapi_types
|
|
56
131
|
{
|
|
132
|
+
:'query_trace_id' => :'String',
|
|
133
|
+
:'query' => :'String',
|
|
134
|
+
:'format' => :'String',
|
|
135
|
+
:'markdown' => :'String',
|
|
136
|
+
:'result_count' => :'Integer',
|
|
137
|
+
:'served_from' => :'String',
|
|
138
|
+
:'as_of' => :'Time',
|
|
139
|
+
:'stale' => :'Boolean',
|
|
140
|
+
:'payment_note' => :'String',
|
|
141
|
+
:'applied_filters' => :'SearchFilterSpec',
|
|
142
|
+
:'decomposition_source' => :'String',
|
|
143
|
+
:'embedder_model' => :'String',
|
|
144
|
+
:'candidates_considered' => :'Integer',
|
|
145
|
+
:'warnings' => :'Array<SearchResponseWarningsInner>',
|
|
146
|
+
:'match_quality' => :'String',
|
|
147
|
+
:'reason' => :'String',
|
|
148
|
+
:'suggestion' => :'String',
|
|
57
149
|
:'results' => :'Array<SearchResult>',
|
|
58
|
-
:'paid_usd' => :'String',
|
|
59
|
-
:'tx_hash' => :'String',
|
|
60
|
-
:'artifact_id' => :'String',
|
|
61
150
|
:'_mock' => :'Boolean'
|
|
62
151
|
}
|
|
63
152
|
end
|
|
@@ -84,24 +173,94 @@ module Weft
|
|
|
84
173
|
h[k.to_sym] = v
|
|
85
174
|
}
|
|
86
175
|
|
|
87
|
-
if attributes.key?(:'
|
|
88
|
-
|
|
89
|
-
|
|
176
|
+
if attributes.key?(:'query_trace_id')
|
|
177
|
+
self.query_trace_id = attributes[:'query_trace_id']
|
|
178
|
+
else
|
|
179
|
+
self.query_trace_id = nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
if attributes.key?(:'query')
|
|
183
|
+
self.query = attributes[:'query']
|
|
184
|
+
else
|
|
185
|
+
self.query = nil
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
if attributes.key?(:'format')
|
|
189
|
+
self.format = attributes[:'format']
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if attributes.key?(:'markdown')
|
|
193
|
+
self.markdown = attributes[:'markdown']
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
if attributes.key?(:'result_count')
|
|
197
|
+
self.result_count = attributes[:'result_count']
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
if attributes.key?(:'served_from')
|
|
201
|
+
self.served_from = attributes[:'served_from']
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if attributes.key?(:'as_of')
|
|
205
|
+
self.as_of = attributes[:'as_of']
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if attributes.key?(:'stale')
|
|
209
|
+
self.stale = attributes[:'stale']
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
if attributes.key?(:'payment_note')
|
|
213
|
+
self.payment_note = attributes[:'payment_note']
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if attributes.key?(:'applied_filters')
|
|
217
|
+
self.applied_filters = attributes[:'applied_filters']
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
if attributes.key?(:'decomposition_source')
|
|
221
|
+
self.decomposition_source = attributes[:'decomposition_source']
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if attributes.key?(:'embedder_model')
|
|
225
|
+
self.embedder_model = attributes[:'embedder_model']
|
|
226
|
+
else
|
|
227
|
+
self.embedder_model = nil
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
if attributes.key?(:'candidates_considered')
|
|
231
|
+
self.candidates_considered = attributes[:'candidates_considered']
|
|
232
|
+
else
|
|
233
|
+
self.candidates_considered = nil
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
if attributes.key?(:'warnings')
|
|
237
|
+
if (value = attributes[:'warnings']).is_a?(Array)
|
|
238
|
+
self.warnings = value
|
|
90
239
|
end
|
|
91
240
|
else
|
|
92
|
-
self.
|
|
241
|
+
self.warnings = nil
|
|
93
242
|
end
|
|
94
243
|
|
|
95
|
-
if attributes.key?(:'
|
|
96
|
-
self.
|
|
244
|
+
if attributes.key?(:'match_quality')
|
|
245
|
+
self.match_quality = attributes[:'match_quality']
|
|
246
|
+
else
|
|
247
|
+
self.match_quality = 'none'
|
|
97
248
|
end
|
|
98
249
|
|
|
99
|
-
if attributes.key?(:'
|
|
100
|
-
self.
|
|
250
|
+
if attributes.key?(:'reason')
|
|
251
|
+
self.reason = attributes[:'reason']
|
|
101
252
|
end
|
|
102
253
|
|
|
103
|
-
if attributes.key?(:'
|
|
104
|
-
self.
|
|
254
|
+
if attributes.key?(:'suggestion')
|
|
255
|
+
self.suggestion = attributes[:'suggestion']
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
if attributes.key?(:'results')
|
|
259
|
+
if (value = attributes[:'results']).is_a?(Array)
|
|
260
|
+
self.results = value
|
|
261
|
+
end
|
|
262
|
+
else
|
|
263
|
+
self.results = nil
|
|
105
264
|
end
|
|
106
265
|
|
|
107
266
|
if attributes.key?(:'_mock')
|
|
@@ -114,6 +273,34 @@ module Weft
|
|
|
114
273
|
def list_invalid_properties
|
|
115
274
|
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
116
275
|
invalid_properties = Array.new
|
|
276
|
+
if @query_trace_id.nil?
|
|
277
|
+
invalid_properties.push('invalid value for "query_trace_id", query_trace_id cannot be nil.')
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
if @query.nil?
|
|
281
|
+
invalid_properties.push('invalid value for "query", query cannot be nil.')
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
if !@result_count.nil? && @result_count < 0
|
|
285
|
+
invalid_properties.push('invalid value for "result_count", must be greater than or equal to 0.')
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
if @embedder_model.nil?
|
|
289
|
+
invalid_properties.push('invalid value for "embedder_model", embedder_model cannot be nil.')
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
if @candidates_considered.nil?
|
|
293
|
+
invalid_properties.push('invalid value for "candidates_considered", candidates_considered cannot be nil.')
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
if @candidates_considered < 0
|
|
297
|
+
invalid_properties.push('invalid value for "candidates_considered", must be greater than or equal to 0.')
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
if @warnings.nil?
|
|
301
|
+
invalid_properties.push('invalid value for "warnings", warnings cannot be nil.')
|
|
302
|
+
end
|
|
303
|
+
|
|
117
304
|
if @results.nil?
|
|
118
305
|
invalid_properties.push('invalid value for "results", results cannot be nil.')
|
|
119
306
|
end
|
|
@@ -125,10 +312,145 @@ module Weft
|
|
|
125
312
|
# @return true if the model is valid
|
|
126
313
|
def valid?
|
|
127
314
|
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
315
|
+
return false if @query_trace_id.nil?
|
|
316
|
+
return false if @query.nil?
|
|
317
|
+
format_validator = EnumAttributeValidator.new('String', ["json", "markdown"])
|
|
318
|
+
return false unless format_validator.valid?(@format)
|
|
319
|
+
return false if !@result_count.nil? && @result_count < 0
|
|
320
|
+
served_from_validator = EnumAttributeValidator.new('String', ["live", "snapshot"])
|
|
321
|
+
return false unless served_from_validator.valid?(@served_from)
|
|
322
|
+
decomposition_source_validator = EnumAttributeValidator.new('String', ["CALLER"])
|
|
323
|
+
return false unless decomposition_source_validator.valid?(@decomposition_source)
|
|
324
|
+
return false if @embedder_model.nil?
|
|
325
|
+
return false if @candidates_considered.nil?
|
|
326
|
+
return false if @candidates_considered < 0
|
|
327
|
+
return false if @warnings.nil?
|
|
328
|
+
match_quality_validator = EnumAttributeValidator.new('String', ["strong", "weak", "none"])
|
|
329
|
+
return false unless match_quality_validator.valid?(@match_quality)
|
|
330
|
+
reason_validator = EnumAttributeValidator.new('String', ["below_relevance_floor", "filter_collapsed_pool", "no_catalog_coverage", "unsupported_filter_value", "index_unavailable"])
|
|
331
|
+
return false unless reason_validator.valid?(@reason)
|
|
128
332
|
return false if @results.nil?
|
|
129
333
|
true
|
|
130
334
|
end
|
|
131
335
|
|
|
336
|
+
# Custom attribute writer method with validation
|
|
337
|
+
# @param [Object] query_trace_id Value to be assigned
|
|
338
|
+
def query_trace_id=(query_trace_id)
|
|
339
|
+
if query_trace_id.nil?
|
|
340
|
+
fail ArgumentError, 'query_trace_id cannot be nil'
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
@query_trace_id = query_trace_id
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Custom attribute writer method with validation
|
|
347
|
+
# @param [Object] query Value to be assigned
|
|
348
|
+
def query=(query)
|
|
349
|
+
if query.nil?
|
|
350
|
+
fail ArgumentError, 'query cannot be nil'
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
@query = query
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
357
|
+
# @param [Object] format Object to be assigned
|
|
358
|
+
def format=(format)
|
|
359
|
+
validator = EnumAttributeValidator.new('String', ["json", "markdown"])
|
|
360
|
+
unless validator.valid?(format)
|
|
361
|
+
fail ArgumentError, "invalid value for \"format\", must be one of #{validator.allowable_values}."
|
|
362
|
+
end
|
|
363
|
+
@format = format
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Custom attribute writer method with validation
|
|
367
|
+
# @param [Object] result_count Value to be assigned
|
|
368
|
+
def result_count=(result_count)
|
|
369
|
+
if result_count.nil?
|
|
370
|
+
fail ArgumentError, 'result_count cannot be nil'
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
if result_count < 0
|
|
374
|
+
fail ArgumentError, 'invalid value for "result_count", must be greater than or equal to 0.'
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
@result_count = result_count
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
381
|
+
# @param [Object] served_from Object to be assigned
|
|
382
|
+
def served_from=(served_from)
|
|
383
|
+
validator = EnumAttributeValidator.new('String', ["live", "snapshot"])
|
|
384
|
+
unless validator.valid?(served_from)
|
|
385
|
+
fail ArgumentError, "invalid value for \"served_from\", must be one of #{validator.allowable_values}."
|
|
386
|
+
end
|
|
387
|
+
@served_from = served_from
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
391
|
+
# @param [Object] decomposition_source Object to be assigned
|
|
392
|
+
def decomposition_source=(decomposition_source)
|
|
393
|
+
validator = EnumAttributeValidator.new('String', ["CALLER"])
|
|
394
|
+
unless validator.valid?(decomposition_source)
|
|
395
|
+
fail ArgumentError, "invalid value for \"decomposition_source\", must be one of #{validator.allowable_values}."
|
|
396
|
+
end
|
|
397
|
+
@decomposition_source = decomposition_source
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Custom attribute writer method with validation
|
|
401
|
+
# @param [Object] embedder_model Value to be assigned
|
|
402
|
+
def embedder_model=(embedder_model)
|
|
403
|
+
if embedder_model.nil?
|
|
404
|
+
fail ArgumentError, 'embedder_model cannot be nil'
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
@embedder_model = embedder_model
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Custom attribute writer method with validation
|
|
411
|
+
# @param [Object] candidates_considered Value to be assigned
|
|
412
|
+
def candidates_considered=(candidates_considered)
|
|
413
|
+
if candidates_considered.nil?
|
|
414
|
+
fail ArgumentError, 'candidates_considered cannot be nil'
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
if candidates_considered < 0
|
|
418
|
+
fail ArgumentError, 'invalid value for "candidates_considered", must be greater than or equal to 0.'
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
@candidates_considered = candidates_considered
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Custom attribute writer method with validation
|
|
425
|
+
# @param [Object] warnings Value to be assigned
|
|
426
|
+
def warnings=(warnings)
|
|
427
|
+
if warnings.nil?
|
|
428
|
+
fail ArgumentError, 'warnings cannot be nil'
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
@warnings = warnings
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
435
|
+
# @param [Object] match_quality Object to be assigned
|
|
436
|
+
def match_quality=(match_quality)
|
|
437
|
+
validator = EnumAttributeValidator.new('String', ["strong", "weak", "none"])
|
|
438
|
+
unless validator.valid?(match_quality)
|
|
439
|
+
fail ArgumentError, "invalid value for \"match_quality\", must be one of #{validator.allowable_values}."
|
|
440
|
+
end
|
|
441
|
+
@match_quality = match_quality
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Custom attribute writer method checking allowed values (enum).
|
|
445
|
+
# @param [Object] reason Object to be assigned
|
|
446
|
+
def reason=(reason)
|
|
447
|
+
validator = EnumAttributeValidator.new('String', ["below_relevance_floor", "filter_collapsed_pool", "no_catalog_coverage", "unsupported_filter_value", "index_unavailable"])
|
|
448
|
+
unless validator.valid?(reason)
|
|
449
|
+
fail ArgumentError, "invalid value for \"reason\", must be one of #{validator.allowable_values}."
|
|
450
|
+
end
|
|
451
|
+
@reason = reason
|
|
452
|
+
end
|
|
453
|
+
|
|
132
454
|
# Custom attribute writer method with validation
|
|
133
455
|
# @param [Object] results Value to be assigned
|
|
134
456
|
def results=(results)
|
|
@@ -144,10 +466,24 @@ module Weft
|
|
|
144
466
|
def ==(o)
|
|
145
467
|
return true if self.equal?(o)
|
|
146
468
|
self.class == o.class &&
|
|
469
|
+
query_trace_id == o.query_trace_id &&
|
|
470
|
+
query == o.query &&
|
|
471
|
+
format == o.format &&
|
|
472
|
+
markdown == o.markdown &&
|
|
473
|
+
result_count == o.result_count &&
|
|
474
|
+
served_from == o.served_from &&
|
|
475
|
+
as_of == o.as_of &&
|
|
476
|
+
stale == o.stale &&
|
|
477
|
+
payment_note == o.payment_note &&
|
|
478
|
+
applied_filters == o.applied_filters &&
|
|
479
|
+
decomposition_source == o.decomposition_source &&
|
|
480
|
+
embedder_model == o.embedder_model &&
|
|
481
|
+
candidates_considered == o.candidates_considered &&
|
|
482
|
+
warnings == o.warnings &&
|
|
483
|
+
match_quality == o.match_quality &&
|
|
484
|
+
reason == o.reason &&
|
|
485
|
+
suggestion == o.suggestion &&
|
|
147
486
|
results == o.results &&
|
|
148
|
-
paid_usd == o.paid_usd &&
|
|
149
|
-
tx_hash == o.tx_hash &&
|
|
150
|
-
artifact_id == o.artifact_id &&
|
|
151
487
|
_mock == o._mock
|
|
152
488
|
end
|
|
153
489
|
|
|
@@ -160,7 +496,7 @@ module Weft
|
|
|
160
496
|
# Calculates hash code according to all attributes.
|
|
161
497
|
# @return [Integer] Hash code
|
|
162
498
|
def hash
|
|
163
|
-
[
|
|
499
|
+
[query_trace_id, query, format, markdown, result_count, served_from, as_of, stale, payment_note, applied_filters, decomposition_source, embedder_model, candidates_considered, warnings, match_quality, reason, suggestion, results, _mock].hash
|
|
164
500
|
end
|
|
165
501
|
|
|
166
502
|
# Builds the object from hash
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
#Weft API
|
|
3
|
+
|
|
4
|
+
#The Weft API is the buyer-runtime surface that powers the `weft` CLI, the hosted MCP server (`weft.network/mcp`), and any third-party agent that wants to discover and pay for paid resources on Weft. v1 covers five buyer concerns: 1. Account onboarding (`/api/v1/auth/*`, `/api/v1/me`) 2. CLI authentication (`/api/v1/api_keys`) 3. Wallet visibility (`/api/v1/balance`) 4. Discovery (`/api/v1/search`) 5. Paid execution (`/api/v1/fetch`) 6. Purchase history (`/api/v1/purchases`) Seller-side concerns (agent management, payout analytics, webhook delivery, the public storefront for `data_api` resources) live in the dashboard and are intentionally not documented here. They will be split out into a separate, dashboard-scoped spec when they need to be SDK-consumable. All errors share the envelope defined by `ErrorResponse`, except the buyer-runtime endpoints (`/search`, `/fetch`) which use bespoke envelopes carrying additional context — see `SearchErrorResponse` and `FetchErrorResponse`.
|
|
5
|
+
|
|
6
|
+
The version of the OpenAPI document: 0.9.0
|
|
7
|
+
|
|
8
|
+
Generated by: https://openapi-generator.tech
|
|
9
|
+
Generator version: 7.19.0
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
require 'date'
|
|
14
|
+
require 'time'
|
|
15
|
+
|
|
16
|
+
module Weft
|
|
17
|
+
class SearchResponseWarningsInner < ApiModelBase
|
|
18
|
+
attr_accessor :code
|
|
19
|
+
|
|
20
|
+
attr_accessor :message
|
|
21
|
+
|
|
22
|
+
# Typed cause for codes that carry one. Null otherwise.
|
|
23
|
+
attr_accessor :cause
|
|
24
|
+
|
|
25
|
+
# Structured context for the warning. Null when the code carries none.
|
|
26
|
+
attr_accessor :context
|
|
27
|
+
|
|
28
|
+
# Attribute mapping from ruby-style variable name to JSON key.
|
|
29
|
+
def self.attribute_map
|
|
30
|
+
{
|
|
31
|
+
:'code' => :'code',
|
|
32
|
+
:'message' => :'message',
|
|
33
|
+
:'cause' => :'cause',
|
|
34
|
+
:'context' => :'context'
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns attribute mapping this model knows about
|
|
39
|
+
def self.acceptable_attribute_map
|
|
40
|
+
attribute_map
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns all the JSON keys this model knows about
|
|
44
|
+
def self.acceptable_attributes
|
|
45
|
+
acceptable_attribute_map.values
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Attribute type mapping.
|
|
49
|
+
def self.openapi_types
|
|
50
|
+
{
|
|
51
|
+
:'code' => :'String',
|
|
52
|
+
:'message' => :'String',
|
|
53
|
+
:'cause' => :'String',
|
|
54
|
+
:'context' => :'Object'
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# List of attributes with nullable: true
|
|
59
|
+
def self.openapi_nullable
|
|
60
|
+
Set.new([
|
|
61
|
+
])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Initializes the object
|
|
65
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
66
|
+
def initialize(attributes = {})
|
|
67
|
+
if (!attributes.is_a?(Hash))
|
|
68
|
+
fail ArgumentError, "The input argument (attributes) must be a hash in `Weft::SearchResponseWarningsInner` initialize method"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# check to see if the attribute exists and convert string to symbol for hash key
|
|
72
|
+
acceptable_attribute_map = self.class.acceptable_attribute_map
|
|
73
|
+
attributes = attributes.each_with_object({}) { |(k, v), h|
|
|
74
|
+
if (!acceptable_attribute_map.key?(k.to_sym))
|
|
75
|
+
fail ArgumentError, "`#{k}` is not a valid attribute in `Weft::SearchResponseWarningsInner`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
|
|
76
|
+
end
|
|
77
|
+
h[k.to_sym] = v
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if attributes.key?(:'code')
|
|
81
|
+
self.code = attributes[:'code']
|
|
82
|
+
else
|
|
83
|
+
self.code = nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if attributes.key?(:'message')
|
|
87
|
+
self.message = attributes[:'message']
|
|
88
|
+
else
|
|
89
|
+
self.message = nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if attributes.key?(:'cause')
|
|
93
|
+
self.cause = attributes[:'cause']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if attributes.key?(:'context')
|
|
97
|
+
self.context = attributes[:'context']
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Show invalid properties with the reasons. Usually used together with valid?
|
|
102
|
+
# @return Array for valid properties with the reasons
|
|
103
|
+
def list_invalid_properties
|
|
104
|
+
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
105
|
+
invalid_properties = Array.new
|
|
106
|
+
if @code.nil?
|
|
107
|
+
invalid_properties.push('invalid value for "code", code cannot be nil.')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if @message.nil?
|
|
111
|
+
invalid_properties.push('invalid value for "message", message cannot be nil.')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
invalid_properties
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Check to see if the all the properties in the model are valid
|
|
118
|
+
# @return true if the model is valid
|
|
119
|
+
def valid?
|
|
120
|
+
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
121
|
+
return false if @code.nil?
|
|
122
|
+
return false if @message.nil?
|
|
123
|
+
true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Custom attribute writer method with validation
|
|
127
|
+
# @param [Object] code Value to be assigned
|
|
128
|
+
def code=(code)
|
|
129
|
+
if code.nil?
|
|
130
|
+
fail ArgumentError, 'code cannot be nil'
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
@code = code
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Custom attribute writer method with validation
|
|
137
|
+
# @param [Object] message Value to be assigned
|
|
138
|
+
def message=(message)
|
|
139
|
+
if message.nil?
|
|
140
|
+
fail ArgumentError, 'message cannot be nil'
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
@message = message
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Checks equality by comparing each attribute.
|
|
147
|
+
# @param [Object] Object to be compared
|
|
148
|
+
def ==(o)
|
|
149
|
+
return true if self.equal?(o)
|
|
150
|
+
self.class == o.class &&
|
|
151
|
+
code == o.code &&
|
|
152
|
+
message == o.message &&
|
|
153
|
+
cause == o.cause &&
|
|
154
|
+
context == o.context
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @see the `==` method
|
|
158
|
+
# @param [Object] Object to be compared
|
|
159
|
+
def eql?(o)
|
|
160
|
+
self == o
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Calculates hash code according to all attributes.
|
|
164
|
+
# @return [Integer] Hash code
|
|
165
|
+
def hash
|
|
166
|
+
[code, message, cause, context].hash
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Builds the object from hash
|
|
170
|
+
# @param [Hash] attributes Model attributes in the form of hash
|
|
171
|
+
# @return [Object] Returns the model itself
|
|
172
|
+
def self.build_from_hash(attributes)
|
|
173
|
+
return nil unless attributes.is_a?(Hash)
|
|
174
|
+
attributes = attributes.transform_keys(&:to_sym)
|
|
175
|
+
transformed_hash = {}
|
|
176
|
+
openapi_types.each_pair do |key, type|
|
|
177
|
+
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
|
|
178
|
+
transformed_hash["#{key}"] = nil
|
|
179
|
+
elsif type =~ /\AArray<(.*)>/i
|
|
180
|
+
# check to ensure the input is an array given that the attribute
|
|
181
|
+
# is documented as an array but the input is not
|
|
182
|
+
if attributes[attribute_map[key]].is_a?(Array)
|
|
183
|
+
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
|
|
184
|
+
end
|
|
185
|
+
elsif !attributes[attribute_map[key]].nil?
|
|
186
|
+
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
new(transformed_hash)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Returns the object in the form of hash
|
|
193
|
+
# @return [Hash] Returns the object in the form of hash
|
|
194
|
+
def to_hash
|
|
195
|
+
hash = {}
|
|
196
|
+
self.class.attribute_map.each_pair do |attr, param|
|
|
197
|
+
value = self.send(attr)
|
|
198
|
+
if value.nil?
|
|
199
|
+
is_nullable = self.class.openapi_nullable.include?(attr)
|
|
200
|
+
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
hash[param] = _to_hash(value)
|
|
204
|
+
end
|
|
205
|
+
hash
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|