From 59f505ec034cdbc27e904d4b06051866a753f4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mien=20Kocher?= Date: Wed, 20 Jul 2022 16:43:34 +0200 Subject: [PATCH 1/6] Updates the documentation --- README.md | 50 ++++++++++++++++++++++++++++++---- deb-package/README.md | 4 ++- docs/assets/audit-black.png | Bin 0 -> 2769 bytes docs/assets/audit-white.png | Bin 0 -> 2945 bytes docs/assets/privacy-black.png | Bin 0 -> 2970 bytes docs/assets/privacy-white.png | Bin 0 -> 3261 bytes docs/assets/spof-black.png | Bin 0 -> 3426 bytes docs/assets/spof-white.png | Bin 0 -> 3811 bytes 8 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 docs/assets/audit-black.png create mode 100644 docs/assets/audit-white.png create mode 100644 docs/assets/privacy-black.png create mode 100644 docs/assets/privacy-white.png create mode 100644 docs/assets/spof-black.png create mode 100644 docs/assets/spof-white.png diff --git a/README.md b/README.md index 26e9b3d47..d1e2ccd26 100644 --- a/README.md +++ b/README.md @@ -61,11 +61,51 @@ # D-Voting **D-Voting** is an e-voting platform based on the -[Dela](https://github.com/dedis/dela) blockchain. In short: +[Dela](https://github.com/dedis/dela) blockchain. It uses state-of-the-art +protocols that guarantee a fully decentralized process. This project was born in +early 2021 and has been iteratively implemented by EPFL student under the +supervision of DEDIS members. -- An open platform to run voting instances on a blockchain -- Provides privacy of votes with state-of-the art protocols -- Fully auditable and decentralized process +⚠️ This project is still under developpment and should not be used for real +elections. + +Main properties of the system are the following: + +
+ + +
+ +**No single point of failure** The system is supported by a decentralized +network of blockchain nodes, making no single party able to take over the +network without compromising a Byzantine threshold of nodes. Additionally, +side-protocols always distribute trust among nodes: The distributed key +generation protocol (DKG) ensures that a threshold of honest node is needed to +decrypt a vote, and the shuffling protocol needs at least one honest node to +ensure privacy of voters. Only the identification and authorization mechanism +make use of a central authority, but can accommodate and any other solution. + +
+ + +
+ +**Privacy** Ballots are cast on the client side using a safely-held +distributed key. The private key cannot not be revealed without coercing a +threshold of nodes, and the public key can be retrieved on any node a client +trust. Ballots are decrypted only once a cryptographic process ensures that cast +ballots cannot be linked to the original voter. + +
+ + +
+ +**Transparency/Verifiability/Auditability** The whole election process is +recorded on the blockchain and signed by a threshold of participants. Anyone can +read and verify the log of events stored on the blockchain. Malicious behavior +can be detected, voters can check that ballots are cast as intended, and +auditors can witness the election process. ## Global architecture @@ -227,7 +267,7 @@ To install a package run the following: ```sh echo "deb http://apt.dedis.ch/ squeeze main" >> /etc/apt/sources.list -wget -q -O- http://apt.dedis.ch/unicore.gpg | sudo apt-key add - +wget -q -O- http://apt.dedis.ch/dvoting-release.pgp | sudo apt-key add - sudo apt update sudo apt install dedis-dvoting ``` diff --git a/deb-package/README.md b/deb-package/README.md index 12a4f0f0f..ca78d477b 100644 --- a/deb-package/README.md +++ b/deb-package/README.md @@ -43,6 +43,8 @@ with the node's public address: export dela_public="//172.16.253.150:9000" ``` +and don't forget to restart the service! + ### Leader's node Get the token and certificate (24h * 30 = 720): @@ -100,7 +102,7 @@ sudo memcoin --config /var/opt/dedis/dvoting/data/dela ordering setup \ ```sh PK=<> # taken from the "ordering export", the part after ":" sudo memcoin --config /var/opt/dedis/dvoting/data/dela pool add \ - --key /home/user/master.key \ + --key /home/dedis/private.key \ --args go.dedis.ch/dela.ContractArg --args go.dedis.ch/dela.Access \ --args access:grant_id --args 0300000000000000000000000000000000000000000000000000000000000000 \ --args access:grant_contract --args go.dedis.ch/dela.Evoting \ diff --git a/docs/assets/audit-black.png b/docs/assets/audit-black.png new file mode 100644 index 0000000000000000000000000000000000000000..9af9d50cd28fd29f8d15621e19128598f78e9254 GIT binary patch literal 2769 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 literal 0 HcmV?d00001 diff --git a/docs/assets/privacy-black.png b/docs/assets/privacy-black.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8b0b166048db6c24a27f48ad7ef5a4d3c4e8f6 GIT binary patch literal 2970 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 Ef~>}WFaQ7m literal 0 HcmV?d00001 diff --git a/docs/assets/spof-white.png b/docs/assets/spof-white.png new file mode 100644 index 0000000000000000000000000000000000000000..10cc721dddb7a70e7718fb2b412bf86e208316ff GIT binary patch literal 3811 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 Z{{d>6u}mI_IGq3h002ovPDHLkV1lXSGg|-v literal 0 HcmV?d00001 From 373b08b43c394583e43881aabae8de1872e0dc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mien=20Kocher?= Date: Wed, 20 Jul 2022 17:28:36 +0200 Subject: [PATCH 2/6] Adds contributors and folders structure --- README.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d1e2ccd26..2bcd960f9 100644 --- a/README.md +++ b/README.md @@ -83,18 +83,18 @@ side-protocols always distribute trust among nodes: The distributed key generation protocol (DKG) ensures that a threshold of honest node is needed to decrypt a vote, and the shuffling protocol needs at least one honest node to ensure privacy of voters. Only the identification and authorization mechanism -make use of a central authority, but can accommodate and any other solution. +make use of a central authority, but can accommodate to other solutions.
-**Privacy** Ballots are cast on the client side using a safely-held -distributed key. The private key cannot not be revealed without coercing a -threshold of nodes, and the public key can be retrieved on any node a client -trust. Ballots are decrypted only once a cryptographic process ensures that cast -ballots cannot be linked to the original voter. +**Privacy** Ballots are cast on the client side using a safely-held distributed +key-pair. The private key cannot not be revealed without coercing a threshold of +nodes, and the public key can be retrieved on any node the voter trusts. Ballots +are decrypted only once a cryptographic process ensured that cast ballots cannot +be linked to the original voter.
@@ -102,20 +102,105 @@ ballots cannot be linked to the original voter.
**Transparency/Verifiability/Auditability** The whole election process is -recorded on the blockchain and signed by a threshold of participants. Anyone can -read and verify the log of events stored on the blockchain. Malicious behavior -can be detected, voters can check that ballots are cast as intended, and -auditors can witness the election process. +recorded on the blockchain and signed by a threshold of blockchain nodes. Anyone +can read and verify the log of events stored on the blockchain. Malicious +behavior can be detected, voters can check that ballots are cast as intended, +and auditors can witness the election process. -## Global architecture +## 🧩 Global architecture Find more about the architecture on the [documentation website](https://dedis.github.io/d-voting/#/). ![Global component diagram](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/dedis/d-voting/main/docs/assets/component-global.puml) +## πŸ“ Folders structure -# Setup +``` +. +β”œβ”€β”€ cli +β”‚ β”œβ”€β”€ cosipbftcontroller +β”‚ β”œβ”€β”€ dvoting +β”‚ β”œβ”€β”€ memcoin +β”‚ └── postinstall +β”œβ”€β”€ contracts +β”‚ └── evoting +β”œβ”€β”€ deb-package +β”œβ”€β”€ docs +β”œβ”€β”€ integration +β”œβ”€β”€ internal +β”œβ”€β”€ metrics +β”‚ └── controller +β”œβ”€β”€ proxy +β”œβ”€β”€ services +β”‚ β”œβ”€β”€ dkg +β”‚ β”‚ └── pedersen +β”‚ └── shuffle +β”‚ └── neff +└── web + β”œβ”€β”€ backend + β”‚ └── src + └── frontend + └── src +``` + +## πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» Contributors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PeriodContributors(s)ActivitiesLinks
Spring 2021Students: Anas Ibrahim, Vincent Parodi
Supervisor: NoΓ©mien Kocher
Initial implementation of the smart contract and servicesReport
Spring 2021Student: Sarah Antille
Supervisor: NoΓ©mien Kocher
Initial implementation of the web frontend in reactReport
Fall 2021Students: Auguste Baum, Emilien Duc
Supervisor: NoΓ©mien Kocher
Adds a flexible election structure. Improves robustness and security. + Report, + Presentation +
Fall 2021Students: Ambroise Borbely
Supervisor: NoΓ©mien Kocher
Adds authentication and authorization mechanism on the frontend.Report
Spring 2022Students: Guanyu Zhang, Igowa Giovanni
Supervisor: NoΓ©mien Kocher
Assistant: Emilien Duc
Improves production-readiness: deploy a test pipeline and analyze the system's robustness. + Report, + Presentation +
Spring 2022Students: Badr Larhdir, Capucine Berger
Supervisor: NoΓ©mien Kocher
Major iteration over the frontend - design and functionalities: implements a flexible election form, nodes setup, and result page. + Report, + Presentation +
+ +# βš™οΈ Setup First be sure to have Go installed (at least 1.17). From 24b2b5800ba70c4b2113305163d74dd3cbd57196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mien=20Kocher?= Date: Thu, 21 Jul 2022 14:45:52 +0200 Subject: [PATCH 3/6] Adds architecture and steps documentation --- README.md | 216 ++++++++++++++++++++++++++++------ docs/assets/cast-black.png | Bin 0 -> 4196 bytes docs/assets/cast-white.png | Bin 0 -> 4429 bytes docs/assets/encrypt-black.png | Bin 0 -> 3935 bytes docs/assets/encrypt-white.png | Bin 0 -> 4239 bytes docs/assets/reveal-black.png | Bin 0 -> 4948 bytes docs/assets/reveal-white.png | Bin 0 -> 5296 bytes docs/assets/shuffle-black.png | Bin 0 -> 4819 bytes docs/assets/shuffle-white.png | Bin 0 -> 5296 bytes 9 files changed, 183 insertions(+), 33 deletions(-) create mode 100644 docs/assets/cast-black.png create mode 100644 docs/assets/cast-white.png create mode 100644 docs/assets/encrypt-black.png create mode 100644 docs/assets/encrypt-white.png create mode 100644 docs/assets/reveal-black.png create mode 100644 docs/assets/reveal-white.png create mode 100644 docs/assets/shuffle-black.png create mode 100644 docs/assets/shuffle-white.png diff --git a/README.md b/README.md index 2bcd960f9..1989c5b08 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,9 @@ **D-Voting** is an e-voting platform based on the [Dela](https://github.com/dedis/dela) blockchain. It uses state-of-the-art -protocols that guarantee a fully decentralized process. This project was born in -early 2021 and has been iteratively implemented by EPFL student under the -supervision of DEDIS members. +protocols that guarantee privacy of votes and a fully decentralized process. +This project was born in early 2021 and has been iteratively implemented by EPFL +students under the supervision of DEDIS members. ⚠️ This project is still under developpment and should not be used for real elections. @@ -77,11 +77,11 @@ Main properties of the system are the following: **No single point of failure** The system is supported by a decentralized -network of blockchain nodes, making no single party able to take over the -network without compromising a Byzantine threshold of nodes. Additionally, +network of blockchain nodes, making no single party able to break the system +without compromising a Byzantine threshold of nodes. Additionally, side-protocols always distribute trust among nodes: The distributed key generation protocol (DKG) ensures that a threshold of honest node is needed to -decrypt a vote, and the shuffling protocol needs at least one honest node to +decrypt ballots, and the shuffling protocol needs at least one honest node to ensure privacy of voters. Only the identification and authorization mechanism make use of a central authority, but can accommodate to other solutions. @@ -92,9 +92,9 @@ make use of a central authority, but can accommodate to other solutions. **Privacy** Ballots are cast on the client side using a safely-held distributed key-pair. The private key cannot not be revealed without coercing a threshold of -nodes, and the public key can be retrieved on any node the voter trusts. Ballots -are decrypted only once a cryptographic process ensured that cast ballots cannot -be linked to the original voter. +nodes, and voters can retrieve the public key on any node. Ballots are decrypted +only once a cryptographic process ensured that cast ballots cannot be linked to +the original voter.
@@ -109,40 +109,190 @@ and auditors can witness the election process. ## 🧩 Global architecture -Find more about the architecture on the [documentation -website](https://dedis.github.io/d-voting/#/). +The project has 4 main high-level components: + +**Blockchain node** A blockchain node is the wide definition of the program that +runs on a host and participate in the election logic. The blockchain node is +built on top of Dela with an additional d-voting smart contract, proxy, and two +services: DKG and verifiable Shuffling. The blockchain node is more accurately a +subsystem, as it wraps many other components. Blockchain nodes communicate +through gRPC with the [minogrpc][minogrpc] network overlay. We sometimes refer +to the blockchain node simply as a "node". + +**Proxy** A proxy enables external interactions on a blockchain node. It is a +component of the blockchain node that exposes HTTP endpoints for external +entities to send commands to the node. The proxy is notably used by the web +clients to use the election system. + +**Web frontend** The web frontend is a web app built with React. It offers a +view for end-users to use the D-Voting system. The app is meant to be used by +voters and admins. Admins can perform administrative tasks such as creating an +election, closing it, or revealing the results. Depending on the task, the web +frontend will directly send HTTP requests to the proxy of a blockchain node, or +to the web-backend. + +**Web backend** The web backend handles authentication and authorization. Some +requests that need specific authorization are relayed from the web-frontend to +the web-backend. The web backend checks the requests and signs messages before +relaying them to the blockchain node, which trusts the web-backend. The +web-backend has a local database to store configuration data such as +authorizations. Admins use the web-frontend to perform update. + +The following component diagrams summarizes the interaction between those +high-level components. + +[minogrpc]: https://github.com/dedis/dela/tree/master/mino/minogrpc ![Global component diagram](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/dedis/d-voting/main/docs/assets/component-global.puml) +You can find more information about the architecture on the [documentation +website](https://dedis.github.io/d-voting/#/). + +## Workflow + +An election follows a specific workflow to ensure privacy of votes. You can +find more about it in the +[documentation](https://dedis.github.io/d-voting/#/api?id=signed-requests), but +here is a high-level recap. + +Once an election is created and open, there are 4 main steps from the cast of a +ballot to getting the result of the election: + +
+ + +
+ +**1) Create ballot** The voter get the shared public key and encrypts locally +its ballot. The shared public key can be retrieved on any node and is associated +to a private key that is distributed among the nodes. This process is done on +the client's browser using the web-frontend. + +
+ + +
+ +**2) Cast ballot** The voter submits its encrypted ballot as a transaction to one +of the blockchain node. This operation is relayed by the web-backend which +verifies that the voters has the right to vote. If successful, the encrypted +ballot is stored on the blockchain. At this stage each encrypted ballot is +recorded with its user on the blockchain. + +
+ + +
+ +**3) Shuffle ballots** Once the election is closed by an admin, ballots are +shuffled to ensure privacy of voters. This operation is done by a threshold of +node that each perform their own shuffling. Each shuffling guaranty the +integrity of votes while re-encrypting and changing the order of votes. At this +stage encrypted ballots cannot ne linked back to their voters. + +
+ + +
+ +**4) Reveal ballots** Once ballots have been shuffled, they are decrypted and +revealed. This operation is done only if the previous step is correctly +executed. The decryption is done by a threshold of nodes that must each provide +a contribution to achieve the decryption. Once done, the result of the election +is stored on the blockchain. + +## Smart contract + +A smart contract is a piece of code that runs on a blockchain. It defines a set +of operations that act on a global state (think of it as database) and can be +triggered with transactions. What makes a smart contract special is that its +executions depends on a consensus among blockchain nodes and operations are +successful only if a consensus is reached. Additionally, transactions and their +results are permanently recorded and signed on an append-only ledger, making any +operations on the blockchain transparent and permanent. + +In the D-Voting system a single D-Voting smart contract handles the elections. +The smart contract ensures that elections follow a correct workflow to +guarantees its desirable properties such as privacy. For example, the smart +contract won't allow ballots to be decrypted if they haven't been shuffled by a +threshold of nodes before. + +## Services + +Apart from executing smart contracts, blockchain nodes need additional side +services to support an election. Side services can read from the global state +and send transactions. They are used to perform specific protocol executions not +directly related to blockchain protocols such as the distributed key generation +(DKG) and verifiable shuffling protocols. + +### DKG + +DKG stands for Distributed Key Generation. This service allows the creation of a +key-pair that is distributed among multiple participants. Data encrypted with +the key-pair can only be decrypted with the contribution of a threshold of +participants. This makes it convenient to distribute trust on encrypted data. +In the D-Voting project we use the Pedersen [[1]] version of DKG. + +The DKG service needs to be setup at the beginning of each new election - we +want each election to have its own key-pair. Doing the setup requires two steps: +1\) Initialization and 2\) Setup. The initialization creates a new RPC for nodes +to communicate and must be done on each node. The second step, setup, must be +executed on one of the node. The setup step starts the DKG protocol and +generates the key-pair. Once done, the D-Voting smart contract can be called to +open the election, which will retrieve the DKG public key and save it on the +smart contract. + +[1]: https://dl.acm.org/doi/10.5555/1754868.1754929 + +### Verifiable shuffling + +The shuffling service ensures that encrypted votes can not be linked to their +voters. Once the service is setup, each node can perform what we call a +"shuffling step". A shuffling step re-orders an array of elements such that +integrity of the elements is guarantee (i.e no elements have been modified, +added, or removed), but one can't trace how elements have been re-ordered. + +In D-Voting we use the Neff [[2]] implementation of verifiable shuffling. Once +an election is closed, an admin can trigger the shuffling steps from the nodes. +During this phase, every node perform a shuffling on the current list of +encrypted ballots and try to submit it to the D-Voting smart contract. The smart +contract will accept only one shuffling step per block, and nodes repeat their +shuffling step with the latest shuffled list until their shuffling step has not +been accepted and a threshold of nodes has not been reached. + +[2]: https://dl.acm.org/doi/10.1145/501983.502000 + ## πŸ“ Folders structure -``` +
+
 .
 β”œβ”€β”€ cli    
-β”‚   β”œβ”€β”€ cosipbftcontroller
-β”‚   β”œβ”€β”€ dvoting    
-β”‚   β”œβ”€β”€ memcoin      
-β”‚   └── postinstall     
-β”œβ”€β”€ contracts           
-β”‚   └── evoting      
-β”œβ”€β”€ deb-package            
-β”œβ”€β”€ docs       
-β”œβ”€β”€ integration
-β”œβ”€β”€ internal            
+β”‚   β”œβ”€β”€ cosipbftcontroller  Custom initialization of the blockchain node
+β”‚   β”œβ”€β”€ memcoin             Build the node CLI
+β”‚   └── postinstall         Custom node CLI setup
+β”œβ”€β”€ contracts           
+β”‚   └── evoting             D-Voting smart contract
+β”‚       └── controller      CLI commands for the smart contract
+β”œβ”€β”€ deb-package             Debian package for deployment
+β”œβ”€β”€ docs                    Documentation 
+β”œβ”€β”€ integration             Integration tests
+β”œβ”€β”€ internal                Internal packages: testing, tooling, tracing
 β”œβ”€β”€ metrics             
-β”‚   └── controller   
-β”œβ”€β”€ proxy      
-β”œβ”€β”€ services    
+β”‚   └── controller          CLI commands for Prometheus
+β”œβ”€β”€ proxy                   Defines and implements HTTP handlers for the REST API
+β”œβ”€β”€ services
 β”‚   β”œβ”€β”€ dkg  
-β”‚   β”‚   └── pedersen  
+β”‚   β”‚   └── pedersen        Implementation of the DKG service
 β”‚   └── shuffle   
-β”‚       └── neff   
-└── web 
-    β”œβ”€β”€ backend  
-    β”‚   └── src   
-    └── frontend   
-        └── src   
-```
+β”‚       └── neff            Implementation of the shuffle service
+└── web
+    β”œβ”€β”€ backend
+    β”‚   └── src             Source of the web backend
+    └── frontend
+        └── src             Sources of the web frontend
+
+ ## πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» Contributors diff --git a/docs/assets/cast-black.png b/docs/assets/cast-black.png new file mode 100644 index 0000000000000000000000000000000000000000..89271f3517f99fd0065a8984f9aaa1ea47973165 GIT binary patch literal 4196 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 literal 0 HcmV?d00001 diff --git a/docs/assets/encrypt-black.png b/docs/assets/encrypt-black.png new file mode 100644 index 0000000000000000000000000000000000000000..d056fc728e0cb3e0eb78525944ce5d8adce62c1e GIT binary patch literal 3935 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 literal 0 HcmV?d00001 diff --git a/docs/assets/encrypt-white.png b/docs/assets/encrypt-white.png new file mode 100644 index 0000000000000000000000000000000000000000..449e4f8d8356c24ca2a971eba6c4187f41f60f7c GIT binary patch literal 4239 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 literal 0 HcmV?d00001 diff --git a/docs/assets/reveal-black.png b/docs/assets/reveal-black.png new file mode 100644 index 0000000000000000000000000000000000000000..e2d9eb39699962149a9ce2869e39a598d2dfd4ac GIT binary patch literal 4948 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 literal 0 HcmV?d00001 diff --git a/docs/assets/shuffle-black.png b/docs/assets/shuffle-black.png new file mode 100644 index 0000000000000000000000000000000000000000..eab510b346fc89f593828a4c94d427e9bcb4f34b GIT binary patch literal 4819 zcmV;^5-jbBP)D%VO8DY=wu;)eBl-fcC>p3`%l&-tG7Je~6#u!Pb|Mz8ln zCY#fO69M-^c+qWp!G;S5Ewo1zT^*gBou;OJ-cx7BTc260_PKwpITqIysB07+QB*A_ zJSjZAmQzjM5q2r5NKE)l*sI9}h3`x~TIN@ilV$!kSqlZnz|t!0PX6NPFIG}oMp#~s zCzH-AmHU`4vB$IXa}vA6JJAU;K>#;Xj5Ed{eGJPyh>w1HWkrpAe<^>4RmoLkR#``5 zg(N9*cty=i^|-`@=y4fo*3JI^?W>*`=r32d2cY5EFy6btwhhICVSF7KM)4S|PjH#7 z=C2;Y(1+-Ss^&QW=O&zARki3YTx>zdqZ-j7CCMsoNhILy6dYk_yMd;qa?dLJoIF5i zL%!-7_V%Gi&O4WX03R}E#f5t!;W@eu~=bm$B=FEBQ@8`2W_s-+&*)y|d zKh|DrZE!do4u`|xa5x+ehr{7;I2;a#!{Kl^91e%W(MYssU4SZR2c`ob1iFD$*%rs) z@Yxu5m^1eO7RM5?AB?Z92w z1@v*?CSY>SO6q7?-UVy{Zp2<2UO=&c{ulT(>a#i=sWS=a0{#Z{vmBpAv5?LI#?`8T zj>aIDV%|eh(>)P*8}NW}d;-#c4hif#2dSF!DVD2Q$)SPe7+_~$6zXPe7x6dv|2Dv@ zs3ltq{0aCmngy&2(h}5m;P=4cz-_>>#_@i@pMiY~+daU^Xw=_K^al<=EyUx%l8E!# zfs=qY0ZW0O1B(O42P5Iz8D9|1zdMoaKywW+19&dMJnN26pjxpTdozAIepBBC98$ZY zmCXQPICjIG9e|6`%-NN|p@H-I0s8@$5w=U%igd)o1NrnvAM?``cY#&|F9Vw_$7+?X zsN{h)8bgppQy#d^a(qYp7uXFN-># zb{qShtYP_2C~ za0)VoJOaIkeSqBx&uI|R-M-aL)%=`7eJ7nmOAOz4XP#@y!+F6(_v{`~!6{W&;-@wcU}x{-|$i)277Xa-$6I zNjU$y;8y$_JkN6cdxc}OseB-p1Ky1WVQW#1_AFrmT?l*&_&4?!|03{CG<7=-xCRNO zcYGu80`L;5snQa_*9zBt2n{wb1HOPhthb^MdT@o$Cn=65T-K&D_!*5~Tjr5kDo8&h zK&w$dwNg$d`o*t7130hWxjpbrBye66wgB~+=b&0Dt>$_i`e5z^t_8jhd>l2wd!sH! znrgwgbP&FuN3$)CNV3^DF_7O%;9th^!;mn461~hy`47;EYM`H?mpu~IuDxh-;XGuG zwHvT2dgv6+ePbcTr3cl_OHl0_{JR7-*Nx0-)KX0c@<2o1l&Z z9xIW@u4qPPI`NHBwj%wYDTLl%Pmk-c^PsW)mP|^KFgc{h3wFRwW9IEq-zTc8(TF?(XaE$&hbS$OuOhY7Y@~mk ziE3bH2ACc<5`G6$vn)&!P5;5h_A3-OtE(vODQeDOEds6wo++f4(8%6VJ4|Dg4(nMp zA_+k~$k>ij&#XWLrPnOS#v0piM>EXFB{tpU84>!b6;PWmgLR_I(y6- zwVL;u7;y#FCQzfQ$Y-^&ooUD20Td62voewa;y3-auWTghi&iqtXbP&UQEN{Q8I+F& zc0qQqC$01=HXGz+==w<6*k}to|gszUksdc z4e*(i%MpvXHR>ibH9E#}tkR}pKE9xCgM8!XS6{SLX+!>bjy7+ZiZsN15}?Aa8r7mFkW^%WGBW+tkM76Nmt$Y&9%g}piD8HMs~sUVNI zy22#LBcH2MP4Y@AyRS4@hyql2ypbjsRL~2th3~0^UR0~jDr^r&4uZcbY}<5&yP^S! zw?B@quv}JCx;b8f27~p^0%LnBas{eO((de6%FXzK3h+y0I6aEm7)88-y$19Iav8~M zB67e7P}BPW@CdchSuQlT>v}*{Z-Ef{A$?vNfqd5!T?=~qvhZC$8o$*5>85W%AMGI^Rxzc<^mtD zOX)gI%ke0hiWjHpU%-9H;p{@>;1_(rzsRPTi7*1Vm(m}i&HX$H&Nr@;WOT)rVIa|Q zng$boz<;P=xsqmk6r-wCP`0h4;{tx9ah(fNxJFBpLs|mw0Y8*&ajNDZ!qEhyQYlyS zIP79vXHH7jX=%KO(0Lj!GIBo@T0Qu&MWr8+d~7X`9P*9wt`%hsmpS#Oo~ndb@fTN1 zTZumj_!=6Nb)k=>3k`ODjbgM`!Zn0rJAozu%=hsX{0QD@kVpE|cNDhAAXT9A0#1-c z_%%V=5B3S7YrOSH@ZL~nUY>1dFfBB;H=_Y%EeM9P&m&EVBSD@d9D^!N{z~6XbRI># zGu_97%%C`|`WYzTMo{n%P2(maIL;`~S8I6fmf(KE4>+xU9B6uR4vOW!iqcE!Y(Q%Y zn0BTeXpTR4?!|%Q??dXM-O{>=2=*|_)X1v7x?~RF2V85V{xIN7G<#$d*!$2@KOWZ` z$LEsn$5k$EsK4)(>-mK8&5^N-b-nOY!Y_VO>C;mqhnCO`c166j7B%Dh6CUBeM8=Uv z3?3$2?zqN19r!DTccS$aT9$7Rez;jLGt(cHDY)Q99*yQZjeYOWrihVTMYw!%0{7;y z>xO5Q`cX6UVZsmMv)LBs|4b#iJCFzNq5h14K25lc$HmBNB=-A`f)b7@^ zYR>|+`0np4$MUEdOiM3XEh~-f(bludBkDa2iP&EjjV!39hwFq)N?~U`nnyQ{lXJjL zXt~FF!W7gvF4~xBt~%Qrh_e&(7Ep4zTu z`7{25=%Ie5gm*xFGE)O!zP#Hgj^A}O(y#7UtHPowXj63-2h+|qk3QOZ>zmh%;M%Ks zYOgG}(N6J;x*yG>KT7cnT!pj%IW*c1zSyg%oqjl|OO0#fa|y-w*+XM@HDmE@!Vlx{ zY>NZHMHJVh-T-4DTBbZ|R6N_Ve>uJ&r%7=2?YQeFT!{VtT9%UtKa5XhSeAkKt7ivw zsE1h2Jsf{QVKYS;P|v})7E6QqMj7JFn%M;P_Be%W^s2aCR8;$+nW@hk`_DpdCMI{I zB{#3P9E*AQSLsMP)9%o+bm)^yn2RtkGoS_|?DDQ!;jz=I@ zmot$^>tlqK`?ge$-_&&MfiVs>@_LR0KID3ta*RVaGX9ue*q(xnk}C})Tn?Qnu8yeK*(Tre4$>{|c$vrcrrU=KILOaVKNHX@&K}3iFMm8Jd15?))E=Nh!)_IBK3J zT2hkJq^r>KJHhk}@!ZP~MG*+ErPwAQ*pl@iyN5(*Cf(K|e4qLrWKq5``t;PuA)V)V zq*Jy1O)@g}Ml?gW*hnv+8tx^0AEvkrM==gYqi4OuIQ}sH+6&jAu0$dhf zM}G3Rrf{7cnqC}Fv>+xu)wvnjHF!d}0h#}`qj2Vr80Sw!df&YZ+ns1i_h*IQPD3+A zgV6*-IY#Hh(WJo6Xco&9(*5y;G|}3$*_cJRe{_G9`Lv-y%Yn$r?Htt1%|!!<4J6Z7 zG}9Ksfh}G{b_A1=KzjD7b1lEU7dQYdP>JV z`6V80rJ0)kcGTPj=fh_pz2PvVPaJ_B`iO|_4kV;$uOS5z%=?ilY7+3?!hX-p&ui_v z&`5d|zIE7EWE0SZ29mbesSg3iq7nVEs9!myaBMkJ)^CFXqy^P`CL>X(A}_YqF%(Br znT&6A@(A!&vS0P3uK7CY)OJawCBV5Tii&MCekE$sJAlujCOLS{2GsWpdNPbd;ovZQPbFq`d4=XzeO(r)CYbu{-Es%GjuF!F+NHiuchi}Y_>&%q_1E%*4~7K)W%7Lb8e-% z)SQkwVjmPG+q4@ErY+c44R1$rTzgSXn#O7^juvAtWH0bE>SM1!U7o)B<}0yB^c#aT z7RyP`R@TvCbRdVpN(Yehkw6A%N2B|vQB52x;F-e_LbdGqXjW-bZzMg;9WGYn$pn#357= literal 0 HcmV?d00001 diff --git a/docs/assets/shuffle-white.png b/docs/assets/shuffle-white.png new file mode 100644 index 0000000000000000000000000000000000000000..d1e046f6f61990bb0490aaeb5a739bebf1bf24d2 GIT binary patch literal 5296 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 Date: Thu, 21 Jul 2022 15:25:04 +0200 Subject: [PATCH 4/6] Updates dark icons - matches Github's font color for light themes --- docs/assets/audit-black.png | Bin 2769 -> 3602 bytes docs/assets/cast-black.png | Bin 4196 -> 5350 bytes docs/assets/encrypt-black.png | Bin 3935 -> 4908 bytes docs/assets/privacy-black.png | Bin 2970 -> 3454 bytes docs/assets/privacy-white.png | Bin 3261 -> 2876 bytes docs/assets/reveal-black.png | Bin 4948 -> 6775 bytes docs/assets/shuffle-black.png | Bin 4819 -> 5712 bytes docs/assets/spof-black.png | Bin 3426 -> 4422 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/assets/audit-black.png b/docs/assets/audit-black.png index 9af9d50cd28fd29f8d15621e19128598f78e9254..ed1a2648d385e5ca962df1b1ef9528ca48906cda 100644 GIT binary patch delta 3181 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 M07*qoM6N<$f|2TyVgLXD diff --git a/docs/assets/cast-black.png b/docs/assets/cast-black.png index 89271f3517f99fd0065a8984f9aaa1ea47973165..2aed094f2ef0b5bc339e48112a5b6af9d8045672 100644 GIT binary patch delta 4943 zcmV-V6R_;$Am%Bs#Q}d43rR#lRCt{2oq5}f` zNW$$dtIM(~;(CE1ve{j{7DZPU6kV7CGfnYe+AVda9}ZTbP`ANnn`zq7F=7P z%TU^E4163o8`#x3v?cIuL}(2YN~$4*(q=2*4B!ihfU;Nxj7{R`?MCwnCDjl>X|o&f z72s50WR2(>0h51$dmGI!h-#3cwCMqkK-x=FsziMXcntWg6E=k=L=~#PL4?v~3*ZFc zNZ|dzj#Z-10DcHO2yBKl(o<`|UjUWFQC}n15lX5q#}U%Wz=wblRidu}eg<5e#L*v| z@MTJyM}foa{!YMO0e@=bnu4gh5G$k;5g{E(bs+&P0WN<7ev-t|q6%?l&@U>GDlmv@ zpi$bq54Z*?5zbEH=#dttJ%-W}sh)dxU=l}3jW{!a?>YNZf&Z%OA}yg!)gqKO9|f+X zzjw7Bn3lxRMNOnRhSCzLmXH?Ne7Et!Pfp_K)*5;B0IvYs+Mw0Im_|$s!|FXDP>RxK zn9}Ba;3j`cyX(V%^OQEb)S2E`rOoL|oBI%vTmu|UWkD@MsA>ZbcjI5DRAgVJv^RAW(h#ooATK~lq?>`?U1$kh4fERz0I9k|bnwtZ^KuQ~zg-8SYP%r#;`}r+k zFT}p&GoSvd?Xe~Vl*OYNVR=RM403G~?Ec|On@y8AdNXh4gQiVo8@^u#zKD!vrSu|2 z`qjX_NgUPX*=S7ycOgP`nG2kl#L;}E&1__>EoF~%7({8aA@G`aO#q)r;^_K%uBCq- zlr~QRlf2;Vk~o^5Q8Ai33wj(I^{QSIB*_xtn{3zYd&|#L+u;{{%`){M-F5coIi{ zM0}ZCh64{6Q(uZJ*wYcY^>qQ0p0QhVBeKpc;-zkZsBa=8f2-ptz7vK#W zXM5ldrOifJiP`GvD&P`I|DU&jlae_4t|uDb@Oej8x=9@U0=U!*-U4_)X;Xi-ZELOe z$181)s20zonUZQH@PxC!1O5MTO}e^GWuKl`fvs%Nmy$U0Z(JHz1NQ+dfa8Htz{(_! zUUcG&L%Q>R!}~>~UGbEc=4iwZDeVm|MA|Kxjcz;9U=FaKcj&4ljy{`lO4{+b4Ka`c zd^w4uTm!vIn*`X|2`V#!+W&uWqP?d5fc=4eDKDYV$vckO?IqPV^b2YM@Z(AmlQ@cj z1CjR49>8ya>2|0E+rD{%azXtX*xwhFWh$lSg*&VD;_R^x(_d<)d`4;W2|vCS`GfQe z3S=CxCbq=&OTZ0*qiw18ZKch<$k^cvNKf?NY+k;gpt_;Agl-qr-p+sbXKM{7SkuDi zkt*sv$Pmj7N}H1qk?r7}ay4*d5=XCBNYbzRZqJNWdJRhvj{|?0$b)t#H0qb>?Drf%6oFRiz;%yAE>k$mR0@OsY$m}+V!u*GT`r$IC`K)yd!{3o&9^P z`5+fb99^NbIUM+y6Fdg^EmEa#?1c9LXC!gtim(h@IFWT#L*4a60-KUTPg41%|=S-i;(+0kA4x&1zv7+fqW&@9khHW? z+MEd7fb{h8@EU)xUlKlw;$(%K7gjmf$f%YjpqIJ&z=8iyjb zy7Atjxxi6L9QhrCw$kklb%67cZav6TdJurp=3K-*C9j}Bs-5Z9pjwSXDQ)1+tXEJ< zn_ZMPmmJpp)``u?}&i1mJ$7dE9*sbYtY zzJq_*n<~vdUWb?o&TpjG*-pCJPUWMt89}MDTo$`2ZT3Lc6xho9Nom)%9Fn+Hg{ zWs@99%tEGySG4IUZT3Zsi7E4vINHyPvkBsNl#1*Fh?PHOMiNJvUX(Wddw{LILo0yM z&i)c$&m@i(RQ*K*NY__?N}H)j?`gDm=x50Km9r_oQ7)GOXXWr+_XncO{LAgS15bb2 zEpyq9V_ki?Fl?(jk8OT((G7DU7_=^f9)s( zM^~<+ZlCUJkT#7gsFjHE@7kq{r7(Y3x_HqmW5$i2i*(7;cGOEqb$4@~{KkwMe=P7R zC+O}Zj;^V7-qOX3R*e}qeq&14eHw)fC4CSv*!p5$j=03ch}g0WrT@8f@uIA0SRFyv z89$XaOHf~>_At_b(p3$0rOn=m)!gqLJ&cr4OWKgF|7I{5zzpb*5MXdd332yrDK_691E2E_y#RbTrzdL1(6ORY+Dv~$W_|cWDKTRC zey+*%x1wJ>sepE;yn1!HuGNFKO5PLmbIRS5e-BJ;)?a)e=txm1Z4O38^|$g4-GfXy zUr~Nm#k4j-#4-u-2j9)^`)Svr4{=Ry8A_I}o(>%19eNO%4W0XUb`l*YDy7XQk%p>2 z`{Vn_6s2A-eh(s$iO7GXfr)n85fPB0xnAzu$e7>EB#vHcBApVHHrpd>HSF#kx(S)+ zPr_X9vXoRO=-^d03AODnA80?QGAtc*cC2{o6O{QNLb{z6XO5JYO0jJfP*Vj#Sim3Lk z9VL?`$T(iQz36>^&6xu@l2TC>+GbJOd=B^t<;xR&q}oJ>ZlqI0btUqLyR4_OSYASA z*4E=j>pSHYA}W8|kvI=A;JUnym<;BYoz&%Yil{CJ45bqgh5_Hn;|-7#zcIhow&gbT zwvm)qyMEiV)_xi`9PyPp(L44Ea2C*G#{?^-(TkL3Z`$pxHV#L%j6xgg_Ng6(IG&A0 zTsz$F=TQ0vh4qL<{Z;yJxG#cg;qI}GD0g`4M%Lg7&3=EbL?&fChj?r}mQ;QXTU%*b zRMvCgNW{TEODO(lNAx&{0PB#c?`Ic1+oq}N&-P|+X*QieTi5{jG*YsiQFO))VP~&g z+e{j5pcnZQv$j4;hh`QbRmEyA-deI9>U{fA-u)3s75rucX^cRc3!{)((VIHo-LPtt zXR}N-ZKZ!1K^#x{oHn1eh>>w6GAktg%=-Qor8n5W*|oyg_(M2D1v?tC1u`_XGcweZ z@?ND)PmxB|W<+(MxBp$FDtuQ!-8_EPP1uKNvEAk>ZB9idRDeuT8;7jDRS3<9$~fQG z1K+D>UC2ON@tpwQOM#+lW*Ed>`DA$zR7a5|s=|M0MpUjbF;sJ%MG#e>x_wD#W&LN0fT1~XJtU_o;RLh<3mDa}$3>@zJbVg9!>fTbC5!H*% z_X)M$Sr;fAf2vtw%U?GmDtBhda3J?k8LEpU2!`ljl6N2;a5$bUl&ce_9|^6N`1-$okt(C%=XhoW!UT!(C}JK zfkNm-7KAHIP|&<9@TJIts8d>SE!{*P;zNIyZoS@qweWi4rr`(BKZ5Z#@{Yh-X)FYO zTIodq?W7g6X+{92Ag-+bAG0f^tNKny7N%(Q&n+r$wKV#QUhhC@^EA@<23V2AQ7t#_ z0i~_er7~VV^o0VJQyg?CZDvvWdX$Yi*;TvUOJ4gcn=ET{euI_Qz5Q{Su{wlyi^_j5 zrVF)~3?h90@*paQAgadjOR9R8mMoN_MHQ;Q#_&t3AS#DYQZ+_sQ#k}twT4hqIr!d& zg}Pu2B0@>!;M-FCWvm1F2ql$+FRH@)qz4(xC|!wWNS9Qry!{}m2C&0IZWTDBOR6BM z))7Qy@kP~&H!}=X+;-I{`_7$?B$R(t-9y(5)dW#>4_#wc2))1Vp=-;D+e`z$yvDXcjyP$&k;s1-WxDzMtq5!Of1jMh(IZW!(Kd<_)imJ322Nc|zsP#X z7ROL~(f0*O9GyGR7g3F(7S#VAU>fy1mW`nQJ;Fnc^}rIuId8H3dU z0S_=V=Kifgy8Nqcatla62^bF$ z1A&NISc)1!5vc;XFBL&4DQ`q$L_m>3kt!8LZUO;R6fsaC2!e(rkOXqU%gM{T)<3?T z+TNbtnV#L*d9!c7Usc!JneFS%eB1r?*I##oq9}@@D2k#eilTogilPiW?E_r_B{z%) z+JN4Hu87jyv;nh$M}Q)*4me~WE2K0pI|5$<{(}gU8SWmydMQoFB;ZP^ct|*asT5UWfg!`Mw%|vv@l?_0pEYZ{gOA4TsIjHoCe&7zaY&+ zTE=$74rRyrfoIt_Sm};SSa&4_Mgo5%`lY`F>>QI%QbBqZ_$g&UGWn1r{^Oqi&q-Fg zd7kN%l-M1y@%ZR8i-4W1^y7gqAi7JhM;@yY`_WNEI|7U#ESTGYp&tL!C@bwU)U=Qp zGk~>33qgOsb$vfD8Tcab0RDn>EpQ~#&HD0$Bd^0e(>`LQduM`jl^Qt>_b}cTGJA;b z5;Rv>g$U9Nk_nQ@_Z<12ZMNcVr`>Yk1i-_-*+mP=212OSTCOgXV zHG&pOam}=QCn&qADFACI|Kn#x#N8WM0W1Ob0QN%+m?jf}#|XcS<+!`5QB;~2Ruips zw;{Tio&R+aX+|ThZV)$#_rU+Ga$H8x0`eR_23%b#%hl!AJCE5kn7_tV#5d8qAeMja z*@zCdnDWTx07Q7~hxr&HY%V@&#r4rW#!=a72H|s#xD%0<%#3%hM;Rb3?s7*tCnBxh zHxZAAI3sQluJ$aq={b(_KmD+0nv1B^mF_?k(=CJ_f`r8c)&@sIJW!@-0t>b<4= z0aFO;ibZ5<$A=#}($*T*0DF0s+w^}NN%B=dnFRa|zX$pTaI{C+ zv#fN#siFS2I?7)TY_sn517G&YuLHL!VY}mA5Y{5D$X5c#la8^t=`od2*Q9^xfrx_c zBTy^w_kXfSh`u%;lVP|Gt9G||ibr0P36I!{z+Xz~*CM*ygTS{DH<#ULF;jsrrta`K zm95nr+`3Yf?y##zne9|6xLwpfmGLgBPc(NTtw$V3B0g4j`X>>Sijt7ARIa!^qICaK z{Ja9}@HFu{#7ryAoi)^Z8sdK+W$I;S_y=P8h++pse{wnY{fe^HU#Wr9k=EiAq)WL4 z_lvp-adP`}mG6TP=kfSUEB@RBb)AOjFj3{-4-ARP=P1PHW~c2&1_9cw)k!7;XEol9jPR%GkOL5~`h9hxLdiMao1rCZyKN+~ZN*+Z-0gv;AS88B7 zvTI3{V3}6$0y0Hn$5|Os#sgLI-Hf!7Hz3}UMnP4k$718b}W01kd?NoO^ zUWrT|Yj@W`K1H-pEh&G+8v*>m@qI5M1TLnKT>0-L?CsD=bT>5;ao~$uecXe1M6|2} zT~-XiZTvGsA2ONzwBx%t!{@~@dHaNQM0a&lfPcs2aUZ%MArr;{58?M>U0vjhM9*&( z2*2zLkS^?Y;J?JTVu3(cV^3s?q+0rZ;7p%~q14abgxx#>y~Te=$QBT9Bs|1Q^Djr7 z;mD-$XOOPR9yr_+lmBaux^1+s*OSb9RjGklgdcnnxEcB7yIzzT=HchNZadhW?UCjf zE6rlUJFg5w=G~HPy74=YvXvSrAl;AM<@6&~=3q2*IPPr;d+_f{I;gbT_fXx(%496z zQQsQGt@kp-l;D5kTW^P@p7mA|Fbw!L;fK8m_gvYrRIX@Qf$SpZ%ZXMwe@c+{Dn~t| zLMJkxc_X5yx#C=$pnS!Hosk6%u3xWfhq!>95P>@yzkLNvY}3O@3DUM9j)6Yi+wT!K z9T1a)%ldvPYLiNpgK&?I79#8Z8o_uf?M1JXTqr>nxVnGV;%!2@!DA^4%khM}&0dnt zF)AK>g7AYb0zV^u^0gk$w92bzdz}K}d2kpqz?eyRRnKXJt>;_OZKzYF4fmb|z4&=U z){DJ^itp|zNhu)98k&gayP(eJHZ{ z;5=l8{|;n6uNIeLTS2< za`S`9ZjrzY+-w68T6UIe z1aW`<+11#9>^BvJ71rmql)I9lNcR%3y~Z+Y?P{MmM*t$;Kb#Sj8nES;B`A?tV8SRINxmGLJYFnQS)~M(lw!9=5>d68qTs ztB?`g+kgo)`TSLrWAAD+DLQ(7F#UhT`)IL!A#;wsoGeo(zj_YZG1u^KM7l2}A1t%3 z<2FxAm3oBA?B24T@=&5tp;A&ug-S^s6)GilHX-X11DZyt%+n2WKgrpGn61@rM4u3! zD)k7}M&t8@dMl!&&N}1s5TdQ_sZx(ntuQ`MAwO<3ieS4(znN9R^$3-D&~tw~x)E32 zFokM687`(sOQ<0IHE~LP3^zV!)=EKo-5*rncU&15%xSZ2Sr%N69%Q#vEpy1=08v01 zf%ej0GuZd`qtcA9kqoIvsGhN|zm6>74*vOS4twVL_eg6H%{g?_%5s zRxA0Th`1yziHn#P_5K2GPNjbqN~7pQR_$aaP*8tM)q!k;@sSkj(o7VQA$kz{tm~-z zN#X|gr&FH6*oLSXae2Io93l5?BOX8$X{>A+f}964mGFbv3)#Xa;7(*?idr9TR&k^9 z2pr$CWC>+I^G)PyT|nm8hYw}3o#J4`J{~34uG;nLRB?>4t~(oC-e7-aoptSVFu;J( zXrZ#3=}he&+os8FSYwp0eT zw_&C(7=s9HsSNA|5gpE0N*vl!8Q4OVnV<9^qm#;=Xj;0Z>awm?sA{7~Wf$1eEtLvY zdZ{ROw+a{B2pGvX{nBZE$&m z8EvUbYzI~w*VXh%eMcL|7&|KHJy!_5q8ss%$M}b)NA;V5V_>1+x3gcFKoB+Mm1e+fg?-RXr-~ z;1MT?Hx!wp41#}soyNU-pZiSU(K_>JdM>24^MAXMV`4WT$6{CjT>sPfsq4t6}UiweCSaiZe&;ueA=_cA?Q uK~WS%Q4~c{6h%=KMNt$*Q4~c{O8g)HUKH92<<0s40000f^!)U$wKmeC=M@DlU$A z!3|Bu=;@^@&U;ELDtb1(2={2JJsNyj*phf8)w+-8xT|o*Rc@1nQ7?G4=^mP7iz0R!=R%h4n zKIK_N*MylBCoumz1b{Ol&nt8abf>u3KqKxQ;7%;u?`Oj`+zS`_)l@1h$X`T5d=fElD$?fbuQML3_RV-A7P_4Hpy(Oj=1)E!AgU zN)n8NV`e35-r3-ZCfQUNd`{RutQm0;CAcougi&w0f%||t%ACjf%(#P$9AagaVso|z z4skHWUDqa_)9*LxK&9`0f#fd@Z=9TKi(UxQ9{FrU=Tj{Qgq zXx&F^YXkN|#Lc(4eYPbPkt|>|k4PN6{8zP#iLK$7DSc@p=ZnFt`VG;SF+Vb>X+J35 zbDuP#GN{Wq22J!G$T_FkU~?HG*d%hVVsNq8`XjKj<;08Fr0jQ{$v$`aQCdv_&AU?! z+D}};%fKkAFy4)R0^pjMnYj9J5~(3=j>diD6MrjZWy$!#TO= za&_ed%L{x2plYZvsWoP4^pFm}zSLw@@74(Lx5`GmPvvPwO5;_(0E{RopnozuK`&w1 zwNA0zNfG%=DxU9NcMPkN;h8!4R`a_OQgj4V~Ty-Nmu{#Qgc zxR6^LSU{~2ebY|9WN9JD9R~+TLa`=7eIrYrz`d3j)^%L2`jbe&Q?5=?F-zZ*V-G<6 zLyYeb@>^lc1IQc#qoNtlhjPtqE_$yY6LWAjf`4g(>*IRQr#50^wve7NwH4g7c{)8c4o@LkPj| zsLRkbrbWO$w6|yo*7=BB5~U^;^^JGxP~g$BNy?s7nwMBWoGg2q$3e`x$frMGay(!#p<*5dS@*40LA4F;Ikd4^6RG8%Yu7)W>phE!k;D3# zS72XWTP0Izd(r+;meQ4;1;%NxrNf;~K`yej8Lzs;bzF=$%=;505wD(Bh|qmih2 zaY(CdRqwP%k&3!zC;CdLcsq6ZN)>Vcts%A%7`;JJlRgZR!a*g%-Y=p*@Cj&GAP8~9 z164T%?Zx_~v+ZGbpxFHnMi{o@LPH5xl?j1y)c6%~_Z<}$Z`WL9H*EzD5pk!7)f0Cm zQL;@w&Aa0M88NJ&t3vbJ!R4Q8hyVtSCs$mr=v(t}^fslz{EX3ZCKUTe^P0Sc5;7O@ zIEHmcj{B~C^O{F*$c{aJ#Ps68lV{z$wL+sdLyE{_1-hRRgpj)bN2e({)lqT5vR?h(~WR zc+UCrzsqDBx||Ef0(yK7=d*$%iF_gpJ{bX$`N$ujSV5wU?M=xxL6qj^B(mrWxiLwW zM1Z%*q)=g35Ro$L8ZEe6&0C|~Surg5hqCJK0$tS61+~G+V}tLHN^4&+f*35D<43HK zxfc@69+6H%U)}M`Jo2K7M%^fYf2$ZXi7lRhUpp8n)4@W#1 zIh|w$#bOI|O=u}*h%HmOr+1E_zx@;R*IQ#U<UL1A-^GCX3$_m zlP?5GJS*#z1Fqc%ALAit;Gq_EOli@7Zv9lBq7@~$b^5URw1?Dd!jOzv9K2C2cVc=1qDl@Kz=rm>S_Y6mJ&;E>=-ME*s-HAq{7R`X zPL4Lof{>d1_eq`JKKv?f^s0#ONDBnS8nFfL_7*A_GorB(Gw1VV1v#O}B?_hre!wqtQ^xc8?EbmL^}S4E|tl|G#i z8hy;7Fs@K9vbU^M)L8$F)Ku6LF|QB#*TogmnUlc#4P$X>hg{+(Ip;7Bw);w3Am>+A;w2R-Q6 zeY*QPMeQ_YT+Qa;?+0unGchEW+RG7V7p@!2(2gfv3p+lk@{rq%~4#&SX((0bybJs3y zoZpq92Fp?Sky*VvIQew=)PWlv#LdqJ zMbKZmV&zU&njundt?<~kSoeGRzm8$Wt})+`CCA%h6l4!(K&w9Z5%(8mKS6T0O}{CS z8yK{F5~0L-&wgoW^w1!_s!HXnApXH!r+>=%^S9HdFvc?IsY~0JcIVOKEeHUq+E-5 zhy>u03;l#!*`&%w@TXa*#9w2r#p*{BH6+h_)dCo@{)g`25|)Ep^O?x57}kQ}ow{v` z8phlq#dYv-R?nunyGRM?WOnAajI?T-U)m8(j#FA+9N|DE->zn#DNQvI3*8K?y97~9 zmqEkTtqu|q$+sQEm$}9%{CGv=4;`#EyUU`>z2VpzlYfobo{rg3+GPDU68h$doYArU z_R)z!%S@@!QDM+#xgLVL=vla=l|oE>c^&U<9h>>JZC2<1oKU_=apE#{*x#cz@0D&i zs@4&qSg`GO_^@+Qkc8@G4r8p~aA}hrAHFptcP5g?jN-~7HX{MP=e(q>R&y2s{=T*M z*HPZgY=`o5j*!p--48}=*(&?Nka5OzbMu}(7GZ(d-g!kDwNI2iSF(?BNhZYsP)E>l zJ9csg2MG*X(VErUZba(Fn61`*L8 z;^%>>*u9&aeQ~o1bVFvcV`3|f#8!DS@tj1sq>?*%3WBBoGs*3GZ$m^iX#a5aK-5Mo z$}1wD0itFY6&;A_l%ozV!nzNH!phuFM>m38MkeHCX+s|^H)hS zlm6L!F&UK$1zw)G2hUNHnR-=*m~sGZNo!wdf8g~X;cQ8Oy_-jFNgFdVZL7g@I9J~Q zVZ0uMADO~(<~9V0C!)RF>7Tadj`_FUymxk8c#Wz4OX^DpCiPUgMGZ1YNBFHK*z`g+ z@jVm+My40XOa&wC5Ed1K=9_u15DeOlA)z{n)X)duaYpe>;;nNI4d8@o)iTXSV*3%h z8VT1PZYq0@f%;u86aFkuf6%DocOM5>lK1S#4H&fX>s~q4KECr0b$K2I_Lcp@k*X=6 zN{&cOpcrh>E61jiWVs(N?RLQ?2uTM^UvGJko$3@wHLLZqdF>4u)A5nqwLnKRt?YhT zsHSe7>@$R(b;TuF)eu-vALPI19OUY1l*V*wJ1@9Yjb8Vg!|jV!$WJB_3Up-)jkc?( zMKhHxQ}Xt%B`hd*abQ$8Gq)@`J3+m|B3|Gv#z4FyI+aOaKm>(k_raFvA&-TOX@vp3 z3^8ch(~iMQ^uxCIht8xj`a1zIXXwa4LWeKdes!<$;g3uDRJowIWN+!Yd(cl7fMR0= zKa13Cj@wO7x_OM5&?z|13p)|}szPa?an`T;k3 z=TSRwR@~7}ZU+`6J56x3FuQm(%+ZQDHJqZsl4=`$8l7=LzOmtk8q$TBisdfw2+sYdKhnv~hzy7a6NyMc;X*4Tt%qiKjz zt>Ki42Ap--4vqtyj=~bU6a^1pys>uQjkS$UlMHQiyjGxTFSMg#Fgx>ZO@XfSYa$_6 z{*LAtG)!V#^d3Ay&d){r^rLLp8C`+r=eOo=FQrJn@)R}Jk++8U9etKo_gj` z7~L4WFSo{wSNgT#Y>Od~CR2ozk>KCt9_R`#;T$*tTzKU%T_BBZ`n#P$qg}|addO#I zE+Lb1c&{W!&LCvB_covw4x`@>Qp6{mn)F3Lq&758wAG0P#$OEF!4H*!`XxM%2a}KRy7< z%IFryb4Qtoq^9*q?^fp@_hwO-O50qg#szxYVm$~7C-3+EB>%|;n5K84vWQs`{^hsR z1xnR|(!?TyF`k*k3mL_Qcl%4l{VvyUlIS;s@|>>pJ78xztyx2gu|UJXua+c|yUUY~ z>I(gtW`xZHs{0@LkYS?pmG1IT=pOhl8|*%Va=!DsBaiY`v$7$$qvHRIz%!eNPOXxk WG|qf12LSj106Qxu%La4*g#Q}c}gh@m}RCt{2ooTQgMHPU*_g+Xs76?=p5~6@nkX;A_B(jO3 z5h(~#0;PZo6oPD8Y?ep@%BF&#K?Ib<1*8x~7EwSJ0f9h32o@pH$d;IpkOay4@-}~* zH@=?JGjr$O=~>=;{Z)03lIeq$^GvM)fJRXn76QX~mYymtCGafh`m#9%^msJK5FU6}*RgL4u)x^2lRl&(G?y)aCzhSm_b2Pvw*xVG1vCLWWR|ERls#zo z2fl_ZNqWNUtiI2$bN>Z3+UvCpD5>8Gz;(c3-QO<+_5gq0DM_9xvIVfX`*RnvbXyN| zjr{?}xe%&9G6c93*nn+Mys<>NJiUmb94nfDBY__R+r-rA0ww`-3X-YnoQhljfw{nA z4%_R~YzEvbrxTb6yjYNY0ZoYA_+VsJDeB@A^SkRhryve6NwgwMv}tUx z&jWvKP*xXp*8>j$OH;^N2}U3>O!}gj+^DucN%4PSBVQo>MJc;1pvM>CGZm00O<4+z zPIoD)!Iuahz&pT}#`cle-uX#xczJL&#a+OxUi?wDy&dr_ErM^WzB{n*6swUi?YwQ=wX6r17bRQK9FUIg&|-x@UE(JTmf>OqxzhRs8AOW?c}o_ z8R&VaSxJNTGGx%2WdzB0+dKyCX2A6^{jEeM-=9^#pPz#qg%B10^dnX0OtpP6l3{-( zPfk~T9%F3V0lB+IU7+WI-5txaGN!Lai|YlO!+^J9`nm(ys=MAN)wW(8uQmypoCOEd zfvlbd3; zog|Z0Ee2sfX&NolGROh2EzyZUx{xrS0}}R~r0Rb^qb!v`>yb+k1wUXc@ScCFb97F! z9Hsg>JHrusRrj(v|n79FAn&`iQh){U?Q@&`#da$knzCz>YdAw@x)~v!-jk5_K;3C2^@bTD_0&N$}!bH{fH4fU`hxiQMD-fsi zvhq(12d+S#T2b=-mYzj|Mj4~pydz_Km16+#GRb#4?H}+O*(V(VyQ;Qbts)IXa>_={ z!n=@1@~0g2m4;>{Z|#4Q7wN9|S$os)GVVI6QF_8R+iM}6<0+I2l? z7>hUqnJa->-_3LJ1SHH!FQJ~=x*ZS_(*b6mgS&sXOEr>P3?B{_T`ltlsu-AY0k5YB?MR(y$GfuU6 zn}asv*baL&Q0u#AAm+X-Y>I^DtWD@ED7WL@Pq!3}|5F}c|?57o3c=$Q-gZF;Y>$|%nj`LCNY(%`}f~E3nBkH&g zC^dbNXFG1YavXwvLR*or7#$jOxP$%%t2SNhUjvXog1*C=5vqF^p>^zaH)Sa0YAe&j^ z!vzhtmG|Vf*D(okDn1u?FD^DCO#hvsogJ|wY8N67BrXW_-6e=$gR6i_h@Uhz5;0Pg z?Ym!N`oS)0u#K&e=nC^G@fFWiyGUoU(;j&`uWl*)7|{b? zL!4UPLQGOikeT>$WJP2Z5>B%kd0ehXPDFnjVUy5gqwNQg$xN-HSHq(6Zl!eudD7UY zJ>@=4NS*`Tr>g~zDiD<={o)k+O;!7xlT{EGVIE_U7$aAhciQ2kd((}}m&BPlYFoNX zt(>YCVW%CMLG2Z<-o&klMZ}Cyz68mNcu&H9I$_D0tb(}ko$PebhDq5kztf48Yb}2Q zoQ{1LzmuK}jD3k|h_{)^uSxbkb3SNY+-X-JrlC$pgH(jD45iY$!l{Y@NZY+w@xHE z-lIhcRdMFivtkx71+ib7ciMjqq+eysm4nE3r;U5TZ&`O*ZK9bS(WidznMb$?`&=zD zJ}-CCi3^?fpGe?ghfzA!_oUyV4ALO)ph_d3YkgARX|@08dGxUys}8vw2?;VS2;+>; ztBVz<{}2^w5|k@Sl&fkqA+DGs5l8P`kc26RV>`eHWv+{k%gT#dW#WHc>ijzLvf`P@ zBrK_Hi1|G#C43j@qimx}6XG9XmVp_68;t0pK^dyP2fx)jA8}$i@PpPSE{X8A-Nn;5 zPITI`J*uk6<7ErbM`_2=`+3WX5*UI!hMF5JE0Nb91q{P}RJ9|{=JhfFiSRuhcNxa} z0&Ba=nut>C_qB*V+em-RorQ}*dmZWCyE+Sb;RJ}`c}j*pXQ)1(#?G2}AK8=A1uJ)h zQk20d>I|eOq{uAIF~6rNU5K}tSvE%eR?qJn2oJt>xc8fG7#BKi+PE&WPSz7plv)#* z<~HKZHI<<(owm0OT2BRWai?8~L<-bmf$@1Z*`gbCHt8p@^(8e|$>Tg8kH_Qjcsw4D r$K&yMJRXn7~b z>&W47&OUqZyZ1fkGUqpQhB=qDzxADazxDba>p+7B4H`6P(4c=og9a7Yrq&8{HcFdq zfbD>tfE~kY9k3c$1+4MTZm6AxwPC9>gz$&%1MCl|l2ls0<-KL*YPK2>9Nvf^=I0`N#Zo=WP*5R^7e zz#wGw9}hIuR-@c_9heB*>YZ(=wK4^2ZU{=7?U2#`Q{;b$mxK+#E5N?gZqKkh^xZq* zbL)X=z}4Q_7clkS#1!|J?69R zz-_=N@9Z1-s8^ku7=qH~7+@UmrI?RwME>{_fLY$zjY^w6fQ8i09%7Vtb_{&%*EkoM z>Eik{J^+8l17p3j@8_dpWjfUmls5f=Yk*^8KJqp&8JOgqeZ5Fdci^wUQ7Khf3)~M_ z;0?sh+!q)E^iL_X9XQrIJG(^B6Oet+F)`(|0apSOyt5ys)Fm;UVhBo`y@4^n88Q2O z5*hvXd1u#^k#{vPGKDJbz}3j8TU9~VgMmAM&!vBm{|;chv&+iJJpdR6{1DhVhOAeC z%YeJRvl~j|ts`CbLVjTHJ{WKx7$E6ATS`Vn=rL2Pdp2$h*msFo2K0s!N@p<_mGB<>51aN;QG5to0bG}5)H4$&jMAp5SMTN# zz}-Zzd#e%aKg&D2u&uQvc9c$Ovm>&HNTTyPU}#%w%g4ttrOkQ3?UWyVeSsmpdN+Sh zZ)2$O+`Q zUcH;2Xlre0OQ2UpI_!uEQ`^JHdb({y)0sd&@9cHn*$+~5HIV94XDK&&XO|Yq>q$8VNTi;kbnD0r1W)L>zxp=OY8B5{CfKDQ!+l(@!ZKG6bc~VZif5f9Ms+ zbUwJ+2C52acJR|m-d|3TA%(&lSv`blI6VLvb% zI3=Rl-+}(#**h{!+0rSVSzLeee*c8e?-ypGO7h~6M(?tCXWvA^^A`b?P7AvMGnF={ zC6yn0geYzH1s(6>+O!qDPfDsiLM6h$x?XAX z3~&$S16nMQL*-;&*@OYHS30%piKlord2fY~O?op5+gr~f-&cvH`u$A zgCPKfndSXF}AhA<`K|3(70g(GF2KclHLP%BX)*>eNBN^Gcg<$B~zU zTt=1BW?QAr@nJ)p2XE(*U8JML&cJk~ z&9zFKsNho?@|s@f0uKR8lr{r%ke|8UA(ifVBp0$0Q-E(3htsQ(Xb0?_T>u=8)Dl$U zVqk7?KxM_E3}t@-ptRW&I5NC#0=}DdA7rSv(x#iz=I6+Mpie~8QHW1xeG>VJV+|p9 z?hs@oRpLnCMWxM!A#brmgu1~@bM`_EWKPkKZqHJFASyNxn-B?|4_r^>Q2YwuJKotb zX+6@q+uSClAaZ#**w;A zdN7WxNM(PxN}HZao6C_6VN`nD8sH4??68y>Uz?Fh&0whNJr>Etjk;gxP~@0-N75r( z_^=bxYq<%f&1aB;+l56hiyV=&U@hYEO`=mbrOnw$mi8E;)AHs32YP3xrq-~8Jkr_w zB2lku$FX%t*!n8(Y^(%KrA;%ige|j=%Q4zJ`>TIAa%1-09m!6P!?oVoSoIJg=V36i z1bm@N^Hs>HY;xAu^JHE{9Fj!`AqAji%gO>hkR*#&!v3MEo7y|O9Jnc_Dp}vF^!b?W z)&SSWX{faMGLq;sgX%``7?SokDUUmvaw#Vd=~a_}1Cf&PD0V^i4=*ci&I%(hig7@k zdx?LJ4jENh5!cUfV@P(bh|)$WZSF*ZMMqbWw*sk`9Fk|*eC|cCVd^^-xQcl9AiM=k z0&c0~9#z_01pGFJtiJ%Kbu?p2X>%lUb6PbcU5Xszwus1v6VqU%GWs~G|LzO-CR`TR zP23SWtt>uF{lk%z@=8IHVm?Aj*Czn;il=|WU|jbhzKm)tLdwja1zHoR+#OjCPDGZl zYDeF7$T9A@;va@gqH~Z+=sq#~o&k*P%$rm?{i2KzFd2zdNmr|lEZ~s6!R>|2WTnk6 zz;i&JQO_itA8HW_hB^Q-{F8}anDZ=B3mUsZDl2Mvby=IOzVrt{Rzh>d~^enI{z|q7h|P# zy1aQBDeC8@~FdzUbTV$`N9`U~I95ZCpaC#%@}s{X}Y z;g4TTmotP?!o`~d!)p+*M<;Y!{N){UkT373i%nlzy1XG26C61QAeUqnf0awOxwDnqD5xGHZ?Coph1HM aarr-SK%%)csMcWs0000upvB>u-89M60*te?|1KSf4}U5{mz_WnCw00KF&S&+;e}=y+6nyha7UqA%`4t z$RURWuu@%t6u<)Vfwut#ebfzH20DQ*;6}=7mm*}NB3Qs(z`KDNLufLh06_;HSAa`E z3vglxH6hB9Rmc`axD$8;c(jk+>7%S3pb^;9M+bpkALWe*GF1`Y4m`}w!M`tsb%_9f zLzH4Ka2!x6tWST|V>Yl3Xh3G5N>h3R_%-k)V2m$4aSP%$;EO;#sUKiB^cL_G;-BQ; z0!6@j;2fzROt0t_;8Qp|s<%7>z&zkj$o4JO1Lqh02Ur74@}}Fe2l>D^fq!G(sl7lm zsr4D!fj3>0>jr)c+@E|GW;O!AVxSeX4m<_?95J)=Ne_SP@d{7^d<*ysvc=Rb8wFkf z-j!5uW+)y7UPr&PZXip>JVb#2rjTAf#1n(scW2-K+YHKI1vUb=n|EjCp%mDKe&?J6 zo#Z4EV&5Wm#(G%$aKG(xqzKwry(t`t_>3yj&F&6eObvQAELq*7GyKZUa6S z5X+Kp(y@P;f@#R!I*MLr)B#^WwvX}fBTYUr6bJ;=nl)?GnKNfpJoNPRsQUVPRa{)` zRvF$ztU)~73v2=|YVvA9ViAFO%rXr@;Bmz4>CC9@I6F^wW3~n>K!rjfRb5>jR{@41 z5{amaiVC;N@Qg$KL%`R7)0+J1fte0G(;CG{OkRJdvAd9ELkG`k@*JR|q9S$V$Pq0i z=tndfRpD@0S(at02;B@{%Hm-R@LlvQ#8qTMWmF6z4_FOc!?}TnfsY&Tz6V2VU|E*h zzkmO*f$r++Qnj_UDjW{0EnBvz=wQux)oC zOQRF-Yd{#8aA}7CVge(TQ(9W8 z&YnFRQ)b1A6>hA;4_venpbR<9bmISa(#(H%n1BRPoGQKxy|ptD7HG(bp;fC^#SG}F zQ>V0M_u|EiW6GUBe_j<97Md!;!6e!m03Jgoj-8AM@VO-9c!m!mv2(l1UIdnqeD1?9 z9OMk6#>U2&0bR0WiB`E_FsPcFn`6q(pFiJ?RY>+cp$NUW%O(ccTcu_o)2!$24LLn4NbvW60-r__MEt^J(*hM06_l5kds>N=D_5FYga9&NXFaWm;5_h2 zU~M18!*b-}&f{JPe1^mt_bM>X3n318*`^M0X~TvM%4-CJK{r;RYy|qJio`p(8^Al9 z80ds}LpFcghr|i|MkZfD8;O6*FaJQ6?sy2G5y{n2gl#r|TMhh5M^KXR!?cbR{I2`M z$X$;_@tWPhf1Q}}L{{B8B2XTQWKU4TJt9p8R*tv5jt*xzoum>^MQ6Kn@18RSOACq`jvK#ma za`Vb_JcvZE?3|;Y0;4>Z`&kE>uAId=bLJ?JaP*!%d;D+~U-!5l0N#(JvDwLe9`DCs z7-k~Z!|f{a8WMo=3Nsw!87so+)2Cy8zkK;}KNR6b5Bng9B(*vn#XrFaUTz)->~N^i z6<{Ua1yug!AkRnC@%Iq11yTH)5#zYaR`qh%W@(dM*OszB;_TA zhY*LvPFt@6-yu2cFwa4Tkws`~YKlort*WZ>+9H@8ZVbnLNEUyRlbmPqfBUYDNytMH zPL)1@ezx*Zj7FZU@k9|SD=TAu9|#0gQ&W?dits&`?HmJqA7@|SGLrY{3B0;IaSkX4 zzK;F-LLWdp>Ft;wRbNB0l#)hUTN@`%oS>|%Y=BBiN~o@`_JTc#fAqXznIN*~Zw7vd zea6vVBuC>VH?-~nWI>+r25 zgKtb1Ay>wA8hRS|3eHF4lhCjV6DLko7cN}zOcB!S>x4Hoc69X=%`C91l*TD7#asLsw#ZR+UgPz?ENamZnb&fUm>Gc`MWK}3Qc71$M~<*B;BG)nEK92C zufRe^;HWs0F$UR29w7At<|SQ1UW0p&cU^Vs-~l95n+|?}TRMsa*AiU^$iV>PklcoS zr1yi|{nU=c03IYm0zny3$sy=}qQC#!4C!EMJBfX&zX?%@j6o(U!ca^>zT5B!@*dMj zMB-=$f4pNavj6WH0lB^*8x&zMEF>H1A!0w}GadKI8|~cujL%8r7`+~eX=DwuO%W0y zfLs8X#LW+SCHlBm|GyFBd?f3>-;_fRIpmN-4msqYi~j?Rb`s~DPNM(-0000KLIgSs_g# zMl)qUD77D?%rrKM(+{(;EG^3!gGkbff@GLzC>$$FQkn@Qt6{)UpH4H)q<}E=dWC?f z$m9Ls(;w^J-sSM_*?XUR?mhRtxu2Q)*WG8WwfA0U|6F??sYQQ_7A;z|Xwl+WT+s#; z1>hu&lr%Chot8d zzunF`>Yt0oGAtYc7$xbQlCCWME>ZpRwpY>yN$Vx8ch2polb(h$Bpm^0lU4RiS;bG6 zHSm)tyoI6siNntd# zBa{YoGbGKIIl=M8S`^JTNk5jf!a29EXk*f7N=E=rk~CM+O_DAw*ql7*mb6;Z66f6C ziZ*62n#vJ?x5z60lafXkY)-w{Drt$N2c2`T6>UtJ!X1ABI8M?WNuQUE{A2l#q*Ek~ z$kVO}{wo`=oDliken~4NEq2cB&fTg=3Uvfvrlf_k89*opB>hn~AnTI!po*I@lzB+f za@ipEDoJmRc(z;8Vo3{}a|h~RTk`@;2L3=CTYwu%YX$;N26jZss3-F)@^>+?1b8Ll z`4@pN07ZX0b^QU(1bzk_2`rpLz;a+}Le6o(!x4p?q#sxhe6LjaUoYv|U4zUXU|Pb? zlYpCmzemW~4txyjGKUw~+q)3x4lIo4fG+~4RFU`Ph=NVB9GFl=ZX57EvOB~Jz{!Ki zb-)Z@HP9O!z$6AV5dV!k*?H&(o&Y%Nep+|N* z@D1QVpuArJZ;mbdrU5vO@aDS%cn`LKvstOzPA0vn~r3^eag=wFmU|8+U!dj$3(9roy2OO1{fYgm69 z{wZ8Hw&;^f`~Yx%hDzv4$e0!R{MN+t^D@}5GLQV1^k0O%SZTa~?cmlIU^F&`N#mb+ z8v}eeLnS`TaLzp} z={qS&Zk4nSs5XYkgQ4mOMDbZ^B@htqn!s`bx73lI9vW6VH3T$~bmQ;U7z;+@lSrTAJ ztRws~$1-rhb@)Tvend`7`yoc10c`RZv@j4G)yk_5-H}q>pt3Z|tH+pTk1= z_IdPd17Z#d9Hcp__FOS(=6ejlJ`4bU7{ z1OVsZAHYz`She}CPsbSid-9d|9ASAPeUHyJ;vC_wjQMN>J`KF&kzbdAdCg$q-`~bI zTGHso7NL$g2oj*fH)X1%sv}@;+b%5BtMYe`M}Mdz^ibsxO^Sc)a=hX*0rES5DKYXJ z4i@#>5s;aEL`E`W&3Wiap*wQUR~zBc%-(J$A^Q^SaF353;0|gG`)e3j@a3I^9p2bU z+}Vbuft9f;=R92ysP`~|8*$iH@~S|&TY-!7%u~a_P6hk+%*zCwb^^{K%)vT=F*)WX z^t|N{17wZEW?X+EW1hpnS83GRK)t}it8T$R1uD~l&4;U2B5-%0tYzd7-3weuSU7tZ zDN|)^IeU4aEU?Jw3u?8$sUZGD^Z_h{{g{HloNHsCoDINqB9~mT!P`Xa*nG&rnttHj zgUA_$olM#iXfME%*d-#v7p!StN!&5A$FTE>BP!&ybL@YywKV#HS0jF*4qN8-L_W{O zW=DG?Wb9zL-i=TVvfY}}iA_=s`p5`Ud7#`^rS2{@?DZ*!_p2)`ho2Jq-s&g4WV#HkgPwJbeZgGy=xSI zLz!ejAdP=+QnTv(hwO^IpEt_|T20{ym0;V~^CW#%(%HpYlPi6a*2o;-@n*Z>z3CjG z3>F7DTh>avS50iIhfYaLB|YGr>nz%sY7B|O1n+$G zFGIo+Dgh>H;JXYnl^$;2D3D#PTmFv2CgvIZPuhNP(LcxvD| z4Sc8JPtAV&x{o342uZM=%(u%N;(QH!!pD2kCxt!@e9~u|q^BiqaL!dbP%k7RCt{2oqdp%RUOB_XTc2?+yu;)SOQEbg|T;3E| z_U_B4KhC}E-rc?TIp^Nz?sJ#9pPA>6ojvDwe&?LuJaXy=7{vjiUDH?K$)aVWIO(RNhd|CQJ)~`Rav9hAZe2^rZZZV z+{kM~h)?KdOIjpr1cRg1$eTAL{YKI%W6Zv&l}Sfl8Uj!%X@R6`Bu$D~oiI2m>0wDL zjWG>TE7KQwWeC8hWjp_?l7>aBPOjK0X{Dq`j4?-|RwjQzgB=zWalfzp857mS|#Z&W6ZmuYvoC#h5%e3>2}!_fGY{U|J73MZgmtjoga^2M(}){d%gat68yP1>3f5 zqoboE8<8*48q0 z>Qst~ijZCRAA3fQ9LfCo^Lgi;cQO_KCNQE8eGPvw8+aIKbCk6eI6t>N(@(@3;LF%y z&xLwmE@^%Zz-a79;YBPKW6`2Ty*j_Ir>v}uEnBwu7LnlgfHo-ueheIRl=nyAqoH+5 ze*=6B_u>0h;B(jwq#(I>`SlAlH#ak9&KxHrNIb>G#XR`ngT6%p90pEtsK?3iy2Ko0 z?gf9of2w9R=PGs6-oZ2Pr0j0rH1p zhh1md+S-^jX;MeW8QCb&L>IvU_2+*TQN% zC;?VEDE=}qIg4^G^6iP5nwq2z9X)z9EiJ)smV58LHz{9vc{zs1YS8C8~V~;4*@D&Rzu03aPx;eR`p@vomP|IBL|Ww6BDoEMLAn z$q<$;Tjo=If-6F(_X*e^Qfok2>&So7@O%{;MDP;sD0b5)6#oI>bl)D>y?b|3M^;u= zdgX6uXh_OmRaNDy0>E#>sDHc-&cgn%((xwt1lJp{;RNdx`naSeX_D=b^jTxfGGk18 zCQ9|e*}fUJZ{MEu_ZerL;g!E<`kwL}`BWyE`ob9VZ%OCM9@3>^oTTS~3w?j(JO5&_ zGt_mGrl(2vsHCfmG4J~-5FLz&O=)SVX3m_cy?ggck~%s%1jrb# zRhzfo>4^WZt_A)fX|?)x*E>o^>I?I(Q#BS65eioh`UL z?d|QpYCwjQH;=Y4zz@=t9|J}O$#I!1rdyJ%=_fa7wLgY5sQ`u#6nN2fMK+$MSPYPIZruIM2(j82aJ`NsU2r0u8|!^Ms^dq)D<=(gq;a z93l(`sv&erdM{VPfv?FLL8{mDTap&I1ot`(TgI4b*&vftQ9E-by#i$7h3rC348a(q zY15|Zq?2+MH1%FCBCLObA;5jIOUR)qlD#BphB0P`i%jSDmoa9gq>Ck`^2Hw`=^5br zgujf;i6N|AyH*Vi4Qgy`)QlN3a#2L+dIO)3v_;Z4(kN$1JN z67 zVvITLBj0;QYmC_{X_~B6rs85r+kwkN8XdMvdOHL;$7pJ5(ym=y5$zi{ZVXd=g1Rt- zU;}_3m-Gior74oNO8SeY}YZsdWUk>0{L-80B{=cii6VYfmG|=pfZLN zd?tU4AVa9FtxZZFi^Ui>Zd{m#aC3(B90Xhi90-u#Mu>kC^H6rZj4`iEnjyQVoo>1G z1xf$GZbJ161PLhPknD0PYsQQjqq%eEYWMEl$DZcqW-VN}FbwgM-QRz}Cj)VRMcK*V z{gOVMCiynmqy9Vd_C6DgxIV1s*t zhygz$OSgZ&ego@#c@u8I8*kwk+fd`u6AwM~P^gA*=9y=@6bttC<#Z5-JxX5VD0eI1 z?VytvV55SA&dd`yMLPlGa4@jO#zuw>8y1=&EM2F%|6G5d=dwB0G)rY{5KApK0LFz4z{GHR zB2U0SBKjcKg}qlpV2x{|i;(*IdS=a`%s+wz!-!Nw3J!d#R(NLoF>W&Uy|W zJXn82hImEf-C&IQS>g}unZQCx-%xs=j_$lE>3Z4wl?KGMd|5+gx27}!w*b?z>+RWC zzrd(@5_@^aDcDOcHhAXWOT@ROL>@>9R7(1}?D>Tc2V_Tz_at4Z=oxj{KX!&jQw|G?L2E)8T2ip98O=g%H}suG!0R1fyr2pGwZD)uhQ510&?{PNCeP-Ro) zlFHM?{tQurRDKoU|2{n>Xe20hP@{BE&7du3vid>Gbvf0N6(l*7{N(h+frGZ*y8Tej zMVEti(0o0BuCxq;BdGAdWW=k-wXsnJgKR(mrk5PJIX?qdh)#*ID3g0>?;WhhTd0r! z9dq5HeeyE-DH$)pygU1}Z)wEAiox?g zt@x-T*pyk@Nz(aLvxQ#2)ffa6Ij5*`Lw+v7WO}lkOS_Gy$~N5-eGb|eyc3G-%`-I;!+hIwtG zo##kIuHLxCiFc|5u2Xq^e!S0;{D(0x2oyCM-9-@Cfz;e)#h0dbCw*~kv`@7~=0k`b z(Z^;yd)ZY%(taNC4s)3gKB>~z2mp<1shj$JiI_1jK|he( z9H!3EHhAl0THFwfZ12(;w=hk-X~q+mvTo(=)*_s3B~}0~7$L8I#t|WAJdQuoQv>B9 zR-b;-LMbpFac%`7h03EAe)QxK7qx8;|LdABO5~gPkg98N#RxUdG7DP!1#qgTB0JTk2h0>ygQP4;?}XZ~e*YrQlR#y>=y09XQv7wm8U6J~KBE)rMe))%}RIRUOqS;R60F&}3 zX?swF7-MX)RmcU2s0a|FoXx1#1md++x?Ne>1axF->hl;QMy118Uh>ClS&<~ei!bzU z*~&UoY4FDP?Cu`~2Hr7{nO`?l5P+P#p^s6g(11V+-`_uA=6L(|vCf`NxUwD})hXqr zesgtwKx}~X>w#$Yn3pJ-%f-9?j|q9)j7J9lYu*4fj?s(;OsP5yT(?N~Hak>b)najk zY5wUURQ(@DauNlt%C8?i$f^r`g^AIox~^MZorjy2gmuf;glWNcI-cL0PE^Je4mY@9 zt4F`h>;{z7oQf?loeV{92iY6r3QcqzE*qhm`Q(_s_erZ#Y~CzKPpqx3hvL6ZcG7)r*yD?u(;#FhBlDF4S|S48T5J3lbH9E4U}!wL4kpd^X*#$Dxo0R$8^cp z0|I}HeVchqZp&68fQ$HuZl@iCPHP-IN4itb*z` z@-}2Zl;}&rWq)OZepWw1{FHtRXMdY|{l9EWB?R&W(nsoWoGR{hLM zy=1zmg((ZtT1tOl#BP5G+4bSiO$oy6f)lD)!0pJ=c~pME&Qo`nKOo6jFCb zpBE0QalL)}o5B|wWPVu&@G9ACAlQY)$7I^Bm7_5et|mG#GQZ4O$Q9pX zS6jVIpq*$WvJNj{DGnQgFr=v|oYCbjD2WsaZ@3dbQU-HtPgEXi4I0NI^G$_UD_IH$ z2Q$bCO!?zAd4ABQd8yKu?t>qg`WK?)pAXA#eKw`4vm)WM0J|G}aoM)-q|vOpy-oV6 zIX`p*EEV#`Ye*%8X>dsL(R;H#eve4yA64BNm-kK}^&7@6#n$-;54Fbsmn{%X_Gd9G zq0+JkeCBpCIwu?Mv|ErIODgLz1<3K4>;X8c0Kvu=S5ZeXNL)BfJcoQkv^?ycN+&Px zqqzM}qBY<=x*4rgDrZ};*F^~roD@U&qEj%H#b+)Q@Q!$U zrnuH|IVU@AY}o_(O*;^+il6xnak2Ql!|zf_=u1ku^PX#S>Ph$|TzMGPk*!(=5~bjX z^1q2IUjb=2j#P*;#^ylWYdWsYfDr97aG!pRXX4SSBuij7b?DoRaZFS>=+v(6jw7HV zy9_Pcc$Y~!2K(juqXgyZ^7ieeg?Ay8oh!Q#v5!y`P<}OJ*aCrK4-krcFVnfIWTKLc zYxEv5yi@;h>ix_Z>)Ck$fHhV)ooFNK3ZFtH(5>3^i{gY%(DcBy>H3u(4;O(=`x)Cs z1xg5vn>YA7D$FgyFii3isU{o)RF`*_#97|(V4WPFKMhY5MzV4Pl@SNa**e#%py-2a zO_2;4+2IOghe-|53shhdv1iK=ah)+XN#19Zo~+a-bi&PUVLXEYTiky)^Xr=z$i1`l zMVVZ?^7=s&#d%4FZ_(d$8ac4^J9BcV7NwM<%^m&)tf3{YRmxl}dk8=%Ucq`ux>4nx zJdo#tUzx&$XGgvXVZqXe3CF_I=%O~9Qqy%|H!9|wrwmhUk$kbXDNb$rntnc9roq+? z2d(#oNdeq9s9rP~M%55mr-rTWZC@0e}|ycL~v)6JiUGhTYgo16NY z$?b!4FiaoTW(6Uzro&NdTG#O zvvD{9en|(Koi#BGi*o)!1@-ArPf1k-!w)C3`b2%KsXpns`q}MttUP$E{5)YNr2da< z-$=XgIy^rir3#fsze#=zk!F?Wd#i zW^<^r2X50si}vJS&ZA0FxHrC>-|2omUF-|v_RlaA-B0dE=F92|?t$ukRNZ>++n>}O z7+mk@#rBm&f`*fN$%&E&;tIC74>A9#dG2q0WK} zA%QoVRobX#Za+<2`3bL|xqf+`E~+~ELBm~AB2LY9@UbY#%Pt9KU>z z#B4!|;5$-$A}|Tol?iszUoVQIv1|YF0jM#I8hg)fo@L}ogNCWq(JDd)dACjWWKB!; zc9?Ak25%uvFHY#1c8%r$6gEN-`X*@G)Pp;cu{7!MMcvTuzi#_9+wZ&2NA_ilUlX<& zzTNvSFg27}^pBHDjiM_8Xwj?&1cx7c&$MBYM4{-B5Kn62p``k~>N0)2$bc6f5Z#v| z`wuUHT)HKgeT~Z86%Q)&J(R{}V7@m4gRzRO*QQ@{315o~hP^|JY;k)ecFJzMTNY_O zdLZ4&J=|?T>hAWnWZWrn>kpGT{V;#Y*iZHbI4Gr;XeyC?72oeiyG_$9Z0DSc`1PtH z4*pHYaK8u{sGzOc5XnJ1a;xebc*fHtIGAu-Ald^X>Bj6=Gl}wK#SO{!TXf-U_M8@F ze#;o{!~3?TWz1s=zWfybhnAcW+iSjtF@@?xK-^=(v*7tnDj1~3EG{`* z&Arm9tuJ+-{X6p!*Lk+~9H<7~PIiIiSU_f|4rhd*ffDGh|CFE1t)BuwI(^=KuZiXG zbVDD_{M{Gx7ik7T(fJ|?(`}-wwRbZTeHBhg{NKS>(QVo^FC1o0H2$`MZ?Y!b zDho)xv%}JU7y)5mH1xdg!pZepG~1uMUif*A!I+PD$(&P$h2tE3c^2lcr~Ed5=^(q< zpGX}a?^~Cj21((jxpE-DNY8$u1ap_uL%tO42l%vJ^3y){KW`Bq!H3hc>w!JKTy-Ux zmLt&RIJ{xYji!zOL<=)RZ8wK9J+@lX4d!Q2TWp8ged3X+T4-)QcQ=BLb=z|OdZG-p zgiW8GEOd`DG(DdA_3}^&O-8U zWnWFik-Mg}9@!(3w)HS8dm0|9=NT43;%+*8Uv7g+pGCHh+C|C_q)~J#T_e0h=Me1i z>@~`xF|R^RLjCag8jJ_Nf8z`3?{LXo4=pS5RhLitQdSCfRQj%d($CojCsoi?vz~Wp zth7+O8Zenb@ks#Zk=ZcxVEjgiSTxL99w9ha}1%s>LU@7#$>%A!4 zP?4c9zWCAFDiM1X;SASJu0>~MHzJR;hm12qs|{l(`u{h<0DN{K^j#j7pDQ}{ zIBC%cf_n1442>5#u^|?5Ru@h6D`0uuJd%1{Smi%;*w;abn_2K;+J?Nk`;itJj)>CQ7h5JlnmT-5hn9|p&bR5!%GKR? zLUnYx)QL0`K6oKwu;=yk^_|>Tlem7Y`?nd)Vs-wR94q3w(qnOSO-7+IKbf`O4~goZQ02*K;77&-C45d zstokV=^*6e@@LU(D&@Q}$r`frV}}N=4Z@7E?iqiUTUArb!5^va<1A;aujDNN z{S+}Tgu$r}cxJk?M@GO!5zQ=P;iGnCkzil6Rev>q1}y*z9skdANhldKEI? zAf|@y@5dJy%dkr=`J87vL(xiWHM2mt0d$q91mS++Fcn|UeHi>kFSEm$lh;J1Cgp-* zdw=dSZ1JojnKVm{4Rh8kIlA}ldo@9Y#f%$PGM3{cS<-)iX+3}GwZz{11{TF=DQ}+k z`ksaauPP_WC))_~VujP?kQosObGv2;ns+ef)t-VS~WyaW^Fgywob;KDff*! zITkn0C;VHPXeA2?G+YmisxQ6uPE&Wx-07#&V>UOl6(B!0T?*MDf*Ue~z3d$sFN!nE z-W$hW*<$F^ThPD3mSy|n4gd#V?A1MHoGm51A(@y}^=dd8h=$!PCQ7HXw+K*bTg+J3 zx0a6&V2u%j2MBA0Vkv%uouAI5eEs8p6aVYvMv#Ag+#k|0SL)J7_o<5gBz+(r!;Q!t zk}a56%+bI5D1U8xvn6;KimO!IVMIELU!`T=*n50|u81&%QT%iYTvP=)6!SiMTRNRt z1czVYp~&)}e(3y%$-c>wPNK8PLewEbmJeD_IKKRJxFzYhKUYm}^?=We$5@Ldsmrk= zdQm*G_nBBC4Q?n5na>ncDKRA6&Wxz;u;8Fg3-v@B;cGB6p$9sS%vE<#3W86(k4UvB z%x8kK`7u^yHUkKNJf9vpAC;D!&w>ry<;4~uK8Jdy8Q;XLerj7nCmr3}Y$`Lcx<|sh zDhZ81HB11fV{Y=f8Bc-DHJLhfEa!ko#=q26$JO8(rm2hwA>8=7Qo5hqp^of(6{BXF5G5sGTZKs73=5d zd>DU=y6SSxXb@f@Lp<=g|2h&k6eqzf6|a^>tTX6Jl7KkM=n)(cxt`hLj?{Lx#kB;L z_g#SGPFZ{CTB0;MfqUHuLT`xi>4sJqQu<7IQ5(#kbnMbJv^|>HEg*&fYN`w-_u&>B%uP1??av6Zx;2 z%Q~68xe>zOv_4NQ@(*N~9$QR6$Dsjfj~8UwqYxeU=O-I}Swry{6 z*e)`eP~P=I`LDA9{oj={X-YH0Ut;?YUpn1#8~*thjz$6P}ONq1~LZr zg!5{|GXJF`B!o2#l%Qc(p>3fBQo$Kp*>x9f^GnnH_L~xM!U%8Clb`#8kgH$SDAkP& zW2|__=+yabAw5SFi`M&nTUiRmy0D(ECtF|`a29P5EC5U0xL3cy2qP|(hJAQo&D(iR z8?*3GY8$l@wXmHc4Z-fS90&rCnpBx6Nyb>+tmrW>1Kl?(f(&Q38XOi2D&0>5*yXj+ zxqdZvn7a)guD+E<_fsRZGt+bKqnbO`O(B7L_DYKXG#O(PGj17n?VsNwOYuFka)e#P zo0|_Am<%GtDt$O;rOV|0r1iR(QG~3$LpI>^TerROGXlxZv1* zvO1R3GvP~Y&l*=W-oC(-^tR4qtjX(fj0EGQvOHmxbtW}+tL*VT<{gq@G^2hoUEBE=Zzo&SqG%PZ8 zyeS>nuuS-=2w$ulVYrp3h|G_yz52SjLYw=5+N5LxeyLRRM{7^{e<2@x?Qc4w6lPC! z0fVZ|jdlsz}fx%Isi~(q}EK3_ooO_J=D}{SvurP+K3Er+ZhhOBi>@R=oqT$8_&)v~_2 z&s%Xt6Xo_2=qdfRC%#hKVttCJU!|(4q=!|C)`>21yFlN0NDtpobc&QJRU2I6Blvcol(vFPu}m%bZ0qJBgQMNg7NYEIr5p^!J-y!=EiqS@LW1?h$&Ap z^?NN@a4AN;uJkvXPR^~Hq*%t&)2~QJdOT<2Y^Kn&CT_*&;KG*KE zap2x@a&@O|_#8jSjvX@h@ZwohEPbZx+v$o~^tmbT`387Vmvy@OuS3YrrgNj((*OUQ j8T`K^ga2=&;#YTA%sq|^&2s}P%7xG~(XG>V`R{)Ky8I*I delta 4538 zcmV;r5k>CzG}I=r#Q}d2c}YY;RCt{2op+d3#TCGRZB6!vf1LNey>I5+ z*Y?f3@9xg;`{rA?ZO*-S-kq7#20R{*$K&yMJRXn7 z0qT_FlE6&hjZ}FZn3v<)37`g8St?;Y@!)5`Ql!xoT2=#30%L)m%C$EEW&ulp;~d_D zrvjNtagE9>%Yi=vje%?59N51MSi||<#F(n61t>8eg=}A;l+{_TQwtoEy53nxR~kIN z4%n`}!g}IEAK-stU;=P7uszTt9#iIkpLGZc7??BlS7biAR2r%dcg_AYW*bfQ%@)lmyj!BhkNfa%B=Y)$2u zw}7eT6v`8S{zPuI#2t}I=ZP)N(jE}giZI8YBfjNKUC12!z; zdI`jl&%EBpWV$PRIxt~lqbGn~?Y#ClY^T4sfZl)YysoFhSr7RtXw7AUVZdkDjp|BDuYWpHspm;V`ReIF>xDmT?U4w62u_OUpfc-+h0=6l$ELDi9 z$CQ6%e3|9&w3BKi++EWtZ4i-6HNYc=JgvZ}h~)7UNFDGXcB7gK^o>w15ZV4krd-Xy zpe*O~1I|XwPW$4$CnBLY@FI4jdW!I{`Et_-I}ypN=xT@&NY`y1TkfvBQ!@bZDK{I{ zT~wYM%huSl)QQG1`ylC$%=<|j$j6mS*v@~|Wf~GuT`Ej% z{!F}PK7$^>v)C`0 zceoEXn({-Hy8Iv>8HB!#{ct7_zfbx$$oR>;muqoj7$1Y}g8i|hx?)8Wx(2!sy-uaD zH+GlQio1xQ!?7FHEPQxBn*g)18`a5C3RNUWVw;;*Ai678^|c!HO((loYNud0Fqg~+ zvzp?Rg;5d~yfGiqvb*3orM`cU5U0mZ&6e0^jg`3jb-SVlxE1>)&%#~u+g~a5O~cOu z8G`+#T1NcbUV0!dE9Oi7FESZ%fu_BG7oXLJChRfQV&Hob%2W*fkOpMFQtEr1(rfQyM=!+UZqEKjM=4YhjK&V#YC)#`E~rKl?3#`074&86 zIu+f~?PX)56sibL#?~1vK@_4c=!OJJn9uDcd{$;^kw|3o;pCH%xKgM>%u41xe2KfL zt|+?h-o(8I#+#b*QrWKeECoQorss4)7V z=Yn_%affliAm9U~&YOszcZV~^lKF5xAU+1=Cg6SS7koeBxaWe+(4(E35mU_!M5#Or zxSUSxx$pxrAJ7BQijz0PfjQVO_`KWqP=mfu(v~-;zH~PbwZ>P!5YZd)0E5Ql5o|)%}Sl`A$b=}SE6*+ zcq#B5WBYZEWQ>Gj2e9cp1Hq*It-$`kW9=2H2pUuMn!%z^A@;yU4(hB$Ok1Y5ejzfZ z(i-zOh+VK58Jq4O*!Lm&Vp9bE-8J?1)>Pdcl3GN$7<_*SixE%Kaxw(FTS<~%mX~7b ziTF(wI`b=4SqW_H=-w)V21L;pyy@AL&!u)pBx#2E;4i|RI-xJRLtwc}+~NodW+?Lc z58m{Lz(B|K9)dl6UyZCv?~1{Q);#J)l?2Xkc%K!+ZrJ*pnYc6To`~)8vJ^?m?~2Wl zq;Td7HiLh1k43)Z1CXyn#pKOiqK5Naqbw_mQisJ=5X6RuqS0 zzwFtRb}Uc@T#fyZ=K|Z7upX10up^LKk&J}T8QZ@Fb}6!+Iz;WDrSCR#aQ(K(I%3Hf z?1wUk(&&(CfqSqY_=mV%Q)fTKkKcUBX>Zxy*e-wC3n=`acSnyNPXf;%O4i`EtBbv% za^PZsdkAnhnKQCxB;EEKMP9Qv;tOVK&R;=Zd~=c4&BZt*e|yka{Vg)x|B$wq+#9h! z20cONBPK9&{Arf%z>koxqRA5AZ@}|NS9(og-;?Nh{5^YP8JnQ5gi-GcC!Tc_e922*^bFpc0f!- zVSeY$cKy+i6fxr`rTxN;G zLRUqxIrht2g}C8>e4We{w33J}Y?wp24np_%JOjz05Zv|%;chUWARepbA^{wM7`A^+ zS(YK=(BQW7$|zge*#!8U%o|RdVIISNKyTu9Q2{Mzbp>sWy_d1?;nem6l>11R+YvL@ zP+%iq!&KP-(X0HP~O#mz3*`#Ll?W5lU>=s@@;nCUyz# zel3kisvxt@DP*P(szSOn^SF;gu3L|oSj?ofaW3Y>svx2Yf;brQKsA+|XCQxL0T*nB ze1QfT+wVaJ!7BpWu0V|HCJREYy$qRkO+}V<3F94P+_;*;)e7eRfk?NtILo>N0G>U9&oaNkf`G{x}(=`x2 zvkjIpQ3+TKS~SaC+^(iNmh6A4$agc2HTMT~SMTSjt0_x8W|>HN7pF=fjip(Ur4=!1 z2e*waqipSBNAzFshS^SP2Vp6-&64&=*cZD2zDTB8VS0`_`{z+#uzZGF=fpJYqA!w_ zL=5~pAd9*Ow;xpoxk`eW$!;q0S$08J;12S8xeZ98H+`<<raYpZk}O z=>4Z5`|rZdvq&HfL{p-+AlZV_>i`{Q?2k>(v-`;u+*Km}-sr21Ekb^s=0n~M+dFh7 zZ2=*{EHz){sQXf--fL+aeD}cCh^Nau#3Qv-6RIKT$=;I4%y_tQyy-}IQi9QCYVO;mM!2U2V%+c60 z-6Z1O5k@U=8Q~L)XOOQ>zEmLt?ywvY|0cV;^j^mCXBAL)?>cg)>D~@~UC1Odc07gLj*+_= z=f%osU5%YzVKL(QPz+s=s21~Kt{^;J(KX8PNo2-11^H4;LR_Ek#!lK6d_h}ckJ*A> zuGjLsj|94zDP4cU#$SEW*Znb{Z$5z?-!smOQyNe}jJM|aq8Z78R|xAMjX-+|T3|vN zGsjn5|XLSeToGbE_y`mU` z{ZN)8U0ObDkLZBR2RaRLRmsLrl=BKHJ&{IjMnr#u_~?HJS7ObjPz{r3GBU}~#%)RT z+@?uH*?c78zqZKO_bl0SS&T4_pOA;_6^RyX(TXgw7Dghq-%MGVM3VF8lZd|yGHaTK zd?~*~)D6oCf04n`MCO1#iHxy!O#Ga;iM`G;EV_PU)PSFJNt6l@?I{IUeeV#Y|-%6%>Am|SC zS(ds+U@r;$F7`k@k-Gj&^hWh0;bW-Nl;gt`pSu{x#Xiz{L-a%&chhFa+Y)`@@;SI) zzV0@q-e5V-I6kOHn;UY?jj(@Ev&o)Fr54H8kdA*`nt{xyv;CkF*m}Db^e8DaD|UxS zI?{l+)S54CI&cfRuIEMEElwFEo0sSX%JFXm_G=2&M(os2^T|IXzY#c^wn;=Tx?v}D zn~!ayjjc&17xjoXKG%36-T%8vs%8>qf_W9ulbwWowZ5i%)rGjteU*y=WDoqvRq7G5jJds(cG7=BI9HM72y6>Rp$h8^Vj1ES0aZxYT0PRG zX{9#x_job`Y|lr296@eE^l?e2QtKp;8F$d+wGw!g%tHj&~Cf%>IOHAKmsQEATBjsa+I1pjtL%@ zKxT2vkuEFvSKAi$H~8;W$hc||x(hP4$K&yMJRXn7cM^2><{9 diff --git a/docs/assets/shuffle-black.png b/docs/assets/shuffle-black.png index eab510b346fc89f593828a4c94d427e9bcb4f34b..e2741868040749cba44fb337f69935bf1e02a1cc 100644 GIT binary patch delta 5308 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 GM*Ig;7aBkS delta 4408 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 Date: Thu, 21 Jul 2022 15:43:14 +0200 Subject: [PATCH 5/6] Applies a self review --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1989c5b08..8ddb83c2c 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ web-backend has a local database to store configuration data such as authorizations. Admins use the web-frontend to perform update. The following component diagrams summarizes the interaction between those -high-level components. +high-level components: [minogrpc]: https://github.com/dedis/dela/tree/master/mino/minogrpc @@ -163,7 +163,7 @@ ballot to getting the result of the election:
-**1) Create ballot** The voter get the shared public key and encrypts locally +**1) Create ballot** The voter gets the shared public key and encrypts locally its ballot. The shared public key can be retrieved on any node and is associated to a private key that is distributed among the nodes. This process is done on the client's browser using the web-frontend. @@ -177,7 +177,7 @@ the client's browser using the web-frontend. of the blockchain node. This operation is relayed by the web-backend which verifies that the voters has the right to vote. If successful, the encrypted ballot is stored on the blockchain. At this stage each encrypted ballot is -recorded with its user on the blockchain. +associated to its voter on the blockchain.
@@ -186,9 +186,9 @@ recorded with its user on the blockchain. **3) Shuffle ballots** Once the election is closed by an admin, ballots are shuffled to ensure privacy of voters. This operation is done by a threshold of -node that each perform their own shuffling. Each shuffling guaranty the -integrity of votes while re-encrypting and changing the order of votes. At this -stage encrypted ballots cannot ne linked back to their voters. +node that each perform their own shuffling. Each shuffling guaranties the +integrity of ballots while re-encrypting and changing the order of ballots. At +this stage encrypted ballots cannot ne linked back to their voters.
@@ -206,7 +206,7 @@ is stored on the blockchain. A smart contract is a piece of code that runs on a blockchain. It defines a set of operations that act on a global state (think of it as database) and can be triggered with transactions. What makes a smart contract special is that its -executions depends on a consensus among blockchain nodes and operations are +executions depends on a consensus among blockchain nodes where operations are successful only if a consensus is reached. Additionally, transactions and their results are permanently recorded and signed on an append-only ledger, making any operations on the blockchain transparent and permanent. @@ -214,24 +214,25 @@ operations on the blockchain transparent and permanent. In the D-Voting system a single D-Voting smart contract handles the elections. The smart contract ensures that elections follow a correct workflow to guarantees its desirable properties such as privacy. For example, the smart -contract won't allow ballots to be decrypted if they haven't been shuffled by a -threshold of nodes before. +contract won't allow ballots to be decrypted if they haven't been previously +shuffled by a threshold of nodes. ## Services Apart from executing smart contracts, blockchain nodes need additional side services to support an election. Side services can read from the global state -and send transactions. They are used to perform specific protocol executions not -directly related to blockchain protocols such as the distributed key generation -(DKG) and verifiable shuffling protocols. +and send transactions to write to it via the D-Voting smart contract. They are +used to perform specific protocol executions not directly related to blockchain +protocols such as the distributed key generation (DKG) and verifiable shuffling +protocols. ### DKG DKG stands for Distributed Key Generation. This service allows the creation of a -key-pair that is distributed among multiple participants. Data encrypted with -the key-pair can only be decrypted with the contribution of a threshold of -participants. This makes it convenient to distribute trust on encrypted data. -In the D-Voting project we use the Pedersen [[1]] version of DKG. +distributed key-pair among multiple participants. Data encrypted with the +key-pair can only be decrypted with the contribution of a threshold of +participants. This makes it convenient to distribute trust on encrypted data. In +the D-Voting project we use the Pedersen [[1]] version of DKG. The DKG service needs to be setup at the beginning of each new election - we want each election to have its own key-pair. Doing the setup requires two steps: @@ -257,8 +258,8 @@ an election is closed, an admin can trigger the shuffling steps from the nodes. During this phase, every node perform a shuffling on the current list of encrypted ballots and try to submit it to the D-Voting smart contract. The smart contract will accept only one shuffling step per block, and nodes repeat their -shuffling step with the latest shuffled list until their shuffling step has not -been accepted and a threshold of nodes has not been reached. +shuffling step with the latest shuffled list until their shuffling step has been +accepted or a threshold of nodes successfully submitted their shuffling steps. [2]: https://dl.acm.org/doi/10.1145/501983.502000 @@ -288,9 +289,9 @@ been accepted and a threshold of nodes has not been reached. β”‚ └── neff Implementation of the shuffle service └── web β”œβ”€β”€ backend - β”‚ └── src Source of the web backend + β”‚ └── src Sources of the web backend (express.js server) └── frontend - └── src Sources of the web frontend + └── src Sources of the web frontend (react app) From 14e301e111fc49ca2531687244156207f51c4dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9mien=20Kocher?= Date: Wed, 27 Jul 2022 16:13:54 +0200 Subject: [PATCH 6/6] Addresses Pierluca's comments --- README.md | 109 +++++++++++++++--------------- docs/assets/component-global.puml | 4 +- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 8ddb83c2c..88dad8ce3 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ protocols that guarantee privacy of votes and a fully decentralized process. This project was born in early 2021 and has been iteratively implemented by EPFL students under the supervision of DEDIS members. -⚠️ This project is still under developpment and should not be used for real +⚠️ This project is still under development and should not be used for real elections. Main properties of the system are the following: @@ -76,7 +76,7 @@ Main properties of the system are the following:
-**No single point of failure** The system is supported by a decentralized +**No single point of failure** - The system is supported by a decentralized network of blockchain nodes, making no single party able to break the system without compromising a Byzantine threshold of nodes. Additionally, side-protocols always distribute trust among nodes: The distributed key @@ -90,18 +90,18 @@ make use of a central authority, but can accommodate to other solutions.
-**Privacy** Ballots are cast on the client side using a safely-held distributed -key-pair. The private key cannot not be revealed without coercing a threshold of -nodes, and voters can retrieve the public key on any node. Ballots are decrypted -only once a cryptographic process ensured that cast ballots cannot be linked to -the original voter. +**Privacy** - Ballots are cast on the client side using a safely-held +distributed key-pair. The private key cannot not be revealed without coercing a +threshold of nodes, and voters can retrieve the public key on any node. Ballots +are decrypted only once a cryptographic process ensured that cast ballots cannot +be linked to the original voter.
-**Transparency/Verifiability/Auditability** The whole election process is +**Transparency/Verifiability/Auditability** - The whole election process is recorded on the blockchain and signed by a threshold of blockchain nodes. Anyone can read and verify the log of events stored on the blockchain. Malicious behavior can be detected, voters can check that ballots are cast as intended, @@ -111,32 +111,32 @@ and auditors can witness the election process. The project has 4 main high-level components: -**Blockchain node** A blockchain node is the wide definition of the program that -runs on a host and participate in the election logic. The blockchain node is -built on top of Dela with an additional d-voting smart contract, proxy, and two -services: DKG and verifiable Shuffling. The blockchain node is more accurately a -subsystem, as it wraps many other components. Blockchain nodes communicate -through gRPC with the [minogrpc][minogrpc] network overlay. We sometimes refer -to the blockchain node simply as a "node". +**Proxy** - A proxy offers the mean for an external actor such as a website to +interact with a blockchain node. It is a component of the blockchain node that +exposes HTTP endpoints for external entities to send commands to the node. The +proxy is notably used by the web clients to use the election system. -**Proxy** A proxy enables external interactions on a blockchain node. It is a -component of the blockchain node that exposes HTTP endpoints for external -entities to send commands to the node. The proxy is notably used by the web -clients to use the election system. - -**Web frontend** The web frontend is a web app built with React. It offers a +**Web frontend** - The web frontend is a web app built with React. It offers a view for end-users to use the D-Voting system. The app is meant to be used by voters and admins. Admins can perform administrative tasks such as creating an election, closing it, or revealing the results. Depending on the task, the web frontend will directly send HTTP requests to the proxy of a blockchain node, or to the web-backend. -**Web backend** The web backend handles authentication and authorization. Some +**Web backend** - The web backend handles authentication and authorization. Some requests that need specific authorization are relayed from the web-frontend to the web-backend. The web backend checks the requests and signs messages before relaying them to the blockchain node, which trusts the web-backend. The web-backend has a local database to store configuration data such as -authorizations. Admins use the web-frontend to perform update. +authorizations. Admins use the web-frontend to perform updates. + +**Blockchain node** - A blockchain node is the wide definition of the program +that runs on a host and participate in the election logic. The blockchain node +is built on top of Dela with an additional d-voting smart contract, proxy, and +two services: DKG and verifiable Shuffling. The blockchain node is more +accurately a subsystem, as it wraps many other components. Blockchain nodes +communicate through gRPC with the [minogrpc][minogrpc] network overlay. We +sometimes refer to the blockchain node simply as a "node". The following component diagrams summarizes the interaction between those high-level components: @@ -150,13 +150,9 @@ website](https://dedis.github.io/d-voting/#/). ## Workflow -An election follows a specific workflow to ensure privacy of votes. You can -find more about it in the -[documentation](https://dedis.github.io/d-voting/#/api?id=signed-requests), but -here is a high-level recap. - -Once an election is created and open, there are 4 main steps from the cast of a -ballot to getting the result of the election: +An election follows a specific workflow to ensure privacy of votes. Once an +election is created and open, there are 4 main steps from the cast of a ballot +to getting the result of the election:
@@ -188,7 +184,7 @@ associated to its voter on the blockchain. shuffled to ensure privacy of voters. This operation is done by a threshold of node that each perform their own shuffling. Each shuffling guaranties the integrity of ballots while re-encrypting and changing the order of ballots. At -this stage encrypted ballots cannot ne linked back to their voters. +this stage encrypted ballots cannot be linked back to their voters.
@@ -201,6 +197,9 @@ executed. The decryption is done by a threshold of nodes that must each provide a contribution to achieve the decryption. Once done, the result of the election is stored on the blockchain. +For a more formal and in-depth overview of the workflow, see the +[documentation](https://dedis.github.io/d-voting/#/api?id=signed-requests) + ## Smart contract A smart contract is a piece of code that runs on a blockchain. It defines a set @@ -226,40 +225,42 @@ used to perform specific protocol executions not directly related to blockchain protocols such as the distributed key generation (DKG) and verifiable shuffling protocols. -### DKG +### Distributed Key Generation (DKG) -DKG stands for Distributed Key Generation. This service allows the creation of a -distributed key-pair among multiple participants. Data encrypted with the -key-pair can only be decrypted with the contribution of a threshold of -participants. This makes it convenient to distribute trust on encrypted data. In -the D-Voting project we use the Pedersen [[1]] version of DKG. +The DKG service allows the creation of a distributed key-pair among multiple +participants. Data encrypted with the key-pair can only be decrypted with the +contribution of a threshold of participants. This makes it convenient to +distribute trust on encrypted data. In the D-Voting project we use the Pedersen +[[1]] version of DKG. -The DKG service needs to be setup at the beginning of each new election - we -want each election to have its own key-pair. Doing the setup requires two steps: -1\) Initialization and 2\) Setup. The initialization creates a new RPC for nodes -to communicate and must be done on each node. The second step, setup, must be -executed on one of the node. The setup step starts the DKG protocol and -generates the key-pair. Once done, the D-Voting smart contract can be called to -open the election, which will retrieve the DKG public key and save it on the -smart contract. +The DKG service needs to be setup at the beginning of each new election, because +we want each election to have its own key-pair. Doing the setup requires two +steps: 1\) Initialization and 2\) Setup. The initialization creates new RPC +endpoints on each node, which they can use to communicate with each other. The +second step, the setup, must be executed on one of the node. The setup step +starts the DKG protocol and generates the key-pair. Once done, the D-Voting +smart contract can be called to open the election, which will retrieve the DKG +public key and save it on the smart contract. [1]: https://dl.acm.org/doi/10.5555/1754868.1754929 ### Verifiable shuffling -The shuffling service ensures that encrypted votes can not be linked to their -voters. Once the service is setup, each node can perform what we call a -"shuffling step". A shuffling step re-orders an array of elements such that +The shuffling service ensures that encrypted votes can not be linked to the user +who cast them. Once the service is setup, each node can perform what we call a +"shuffling step". A shuffling step re-orders an array of elements such that the integrity of the elements is guarantee (i.e no elements have been modified, added, or removed), but one can't trace how elements have been re-ordered. In D-Voting we use the Neff [[2]] implementation of verifiable shuffling. Once an election is closed, an admin can trigger the shuffling steps from the nodes. -During this phase, every node perform a shuffling on the current list of -encrypted ballots and try to submit it to the D-Voting smart contract. The smart -contract will accept only one shuffling step per block, and nodes repeat their -shuffling step with the latest shuffled list until their shuffling step has been -accepted or a threshold of nodes successfully submitted their shuffling steps. +During this phase, every node performs a shuffling on the current list of +encrypted ballots and tries to submit it to the D-Voting smart contract. The +smart contract will accept only one shuffling step per block in the blockchain. +Nodes re-try to shuffle the ballots, using the latest shuffled list in the +blockchain, until the result of their shuffling has been committed to the +blockchain or a threshold of nodes successfully submitted their own shuffling +results. [2]: https://dl.acm.org/doi/10.1145/501983.502000 @@ -292,8 +293,8 @@ accepted or a threshold of nodes successfully submitted their shuffling steps. β”‚ └── src Sources of the web backend (express.js server) └── frontend └── src Sources of the web frontend (react app) - + ## πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» Contributors diff --git a/docs/assets/component-global.puml b/docs/assets/component-global.puml index e1ead90e9..89f5592d2 100644 --- a/docs/assets/component-global.puml +++ b/docs/assets/component-global.puml @@ -30,8 +30,8 @@ wb -> teq: authenticate wf ~down~ iproxy2 wb ~down~ iproxy2 -interface TPC as inode -interface TPC as inode2 +interface gRPC as inode +interface gRPC as inode2 bc -- inode bc2 -- inode2