<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/132666>132666</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [AVX-512] Consider that summing every odd element of an array can be done without gathers/perms
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Validark
      </td>
    </tr>
</table>

<pre>
    In my real code, I have a bunch of slices (each is a `struct { ptr, len }`) and I want to sum together the `len` values to determine the total size. [Zig Godbolt](https://zig.godbo.lt/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXAGx8BBAKoBnTAAUAHpwAMvAFYTStJg1AAvPMFJL6yAngGVG6AMKpaAVxYM9DgDJ4GmADl3ACNMYhAAZmkAB1QFQlsGZzcPPVj4mwFffyCWUPCoi0wrTIYhAiZiAmT3Ty4iksTyyoJswJCwyOkFCqqa1Pqelrbc/K6ASgtUV2Jkdg40Bh6Aah70ZYBSCIARZYABPBZYqogNgCYztfOz8a2AIQ2NAEFHp8xVY4JlqgZlhnc7gBPAiYBQASQYADE6KDqDCFCBNgBWO4AKg2SO2GIemMWK1cAA5SH93AB9Gj0BHLVzxYyYcbU2mYTYAdgez2WnOWeCoyyg/xY5PhmzOkmWES4DLAYC2uw0yxIJMFFNBmx2suWGgZrgYxEwTGQCCYwXo91eXOWADdKkrScFgaDETS8HS1XKzc9zVz%2BMQ%2BSqFNiNAA6IMCoWUjHbBkbFmOFWk9BMCoxxxei2csP2kEKEUPHbfGEJpNMIP0Bgel4crl6ggzX6Zh0BiLsl4srGe54/JVA7MQ6GUyFMHphOGUxHY9GYsRmBgQM5IyS3FGRvFfQnEsP%2Bp1M7VM1kti08vkQTfC85iiVSmX5%2BWK0%2BUt0arXU3X6w3G03NtNWm0N7OIvYADVMGsEgIAiM5iWdOlo3zPYFGiAwCAgLUKwtVcrRAqlsUjICQKIYhwMgxkXXpN19miAhiEcIdkP9QMQ3vUFI1uL8q05H0%2BUtLDo1jeNE2TWNvwtP9VXOPNdn44sK2/DD4iMehSWMFgWEfdj0zWIN4hYdAg3eKiDWQ0SFGJDRiQJaMzjuTZ1ItTTtN0/TiEMk8ySzUFzPMyyD3TTl7MORzVAM6xXMFdyTOWKQvNzYSuX8nS9KC5yQuM4kzgAFi8mT1LkvxgEUwEVLUp5fL8ghdIcxLguQ%2BT8swJSVNM4l0u82KyoqgKquSmq8sU5SWGa5rWJ8zlZIEFZasU1QitlNrVnKrTOqclzJvqwqBs1NLWtsuKFsq5aQtW0l1rSrbspK6tMFrYhfiO6aWGxLhIxkttXg4SZaE4JFeE8DgtFIVBOAALTMVZplmZlzglXgCE0d7JgAaxAJECSDLgAE50ZZSQWRZLgMckM4CSRfROHS3gWAkDQzN%2B/7AY4XgETM2G/ve0g4FgJA0COGEyAoCBueiXmQGMDQuHSsyKRBYgEQgYI4dIYI/EqQFOB4RXleIQEAHlgm0fC1d4bm2EEbWGFoVXWdILBglcYAaNoWgEW4XgsBYQw6oV/A9WsPBuOd/73hA1wQUN8hBGKBXaDwYJnK15wsAVqjDjD7jiGCOJMG2TB3YUvK4cmKgDGABRALwTAAHdteiRgw/4QQRDEdguBZGRBEUFR1Ct3R6gMIwRbMfQY4RSBJlQSjEmdgBabXlgAJWKfUlEHFYp96YAruWVQCUkUlJHSqfo/%2BVRlinlhkGiVxZWMBg0%2B%2BgG0%2BIPAsBHiBJksfDEnsBgnBcWovB/iMDo4R6jpASAIfodRSBgNKEAvInRBiL19gIZofQ/4DAaJ/FBvRWh%2BHaPAkBFgcGQL0EMKocCxiSimDMOYEgPpfR%2BgremyxTDAE1GjdKQZ5QQFwIQRUUNJQwwLpMBA%2BosDhDfqQJG6UuBBgJNTM4EEibyIiHjIkn0ODk1IJTLg1NSC014PTRmIBmbCNJhwM4FMqY0yYZwIRrNxiTDTvEOw6UgA%3D%3D)

```zig
export fn numBytesInFiles(files: [*][]const u8, num_files: usize) usize {
    if ((num_files & 31) != 0 or num_files == 0) unreachable; // make emit simpler
 var num_bytes: usize = 0;

    for (files[0..num_files]) |file_data|
 num_bytes += file_data.len;

    return num_bytes;
}
```

By default, this is what I get:

```asm
.LCPI0_1:
        .quad 32
.LCPI0_2:
        .byte   0
        .byte   1
        .byte   2
 .byte   3
        .byte   4
        .byte   5
        .byte   6
 .byte   7
numBytesInFiles:
        push    rbp
        mov     rbp, rsp
 vpmovsxbq       zmm1, qword ptr [rip + .LCPI0_2]
        vpbroadcastq zmm2, qword ptr [rip + .LCPI0_1]
        vpxor   xmm0, xmm0, xmm0
 vpxor   xmm3, xmm3, xmm3
        vpxor   xmm4, xmm4, xmm4
        vpxor xmm5, xmm5, xmm5
.LBB0_1:
        vpsllq  zmm6, zmm1, 4
        kxnorw k1, k0, k0
        vpxor   xmm7, xmm7, xmm7
        vpaddq  zmm1, zmm1, zmm2
        add     rsi, -32
        vpgatherqq      zmm7 {k1}, zmmword ptr [rdi + zmm6 + 8]
        kxnorw  k1, k0, k0
        vpaddq  zmm0, zmm7, zmm0
        vpxor   xmm7, xmm7, xmm7
        vpgatherqq      zmm7 {k1}, zmmword ptr [rdi + zmm6 + 136]
        kxnorw  k1, k0, k0
        vpaddq zmm3, zmm7, zmm3
        vpxor   xmm7, xmm7, xmm7
        vpgatherqq zmm7 {k1}, zmmword ptr [rdi + zmm6 + 264]
        kxnorw  k1, k0, k0
 vpaddq  zmm4, zmm7, zmm4
        vpxor   xmm7, xmm7, xmm7
 vpgatherqq      zmm7 {k1}, zmmword ptr [rdi + zmm6 + 392]
        vpaddq zmm5, zmm7, zmm5
        jne     .LBB0_1
        vpaddq  zmm0, zmm3, zmm0
 vpaddq  zmm0, zmm4, zmm0
        vpaddq  zmm0, zmm5, zmm0
 vextracti64x4   ymm1, zmm0, 1
        vpaddq  zmm0, zmm0, zmm1 ; why is this not a ymm operation?
        vextracti128    xmm1, ymm0, 1
        vpaddq xmm0, xmm0, xmm1
        vpshufd xmm1, xmm0, 238
        vpaddq  xmm0, xmm0, xmm1
        vmovq   rax, xmm0
        pop     rbp
 vzeroupper
        ret
```

There are a number of issues with this emit. There are serial dependency chains that could have been parallel and we are using `vpgatherqq` at a high cost for little benefit. On LLVM's Godbolt (I assume a newer version of LLVM) I got this emit: [LLVM Godbolt](https://llvm.godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1C1aANxakl9ZATwDKjdAGFUtAK4sGexwBk8DTAA5DwAjTGIQAHYATlIAB1QFQjsGF3dPPQSk2wE/AOCWMIiYy0xrHIYhAiZiAjSPLy5S8pSqmoI8oNDwqNiFatr6jKb%2B9s6Cot6ASktUN2Jkdg4AUgBmACEAagBZDDd6AEkAEU21k7AOYlRUAgvljQBBBTmFzAB9GnpmNlPVk%2BWAEwAq43QEA%2B4PAbATAETboJjVAwATzmsLOpyBmAAtCwQNi4gDIhoQKsASSAViCZEuOTyZTCWSAGySEDMrF4ZmsyTsrgAgAcEn5WKofOJvL5WIYAq4jNpbKE4rBEKhMM2BGIeDi9F%2B/yBqj5jLebLcDAA1gxUAB3BhY2j%2BNyqSQAOi40SdGhxbgUtCVjwhAAEQm46LYGE6AF54YBvEJMZCmxw6zb%2BAjhZi0TYm76YdBvJjodDETZoBijQTJ5mbAGkTZiKMMTZ8gOjWpOpIsLV4Gg5t60VDAPDIJMptNiTMMbO5/OF4sCMuwvBcTZUMRKGt14ANrgBoMh/xO1FxNwEN4sDCYYeCUcZrOsHvTosl%2BfJgGbLHV2t2zebbd%2Bv0bTYADETRsFJNkhdUFBATYLRNS1/HQTNLWqEJtQtBRDGScN3jQUxwiYaFNgUU1NTiK5PkwCEsBoAI4WeXtUFEDMOUkTZ/QYDx1iRVMFAOBhALoTAFAgOJ1U/etGxggQOJMDEAFYNBrFj5K4KYMVWDRTkidYITJCFNnk1YkzEPtRFOOT1j5TZVGTJs5KOdcvwbJtHgMwE5NY9ETMYphzMs6zbOWezHIklyHjcgE5Lk4yTB8vyrJsvA7Ic8TvzCgz%2BhIC9RKLdzFM2HL5LkkK0v0%2BTGWMhhEOU9ymk2VZf3C%2BTImHZAOxgi8asixkaw0MqQiLRdmprAwwgzWqes2UayhUyIIQhAUysy4hOsrfLCvc6RUucpaiBWitWPWsT3NWEqdtc%2BToiTPt8wK9Uaw2yLiu2xsytqzT0WhVN6DYQRCv8EI5iqhQtK2HKlMrZZIhSx65NiA7Nj6i7aqXdF/CUWpTDENwLyhsH7oRqGTgSPBngYB7jsirh8qRpratfNHS3CAgsfcXHtLushCehlS6q6uS6saiKBaM9FMFUdU4xZ7H2fxrmap5%2BmayFzYBqmpgxvkgFVnmx4pBAN6qei9E4gQPBk1Riy1WIHGawm8yUqCrZar5O2qZaoKjn6wbUaNkaNZm2r4em8bIoBWmIRlA2LrVkOVMkXWHi4SJo7pqmrLRtq4k2TAAEdCap3rvfVzXaoTv8k%2BiVODJNFa4wQDX6ET8Pq9Vos4/csLdJpQ25KBa7UFuliKdyyKto3c6mpWhdIbD8EK%2B11v3IBTy/imwfquZEfDLO17kbD4218Hdr9hnzyw622qdZjn2teejuw9dkvA8i1Y5Ob2Ve8JYyCxgtxLQLn3LaKtlqrXPn3SI28Tq73Sm3Z%2Boc%2B7XweLpRa%2B8%2B5XTFhLYgUtWY41BpzCGnlFZUw/LTYWGkkxfTKJgX6BB/oMEBiadAIM8YEO5jDSm6DCFa3LmnOSDUB63VYeDdhUDX75QnnvPhpJBGby2rDceTkpHkNFmvcWksbC4NlmwhWup%2BGC17qsVeJxpx/wAfzUkbt%2BFIIyntMBhl5GcMUaFYuD8%2B6MkTm/VuscA4IIBI1ImicETqjwEGHi6kPpr1YbBBg8EqpIRQmhRImFbDYTeLhfChFiKkXIoJDEAIqDYLYJSVAI5iBKj%2BGCEyYJ8kqgIFiZAR4KleyBOGBgeFiDv37mCOpwpMAInmEJZpSoATrGZCEQgpBATrHzKoKZoymBCXmTM2KlpbRRgQPU7qWIJkEGWUwUwczpkHNUNWY5hyBYAhCFQGU%2ByLm8l2WIYAdzVCXJCJaF5lzkDoE%2BbydAudfkFMBV2FgTBAWmBCCwPA4LIV4DOQs%2B5AJTC0HBROaF5zXm8lMASMpSgbDgoSHEZAgh/kvNMGi5ZsLKVQvhesAahhkAICoF6FIyzkC0CoO4BQCBUCiTZbQS0IR%2BXYSuGys8pg2ULEsdM5Aqhbkyv1MszAeFMW0puYyZAyyVz9CxFwOSIRuKMF5VqpgOqwhYJNTq9AcRLQKAUD86Z2r6l4BYCweVoynW2nDMSvZjrTX1PFWES19SFBMRqMKBQudajBqxKGsQ4buVdgDaa00CgY1Yw1I3fE4QDABFjQgNwVBOWYHTZgGwJAI1Rt9R60FWqFDAAULGNcjqFDEAsI61QrblnACoAwdFoy8D4FMLnLERAsRDpRdM/w2LkCDuWbQb1ghlmguQORFlAhl0sCOaMwNJbpnivwMQcZy7UCmEPf29YLBLRMEINu9YFotTLKJbQFg%2Bwn2mjcE%2B3lPqn0rSoDCRlF6yJUEZR86ZxBrVzvA9am2yyIPECqnB5hmAczLIwkytDIQQjjswHEHZdcSJGDQw3Yj/RTRob7Gs7ltAHWjLtXuujShaX0dOtM%2BjzomhsaUM6Zj3GwVcaUKx0ZWMlnTJnS%2B/YudSViZFXMOIcRwjLMFRaadtH1j6kgdMztByGPqYwnhTVWn9OYF5dWvTOm026sZLsnE55SBYlJDZs8WB7OsFUDs9Vrmt0NNQB2egcysRueFHEW5gXvMpldmF9zth6CucOdTF0745I9UC/FjQiXLlxdVVQELKWTkgrBal1QAQSwdL2UV8lfaUyhZOZVvAEX7P0oYIyrEZsl0NKzvZ5AVAus0ZoTcEtDSOzIFldOezmBgBkXGwwXObUflYnCCwRt9mVy0CUDhuICgsRfVBe11b62sCba9T60di7yv7exIdrbr7aCauFKuS7uHrv7FoAC%2B7a3HtHYU22lbD2NtbcJT%2B97B2ntYmwUYQbnquBcANamB9v2dWRFh0auICP6nAARAgRT92dU8s22j/NNGwc3ARJD/1WIM14CzQ0q4drc3Ym5YW4tBODN7XzUmnEKbLNOvCOzqg9SCANxtIzotsXhSgukK1moWBhdrfZNoDs9mG4QcYLGuX08lcrSUOVwdeBkWjtQOOvXQr2QMDtHm01LAsRemxJN4glisSmhRbafpsbUcu6YNbpQW2CL2bMHgBpNA/emADzddAUuVd9qI7aS07uqrzYYD1yUhuDVxFNVtrAyJ7MWh2UiNPdqcPIh2V8BPKe8/p8L0wJEtmJXJ9z/njPZQq/5qZ2LtP4fuUkHqcy5rFRLNEoEDQZ5lI4gBbIpgf9xBdVCl2fZ8fk%2BkuMh2ZMykf7eeguImDibpNUzEH72vqf4qlumixKe3npgeLlfn7znPGPBfY%2Bv1PnPcaCC77nwQS0GpUxz69AgAEhLqwwcmBSl2tp4EhzdBswDXB/BsR1FrxR0C0zR7MoCIDTdD0y16kmtGUlkt86FoC80EI8AVobAGkTJLNagLBY1wgqc7RsJ7NvccD60AtuUmBMs1crQHNeUtt6BCtvQOD/Bvky16DKMPdhCOC4hQUCxLR5s%2BC1kJCXsZCRCP9Dc2ArcuCxC1kTQJ4cwcQaErMNDrd0x6wdDVCHNACFAWBTpY0WBJdnh%2BdhQbpyt6NDDtDw9VD7NqhgBoRw9gA%2BxYw1sPDIUPCFBVAaN1RyNR0TR/BgAcdnVXUKcMCK1E1%2Bd7NgxBAyAvdbcX0jdTBY0q0fN%2BhLMbc1crcahCAEACiCAiiMYlsMjr1CA4hTRh94IsAnd7NVBjUsRww3AalAkK4wAwATBzAnRnN9hMAnROUCIWE14Bi8Y%2BiHgOAZhaBOA5JeAvAOAtBSBUBOAfAfAAA1bYTYA4AAJSIheEWHUh4FIAIE0EWJmFNBAEkDdGTlFD5H8WiBeI0DeOkGWI4EkDWNuK2M4F4CgkUhuI2MWNIDgFgCQDQA7EEjIAoAgDhLiARJACIPZUMGAHVBNHI0%2BF3ygggBCEBImWYGICRE4CuNJJqCRAAHkQhtAMDKTeA4TaFaSzcKSITSAsAgxgAnAyDmTuSaEsTxAuT0DQI8IoIuTxYy1jwlgriRxfjNi7R6VySXAsBASQlcRuBeAOlAYlAjhhSjBzdQAISZhJiG09i8BMBLRaSFN1irj%2BBBARAxB2ApAZBBBFAVB1AuTdAmhc1jAzALAVSoJIAZhTMUgpSsRaSjJOcFgEAzg2kOlVitiOkNQsBQyIAZgrAMCUgHAqohhGhqxfAYCJgeg3j4hEhkgBBCzBRKzsgUhxhugIgKyczQIBA2hBhXAGg9A2yKhOyOhSzmzeyBg6huzhhLBRymzCgehVJZh5hFgJAliViASuTtiOBiwAzNgIAcSzQ1IIBcBCASBLipheBwStAph7iQAFInQ3jXRPi7yPjXZfj/jSBcRqZFJ1jNj1yQSQAwTbjLz9BOAARVzvzgTriAKZgOkkh7BJAgA%3D)

```asm
.LCPI0_1:
 .byte   0
        .byte   2
        .byte   4
        .byte   6
 .byte   8
        .byte   10
        .byte   12
        .byte 14
numBytesInFiles:
.LnumBytesInFiles$local:
        push    rbp
 mov     rbp, rsp
        cmp     rsi, 33
        jae     .LBB0_2
 xor     eax, eax
        xor     edx, edx
        jmp .LBB0_5
.LBB0_2:
        vpmovsxbq       zmm1, qword ptr [rip + .LCPI0_1]
 lea     rax, [rsi - 32]
        lea     rcx, [rdi + 392]
 vpxor   xmm0, xmm0, xmm0
        vpxor   xmm2, xmm2, xmm2
        vpxor xmm3, xmm3, xmm3
        vpxor   xmm4, xmm4, xmm4
        mov     rdx, rax
.LBB0_3:
        vmovdqu64       zmm5, zmmword ptr [rcx - 384]
 vmovdqu64       zmm6, zmmword ptr [rcx - 256]
        vmovdqu64       zmm7, zmmword ptr [rcx - 128]
        vmovdqu64       zmm8, zmmword ptr [rcx]
 vpermt2q        zmm5, zmm1, zmmword ptr [rcx - 320]
        vpermt2q zmm6, zmm1, zmmword ptr [rcx - 192]
        vpermt2q        zmm7, zmm1, zmmword ptr [rcx - 64]
        vpermt2q        zmm8, zmm1, zmmword ptr [rcx + 64]
        add     rcx, 512
        add     rdx, -32
        vpaddq zmm0, zmm5, zmm0
        vpaddq  zmm2, zmm6, zmm2
        vpaddq  zmm3, zmm7, zmm3
        vpaddq  zmm4, zmm8, zmm4
        jne     .LBB0_3
 vpaddq  zmm0, zmm2, zmm0
        vpaddq  zmm0, zmm3, zmm0
        vpaddq zmm0, zmm4, zmm0
        vextracti64x4   ymm1, zmm0, 1
        vpaddq zmm0, zmm0, zmm1; why is this not a ymm operation?
        vextracti128 xmm1, ymm0, 1
        vpaddq  xmm0, xmm0, xmm1
        vpshufd xmm1, xmm0, 238
        vpaddq  xmm0, xmm0, xmm1
        vmovq   rdx, xmm0; Why do we need all the stuff below???
.LBB0_5:
        lea     rcx, [rsi - 4]
 vmovq   xmm0, rdx
        mov     rdx, rcx
        sub     rdx, rax
 shl     rax, 4
        lea     rax, [rax + rdi + 8]
.LBB0_6:
 vmovdqu ymm1, ymmword ptr [rax]
        vpunpcklqdq     ymm1, ymm1, ymmword ptr [rax + 32]
        add     rax, 64
        add     rdx, -4
 vpermq  ymm1, ymm1, 216
        vpaddq  ymm0, ymm1, ymm0
        jne .LBB0_6
        vextracti128    xmm1, ymm0, 1
        shl     rcx, 4
 shl     rsi, 4
        vpaddq  xmm0, xmm0, xmm1
        vpshufd xmm1, xmm0, 238
        vpaddq  xmm0, xmm0, xmm1
        vmovq   rax, xmm0
 add     rax, qword ptr [rdi + rcx + 8]
        add     rax, qword ptr [rsi + rdi - 40]
        add     rax, qword ptr [rsi + rdi - 24]
        add rax, qword ptr [rsi + rdi - 8]
        pop     rbp
        vzeroupper
 ret
```

I can see what the compiler was going for until `LBB0_5`. After that, I am at a loss of what it is doing, and I did not spend enough time walking through each step to see what is happening. But I would prefer an emit similar to this, which I was able to coerce the compiler to do for a size-optimized build:

```asm
numBytesInFilesFaster:
        push rbp
        mov     rbp, rsp
        shr     rsi, 4
        vpxor   xmm0, xmm0, xmm0
        vpxor   xmm1, xmm1, xmm1
        vpxor   xmm2, xmm2, xmm2
        vpxor   xmm3, xmm3, xmm3
.LBB0_1:
        sub     rsi, 1
 jb      .LBB0_3
        vpaddq  zmm0, zmm0, zmmword ptr [rdi]
 vpaddq  zmm1, zmm1, zmmword ptr [rdi + 64]
        vpaddq  zmm2, zmm2, zmmword ptr [rdi + 128]
        vpaddq  zmm3, zmm3, zmmword ptr [rdi + 192]
        add     rdi, 256
        jmp     .LBB0_1
.LBB0_3:
 vpaddq  zmm0, zmm0, zmm1
        vpaddq  zmm1, zmm2, zmm3
        vpaddq zmm0, zmm0, zmm1
        vextracti64x4   ymm1, zmm0, 1
        vpaddq ymm0, ymm0, ymm1; Yay! Not a zmm operation!
        vextracti128    xmm1, ymm0, 1
        vpaddq  xmm0, xmm0, xmm1
        vpextrq rax, xmm0, 1; just forget about xmm0[0]
        pop     rbp
        vzeroupper
 ret
```

I feel like this strategy makes a lot more sense. I didn't speedtest against the new LLVM version but if I remember correctly, my idea was 2-3x faster than the `vpgatherqq` strategy. The `vpermt2q` strategy is definitely a lot smarter than the `vpgatherqq` strategy, so I am not sure how the two compare. It would be easiest for me to compare with Zig using a newer version of LLVM, and I am not sure what the timeframe for that looks like. Hence, since I am a bit pressed for time at the moment, I didn't want to commit at this exact moment to set up a benchmark but I wanted to get this idea out there in case someone wanted to dig into this idea sooner rather than later.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMe1uTmzrT7q_xuqFWCjDG9kUuJA42mIM5GcPNVxiwwJxPxvDrd2FmJjOTSbLW-3679nZNrFhqNa2W1N3S03hNE6M8DL8vVnCxYv_yujYq6u8nL40Dr07-uhTB8F3IsWzA6tBLMb8IwgXJYAIWefcQ87BLl_sRVlyxJo39sMEW5Cb0_AiLG8zDFjTetHXnt9hiDbGyraeuaZhjizW7oPEFucW8PMAErPfyFmsLrOkyrC1Q2EZhjbVROHFIw3xB49jdS7uwmYiCsA3rLM7DJ0VbtF6KNfEYfsMWK-jGCNsVwaVI28WKXZCbqG3LZrEEC5JfkPwYo29oav6Wts-a5bhYAtWRUAR4WAUrjXkApz86UGYyqAdQAjyhMT7wjhwD5LGHrQzWQOv5VtbgAHS0PbSaw4GhiS-4dga7xwZCcChgbgJggX3ZA_kOeMc0WhERANyPMi9K9ABytDvtaCAfSg-cHo68ZRErUrsMsOkSMIrsRAC4WQIgofFa2uzc0T8eTzcq6_nrdWBs68gUMd7XpuBEIHZjkJlLc6DipDGHoRCbXmT6QU14pqo84liFaX3xFyR_oIGBWutEikmAKBxGNPCiNe460GAEoLsOgEfoOlWBFMQ4Y3tVx41HAkEjFcDx-3LzODmUmFbITaPcXyN4BLEDNWBoDmA5-sBWLMMzUEHQVilwQKShkjshzGT7QPgArIz9dgngdnfD4V46jQ9ncPyLRWaO6YAAhSNp56odMsUwoAXJP5zVMcpGNclszqBYCTgM2fX48BBEmecVmD3IprN3yK2R8-B6c6cxjNOfiy0RnlUbsMEhqQ2fRx7LmcZmbxDnw-hvx9O4IFcklLVnYVS8EisA0ILMFLZ1219gcuEzlbeTLZSZ4vF4hDHpN0cy4Q6cddxfrjtOLBVZOOIQhSnl1ymN0Him3QiHsdSkVFPvwhW1IHnxBNayRu-sgZf3ZaTurMfe2e6cRs8g0uSVMBhLfqff-auWc83xKU9JyOuTTCRtjG_uiWZemc0qjk9Gdl492-0D_iytFvfqs7U80_1yhy-VVrEzXFmrwt0B7EneNRwSQCyvYjtQ02I5Hh1-F4OeAUiyDn178msdVGlj3QRGOwhO1MvokZzPpUJssxhEMecLQXLcarK2vFu8QHTSpsJX-9eHS2xB3EKFI01bufftcXs6q0clyCmqOZALkmdZKpbDyLBlHtncNbjhoy0oVOQEAC3DQ8zaGm7wO5HVY0305PHWmS4htKbZKviC5M2Yk5PNYIwWPx7lYWCXppmuZVUfT0CmH2eZDwZTtQ_aXRkdoztvcmN7YFaD1slUMiLAx5vMJKTk_kCc1XMnySpXV2mDokDwHxLq5rk3N00vGidFplK825CHoajQoeqMrNo01sqwd96qtsXNmLoCx7teYxFa3KZKfcoPtalWfjqK96qvYEMokt023YFvqpWntTaeErVRX5ryQLcyXzvRNVZpz949pEh4JG17RpThehwl8iG3YVHLCyeoAiCZ8skt08xNR5SeEcPhwVpEwHsAkWMMVkKAW-Gua2i27kpI9hOZYgz9qqt7Y4lskLDaqDwHtiD5NXCoM-JMmdwtSP4e4ojikQhwRt1xAygY2IXxOdN2Mqt1e6MZDjp0EKchR6ACwREWJM9VGq9CSj-noaBxYJ-iDL8yREBdMpLjLvaOL05nOxAkiFLfAZ5S2IizqTNqoKP1dHFakDzY2s0RdmowSbSMANFrlrKJ4O4Azx7bO2J-IFZ9A07Vjb2x61u8Y1RR3pEmXDrW_UD52QGxOwB1IPUmAPugDWMd9QuSpzRNZ7kAddDd6ZCzeJ1g2qVOI1no9Yt81RxKN6CYasaNywIEvcs5RUC0D1cr5fa8U25pB9SdfdIYK7FScW9U1-LpFFYkPOlpnKdRsotPD9eWIcJf1LoiIdrNP4QjaOA-hmLSXFkubyDKoW8X90n5scwWlE7fSmAA4VoEugGRcuDAXch1GEvEFglucdWmYbDAExckz8O7bkdPxnvvCBLII3-nSTgnHwqfecRGnLGy6nDoWF71WY46zIaHyQKO2N2Cg-auNI3vBU23LEXU-l4qZQielEXDRuy10sQdbXUQIlExZYrj4ssgxPubkOS4yiaEIJoSIhSDwQnqaOqZALMLo4hRL1O8XDn44Li9oNfKIzZZ886pPW2hif-SffnaLnAw_dH4_DfGaIGD8FEWdYtdcyzvMji0YSPkfJyGzYLcXJ_lEkyue0GCyWU_AxG_yJsW6zZTwJB32f-80XWTp58Ch-d_prhigQMMw7D4OsUeC3LzRo4tSBpbEhPxgiQWSxbDsaLG3rUv2Wftk11eT3GLd0nDxRJic7SAZV4SYmEWt1gTZ2Ua1tPD7t7M5DIN5U0mbGa1hLMOJpGuRY29jXEF8W_ffgxlik222GLNTD__J_Bab7Fmpn5vnLEFCSeebwTfpkjoPf86bLs6fy_Ls3HNvp-DmRwOWBBevW6KehisjeJmitD6yGsxAUNhOwVIH-fOa7IFDr5JzFHA_4eY27GXz7eq8wJsSf4gID8RTPJgGIZ_UUd8UTdxevux_IKA-qJu9UUd_Z7ReoGDz0vug5hl10RPRV7Kd7VZccdea0kGq5tn473MinvzuFQvVGOWEVNz1Rd1MMW20xKu43KaNuxNKyv2HeN7eakLL_C9pq2m_uSf-hOf-z-KGsOwR5bhU9cP5VPEt_blS_2P8ks21Evzj_Iz2SPLVi-NP8pp2iH8aVncyyZNq6dq6In2VUXvuSaPvKh7LHk2JPjL95fCrV-e96N8T-YFQfVjFt6V5DsyLwjmqWziqfXvJfmBB_Kmg0ZVvc3oejIoCTFtoZnZh8kJ4ufkTMN7_mfzcXpehva7sb0Jjb_wX7-U_5EK_kvxiSX9nw1gfFlX7-T_xfr6h_L_a9FJmvqnor9TOvVJ6J9X-6-F_q-1vdz-ZA1elbn6JNd7w3bLw2f5uuF-u5qW71fTF-3Ul6vtJ7LVBzbho609v41p6kFhGDb82GlP-j-I9FoS2ORW-2iY_M7T_-RFi3kTO6wow9pr4yJfLPn33F6fTJAbbJ6a55OHXz_5C8v4kaqJumvwxumVjFxuvhjFn5hlxX1aDLX3eG-EXz5lUc6WZ3Yt9zGsi64s5wji5VOH7c-e2ozCOsS86d_k2S9hjRVXLG6aLmywPm6jWXtTUPIN-0HchHXspVgQlmEehLk_YH7kxfmka6_F_KJLg_nK5hKGOVZ6tZemYfq8fulnDl0T5whb0PiPpb6gccybZimKUYT5RdM-Y5o0btt04pSH10kKNcck6SQvyHXzevcyxT0C5jVNlz0HEvZhjd3DuomLfBrPTL-dgo-i_TGil0hwav3dLU6a3rP5GidtvxU1-r9yk8P89iaHITygPLwk3brA7NnDLQA73mrBgWp24aOHyYY1AVixPbiZO0EDeweYqTDf5tyaHb8MjkfNSMiem85IKmPLQuwM-KPev97n3IyjNKyMTWlUWSFsCoXtKyXmvbamb4fLM6zfNjRTtDQwktZS5hsdYCGYAYYDHoIuywY04BLAWSSRrIHqpLoF0D29aRBCM-NHALe7vMyU9HhK5rsFwPWgopYaNx8cqCO4ABNw5qUQbyfQA3PMGkktB5gB0DK9psQUYoWo0A4NMAxwihmX61RzcE3GNsBuMDhWrnnKzZrBbGoEEPC5fGUfiqsq3qWVLTigom5KeTlwVA25QyTLJNwJIRtv-deD7ACr2-omhRfJZwEg0MMCcAkjh7w9KZShMjSgxhRuBLvocUFWy5xufQQAp2UULTk7jgb8inLgnRNll8kePT3OCgS3yI1x08nWtBPAu3grApYz3QLGN80UV9kF7BLTjQ-ybLobpN7sUi2FRjpRO7RqafzEgiMriHLZKrEpyxd1tSB5lacaRu76O_RN15L1w64lKKDUCBZytCD5h0rwD6XnFKphGccJGct3a7XZ382iSZ9SXUW0u0j7E9mSY3i5BM_KO34xHcBypt7wopJEgcVDYDqSrhjEguT3mqlIdsWJrdZCnd0ZvrK8adajjx2PV5BlEYoZH1bHpGe4BhZAoOzw3Fo8x8qqlZjuguQ1h30QsX6SeaDCCEiFCXiAVJGwFiQftrsHQpoqyiwHeEeBNX9bHaiDI59sVjeTOHAEU2R4JU8IJxm5Y6vzqmoSt5Xpnnam2KwOauDf-4vY7pHccyvF2XKm7JTRKDf0eFHtcNwLSTrsbz7iVlJCDSbc3IdabO5gLfgb8z4yaL63iwRmqx-kYORlci-tpCQ54Pf5SG7ubDmKONXaDllCntzrkpnrhWzvAvWB4o3XxI_E63G50mJJD7KyBn2PRrsKG9LyhsgaBEGLgDU0AxWpTX2VmLtP61bnl14M7bi1j3ZjLhWbq4LWn7kXsXlsN_1ha3k9OUhxRz6aoa1GE7ejk0KzjqYz9w0nrOIq0toDuT-kcu26QmQ86JUSg7Vyo-O1V52Dybwxll2aLKf00hA1-3WhVzsTGUeYIweub01cR5tKL2uvvSp7Y8kA1Fz9876VuiZiwig16IruDLrx4gP05C0v81ZgUQ93vSevjzrzyvkaMfMGfnRglZXocU8Qf8qzB1VCoNBVGG85CmlHmBB6PBC2sN95fbYZrIqpXa9eqWTlesXhltP9xfKUxFPcjKypMNtchALamaCngJTqU6Ke5ORs72PKEIt1WWW1pLcVlZAmAFzAeOWyvl9P49krzPtmNkDxSWVFhfeoXmPPNGdujtX2VDTUguT9RgrEUiNXB-itLb5L40MwDIe2WPp0VtpRIFzYDXd4siGI-1KA5rAg-Tjrr1XncldWUol1cmEpktjsg3ob5ePQ0yRZBe4tJ9swvHX9NkjuYBMTzkq9kKdwIzoD80DtQ9KkfCl5hzat6vMxXxoCuTGr9dLIlu58wzKvhPW5D6VS954_Ns_v1dnkI8lBVms7FAHLkdnlKe9a_YLkJdOxd0nyuJoHEZ1pOFm7QuZg7AVAkDcOp65urJHRLMN7SynLVYO1IL08OSEbRBZ7Xq-0PL8fo1KEu8tA1qwfmkm5TxQ-u_t20lwYSkmzPrK78inLjiHWVXMKxUf5WJB8D66jlVzaZxsvCEPeyjBKVztftjze6dh5BLScmNmC5E9d4wNKEKBACFnsc2Z167ndPqaTY1kTzgVCtOGqUtC1LNKFjL-wjhlK0ZWJ-PiQnIVCZDkgVKwjOaJxAsIqhofbi1zc4IibpEICH7tApw5pOEB1B1HIx-x9uc4YtexLGQh5xoluaRTArHcuw2mohMCs9-OhOLjFkEHmnJkyeUjLi64j7WitK1sQE25nW73V-2OZ7BVLsZ1VNEAHRAyv7aynBIOUbVJyckfBeGLOIiN6_CodE7bgnu2XIQBdcE14GZ5IHpkQ2BlkmP4IKEk4UayqNfNsA9Fk8D3UVY9fjedsk8rAkEsDXVhUGHvOBWhyAsldkXfxym2kw0m7R2EDvChKgMAUPM0Lw5gwOFOoFNQYaDGx6V40AxfmW7-zY3S7odmUiLQkrgnkFaiiSzLcCbkZQcjLNl52zuCCYTiNW-bB96oh6N1B5lenqkRq1UeOqJjVFvi6pB2AxW5ol6zplIIO04enYshtMmdl4-7eavNMHHmbM4itwUNZr-QD1LrAu8Hqcdg1GnXpTgFiPQ_HGeQQTk8IyytHaSyA_E1DSn-Cqu3sTRftehEIhN5udRrn7YpnAbCkneLfKp7lQCPQhFZf0hwwBegDvhg2LMXLUi5xOmh0ttQDeVqvpJQwbGdftAuBojRDnabqfAqiFG8Y1ZN7RbyUeXzvZc13h7XFZNzxSm4dCUq6zAlKt3X4ojWlg3jRePTUZp-T2c2f53iZHqscr42CZfSUpwfR4lx9Q7sPWJ_GO9h6GTkMwpFjqhyuogz4oyT0ydCygqbdbk2_5_Zu4BvijtX6pXNbkLxu6sVlvWvWaQv29k1qz113MyLvjAdqKz8fehuLLGo8S6bd23LXn3zPOjxw15bT3BRz4zUGcrrAOMUuf5ZVwdf7myTzuucF7Z640QkK5LGFw-5YOX0emSc736oOvwrsu6lmOEk3rtTk3GplQCcVWbfZ2HCtNrzFNttTnbW4omiQDJE_NHoX8nvOXqHzXS7TIOO3YxvRTOergcnja2olbC1mQfL8TYvPUvoITieNkw62maAaeimhAc3oA4m0Tpv06llD5Kru6Q648_qIF44w1JzbpLhyGO_uCpxA1-BuYfpcyxrqKPBpoIZjBhFMzru-P6sX65o6OcP0ervNTgPOWGzUCQxq9OsJhgRxocmGuXhbk8aDeD3c1-FDCOpLvfYYr-MPnbHu9vV9zRdgjgLW3nLf7h2LJNMLSyrtxRfNOZBeQzJvnay3HO2SVx30geJlcHsnA1vnI9zrBOZI5wDoAOnmlgysTUNO4SevKLveXwJdZBckT9iCTFDMqOEVFdT-0slWjk21UGWV9Xm0spw7XCRFvTPqWKGtwQDl0Qpj0TbnyEBdciCywoZRUF9dpWCbbbajNN-Rdt0Z36R-bVjqqQ9CmNi3VlPV-1mrSU1m232GExJo9DB7iAqF0rgxski_eNeyuVh-RzvKpdRskpHIi7xHsFSmU1SYAXYMAmB1p2BbCWvPwNddVY-OwxKDFXXs6cErp7YGg7iW7Yi0YuUYVP5RiMjTBh4P4WZB8uVGwnuRazPxLG7HBcnnt6OrVQuSX1UuKbVH6tpZyb7yh1XN65LCFRyruatUoBC8CCW6bh8wODEpeXU319n_J50cka48JNd1GKJOyNj4UirWyO3X5L26UlXaZfHjEC7zEoVSes3XY37cHeHVmaNk4pgffY9h1uu81wx8V1qPkd4CBLhIqvrez6CRkm1JcdEYwKZnz9Pmgo1O8PVDxxl81NdywQisGbD4QNBJ1u6sNGk3NF8wG5wTNuBUPE8FoqR4SIIO0aPKX-uNuFbuvs_SOGg7K4NyQ_i1tldCq21pyLR3TZ1WCLwnA0GzB_kYRIzKUJFmMQ9JX83OgyESkTk3LqMzxy3rk6D2O-bBEImpiZTf-5rH1bLC1gH-oPuAPTF7BTA8sKFZOrgNxSCf8aMg0i7l0NIKy7Zsvz2xa6WKECz0fovmc93D6YnmyArWkeHhCXgKoQ-Kjpv6JCMCfpCfztbBl5kDwREzz7WCHhAM4B5c_DN-C0zo4BV-neHGSJIvPuHXvhcxgANMzIA4lp20kW81wQAqMvVoSwkNyIO1coI3q9H7fgm8FCQHqp_OlXAEuZ4r20gGua5ajGBzBAXjzTyv8R6pwI08qIKVGII7UEELDWhBFVzBFQBAXBzTARQAoiFEIWfvrYjiBSBwOGeLGa9AwCVssDNTnl3tN3YMQwFnQzXZ2QLFJaytdAdSpniKQYkVdQIp24rAIh4xGquBNcfdBFAAxEZSDHQRMMLRteQd2J-gshfmowe_HBBCkOGgkNnOTmB0jmI6RRQrRgdgn2hRC2T2YIaAMj3eM0b_YAimARqAHgjkYGAzszM8rjEfoDNxVhM2QiF05sMZiFufojrWH9ebEq91-jQYZ9BAYGipr3cwBGoKnBTcosi4wTHQgGC4kRjv8G28gTKUdM_gFSKu52ALQqCDByRBCVwIIQ9OkACdGYAs8okbGIEETkYhCsCNTNlCpdHonnETVZ9HHBgRmajpKW5jNVG0BmqDAFxUA5mx0B5URRTtoupxBQ4johAtb1TERQmCkBmhfhgbZEWPqEMCOgz-qAkQkBGMzmCHtoAcDpE6qJExZmM4QERH3RhFEtSHbGRQGJ1EN1pFPBJBGp9iYHRmG6sw7sGoIAH4xqgRggB9yAADSnEZhbA3WlBG61gDvJBry9tZP8br4Xg7u9fJdN8M6OuVy4vETbkRg2ZooDcvN2ncQhUA_TTeR2TWMTi4SE2SaA1F8AZ3fkY6v0TLfoeCkf8Q5PoAaG2-gtO-xNh-Zk9Qv0LDvkk_4bJUWvhe-luw7GuU7OXjZy-3nzPusnwPD9y89zfaT0Hnq3cMC-er1Kn4Qf_WGMyNwfvGW1a-MPqBSpGfUal_D9y9Am9p6M3jmAWbCJsY-xtbfrrLf6Pz3-he7v9_XPv_Cb17E_eNjHxp_lF-gc79LyB9b1M5a7h-qn_W5fKTLrPiHlQdTf3Q5eor8MN_TEravII0X3Sjf9mNXH2Cpb7ovf5lb4Lc_LH35uveb_MU1llLvi6X92Mkfj1WEv-M7rxw-QyGfi31z-DQT0Ks_8jlMyj2BZPNH5hMS_YzmzcQdV7cK-JLhHVeO58R1leI60to6SPVGyL-TmNfMPsz-vgT3rf5Au_7iKstfwGYkf8MMFv-muxP6Nu_R9e-Atf-O2ztHwBr_2-QteAHsraEmB0NWFBgfYjlYRhgXpo-E4CbtrtesUuYFv00xvnv1X6tPtqvL-z0056_N1TVOxtdf3A2n-2k_76x6S4fGmcf1kTpXDs7EOorWX74Fm_egK--48WSzSOhX0byYs_eVsrwaRN7j89GoMtLP0mrYLYD7_r9ov_st8hfGIFZWpr6jQ2g3sxo9fPzSIL-YkW8Lr3h_VL8uFtf1fCfAcRvE-H_mIi3ujlKof5_WfYfAeVPmq--yjJ4Nd2b307ax65N_LbY_sYo_D_tSX7hLf7c65Ogn9DyV4V8AM2_RMsFzPdyrAnDOZdtsgd-kZVxGtZY7zUYKuIcPUHrLm_jFFvQ-ItdoPFvGLi2z_cMvGdWnIB52Qx3p0XTYMV15hm3k1kNJkYT1fzCQhAHTyPblGEeYGFedCjC2jgLsd5Lk-mZbVQ_K59vQzRtWD7fb3gVNG6wyCvLMI9z9A2DXYsJWP8E6cs6vIY15uVveYdx6tVT58myTxL0UexHz5cmGsy7pOHU5hdh7Ycfx98Wk7mcxu4934_4uyjbOIvHMMAuXZwGv8r5-3Qa4L2mDesvzgL_JGvubffVv95p_zYsJt72zlcb8l9Ez7_MlPsyu-3NwM9jeD71Nle9jyI-7fkvvPWnDfwWdv4yo-2rHf9zrPdTEEX-pvvPYfLP0dXyd_0_B6w_fMBTO1MQ__GUhn1IYvp4uvhd3tDvk_7IX0eAf2L27yOvd07qh7NaQszxhgVJYMoz6Bo_BF3kl4_85wlNf3ZAE8_qg894clpC7NbN-ToobDHvUnTt3LyC-P-a8b2GYYqlcRLOYWfT1l4bouGZN908DWmLZcUzPSlvwm-z4cwX5PppOcOgDZsW85AX581svPOwf-YGveUKXboWi6-YgNVhFj6zofyirkO_TYdpoNmAxUHoPW0h-ffygV2f1mqy6fnrC2Qf85leZXwmT83N8ynpfePT4ofXOI_bMB1eBtJkXv3PeE-SNcXsUJ5eoqtDLCr6-YW1vnjaaK-eFNK-mP1LiIVeE4cvKVbZi1V_ks1pX26MXnK0fplP9eqd3j_2zS9O3ulae1n4fMAzLSwtiqR5zt83bB_m_vPVvibO_fDFGWKXuJ08UtOEwdxtcnEvDLMiC_MXz_k2ra9v8vlFNrkv7zW56-H57UuP2RG2WFdODwhzP8q8OnnO9PwmYBhMJNOynRPVpwmelm_7zHaLc8z3mhBriiws8vBdjyBGWJy_eMq5W1MUeVhjtffyRqGXY6nXhvW3v4Lvy2C73Hp_hd-JNUWuN1t8tf4r-r7Fr5fL1fNWFBkEvrcNVmuf2Kxowl8u_aW__Cv-TuLkCl-SFE7hFLH8FhJLiiYD_Oov1zRFEwsKDzMvTr8909SKGv31zN77TixJmqb_Sr1LmDbPFy5Jclrvz9YFORnUv-rvU6e_Lx1qFhSexk3b_GDTxm36fFMTnM5_T8fwFYsxRd7EwUsUgzVdlk0rJLyH9YAVQYCFafjUeXGdQgqvrr3hGTJdQix4ai9uo0m38zJuFiQ_bYfmr65Ov39MukNxG3WXb36RvWTgvRR_l3VxC_12QfJzluKC5F-Gev9O_p8AAAD__-u916s">