blocket-api 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {blocket_api-0.3.1/blocket_api.egg-info → blocket_api-0.3.3}/PKG-INFO +35 -3
- blocket_api-0.3.1/PKG-INFO → blocket_api-0.3.3/README.md +33 -18
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api/blocket.py +51 -6
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api/models.py +18 -0
- blocket_api-0.3.1/README.md → blocket_api-0.3.3/blocket_api.egg-info/PKG-INFO +50 -1
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api.egg-info/requires.txt +1 -1
- {blocket_api-0.3.1 → blocket_api-0.3.3}/pyproject.toml +2 -2
- {blocket_api-0.3.1 → blocket_api-0.3.3}/LICENSE +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api/__init__.py +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api/qasa.py +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api.egg-info/SOURCES.txt +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api.egg-info/dependency_links.txt +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/blocket_api.egg-info/top_level.txt +0 -0
- {blocket_api-0.3.1 → blocket_api-0.3.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blocket_api
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A python API wrapper for blocket.se
|
|
5
5
|
Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -12,7 +12,7 @@ Requires-Dist: pytest>=8.2.2
|
|
|
12
12
|
Requires-Dist: respx>=0.21.1
|
|
13
13
|
Requires-Dist: mypy>=1.15.0
|
|
14
14
|
Requires-Dist: pydantic>=2.11.7
|
|
15
|
-
Requires-Dist: ruff>=0.13.
|
|
15
|
+
Requires-Dist: ruff>=0.13.2
|
|
16
16
|
Dynamic: license-file
|
|
17
17
|
|
|
18
18
|
# BlocketAPI
|
|
@@ -61,7 +61,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
61
61
|
|
|
62
62
|
| Function | Token required | `as_objects` | Description |
|
|
63
63
|
|---|---|---|---|
|
|
64
|
-
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes |
|
|
64
|
+
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
|
|
65
65
|
| [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
|
|
66
66
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
67
67
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
@@ -71,6 +71,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
71
71
|
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
72
72
|
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
73
73
|
| [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
|
|
74
|
+
| [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
75
|
+
| [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
74
76
|
|
|
75
77
|
|
|
76
78
|
## 🤓 Detailed usage
|
|
@@ -79,6 +81,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
79
81
|
|
|
80
82
|
Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
|
|
81
83
|
|
|
84
|
+
Parameters:
|
|
85
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
86
|
+
|
|
82
87
|
```py
|
|
83
88
|
>>> api.saved_searches()
|
|
84
89
|
[
|
|
@@ -327,6 +332,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
|
|
|
327
332
|
}
|
|
328
333
|
```
|
|
329
334
|
|
|
335
|
+
### save_ad
|
|
336
|
+
This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
|
|
337
|
+
|
|
338
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
339
|
+
|
|
340
|
+
```py
|
|
341
|
+
>>> api.save_ad(1234)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### get_saved_ads
|
|
345
|
+
Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
|
|
346
|
+
|
|
347
|
+
```py
|
|
348
|
+
>>> api.get_saved_ads()
|
|
349
|
+
{
|
|
350
|
+
'data': [{
|
|
351
|
+
'ad_id': '1213682185'
|
|
352
|
+
'list_id': '1213682185'
|
|
353
|
+
'subject': 'Jeans från Gina tricot 158'
|
|
354
|
+
'body': 'Moderna jeans från Gina Tricot!'
|
|
355
|
+
...
|
|
356
|
+
}]
|
|
357
|
+
...
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
|
|
330
362
|
## 🔐 Blocket API token
|
|
331
363
|
|
|
332
364
|
There are two ways to acquire your token:
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: blocket_api
|
|
3
|
-
Version: 0.3.1
|
|
4
|
-
Summary: A python API wrapper for blocket.se
|
|
5
|
-
Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
Requires-Dist: httpx>=0.27.0
|
|
10
|
-
Requires-Dist: pre-commit>=3.7.1
|
|
11
|
-
Requires-Dist: pytest>=8.2.2
|
|
12
|
-
Requires-Dist: respx>=0.21.1
|
|
13
|
-
Requires-Dist: mypy>=1.15.0
|
|
14
|
-
Requires-Dist: pydantic>=2.11.7
|
|
15
|
-
Requires-Dist: ruff>=0.13.1
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
1
|
# BlocketAPI
|
|
19
2
|
|
|
20
3
|
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE)  
|
|
@@ -61,7 +44,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
61
44
|
|
|
62
45
|
| Function | Token required | `as_objects` | Description |
|
|
63
46
|
|---|---|---|---|
|
|
64
|
-
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes |
|
|
47
|
+
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
|
|
65
48
|
| [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
|
|
66
49
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
67
50
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
@@ -71,6 +54,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
71
54
|
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
72
55
|
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
73
56
|
| [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
|
|
57
|
+
| [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
58
|
+
| [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
74
59
|
|
|
75
60
|
|
|
76
61
|
## 🤓 Detailed usage
|
|
@@ -79,6 +64,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
79
64
|
|
|
80
65
|
Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
|
|
81
66
|
|
|
67
|
+
Parameters:
|
|
68
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
69
|
+
|
|
82
70
|
```py
|
|
83
71
|
>>> api.saved_searches()
|
|
84
72
|
[
|
|
@@ -327,6 +315,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
|
|
|
327
315
|
}
|
|
328
316
|
```
|
|
329
317
|
|
|
318
|
+
### save_ad
|
|
319
|
+
This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
|
|
320
|
+
|
|
321
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
322
|
+
|
|
323
|
+
```py
|
|
324
|
+
>>> api.save_ad(1234)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### get_saved_ads
|
|
328
|
+
Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
|
|
329
|
+
|
|
330
|
+
```py
|
|
331
|
+
>>> api.get_saved_ads()
|
|
332
|
+
{
|
|
333
|
+
'data': [{
|
|
334
|
+
'ad_id': '1213682185'
|
|
335
|
+
'list_id': '1213682185'
|
|
336
|
+
'subject': 'Jeans från Gina tricot 158'
|
|
337
|
+
'body': 'Moderna jeans från Gina Tricot!'
|
|
338
|
+
...
|
|
339
|
+
}]
|
|
340
|
+
...
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
|
|
330
345
|
## 🔐 Blocket API token
|
|
331
346
|
|
|
332
347
|
There are two ways to acquire your token:
|
|
@@ -15,6 +15,7 @@ from blocket_api.models import (
|
|
|
15
15
|
CustomSearchResults,
|
|
16
16
|
HomeSearchResults,
|
|
17
17
|
MotorSearchResults,
|
|
18
|
+
SavedSearchResponse,
|
|
18
19
|
StoreListings,
|
|
19
20
|
StoreSearchResults,
|
|
20
21
|
)
|
|
@@ -165,7 +166,11 @@ def public_token(method: Callable) -> Callable:
|
|
|
165
166
|
|
|
166
167
|
|
|
167
168
|
def _make_request(
|
|
168
|
-
*,
|
|
169
|
+
*,
|
|
170
|
+
method: Callable[..., Response] = httpx.get,
|
|
171
|
+
url: str,
|
|
172
|
+
token: str | None,
|
|
173
|
+
raise_for_status: bool = True,
|
|
169
174
|
) -> Response:
|
|
170
175
|
headers = {
|
|
171
176
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
|
|
@@ -173,11 +178,11 @@ def _make_request(
|
|
|
173
178
|
if token:
|
|
174
179
|
headers["Authorization"] = f"Bearer {token}"
|
|
175
180
|
try:
|
|
176
|
-
response =
|
|
181
|
+
response = method(url, headers=headers)
|
|
177
182
|
if raise_for_status:
|
|
178
183
|
response.raise_for_status()
|
|
179
|
-
except Exception as
|
|
180
|
-
raise APIError(
|
|
184
|
+
except Exception as e:
|
|
185
|
+
raise APIError(e)
|
|
181
186
|
return response
|
|
182
187
|
|
|
183
188
|
|
|
@@ -185,8 +190,28 @@ def _make_request(
|
|
|
185
190
|
class BlocketAPI:
|
|
186
191
|
token: str | None = None
|
|
187
192
|
|
|
193
|
+
@overload
|
|
194
|
+
def saved_searches(
|
|
195
|
+
self,
|
|
196
|
+
limit: int = 99,
|
|
197
|
+
*,
|
|
198
|
+
as_objects: Literal[True],
|
|
199
|
+
) -> SavedSearchResponse: ...
|
|
200
|
+
|
|
201
|
+
@overload
|
|
202
|
+
def saved_searches(
|
|
203
|
+
self,
|
|
204
|
+
limit: int = 99,
|
|
205
|
+
*,
|
|
206
|
+
as_objects: Literal[False] = False,
|
|
207
|
+
) -> list[dict]: ...
|
|
208
|
+
|
|
188
209
|
@auth_token
|
|
189
|
-
def saved_searches(
|
|
210
|
+
def saved_searches(
|
|
211
|
+
self,
|
|
212
|
+
*,
|
|
213
|
+
as_objects: bool = False,
|
|
214
|
+
) -> list[dict] | SavedSearchResponse:
|
|
190
215
|
"""
|
|
191
216
|
Retrieves saved searches data, also known as "Bevakningar".
|
|
192
217
|
"""
|
|
@@ -205,7 +230,8 @@ class BlocketAPI:
|
|
|
205
230
|
.get("data", [])
|
|
206
231
|
)
|
|
207
232
|
|
|
208
|
-
|
|
233
|
+
result = searches + mobility_searches
|
|
234
|
+
return SavedSearchResponse(searches=result) if as_objects else result
|
|
209
235
|
|
|
210
236
|
def _for_search_id(self, search_id: int, limit: int) -> dict:
|
|
211
237
|
assert self.token
|
|
@@ -568,3 +594,22 @@ class BlocketAPI:
|
|
|
568
594
|
url = f"{BASE_URL}/profile-be/v1/public-profiles/{user_id}"
|
|
569
595
|
response = _make_request(url=f"{url}", token=self.token).json()
|
|
570
596
|
return BlocketUser.model_validate(response) if as_objects else response
|
|
597
|
+
|
|
598
|
+
@auth_token
|
|
599
|
+
def save_ad(self, ad_id: int) -> dict:
|
|
600
|
+
"""
|
|
601
|
+
Save an ad to "Saved ads" which can be found here:
|
|
602
|
+
https://www.blocket.se/sparade/annonser
|
|
603
|
+
"""
|
|
604
|
+
url = f"{BASE_URL}/search_bff/v1/saved_content/{ad_id}"
|
|
605
|
+
response = _make_request(method=httpx.put, url=f"{url}", token=self.token)
|
|
606
|
+
return {"status_code": response.status_code}
|
|
607
|
+
|
|
608
|
+
@auth_token
|
|
609
|
+
def get_saved_ads(self, limit: int = 100) -> dict:
|
|
610
|
+
"""
|
|
611
|
+
Returns all of your saved ads from https://www.blocket.se/sparade/annonser.
|
|
612
|
+
"""
|
|
613
|
+
url = f"{BASE_URL}/search_bff/v1/saved_content?lim={limit}"
|
|
614
|
+
response = _make_request(url=f"{url}", token=self.token).json()
|
|
615
|
+
return response
|
|
@@ -590,3 +590,21 @@ class BlocketUser(BaseModel):
|
|
|
590
590
|
co2_savings: BlocketUserCO2Savings
|
|
591
591
|
profile_info: BlocketUserProfileInfo
|
|
592
592
|
review_scores: dict | None = None
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
### SavedSearchesResult ###
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
class SavedSearch(BaseModel):
|
|
599
|
+
id: str
|
|
600
|
+
name: str
|
|
601
|
+
query: str
|
|
602
|
+
total_count: int
|
|
603
|
+
new_count: int
|
|
604
|
+
push_enabled: bool
|
|
605
|
+
push_available: bool
|
|
606
|
+
email_enabled: bool | None = None
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
class SavedSearchResponse(BaseModel):
|
|
610
|
+
searches: list[SavedSearch]
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blocket_api
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: A python API wrapper for blocket.se
|
|
5
|
+
Author-email: dunderrrrrr <emil.bjorkroth@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: httpx>=0.27.0
|
|
10
|
+
Requires-Dist: pre-commit>=3.7.1
|
|
11
|
+
Requires-Dist: pytest>=8.2.2
|
|
12
|
+
Requires-Dist: respx>=0.21.1
|
|
13
|
+
Requires-Dist: mypy>=1.15.0
|
|
14
|
+
Requires-Dist: pydantic>=2.11.7
|
|
15
|
+
Requires-Dist: ruff>=0.13.2
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
1
18
|
# BlocketAPI
|
|
2
19
|
|
|
3
20
|
[](https://pypi.org/project/blocket_api/) [](https://github.com/dunderrrrrr/blocket_api/blob/main/LICENSE)  
|
|
@@ -44,7 +61,7 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
44
61
|
|
|
45
62
|
| Function | Token required | `as_objects` | Description |
|
|
46
63
|
|---|---|---|---|
|
|
47
|
-
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes |
|
|
64
|
+
| [`api.saved_searches()`](#saved_searches) | 🔐 Yes | Yes | List your saved searches (bevakningar) |
|
|
48
65
|
| [`api.get_listings()`](#get_listings) | 🔐 Yes | - | List items related to a saved search |
|
|
49
66
|
| [`api.custom_search()`](#custom_search) | 👏 No | Yes | Search for everything on Blocket and filter by region |
|
|
50
67
|
| [`api.motor_search()`](#motor_search) | 👏 No | Yes | Advanced search for car-listings. |
|
|
@@ -54,6 +71,8 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
54
71
|
| [`api.get_store_listings()`](#get_store_listings) | 👏 No | Yes | Get listings from a specific store.
|
|
55
72
|
| [`api.get_ad_by_id()`](#get_ad_by_id) | 👏 No | Yes | Get ad data from id.
|
|
56
73
|
| [`api.get_user_by_id()`](#get_user_by_id) | 👏 No | Yes | Get user data from id.
|
|
74
|
+
| [`api.save_ad()`](#save_ad) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
75
|
+
| [`api.get_saved_ads()`](#get_saved_ads) | 🔐 Yes | - | Save ad to "Saved ads".
|
|
57
76
|
|
|
58
77
|
|
|
59
78
|
## 🤓 Detailed usage
|
|
@@ -62,6 +81,9 @@ Some calls require a `bearerToken`. However, some calls are public and don't req
|
|
|
62
81
|
|
|
63
82
|
Saved searches are your so called "Bevakningar" and can be found [here](https://www.blocket.se/sparade/bevakningar). Each saved search has and unique `id` which can be used as a parameter to `get_listings()`, see below.
|
|
64
83
|
|
|
84
|
+
Parameters:
|
|
85
|
+
- `as_objects` (`bool`, optional) - Return results as pydantic models, default is `False`.
|
|
86
|
+
|
|
65
87
|
```py
|
|
66
88
|
>>> api.saved_searches()
|
|
67
89
|
[
|
|
@@ -310,6 +332,33 @@ Get user data from a user id. User id can be found in ads, searches and in block
|
|
|
310
332
|
}
|
|
311
333
|
```
|
|
312
334
|
|
|
335
|
+
### save_ad
|
|
336
|
+
This saves the ad to "Saved ads" which can be found here at `https://www.blocket.se/sparade/annonser`. When saving an ad, blocket always responds with 204, even if the ad is already saved or does not exist.
|
|
337
|
+
|
|
338
|
+
- `ad_id` (`int`, required) - The ad id. Can be found by calling any other method or from ad url.
|
|
339
|
+
|
|
340
|
+
```py
|
|
341
|
+
>>> api.save_ad(1234)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### get_saved_ads
|
|
345
|
+
Returns all of your saved ads from `https://www.blocket.se/sparade/annonser`.
|
|
346
|
+
|
|
347
|
+
```py
|
|
348
|
+
>>> api.get_saved_ads()
|
|
349
|
+
{
|
|
350
|
+
'data': [{
|
|
351
|
+
'ad_id': '1213682185'
|
|
352
|
+
'list_id': '1213682185'
|
|
353
|
+
'subject': 'Jeans från Gina tricot 158'
|
|
354
|
+
'body': 'Moderna jeans från Gina Tricot!'
|
|
355
|
+
...
|
|
356
|
+
}]
|
|
357
|
+
...
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
|
|
313
362
|
## 🔐 Blocket API token
|
|
314
363
|
|
|
315
364
|
There are two ways to acquire your token:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "blocket_api"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.3"
|
|
4
4
|
description = "A python API wrapper for blocket.se"
|
|
5
5
|
authors = [{name = "dunderrrrrr", email = "emil.bjorkroth@gmail.com"}]
|
|
6
6
|
readme = "README.md"
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
"respx>=0.21.1",
|
|
13
13
|
"mypy>=1.15.0",
|
|
14
14
|
"pydantic>=2.11.7",
|
|
15
|
-
"ruff>=0.13.
|
|
15
|
+
"ruff>=0.13.2",
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|