docs: add Zenodo DOI badge
Browse files
README.md
CHANGED
|
@@ -1,143 +1 @@
|
|
| 1 |
-
|
| 2 |
-
language:
|
| 3 |
-
- en
|
| 4 |
-
license: apache-2.0
|
| 5 |
-
tags:
|
| 6 |
-
- emotion-detection
|
| 7 |
-
- emotional-intelligence
|
| 8 |
-
- mental-health
|
| 9 |
-
- wellbeing
|
| 10 |
-
- psychology
|
| 11 |
-
- text-classification
|
| 12 |
-
- multi-label-classification
|
| 13 |
-
- deberta
|
| 14 |
-
- distillation
|
| 15 |
-
pipeline_tag: text-classification
|
| 16 |
-
library_name: resonance-layer
|
| 17 |
-
---
|
| 18 |
-
|
| 19 |
-
# Resonance — Emotional Intelligence Layer for LLMs
|
| 20 |
-
|
| 21 |
-
**resonance-layer** sits between your users and your LLM. It reads the emotion behind what someone writes and injects that context before the LLM responds.
|
| 22 |
-
|
| 23 |
-
```python
|
| 24 |
-
from resonance import Resonance
|
| 25 |
-
|
| 26 |
-
r = Resonance(user_id="your-user-id")
|
| 27 |
-
context = r.process("I've been so anxious about this")
|
| 28 |
-
llm.chat(system=context.to_prompt(), message=message)
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
That's it. The LLM now knows the emotional state, psychological signals, and longitudinal pattern for this user — before it says a word.
|
| 32 |
-
|
| 33 |
-
---
|
| 34 |
-
|
| 35 |
-
## The problem this solves
|
| 36 |
-
|
| 37 |
-
Text doesn't carry emotion. When someone types *"I'm fine"* or *"whatever, doesn't matter"* — the LLM sees words. It has no idea if that person is exhausted, shutting down, or genuinely okay.
|
| 38 |
-
|
| 39 |
-
Resonance gives it that context, continuously, per user, without any extra effort from the developer or the user.
|
| 40 |
-
|
| 41 |
-
---
|
| 42 |
-
|
| 43 |
-
## What this model detects
|
| 44 |
-
|
| 45 |
-
This is a custom 86M parameter student model distilled from three specialist teachers, trained on real human emotional expression across 29 datasets (~740K rows).
|
| 46 |
-
|
| 47 |
-
**18 output heads across 4 groups:**
|
| 48 |
-
|
| 49 |
-
| Group | Heads |
|
| 50 |
-
|---|---|
|
| 51 |
-
| Core | Primary emotion (7-class), VAD continuous, CNN local patterns, confidence calibration |
|
| 52 |
-
| Frameworks | Secondary emotion (21-class TONE), PERMA Ã--5, Window of Tolerance, reappraisal/suppression, Wise Mind |
|
| 53 |
-
| Ethics | Crisis detection, alexithymia screening |
|
| 54 |
-
| SDT | Autonomy, competence, relatedness |
|
| 55 |
-
|
| 56 |
-
All framework scores are **continuous outputs**, not binary flags — grounded in the clinical research each framework comes from.
|
| 57 |
-
|
| 58 |
-
**What makes it different from general emotion models:**
|
| 59 |
-
|
| 60 |
-
The three specialist teachers each cover a distinct psychological blind spot:
|
| 61 |
-
- **T1 (DeBERTa-v3-large + CNN):** shame/guilt separation with PoliGuilt typing — the distinction most models collapse or miss entirely
|
| 62 |
-
- **T2 (XLNet-large):** anger and complex social context
|
| 63 |
-
- **T3 (ELECTRA-large):** fear, PERMA wellbeing, and efficiency
|
| 64 |
-
|
| 65 |
-
---
|
| 66 |
-
|
| 67 |
-
## Installation
|
| 68 |
-
|
| 69 |
-
```bash
|
| 70 |
-
pip install resonance-layer
|
| 71 |
-
```
|
| 72 |
-
|
| 73 |
-
Weights download automatically on first use (~700MB). Fully local after that — no API call, no data leaving your infrastructure.
|
| 74 |
-
|
| 75 |
-
---
|
| 76 |
-
|
| 77 |
-
## Quick start
|
| 78 |
-
|
| 79 |
-
```python
|
| 80 |
-
from resonance import Resonance
|
| 81 |
-
|
| 82 |
-
r = Resonance(user_id="alice")
|
| 83 |
-
result = r.process("I keep second-guessing everything I do")
|
| 84 |
-
|
| 85 |
-
print(result.primary_emotion) # e.g. "anxiety"
|
| 86 |
-
print(result.vad) # valence, arousal, dominance
|
| 87 |
-
print(result.perma) # PERMA scores across 5 dimensions
|
| 88 |
-
print(result.crisis_detected) # always check this first
|
| 89 |
-
print(result.to_prompt()) # ready-made system prompt context
|
| 90 |
-
```
|
| 91 |
-
|
| 92 |
-
**If `crisis_detected` is True, surface a crisis resource immediately.** This is non-negotiable — it's in the ethics documentation and built into the API contract.
|
| 93 |
-
|
| 94 |
-
---
|
| 95 |
-
|
| 96 |
-
## Longitudinal learning
|
| 97 |
-
|
| 98 |
-
Resonance learns in two ways per user:
|
| 99 |
-
|
| 100 |
-
1. **Passive** — every call to `r.process()` updates the user's local profile. Patterns, suppression signals, regulation style — all accumulate silently. The LLM gets richer context with every conversation.
|
| 101 |
-
2. **Active** — explicit corrections (e.g. a user tapping a different emotion chip) feed directly into per-user reinforcement and adjust future detections for them specifically.
|
| 102 |
-
|
| 103 |
-
Both paths are local. No opt-in required.
|
| 104 |
-
|
| 105 |
-
---
|
| 106 |
-
|
| 107 |
-
## Upgrading from v1
|
| 108 |
-
|
| 109 |
-
```bash
|
| 110 |
-
pip install --upgrade resonance-layer
|
| 111 |
-
```
|
| 112 |
-
|
| 113 |
-
No API changes. Drop-in replacement.
|
| 114 |
-
|
| 115 |
-
---
|
| 116 |
-
|
| 117 |
-
## Honest limitations
|
| 118 |
-
|
| 119 |
-
- Shame F1 is the lowest of any class — it's the hardest psychological distinction to learn
|
| 120 |
-
- Sadness is weaker than anger, fear, and joy
|
| 121 |
-
- Some high-arousal distress returns as surprise
|
| 122 |
-
- All gaps are documented in the repo
|
| 123 |
-
|
| 124 |
-
---
|
| 125 |
-
|
| 126 |
-
## Architecture
|
| 127 |
-
|
| 128 |
-
- **Student:** 86M parameter DeBERTa-v3-base, 18 active heads
|
| 129 |
-
- **Teachers:** DeBERTa-v3-large+CNN (T1), XLNet-large (T2), ELECTRA-large (T3)
|
| 130 |
-
- **Distillation:** Multi-teacher knowledge distillation with per-head weighting, mutual information maximisation, born-again networks, uncertainty-aware loss
|
| 131 |
-
- **Training data:** 29 datasets, ~740K rows, 7 locked dataset rules (commercial licence, institutional/peer-reviewed, real human expression, framework-mapped, not too narrow, no gated access, no severe class imbalance)
|
| 132 |
-
|
| 133 |
-
---
|
| 134 |
-
|
| 135 |
-
## Links
|
| 136 |
-
|
| 137 |
-
- **PyPI:** [resonance-layer](https://pypi.org/project/resonance-layer/)
|
| 138 |
-
- **GitHub:** [wpferrell/Resonance](https://github.com/wpferrell/Resonance)
|
| 139 |
-
- **Docs & landing page:** [resonance-layer.com](https://resonance-layer.com)
|
| 140 |
-
|
| 141 |
-
---
|
| 142 |
-
|
| 143 |
-
*Named after Jody. She walks into a room and just knows. That's the standard.*
|
|
|
|
| 1 |
+
LS0tDQpsYW5ndWFnZToNCi0gZW4NCmxpY2Vuc2U6IGFwYWNoZS0yLjANCnRhZ3M6DQotIGVtb3Rpb24tZGV0ZWN0aW9uDQotIGVtb3Rpb25hbC1pbnRlbGxpZ2VuY2UNCi0gbWVudGFsLWhlYWx0aA0KLSB3ZWxsYmVpbmcNCi0gcHN5Y2hvbG9neQ0KLSB0ZXh0LWNsYXNzaWZpY2F0aW9uDQotIG11bHRpLWxhYmVsLWNsYXNzaWZpY2F0aW9uDQotIGRlYmVydGENCi0gZGlzdGlsbGF0aW9uDQpwaXBlbGluZV90YWc6IHRleHQtY2xhc3NpZmljYXRpb24NCmxpYnJhcnlfbmFtZTogcmVzb25hbmNlLWxheWVyDQotLS0NCgpbIVtET0ldKGh0dHBzOi8vemVub2RvLm9yZy9iYWRnZS9ET0kvMTAuNTI4MS96ZW5vZG8uMjAyNzkyNDguc3ZnKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjUyODEvemVub2RvLjIwMjc5MjQ4KQoNCiMgUmVzb25hbmNlIMOi4oKs4oCdIEVtb3Rpb25hbCBJbnRlbGxpZ2VuY2UgTGF5ZXIgZm9yIExMTXMNCg0KKipyZXNvbmFuY2UtbGF5ZXIqKiBzaXRzIGJldHdlZW4geW91ciB1c2VycyBhbmQgeW91ciBMTE0uIEl0IHJlYWRzIHRoZSBlbW90aW9uIGJlaGluZCB3aGF0IHNvbWVvbmUgd3JpdGVzIGFuZCBpbmplY3RzIHRoYXQgY29udGV4dCBiZWZvcmUgdGhlIExMTSByZXNwb25kcy4NCg0KYGBgcHl0aG9uDQpmcm9tIHJlc29uYW5jZSBpbXBvcnQgUmVzb25hbmNlDQoNCnIgPSBSZXNvbmFuY2UodXNlcl9pZD0ieW91ci11c2VyLWlkIikNCmNvbnRleHQgPSByLnByb2Nlc3MoIkkndmUgYmVlbiBzbyBhbnhpb3VzIGFib3V0IHRoaXMiKQ0KbGxtLmNoYXQoc3lzdGVtPWNvbnRleHQudG9fcHJvbXB0KCksIG1lc3NhZ2U9bWVzc2FnZSkNCmBgYA0KDQpUaGF0J3MgaXQuIFRoZSBMTE0gbm93IGtub3dzIHRoZSBlbW90aW9uYWwgc3RhdGUsIHBzeWNob2xvZ2ljYWwgc2lnbmFscywgYW5kIGxvbmdpdHVkaW5hbCBwYXR0ZXJuIGZvciB0aGlzIHVzZXIgw6LigqzigJ0gYmVmb3JlIGl0IHNheXMgYSB3b3JkLg0KDQotLS0NCg0KIyMgVGhlIHByb2JsZW0gdGhpcyBzb2x2ZXMNCg0KVGV4dCBkb2Vzbid0IGNhcnJ5IGVtb3Rpb24uIFdoZW4gc29tZW9uZSB0eXBlcyAqIkknbSBmaW5lIiogb3IgKiJ3aGF0ZXZlciwgZG9lc24ndCBtYXR0ZXIiKiDDouKCrOKAnSB0aGUgTExNIHNlZXMgd29yZHMuIEl0IGhhcyBubyBpZGVhIGlmIHRoYXQgcGVyc29uIGlzIGV4aGF1c3RlZCwgc2h1dHRpbmcgZG93biwgb3IgZ2VudWluZWx5IG9rYXkuDQoNClJlc29uYW5jZSBnaXZlcyBpdCB0aGF0IGNvbnRleHQsIGNvbnRpbnVvdXNseSwgcGVyIHVzZXIsIHdpdGhvdXQgYW55IGV4dHJhIGVmZm9ydCBmcm9tIHRoZSBkZXZlbG9wZXIgb3IgdGhlIHVzZXIuDQoNCi0tLQ0KClshW0RPSV0oaHR0cHM6Ly96ZW5vZG8ub3JnL2JhZGdlL0RPSS8xMC41MjgxL3plbm9kby4yMDI3OTI0OC5zdmcpXShodHRwczovL2RvaS5vcmcvMTAuNTI4MS96ZW5vZG8uMjAyNzkyNDgpCg0KIyMgV2hhdCB0aGlzIG1vZGVsIGRldGVjdHMNCg0KVGhpcyBpcyBhIGN1c3RvbSA4Nk0gcGFyYW1ldGVyIHN0dWRlbnQgbW9kZWwgZGlzdGlsbGVkIGZyb20gdGhyZWUgc3BlY2lhbGlzdCB0ZWFjaGVycywgdHJhaW5lZCBvbiByZWFsIGh1bWFuIGVtb3Rpb25hbCBleHByZXNzaW9uIGFjcm9zcyAyOSBkYXRhc2V0cyAofjc0MEsgcm93cykuDQoNCioqMTggb3V0cHV0IGhlYWRzIGFjcm9zcyA0IGdyb3VwczoqKg0KDQp8IEdyb3VwIHwgSGVhZHMgfA0KfC0tLXwtLS18DQp8IENvcmUgfCBQcmltYXJ5IGVtb3Rpb24gKDctY2xhc3MpLCBWQUQgY29udGludW91cywgQ05OIGxvY2FsIHBhdHRlcm5zLCBjb25maWRlbmNlIGNhbGlicmF0aW9uIHwNCnwgRnJhbWV3b3JrcyB8IFNlY29uZGFyeSBlbW90aW9uICgyMS1jbGFzcyBUT05FKSwgUEVSTUEgw4MtLTUsIFdpbmRvdyBvZiBUb2xlcmFuY2UsIHJlYXBwcmFpc2FsL3N1cHByZXNzaW9uLCBXaXNlIE1pbmQgfA0KfCBFdGhpY3MgfCBDcmlzaXMgZGV0ZWN0aW9uLCBhbGV4aXRoeW1pYSBzY3JlZW5pbmcgfA0KfCBTRFQgfCBBdXRvbm9teSwgY29tcGV0ZW5jZSwgcmVsYXRlZG5lc3MgfA0KDQpBbGwgZnJhbWV3b3JrIHNjb3JlcyBhcmUgKipjb250aW51b3VzIG91dHB1dHMqKiwgbm90IGJpbmFyeSBmbGFncyDDouKCrOKAnSBncm91bmRlZCBpbiB0aGUgY2xpbmljYWwgcmVzZWFyY2ggZWFjaCBmcmFtZXdvcmsgY29tZXMgZnJvbS4NCg0KKipXaGF0IG1ha2VzIGl0IGRpZmZlcmVudCBmcm9tIGdlbmVyYWwgZW1vdGlvbiBtb2RlbHM6KioNCg0KVGhlIHRocmVlIHNwZWNpYWxpc3QgdGVhY2hlcnMgZWFjaCBjb3ZlciBhIGRpc3RpbmN0IHBzeWNob2xvZ2ljYWwgYmxpbmQgc3BvdDoNCi0gKipUMSAoRGVCRVJUYS12My1sYXJnZSArIENOTik6Kiogc2hhbWUvZ3VpbHQgc2VwYXJhdGlvbiB3aXRoIFBvbGlHdWlsdCB0eXBpbmcgw6LigqzigJ0gdGhlIGRpc3RpbmN0aW9uIG1vc3QgbW9kZWxzIGNvbGxhcHNlIG9yIG1pc3MgZW50aXJlbHkNCi0gKipUMiAoWExOZXQtbGFyZ2UpOioqIGFuZ2VyIGFuZCBjb21wbGV4IHNvY2lhbCBjb250ZXh0DQotICoqVDMgKEVMRUNUUkEtbGFyZ2UpOioqIGZlYXIsIFBFUk1BIHdlbGxiZWluZywgYW5kIGVmZmljaWVuY3kNCg0KLS0tDQoKWyFbRE9JXShodHRwczovL3plbm9kby5vcmcvYmFkZ2UvRE9JLzEwLjUyODEvemVub2RvLjIwMjc5MjQ4LnN2ZyldKGh0dHBzOi8vZG9pLm9yZy8xMC41MjgxL3plbm9kby4yMDI3OTI0OCkKDQojIyBJbnN0YWxsYXRpb24NCg0KYGBgYmFzaA0KcGlwIGluc3RhbGwgcmVzb25hbmNlLWxheWVyDQpgYGANCg0KV2VpZ2h0cyBkb3dubG9hZCBhdXRvbWF0aWNhbGx5IG9uIGZpcnN0IHVzZSAofjcwME1CKS4gRnVsbHkgbG9jYWwgYWZ0ZXIgdGhhdCDDouKCrOKAnSBubyBBUEkgY2FsbCwgbm8gZGF0YSBsZWF2aW5nIHlvdXIgaW5mcmFzdHJ1Y3R1cmUuDQoNCi0tLQ0KDQojIyBRdWljayBzdGFydA0KDQpgYGBweXRob24NCmZyb20gcmVzb25hbmNlIGltcG9ydCBSZXNvbmFuY2UNCg0KciA9IFJlc29uYW5jZSh1c2VyX2lkPSJhbGljZSIpDQpyZXN1bHQgPSByLnByb2Nlc3MoIkkga2VlcCBzZWNvbmQtZ3Vlc3NpbmcgZXZlcnl0aGluZyBJIGRvIikNCg0KcHJpbnQocmVzdWx0LnByaW1hcnlfZW1vdGlvbikgICAgICAgICMgZS5nLiAiYW54aWV0eSINCnByaW50KHJlc3VsdC52YWQpICAgICAgICAgICAgICAgICAgICAjIHZhbGVuY2UsIGFyb3VzYWwsIGRvbWluYW5jZQ0KcHJpbnQocmVzdWx0LnBlcm1hKSAgICAgICAgICAgICAgICAgICMgUEVSTUEgc2NvcmVzIGFjcm9zcyA1IGRpbWVuc2lvbnMNCnByaW50KHJlc3VsdC5jcmlzaXNfZGV0ZWN0ZWQpICAgICAgICAjIGFsd2F5cyBjaGVjayB0aGlzIGZpcnN0DQpwcmludChyZXN1bHQudG9fcHJvbXB0KCkpICAgICAgICAgICAgIyByZWFkeS1tYWRlIHN5c3RlbSBwcm9tcHQgY29udGV4dA0KYGBgDQoNCioqSWYgYGNyaXNpc19kZXRlY3RlZGAgaXMgVHJ1ZSwgc3VyZmFjZSBhIGNyaXNpcyByZXNvdXJjZSBpbW1lZGlhdGVseS4qKiBUaGlzIGlzIG5vbi1uZWdvdGlhYmxlIMOi4oKs4oCdIGl0J3MgaW4gdGhlIGV0aGljcyBkb2N1bWVudGF0aW9uIGFuZCBidWlsdCBpbnRvIHRoZSBBUEkgY29udHJhY3QuDQoNCi0tLQ0KClshW0RPSV0oaHR0cHM6Ly96ZW5vZG8ub3JnL2JhZGdlL0RPSS8xMC41MjgxL3plbm9kby4yMDI3OTI0OC5zdmcpXShodHRwczovL2RvaS5vcmcvMTAuNTI4MS96ZW5vZG8uMjAyNzkyNDgpCg0KIyMgTG9uZ2l0dWRpbmFsIGxlYXJuaW5nDQoNClJlc29uYW5jZSBsZWFybnMgaW4gdHdvIHdheXMgcGVyIHVzZXI6DQoNCjEuICoqUGFzc2l2ZSoqIMOi4oKs4oCdIGV2ZXJ5IGNhbGwgdG8gYHIucHJvY2VzcygpYCB1cGRhdGVzIHRoZSB1c2VyJ3MgbG9jYWwgcHJvZmlsZS4gUGF0dGVybnMsIHN1cHByZXNzaW9uIHNpZ25hbHMsIHJlZ3VsYXRpb24gc3R5bGUgw6LigqzigJ0gYWxsIGFjY3VtdWxhdGUgc2lsZW50bHkuIFRoZSBMTE0gZ2V0cyByaWNoZXIgY29udGV4dCB3aXRoIGV2ZXJ5IGNvbnZlcnNhdGlvbi4NCjIuICoqQWN0aXZlKiogw6LigqzigJ0gZXhwbGljaXQgY29ycmVjdGlvbnMgKGUuZy4gYSB1c2VyIHRhcHBpbmcgYSBkaWZmZXJlbnQgZW1vdGlvbiBjaGlwKSBmZWVkIGRpcmVjdGx5IGludG8gcGVyLXVzZXIgcmVpbmZvcmNlbWVudCBhbmQgYWRqdXN0IGZ1dHVyZSBkZXRlY3Rpb25zIGZvciB0aGVtIHNwZWNpZmljYWxseS4NCg0KQm90aCBwYXRocyBhcmUgbG9jYWwuIE5vIG9wdC1pbiByZXF1aXJlZC4NCg0KLS0tDQoNCiMjIFVwZ3JhZGluZyBmcm9tIHYxDQoNCmBgYGJhc2gNCnBpcCBpbnN0YWxsIC0tdXBncmFkZSByZXNvbmFuY2UtbGF5ZXINCmBgYA0KDQpObyBBUEkgY2hhbmdlcy4gRHJvcC1pbiByZXBsYWNlbWVudC4NCg0KLS0tDQoKWyFbRE9JXShodHRwczovL3plbm9kby5vcmcvYmFkZ2UvRE9JLzEwLjUyODEvemVub2RvLjIwMjc5MjQ4LnN2ZyldKGh0dHBzOi8vZG9pLm9yZy8xMC41MjgxL3plbm9kby4yMDI3OTI0OCkKDQojIyBIb25lc3QgbGltaXRhdGlvbnMNCg0KLSBTaGFtZSBGMSBpcyB0aGUgbG93ZXN0IG9mIGFueSBjbGFzcyDDouKCrOKAnSBpdCdzIHRoZSBoYXJkZXN0IHBzeWNob2xvZ2ljYWwgZGlzdGluY3Rpb24gdG8gbGVhcm4NCi0gU2FkbmVzcyBpcyB3ZWFrZXIgdGhhbiBhbmdlciwgZmVhciwgYW5kIGpveQ0KLSBTb21lIGhpZ2gtYXJvdXNhbCBkaXN0cmVzcyByZXR1cm5zIGFzIHN1cnByaXNlDQotIEFsbCBnYXBzIGFyZSBkb2N1bWVudGVkIGluIHRoZSByZXBvDQoNCi0tLQ0KDQojIyBBcmNoaXRlY3R1cmUNCg0KLSAqKlN0dWRlbnQ6KiogODZNIHBhcmFtZXRlciBEZUJFUlRhLXYzLWJhc2UsIDE4IGFjdGl2ZSBoZWFkcw0KLSAqKlRlYWNoZXJzOioqIERlQkVSVGEtdjMtbGFyZ2UrQ05OIChUMSksIFhMTmV0LWxhcmdlIChUMiksIEVMRUNUUkEtbGFyZ2UgKFQzKQ0KLSAqKkRpc3RpbGxhdGlvbjoqKiBNdWx0aS10ZWFjaGVyIGtub3dsZWRnZSBkaXN0aWxsYXRpb24gd2l0aCBwZXItaGVhZCB3ZWlnaHRpbmcsIG11dHVhbCBpbmZvcm1hdGlvbiBtYXhpbWlzYXRpb24sIGJvcm4tYWdhaW4gbmV0d29ya3MsIHVuY2VydGFpbnR5LWF3YXJlIGxvc3MNCi0gKipUcmFpbmluZyBkYXRhOioqIDI5IGRhdGFzZXRzLCB+NzQwSyByb3dzLCA3IGxvY2tlZCBkYXRhc2V0IHJ1bGVzIChjb21tZXJjaWFsIGxpY2VuY2UsIGluc3RpdHV0aW9uYWwvcGVlci1yZXZpZXdlZCwgcmVhbCBodW1hbiBleHByZXNzaW9uLCBmcmFtZXdvcmstbWFwcGVkLCBub3QgdG9vIG5hcnJvdywgbm8gZ2F0ZWQgYWNjZXNzLCBubyBzZXZlcmUgY2xhc3MgaW1iYWxhbmNlKQ0KDQotLS0NCgpbIVtET0ldKGh0dHBzOi8vemVub2RvLm9yZy9iYWRnZS9ET0kvMTAuNTI4MS96ZW5vZG8uMjAyNzkyNDguc3ZnKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjUyODEvemVub2RvLjIwMjc5MjQ4KQoNCiMjIExpbmtzDQoNCi0gKipQeVBJOioqIFtyZXNvbmFuY2UtbGF5ZXJdKGh0dHBzOi8vcHlwaS5vcmcvcHJvamVjdC9yZXNvbmFuY2UtbGF5ZXIvKQ0KLSAqKkdpdEh1YjoqKiBbd3BmZXJyZWxsL1Jlc29uYW5jZV0oaHR0cHM6Ly9naXRodWIuY29tL3dwZmVycmVsbC9SZXNvbmFuY2UpDQotICoqRG9jcyAmIGxhbmRpbmcgcGFnZToqKiBbcmVzb25hbmNlLWxheWVyLmNvbV0oaHR0cHM6Ly9yZXNvbmFuY2UtbGF5ZXIuY29tKQ0KDQotLS0NCg0KKk5hbWVkIGFmdGVyIEpvZHkuIFNoZSB3YWxrcyBpbnRvIGEgcm9vbSBhbmQganVzdCBrbm93cy4gVGhhdCdzIHRoZSBzdGFuZGFyZC4qDQo=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|