python-skills 1.0.0__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.
Files changed (105) hide show
  1. python_skills/__init__.py +10 -0
  2. python_skills/__main__.py +6 -0
  3. python_skills/adapters/__init__.py +48 -0
  4. python_skills/adapters/agent_skills.py +415 -0
  5. python_skills/adapters/aider_adapter.py +226 -0
  6. python_skills/adapters/base.py +153 -0
  7. python_skills/adapters/claude.py +474 -0
  8. python_skills/adapters/cline.py +332 -0
  9. python_skills/adapters/codex.py +24 -0
  10. python_skills/adapters/continue_adapter.py +198 -0
  11. python_skills/adapters/cursor.py +327 -0
  12. python_skills/adapters/gemini.py +26 -0
  13. python_skills/adapters/goose.py +26 -0
  14. python_skills/adapters/junie.py +25 -0
  15. python_skills/adapters/kiro.py +382 -0
  16. python_skills/adapters/opencode.py +27 -0
  17. python_skills/adapters/roo.py +25 -0
  18. python_skills/adapters/universal.py +203 -0
  19. python_skills/adapters/vscode.py +27 -0
  20. python_skills/adapters/windsurf.py +26 -0
  21. python_skills/adapters/zed.py +27 -0
  22. python_skills/cli.py +326 -0
  23. python_skills/config.py +160 -0
  24. python_skills/detector.py +152 -0
  25. python_skills/installer.py +163 -0
  26. python_skills/markers.py +115 -0
  27. python_skills/skills/__init__.py +14 -0
  28. python_skills/skills/loader.py +171 -0
  29. python_skills/skills/metadata.py +152 -0
  30. python_skills/skills/registry.py +101 -0
  31. python_skills/state.py +204 -0
  32. python_skills-1.0.0.dist-info/METADATA +99 -0
  33. python_skills-1.0.0.dist-info/RECORD +105 -0
  34. python_skills-1.0.0.dist-info/WHEEL +4 -0
  35. python_skills-1.0.0.dist-info/entry_points.txt +2 -0
  36. python_skills-1.0.0.dist-info/licenses/LICENSE +21 -0
  37. skills/advanced_python.md +239 -0
  38. skills/anti_patterns/index.md +406 -0
  39. skills/comprehensions.md +167 -0
  40. skills/control_flow.md +175 -0
  41. skills/data_structures.md +243 -0
  42. skills/debugging/common_bugs.md +222 -0
  43. skills/debugging/inspection_techniques.md +249 -0
  44. skills/debugging/root_cause.md +203 -0
  45. skills/engineering/application_logging.md +195 -0
  46. skills/engineering/cli_apps.md +207 -0
  47. skills/engineering/configuration.md +218 -0
  48. skills/engineering/database.md +240 -0
  49. skills/engineering/dependency_management.md +205 -0
  50. skills/engineering/http_clients.md +267 -0
  51. skills/engineering/modules_packages.md +211 -0
  52. skills/engineering/packaging.md +197 -0
  53. skills/engineering/project_structure.md +155 -0
  54. skills/engineering/pyproject_toml.md +302 -0
  55. skills/engineering/virtual_environments.md +206 -0
  56. skills/functions.md +244 -0
  57. skills/generation/async_concurrency.md +291 -0
  58. skills/generation/error_handling.md +276 -0
  59. skills/generation/protocols_generics.md +243 -0
  60. skills/generation/type_hints.md +290 -0
  61. skills/generation/validation_pipeline.md +274 -0
  62. skills/generation/workflow.md +190 -0
  63. skills/oop.md +228 -0
  64. skills/quality/abstractions.md +154 -0
  65. skills/quality/comments.md +177 -0
  66. skills/quality/documentation.md +176 -0
  67. skills/quality/duplication.md +137 -0
  68. skills/quality/maintainability.md +142 -0
  69. skills/quality/naming.md +171 -0
  70. skills/quality/quality_functions.md +245 -0
  71. skills/quality/readability.md +239 -0
  72. skills/quality/type_annotations.md +192 -0
  73. skills/refactoring/behavior_preservation.md +157 -0
  74. skills/refactoring/incremental.md +187 -0
  75. skills/refactoring/interface_stability.md +199 -0
  76. skills/refactoring/safe_refactoring.md +206 -0
  77. skills/security/auth_boundaries.md +200 -0
  78. skills/security/command_injection.md +207 -0
  79. skills/security/dependency_risks.md +282 -0
  80. skills/security/file_handling.md +156 -0
  81. skills/security/input_validation.md +190 -0
  82. skills/security/path_traversal.md +172 -0
  83. skills/security/secrets.md +171 -0
  84. skills/security/sql_injection.md +188 -0
  85. skills/security/unsafe_deserialization.md +164 -0
  86. skills/stdlib/argparse.md +178 -0
  87. skills/stdlib/collections.md +212 -0
  88. skills/stdlib/datetime.md +187 -0
  89. skills/stdlib/functools.md +238 -0
  90. skills/stdlib/itertools.md +183 -0
  91. skills/stdlib/json.md +162 -0
  92. skills/stdlib/logging.md +185 -0
  93. skills/stdlib/os_sys.md +184 -0
  94. skills/stdlib/pathlib.md +218 -0
  95. skills/stdlib/re.md +171 -0
  96. skills/stdlib/statistics.md +112 -0
  97. skills/stdlib/subprocess.md +211 -0
  98. skills/testing/async_tests.md +249 -0
  99. skills/testing/coverage.md +168 -0
  100. skills/testing/edge_cases.md +197 -0
  101. skills/testing/fixtures_mocks.md +203 -0
  102. skills/testing/organization.md +205 -0
  103. skills/testing/parameterized.md +174 -0
  104. skills/testing/regression_tests.md +165 -0
  105. skills/variables_types.md +107 -0
@@ -0,0 +1,199 @@
1
+ # Refactoring: Interface Stability
2
+
3
+ **Purpose**: Maintain stable public APIs during refactoring.
4
+
5
+ **When to use**: Any change to public functions, classes, or module APIs.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Public API Definition
12
+ - Functions/classes in `__all__`
13
+ - Exported in package `__init__.py`
14
+ - Documented in public docs
15
+ - Used by external consumers
16
+
17
+ ### Stability Principles
18
+ 1. **Add, don't remove** — Add new parameters with defaults
19
+ 2. **Deprecate gracefully** — Warn before removing
20
+ 3. **Version bump** — Breaking changes = major version
21
+ 4. **Migration path** — Provide upgrade guide
22
+
23
+ ### Safe API Evolution
24
+
25
+ #### Adding Parameters
26
+ ```python
27
+ # Before
28
+ def fetch_users(client, limit=100):
29
+ ...
30
+
31
+ # After — add with default (backward compatible)
32
+ def fetch_users(client, limit=100, *, filter=None, sort=None):
33
+ ...
34
+ ```
35
+
36
+ #### Changing Return Type
37
+ ```python
38
+ # BAD — breaks callers
39
+ def get_user(id) -> User:
40
+ ...
41
+
42
+ def get_user(id) -> User | None: # Breaking!
43
+ ...
44
+
45
+ # GOOD — add new function
46
+ def get_user(id) -> User:
47
+ ...
48
+
49
+ def get_user_or_none(id) -> User | None:
50
+ ...
51
+
52
+ # Or use Result type
53
+ def get_user(id) -> Result[User, NotFoundError]:
54
+ ...
55
+ ```
56
+
57
+ #### Deprecation Pattern
58
+ ```python
59
+ import warnings
60
+ from functools import wraps
61
+
62
+ def deprecated(reason: str, version: str):
63
+ def decorator(func):
64
+ @wraps(func)
65
+ def wrapper(*args, **kwargs):
66
+ warnings.warn(
67
+ f"{func.__name__} is deprecated since {version}: {reason}",
68
+ DeprecationWarning,
69
+ stacklevel=2,
70
+ )
71
+ return func(*args, **kwargs)
72
+ return wrapper
73
+ return decorator
74
+
75
+ @deprecated("Use fetch_users_v2()", "2.0")
76
+ def fetch_users(client, limit=100):
77
+ ...
78
+
79
+ # Type stub for deprecated
80
+ from typing import TYPE_CHECKING
81
+ if TYPE_CHECKING:
82
+ def fetch_users(...) -> list[User]: ...
83
+ ```
84
+
85
+ #### Removing Parameters
86
+ ```python
87
+ # Step 1: Make optional with deprecation
88
+ def process(data, *, old_param=None, new_param=None):
89
+ if old_param is not None:
90
+ warnings.warn("old_param deprecated", DeprecationWarning)
91
+ new_param = old_param
92
+ # Use new_param
93
+
94
+ # Step 2: Remove after deprecation period (major version)
95
+ def process(data, *, new_param):
96
+ ...
97
+ ```
98
+
99
+ ### Versioning
100
+ ```toml
101
+ # pyproject.toml
102
+ [project]
103
+ version = "2.1.0" # Semantic: MAJOR.MINOR.PATCH
104
+
105
+ # MAJOR: Breaking API changes
106
+ # MINOR: New features, backward compatible
107
+ # PATCH: Bug fixes, backward compatible
108
+ ```
109
+
110
+ ### Interface Testing
111
+ ```python
112
+ # Test public API surface
113
+ def test_public_api_surface():
114
+ """Ensure public API hasn't accidentally changed"""
115
+ from mypackage import __all__
116
+
117
+ expected = {
118
+ "UserService",
119
+ "User",
120
+ "create_user",
121
+ "get_user",
122
+ "ValidationError",
123
+ }
124
+ assert set(__all__) == expected
125
+
126
+ # Test signatures
127
+ import inspect
128
+
129
+ def test_user_service_signatures():
130
+ sig = inspect.signature(UserService.create)
131
+ params = list(sig.parameters.keys())
132
+ assert params == ["self", "data", "validate"]
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Decision Rules
138
+
139
+ | Change | Approach |
140
+ |--------|----------|
141
+ | New optional parameter | Add with default |
142
+ | New function | Add alongside old |
143
+ | Change return type | New function + deprecate old |
144
+ | Remove parameter | Deprecate → Major version remove |
145
+ | Change behavior | New function + deprecate old |
146
+ | Rename | Add alias + deprecate old |
147
+
148
+ ---
149
+
150
+ ## Preferred Patterns
151
+
152
+ ```python
153
+ # Version-gated imports
154
+ # mypackage/__init__.py
155
+ __version__ = "2.1.0"
156
+
157
+ # V1 API (deprecated)
158
+ from .v1 import UserService as UserServiceV1
159
+ from .v1 import create_user as create_user_v1
160
+
161
+ # V2 API (current)
162
+ from .v2 import UserService
163
+ from .v2 import create_user
164
+
165
+ # Deprecated aliases
166
+ import warnings
167
+ warnings.warn(
168
+ "UserServiceV1 is deprecated, use UserService",
169
+ DeprecationWarning,
170
+ )
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Avoid
176
+
177
+ - Silent breaking changes
178
+ - Removing public API in patch/minor
179
+ - Changing exception types
180
+ - Modifying default behavior
181
+ - Breaking `__all__` without major version
182
+
183
+ ---
184
+
185
+ ## Validation Considerations
186
+
187
+ - `pytest --collect-only` shows API surface
188
+ - `pip install -e . && python -c "import mypackage"` works
189
+ - Downstream consumers tested (if possible)
190
+ - Changelog documents all API changes
191
+
192
+ ---
193
+
194
+ ## Related Skills
195
+
196
+ - `refactoring/safe_refactoring.md`
197
+ - `refactoring/behavior_preservation.md`
198
+ - `engineering/pyproject_toml.md`
199
+ - `engineering/packaging.md`
@@ -0,0 +1,206 @@
1
+ # Refactoring: Safe Refactoring
2
+
3
+ **Purpose**: Refactoring rules that preserve behavior and minimize risk.
4
+
5
+ **When to use**: Any code restructuring, cleanup, or improvement.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Refactoring Principles
12
+ 1. **Tests first** — No refactoring without tests
13
+ 2. **Small steps** — One change at a time
14
+ 3. **Run tests after each step** — Verify immediately
15
+ 4. **Preserve behavior** — No functional changes
16
+ 5. **Commit often** — Easy rollback
17
+
18
+ ### Refactoring Workflow
19
+ ```
20
+ 1. RUN TESTS (baseline)
21
+ 2. IDENTIFY refactoring goal
22
+ 3. MAKE SMALLEST CHANGE
23
+ 4. RUN TESTS
24
+ 5. REPEAT 3-4 until goal achieved
25
+ 6. RUN FULL TEST SUITE
26
+ 7. REVIEW DIFF
27
+ ```
28
+
29
+ ### Safe Refactoring Patterns
30
+
31
+ #### Extract Function
32
+ ```python
33
+ # Before
34
+ def process_order(order):
35
+ validate(order)
36
+ total = calculate_total(order.items)
37
+ tax = total * TAX_RATE
38
+ final = total + tax
39
+ save_order(order, final)
40
+ send_confirmation(order)
41
+
42
+ # After — extract calculation
43
+ def calculate_final_total(items):
44
+ total = calculate_total(items)
45
+ tax = total * TAX_RATE
46
+ return total + tax
47
+
48
+ def process_order(order):
49
+ validate(order)
50
+ final = calculate_final_total(order.items)
51
+ save_order(order, final)
52
+ send_confirmation(order)
53
+ ```
54
+
55
+ #### Extract Class
56
+ ```python
57
+ # Before — mixed responsibilities
58
+ class OrderProcessor:
59
+ def process(self, order):
60
+ self.validate(order)
61
+ self.calculate_pricing(order)
62
+ self.save(order)
63
+ self.notify(order)
64
+
65
+ # After — separate concerns
66
+ class OrderValidator:
67
+ def validate(self, order): ...
68
+
69
+ class PricingCalculator:
70
+ def calculate(self, order): ...
71
+
72
+ class OrderRepository:
73
+ def save(self, order): ...
74
+
75
+ class NotificationService:
76
+ def notify(self, order): ...
77
+
78
+ class OrderProcessor:
79
+ def __init__(self, validator, calculator, repo, notifier):
80
+ self.validator = validator
81
+ self.calculator = calculator
82
+ self.repo = repo
83
+ self.notifier = notifier
84
+
85
+ def process(self, order):
86
+ self.validator.validate(order)
87
+ self.calculator.calculate(order)
88
+ self.repo.save(order)
89
+ self.notifier.notify(order)
90
+ ```
91
+
92
+ #### Replace Conditional with Polymorphism
93
+ ```python
94
+ # Before
95
+ def process_payment(payment):
96
+ if payment.type == "credit":
97
+ process_credit(payment)
98
+ elif payment.type == "debit":
99
+ process_debit(payment)
100
+ elif payment.type == "paypal":
101
+ process_paypal(payment)
102
+
103
+ # After
104
+ class PaymentProcessor(Protocol):
105
+ def process(self, payment): ...
106
+
107
+ class CreditProcessor:
108
+ def process(self, payment): ...
109
+
110
+ class DebitProcessor:
111
+ def process(self, payment): ...
112
+
113
+ class PayPalProcessor:
114
+ def process(self, payment): ...
115
+
116
+ PROCESSORS = {
117
+ "credit": CreditProcessor(),
118
+ "debit": DebitProcessor(),
119
+ "paypal": PayPalProcessor(),
120
+ }
121
+
122
+ def process_payment(payment):
123
+ PROCESSORS[payment.type].process(payment)
124
+ ```
125
+
126
+ #### Introduce Parameter Object
127
+ ```python
128
+ # Before
129
+ def create_user(email, name, age, address, phone, preferences, referral):
130
+ ...
131
+
132
+ # After
133
+ @dataclass
134
+ class UserData:
135
+ email: str
136
+ name: str
137
+ age: int
138
+ address: str
139
+ phone: str
140
+ preferences: dict
141
+ referral: str | None = None
142
+
143
+ def create_user(data: UserData):
144
+ ...
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Decision Rules
150
+
151
+ | Refactoring | When Safe |
152
+ |-------------|-----------|
153
+ | Extract function | Pure logic, well-tested |
154
+ | Extract class | Clear responsibility boundary |
155
+ | Rename | IDE refactoring, all references updated |
156
+ | Move method | No behavior change |
157
+ | Replace conditional | Open/closed principle needed |
158
+ | Introduce parameter object | >4 related parameters |
159
+
160
+ ---
161
+
162
+ ## Preferred Patterns
163
+
164
+ ```python
165
+ # Strangler Fig for large refactors
166
+ # 1. Create new implementation alongside old
167
+ # 2. Route new calls to new implementation
168
+ # 3. Migrate callers one by one
169
+ # 4. Remove old implementation
170
+
171
+ # Feature flag for safe rollout
172
+ def process_order(order):
173
+ if settings.use_new_pricing:
174
+ return new_pricing.calculate(order)
175
+ return old_pricing.calculate(order)
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Avoid
181
+
182
+ - Refactoring without tests
183
+ - Multiple changes in one step
184
+ - "While I'm here" changes
185
+ - Changing behavior during refactor
186
+ - Big bang refactoring
187
+ - Refactoring working code unnecessarily
188
+
189
+ ---
190
+
191
+ ## Validation Considerations
192
+
193
+ - Tests pass at every step
194
+ - `git diff` shows only refactoring
195
+ - No behavior changes in diff
196
+ - Performance regression check
197
+ - Code review focused on structure
198
+
199
+ ---
200
+
201
+ ## Related Skills
202
+
203
+ - `refactoring/incremental.md`
204
+ - `refactoring/behavior_preservation.md`
205
+ - `testing/regression_tests.md`
206
+ - `testing/organization.md`
@@ -0,0 +1,200 @@
1
+ # Security: Authentication/Authorization Boundaries
2
+
3
+ **Purpose**: Enforce auth boundaries correctly in code.
4
+
5
+ **When to use**: Any code with user identity, permissions, or access control.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Authentication vs Authorization
12
+ - **Authentication**: Who are you? (Identity)
13
+ - **Authorization**: What can you do? (Permissions)
14
+
15
+ ### Never Trust Client-Side Identity
16
+ ```python
17
+ # WRONG — trusting header
18
+ def get_user_profile(request, user_id: str):
19
+ return db.get_user(user_id) # User can access ANY profile!
20
+
21
+ # CORRECT — verified identity
22
+ def get_user_profile(request, current_user: User):
23
+ if current_user.id != request.path_params["user_id"]:
24
+ raise ForbiddenError()
25
+ return current_user
26
+ ```
27
+
28
+ ### Authorization at Boundary
29
+ ```python
30
+ # Dependency injection (FastAPI example)
31
+ async def get_current_user(
32
+ token: str = Depends(oauth2_scheme),
33
+ user_service: UserService = Depends(),
34
+ ) -> User:
35
+ user = await user_service.verify_token(token)
36
+ if not user:
37
+ raise UnauthorizedError()
38
+ return user
39
+
40
+ @app.get("/users/{user_id}")
41
+ async def get_user(
42
+ user_id: str,
43
+ current_user: User = Depends(get_current_user),
44
+ user_service: UserService = Depends(),
45
+ ):
46
+ # Authorization check
47
+ if not current_user.can_access_user(user_id):
48
+ raise ForbiddenError("Cannot access this user")
49
+ return await user_service.get(user_id)
50
+ ```
51
+
52
+ ### Permission Models
53
+ ```python
54
+ # Role-based
55
+ class Role(str, Enum):
56
+ ADMIN = "admin"
57
+ USER = "user"
58
+ VIEWER = "viewer"
59
+
60
+ # Permission-based (more flexible)
61
+ class Permission(str, Enum):
62
+ USER_READ = "user:read"
63
+ USER_WRITE = "user:write"
64
+ ADMIN_PANEL = "admin:panel"
65
+
66
+ # User model
67
+ class User(BaseModel):
68
+ id: str
69
+ roles: list[Role] = []
70
+ permissions: list[Permission] = []
71
+
72
+ def has_permission(self, perm: Permission) -> bool:
73
+ return perm in self.permissions or Role.ADMIN in self.roles
74
+
75
+ def can_access_user(self, user_id: str) -> bool:
76
+ return self.id == user_id or self.has_permission(Permission.USER_READ)
77
+ ```
78
+
79
+ ### Resource-Level Authorization
80
+ ```python
81
+ # Policy-based
82
+ class AuthorizationPolicy:
83
+ def can_read(self, user: User, resource: Resource) -> bool:
84
+ if user.has_permission(Permission.ADMIN):
85
+ return True
86
+ return resource.owner_id == user.id or resource.is_public
87
+
88
+ def can_write(self, user: User, resource: Resource) -> bool:
89
+ if user.has_permission(Permission.ADMIN):
90
+ return True
91
+ return resource.owner_id == user.id
92
+
93
+ # Usage
94
+ policy = AuthorizationPolicy()
95
+
96
+ @app.put("/resources/{resource_id}")
97
+ async def update_resource(
98
+ resource_id: str,
99
+ data: ResourceUpdate,
100
+ current_user: User = Depends(get_current_user),
101
+ resource_service: ResourceService = Depends(),
102
+ ):
103
+ resource = await resource_service.get(resource_id)
104
+ if not policy.can_write(current_user, resource):
105
+ raise ForbiddenError()
106
+ return await resource_service.update(resource_id, data)
107
+ ```
108
+
109
+ ### Secure Session/Cookie Handling
110
+ ```python
111
+ # HttpOnly, Secure, SameSite cookies
112
+ response.set_cookie(
113
+ "session",
114
+ session_token,
115
+ httponly=True,
116
+ secure=True, # HTTPS only
117
+ samesite="lax", # CSRF protection
118
+ max_age=3600,
119
+ )
120
+
121
+ # CSRF protection for state-changing operations
122
+ @app.post("/action")
123
+ async def action(
124
+ request: Request,
125
+ csrf_token: str = Form(),
126
+ session: Session = Depends(get_session),
127
+ ):
128
+ if not verify_csrf(session, csrf_token):
129
+ raise ForbiddenError("Invalid CSRF token")
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Decision Rules
135
+
136
+ | Boundary | Enforcement |
137
+ |----------|-------------|
138
+ | API endpoint | Dependency injection + policy check |
139
+ | Database query | Filter by user_id in query (not post-filter) |
140
+ | File access | Verify ownership before serve |
141
+ | Admin panel | Role check + audit log |
142
+ | Internal service | mTLS / service mesh / shared secret |
143
+
144
+ ---
145
+
146
+ ## Preferred Patterns
147
+
148
+ ```python
149
+ # Centralized authorization
150
+ class AuthorizationService:
151
+ def __init__(self, policy: AuthorizationPolicy):
152
+ self.policy = policy
153
+
154
+ def authorize(self, user: User, action: str, resource: Resource) -> None:
155
+ if not self.policy.check(user, action, resource):
156
+ raise ForbiddenError(f"Cannot {action} {resource}")
157
+
158
+ # Decorator for endpoints
159
+ def require_permission(perm: Permission):
160
+ def decorator(func):
161
+ @wraps(func)
162
+ async def wrapper(*args, current_user: User = Depends(get_current_user), **kwargs):
163
+ if not current_user.has_permission(perm):
164
+ raise ForbiddenError(f"Requires {perm}")
165
+ return await func(*args, current_user=current_user, **kwargs)
166
+ return wrapper
167
+ return decorator
168
+
169
+ @require_permission(Permission.USER_WRITE)
170
+ async def create_user(...):
171
+ ...
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Avoid
177
+
178
+ - Checking permissions after fetching data (leak via error messages)
179
+ - Client-controlled authorization (user_id in body/query)
180
+ - Missing authorization on any state-changing endpoint
181
+ - Hardcoded role checks (`if user.role == "admin"`) instead of permissions
182
+ - No audit logging for sensitive operations
183
+
184
+ ---
185
+
186
+ ## Validation Considerations
187
+
188
+ - Test with different user roles
189
+ - Test resource access boundaries
190
+ - Test privilege escalation attempts
191
+ - Audit log review
192
+
193
+ ---
194
+
195
+ ## Related Skills
196
+
197
+ - `security/input_validation.md`
198
+ - `security/secrets.md`
199
+ - `generation/error_handling.md`
200
+ - `engineering/http_clients.md`