resilient-circuit 0.4.1__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.
@@ -0,0 +1,443 @@
1
+ Metadata-Version: 2.4
2
+ Name: resilient-circuit
3
+ Version: 0.4.1
4
+ Summary: A resilient circuit breaker and retry library with PostgreSQL support for distributed systems
5
+ Author-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
6
+ License: Apache Software License 2.0
7
+ Project-URL: Homepage, https://github.com/rodmena-limited/resilient-circuit
8
+ Project-URL: Repository, https://github.com/rodmena-limited/resilient-circuit
9
+ Project-URL: Documentation, https://resilient-circuit.readthedocs.io
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: System :: Distributed Computing
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: typing-extensions>=4.0.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: black>=23.0.0; extra == "dev"
28
+ Requires-Dist: isort>=5.0.0; extra == "dev"
29
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-mock>=3.0.0; extra == "dev"
32
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
33
+ Provides-Extra: postgres
34
+ Requires-Dist: psycopg[binary]>=3.1.0; extra == "postgres"
35
+ Requires-Dist: python-dotenv>=1.0.0; extra == "postgres"
36
+ Provides-Extra: docs
37
+ Requires-Dist: sphinx>=7.0.0; extra == "docs"
38
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
39
+ Requires-Dist: sphinx-autodoc-typehints>=1.25.0; extra == "docs"
40
+ Dynamic: license-file
41
+
42
+ # Resilient Circuit
43
+
44
+ <div align="center">
45
+
46
+ [![PyPI version](https://badge.fury.io/py/resilient-circuit.svg)](https://badge.fury.io/py/resilient-circuit)
47
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
48
+ [![Python Versions](https://img.shields.io/pypi/pyversions/resilient-circuit.svg)](https://pypi.org/project/resilient-circuit/)
49
+ [![Documentation Status](https://readthedocs.org/projects/resilient-circuit/badge/?version=latest)](https://resilient-circuit.readthedocs.io/)
50
+
51
+ **Part of the Highway Workflow Engine** - A robust resilience library for Python applications
52
+ </div>
53
+
54
+ ---
55
+
56
+ ## Overview
57
+
58
+ Resilient Circuit is a powerful resilience library designed to make your Python applications fault-tolerant and highly available. It's an integral component of the Highway Workflow Engine, providing essential failure handling capabilities for modern distributed systems.
59
+
60
+ This library implements the Circuit Breaker and Retry patterns, offering elegant solutions for handling failures in networked systems, external service calls, and unreliable dependencies.
61
+
62
+ For comprehensive documentation, visit our [Read the Docs page](https://resilient-circuit.readthedocs.io/).
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ pip install resilient_circuit
68
+ ```
69
+
70
+ ### PostgreSQL Storage Support (Optional)
71
+
72
+ For shared state across multiple instances, you can use PostgreSQL as the storage backend:
73
+
74
+ ```bash
75
+ pip install resilient_circuit[postgres]
76
+ ```
77
+
78
+ Or install the dependencies separately:
79
+
80
+ ```bash
81
+ pip install psycopg[binary] python-dotenv
82
+ ```
83
+
84
+ ## Features
85
+
86
+ - **Circuit Breaker Pattern**: Prevents cascading failures in distributed systems
87
+ - **Retry Pattern**: Automatically retries failed operations with configurable backoff
88
+ - **Composable**: Chain multiple policies together for sophisticated error handling
89
+ - **Decorator Support**: Clean, easy-to-read syntax with Python decorators
90
+ - **Fine-grained Control**: Configure failure thresholds, cooldown periods, and backoff strategies
91
+ - **State Monitoring**: Track breaker state and execution history
92
+ - **Shared State Storage**: Optional PostgreSQL backend for distributed applications
93
+
94
+ ## Quick Start
95
+
96
+ ### Basic Circuit Protector
97
+
98
+ ```python
99
+ from datetime import timedelta
100
+ from fractions import Fraction
101
+ from resilient_circuit import CircuitProtectorPolicy
102
+
103
+ # Create a circuit protector that trips after 3 failures
104
+ protector = CircuitProtectorPolicy(
105
+ failure_limit=Fraction(3, 10), # 3 out of 10 failures
106
+ cooldown=timedelta(seconds=30) # 30-second cooldown
107
+ )
108
+
109
+ @protector
110
+ def unreliable_service_call():
111
+ # Your potentially failing external service call
112
+ import random
113
+ if random.random() < 0.7:
114
+ raise Exception("Service temporarily unavailable")
115
+ return "Success!"
116
+ ```
117
+
118
+ ### Advanced Retry with Exponential Backoff
119
+
120
+ ```python
121
+ from datetime import timedelta
122
+ from resilient_circuit import RetryWithBackoffPolicy, ExponentialDelay
123
+
124
+ # Create an exponential backoff strategy
125
+ backoff = ExponentialDelay(
126
+ min_delay=timedelta(seconds=1),
127
+ max_delay=timedelta(seconds=10),
128
+ factor=2,
129
+ jitter=0.1
130
+ )
131
+
132
+ # Apply retry policy with backoff
133
+ retry_policy = RetryWithBackoffPolicy(
134
+ max_retries=3,
135
+ backoff=backoff
136
+ )
137
+
138
+ @retry_policy
139
+ def unreliable_database_operation():
140
+ # Operation that might fail temporarily
141
+ import random
142
+ if random.random() < 0.5:
143
+ raise ConnectionError("Database temporarily unavailable")
144
+ return "Database operation completed"
145
+ ```
146
+
147
+ ### Combining Circuit Protector and Retry
148
+
149
+ ```python
150
+ from resilient_circuit import SafetyNet, CircuitProtectorPolicy, RetryWithBackoffPolicy
151
+
152
+ # Combine both patterns using SafetyNet
153
+ safety_net = SafetyNet(
154
+ policies=(
155
+ RetryWithBackoffPolicy(max_retries=2),
156
+ CircuitProtectorPolicy(failure_limit=Fraction(2, 5))
157
+ )
158
+ )
159
+
160
+ @safety_net
161
+ def resilient_external_api_call():
162
+ # This will first retry, then circuit-protect if needed
163
+ import requests
164
+ response = requests.get("https://external-api.example.com/data")
165
+ return response.json()
166
+ ```
167
+
168
+ ## Detailed Examples
169
+
170
+ ### Circuit Protector Customization
171
+
172
+ ```python
173
+ from datetime import timedelta
174
+ from fractions import Fraction
175
+ from resilient_circuit import CircuitProtectorPolicy, CircuitState
176
+
177
+ def custom_exception_handler(exc):
178
+ """Only handle specific exceptions"""
179
+ return isinstance(exc, (ConnectionError, TimeoutError))
180
+
181
+ def status_change_handler(policy, old_status, new_status):
182
+ """Handle status transitions"""
183
+ print(f"Circuit protector changed status: {old_status.name} -> {new_status.name}")
184
+
185
+ # Fully customized circuit protector
186
+ custom_protector = CircuitProtectorPolicy(
187
+ cooldown=timedelta(minutes=1), # 1-minute cooldown
188
+ failure_limit=Fraction(3, 10), # Trip after 30% failure rate
189
+ success_limit=Fraction(5, 5), # Close after 5 consecutive successes
190
+ should_handle=custom_exception_handler, # Custom exception filter
191
+ on_status_change=status_change_handler # Status change listener
192
+ )
193
+
194
+ @custom_protector
195
+ def monitored_service_call():
196
+ # Your service call with enhanced monitoring
197
+ pass
198
+ ```
199
+
200
+ ### Complex Retry Scenarios
201
+
202
+ ```python
203
+ from resilient_circuit import RetryWithBackoffPolicy, FixedDelay
204
+
205
+ # Constant delay between retries
206
+ constant_backoff = FixedDelay(delay=timedelta(seconds=2))
207
+
208
+ retry_with_constant_backoff = RetryWithBackoffPolicy(
209
+ max_retries=5,
210
+ backoff=constant_backoff,
211
+ should_handle=lambda e: isinstance(e, ConnectionError)
212
+ )
213
+
214
+ @retry_with_constant_backoff
215
+ def service_with_constant_retry():
216
+ # This will retry every 2 seconds up to 5 times
217
+ pass
218
+ ```
219
+
220
+ ### Accessing Circuit Protector Status
221
+
222
+ ```python
223
+ from resilient_circuit import CircuitProtectorPolicy
224
+
225
+ protector = CircuitProtectorPolicy(failure_limit=Fraction(2, 5))
226
+
227
+ @protector
228
+ def service_call():
229
+ pass
230
+
231
+ # Check protector status and execution log
232
+ print(f"Current status: {protector.status.name}")
233
+ print(f"Execution log: {list(protector.execution_log)}")
234
+
235
+ # The execution_log buffer maintains success/failure record
236
+ if protector.status == CircuitState.OPEN:
237
+ print("Circuit protector is currently open - requests are blocked")
238
+ else:
239
+ service_call() # Execute call if not in OPEN status
240
+ ```
241
+
242
+ ## PostgreSQL Shared Storage
243
+
244
+ For distributed applications running across multiple instances, Resilient Circuit supports PostgreSQL as a shared storage backend. This allows circuit breaker state to be synchronized across all instances of your application.
245
+
246
+ ### Setting Up PostgreSQL Storage
247
+
248
+ 1. **Install PostgreSQL dependencies:**
249
+
250
+ ```bash
251
+ pip install resilient_circuit[postgres]
252
+ ```
253
+
254
+ 2. **Create the database:**
255
+
256
+ You need to create the database first (the CLI assumes the database exists). Create it using your preferred method:
257
+
258
+ ```bash
259
+ createdb -h localhost -p 5432 -U postgres resilient_circuit_db
260
+ ```
261
+
262
+ Or using psql:
263
+ ```sql
264
+ CREATE DATABASE resilient_circuit_db;
265
+ ```
266
+
267
+ 3. **Configure environment variables:**
268
+
269
+ Create a `.env` file in your project root:
270
+
271
+ ```env
272
+ RC_DB_HOST=localhost
273
+ RC_DB_PORT=5432
274
+ RC_DB_NAME=resilient_circuit_db
275
+ RC_DB_USER=postgres
276
+ RC_DB_PASSWORD=your_password
277
+ ```
278
+
279
+ 4. **Use the CLI to set up the table:**
280
+
281
+ ```bash
282
+ resilient-circuit-cli pg-setup
283
+ ```
284
+
285
+ This command will read the database configuration from your environment variables and create the necessary table and indexes.
286
+
287
+ You can also use additional options:
288
+ - `--yes` to skip the confirmation prompt
289
+ - `--dry-run` to see what would be done without making changes
290
+
291
+ Example:
292
+ ```bash
293
+ resilient-circuit-cli pg-setup --yes # Skip confirmation
294
+ resilient-circuit-cli pg-setup --dry-run # Show what would be done
295
+ ```
296
+
297
+ ### Using PostgreSQL Storage
298
+
299
+ Once configured, the circuit breaker will automatically use PostgreSQL storage when environment variables are present:
300
+
301
+ ```python
302
+ from datetime import timedelta
303
+ from fractions import Fraction
304
+ from resilient_circuit import CircuitProtectorPolicy
305
+
306
+ # This will automatically use PostgreSQL if RC_DB_* env vars are set
307
+ circuit_breaker = CircuitProtectorPolicy(
308
+ resource_key="payment_service",
309
+ cooldown=timedelta(seconds=60),
310
+ failure_limit=Fraction(5, 10), # 50% failure rate
311
+ success_limit=Fraction(3, 3) # 3 consecutive successes to close
312
+ )
313
+
314
+ @circuit_breaker
315
+ def process_payment():
316
+ # Your payment processing logic
317
+ pass
318
+ ```
319
+
320
+ ### Benefits of PostgreSQL Storage
321
+
322
+ - **Shared State**: Circuit breaker state is synchronized across all application instances
323
+ - **Persistence**: State survives application restarts
324
+ - **Monitoring**: Query circuit breaker state directly from the database
325
+ - **Scalability**: Supports high-concurrency applications
326
+ - **Atomic Operations**: Uses PostgreSQL row-level locking for thread-safe updates
327
+
328
+ ### Monitoring Circuit Breakers
329
+
330
+ Query the database to monitor circuit breaker status:
331
+
332
+ ```sql
333
+ -- View all circuit breakers and their status
334
+ SELECT resource_key, state, failure_count, open_until, updated_at
335
+ FROM rc_circuit_breakers
336
+ ORDER BY updated_at DESC;
337
+
338
+ -- Find all open circuit breakers
339
+ SELECT resource_key, open_until
340
+ FROM rc_circuit_breakers
341
+ WHERE state = 'OPEN';
342
+
343
+ -- Check failure rates for specific services
344
+ SELECT resource_key, failure_count
345
+ FROM rc_circuit_breakers
346
+ WHERE state = 'CLOSED';
347
+ ```
348
+
349
+ ### Fallback to In-Memory Storage
350
+
351
+ If PostgreSQL is not configured or unavailable, the circuit breaker automatically falls back to in-memory storage:
352
+
353
+ ```python
354
+ # No environment variables set - uses in-memory storage
355
+ circuit_breaker = CircuitProtectorPolicy(resource_key="my_service")
356
+
357
+ # Or explicitly specify in-memory storage
358
+ from resilient_circuit.storage import InMemoryStorage
359
+
360
+ circuit_breaker = CircuitProtectorPolicy(
361
+ resource_key="my_service",
362
+ storage=InMemoryStorage()
363
+ )
364
+ ```
365
+
366
+ ### Environment Variables Reference
367
+
368
+ | Variable | Description | Default |
369
+ |----------|-------------|---------|
370
+ | `RC_DB_HOST` | PostgreSQL host | Required |
371
+ | `RC_DB_PORT` | PostgreSQL port | `5432` |
372
+ | `RC_DB_NAME` | Database name | `resilient_circuit_db` |
373
+ | `RC_DB_USER` | Database user | `postgres` |
374
+ | `RC_DB_PASSWORD` | Database password | Required |
375
+
376
+ ## Highway Workflow Engine Integration
377
+
378
+ Resilient Circuit is a core component of the Highway Workflow Engine, designed for building resilient, distributed applications. The Highway Workflow Engine provides:
379
+
380
+ - **Workflow Orchestration**: Define complex business processes
381
+ - **Task Management**: Execute and monitor long-running tasks
382
+ - **Resilience Patterns**: Built-in fault tolerance with circuit breakers and retries
383
+ - **Monitoring & Observability**: Track workflow execution and identify bottlenecks
384
+
385
+ Learn more about the complete Highway Workflow Engine at [highway-workflow-engine.readthedocs.io](https://highway-workflow-engine.readthedocs.io).
386
+
387
+ ## API Reference
388
+
389
+ ### CircuitProtectorPolicy
390
+
391
+ Implements the circuit protector pattern with three statuses: CLOSED, OPEN, HALF_OPEN.
392
+
393
+ **Parameters:**
394
+ - `cooldown` (timedelta): Duration before transitioning from OPEN to HALF_OPEN
395
+ - `failure_limit` (Fraction): Failure rate to trip the protector (e.g., Fraction(3, 10) for 3 out of 10)
396
+ - `success_limit` (Fraction): Success rate to close the protector in HALF_OPEN status
397
+ - `should_handle` (Callable): Predicate to determine which exceptions to count as failures
398
+ - `on_status_change` (Callable): Callback when the protector changes status
399
+
400
+ ### RetryWithBackoffPolicy
401
+
402
+ Implements the retry pattern with configurable backoff strategies.
403
+
404
+ **Parameters:**
405
+ - `backoff` (ExponentialDelay | FixedDelay): Backoff strategy between retries
406
+ - `max_retries` (int): Maximum number of retry attempts
407
+ - `should_handle` (Callable): Predicate to determine which exceptions to retry
408
+
409
+ ### SafetyNet
410
+
411
+ Combines multiple policies for comprehensive error handling.
412
+
413
+ **Parameters:**
414
+ - `policies` (tuple): Tuple of policies to apply
415
+
416
+ ### ExponentialDelay Strategies
417
+
418
+ - `ExponentialDelay`: Exponential backoff with configurable parameters
419
+ - `FixedDelay`: Constant delay between attempts
420
+
421
+ ## Best Practices
422
+
423
+ 1. **Configure Appropriate Limits**: Set failure limits based on your service's expected error rate
424
+ 2. **Use Meaningful Cooldown Periods**: Balance between detecting recovery and avoiding thrashing
425
+ 3. **Handle Specific Exceptions**: Use the `should_handle` parameter to only respond to expected failures
426
+ 4. **Monitor Status Changes**: Use `on_status_change` to detect and log circuit protector transitions
427
+ 5. **Chain Policies Thoughtfully**: Apply retry before circuit protector for optimal resilience
428
+
429
+ ## Contributing
430
+
431
+ We welcome contributions to Resilient Circuit! See our [contributing guide](CONTRIBUTING.md) for details.
432
+
433
+ ## License
434
+
435
+ Distributed under the Apache Software License 2.0. See [LICENSE](LICENSE) for more information.
436
+
437
+ ## Support
438
+
439
+ Need help? Check out our documentation or open an issue on GitHub.
440
+
441
+ ---
442
+
443
+ *Part of the Highway Workflow Engine family of resilience tools*
@@ -0,0 +1,17 @@
1
+ resilient_circuit/__init__.py,sha256=Z3WOzwCT5fP0VptBNu-bkrbKGGljaDB9QL9FwkcBpQI,552
2
+ resilient_circuit/backoff.py,sha256=aLSFYqU_CROrkDaepZaTF_vUy05fBvRhUruXe3Wcmlk,1148
3
+ resilient_circuit/buffer.py,sha256=UIOxPgo07TmveTbaSSJXHzDZwu_aYRVkgIWbGuMhH-8,1385
4
+ resilient_circuit/circuit_breaker.py,sha256=RwQu490pBulAk5Fl4Kn3URsfrEHqwXqVGa3WxSZuwHc,12190
5
+ resilient_circuit/cli.py,sha256=fQpoajQWO-KOpxjVcRsw_oPtXXPw8mfid4pqFwHmRkw,9563
6
+ resilient_circuit/exceptions.py,sha256=f1A9hK1y9kxOFtzldIMCOy0Ui9cKnLuCkUzPUU7zyR4,162
7
+ resilient_circuit/failsafe.py,sha256=B6piP5gWAn88maJnk_Gp3nSRp0FCCtZ4Lnd7Ekrgo-M,1068
8
+ resilient_circuit/policy.py,sha256=MJeETZKw_oMrRkgfq160nrFrSm6tv1N2pgkGxsaQmRs,289
9
+ resilient_circuit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ resilient_circuit/retry.py,sha256=I0QWkhXlEj3Pn6yMbTgT70XPM99Rr3wEoIWL6ThaLCY,1476
11
+ resilient_circuit/storage.py,sha256=PI31JdWT11H7Sxc8YrwSth351bWPT_ZfdzTGuhZ78E8,10874
12
+ resilient_circuit-0.4.1.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
13
+ resilient_circuit-0.4.1.dist-info/METADATA,sha256=PmpXbOfalK3TjPz6LEDbapvtRgealXZhtRskcl8AKec,14761
14
+ resilient_circuit-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ resilient_circuit-0.4.1.dist-info/entry_points.txt,sha256=JbXU75gDeU3PsVykHG7Bq1lYJG7hr5KG-3ny-HGCcZI,65
16
+ resilient_circuit-0.4.1.dist-info/top_level.txt,sha256=SFJWwSDlbsmTWV8F67fdmfAK_dtTT9c8L-kfdnior4s,18
17
+ resilient_circuit-0.4.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ resilient-circuit = resilient_circuit.cli:main
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1 @@
1
+ resilient_circuit