From: Rémi Bernon rbernon@codeweavers.com
--- dlls/evr/tests/Makefile.in | 2 + dlls/evr/tests/evr.c | 271 ++++++++++++++++++++++++++++- dlls/evr/tests/nv12frame.bmp | Bin 0 -> 50742 bytes dlls/evr/tests/resource.rc | 33 ++++ dlls/evr/tests/rgb32frame-flip.bmp | Bin 0 -> 36918 bytes dlls/evr/tests/rgb32frame.bmp | Bin 0 -> 36918 bytes 6 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 dlls/evr/tests/nv12frame.bmp create mode 100644 dlls/evr/tests/resource.rc create mode 100644 dlls/evr/tests/rgb32frame-flip.bmp create mode 100644 dlls/evr/tests/rgb32frame.bmp
diff --git a/dlls/evr/tests/Makefile.in b/dlls/evr/tests/Makefile.in index c5db2226ebc..6b89635225a 100644 --- a/dlls/evr/tests/Makefile.in +++ b/dlls/evr/tests/Makefile.in @@ -3,3 +3,5 @@ IMPORTS = dxva2 mfplat mfuuid mf strmiids uuid dxguid ole32 oleaut32 evr d3d9
C_SRCS = \ evr.c + +RC_SRCS = resource.rc diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index e0cec1ba8c9..662919c7d94 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -31,6 +31,95 @@
static const WCHAR sink_id[] = L"EVR Input0";
+static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *length) +{ + HRSRC resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); + *data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + *length = SizeofResource(GetModuleHandleW(NULL), resource); +} + +static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +{ + DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + + /* skip BMP header from the dump */ + size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + size; + expect = expect + size; + + for (y = 0; y < height; y++, data += width * 4, expect += width * 4) + { + if (y < rect->top || y >= rect->bottom) continue; + for (x = 0; x < width; x++) + { + if (x < rect->left || x >= rect->right) continue; + diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]); + diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]); + diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]); + } + } + + size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3; + return diff * 100 / 256 / size; +} + +static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +{ + DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + static const char magic[2] = "BM"; + struct + { + DWORD length; + DWORD reserved; + DWORD offset; + BITMAPINFOHEADER biHeader; + } header = + { + .length = length + sizeof(header) + 2, .offset = sizeof(header) + 2, + .biHeader = + { + .biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1, + .biBitCount = 32, .biCompression = BI_RGB, .biSizeImage = width * height * 4, + }, + }; + DWORD written; + BOOL ret; + + ret = WriteFile(output, magic, sizeof(magic), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(magic), "written %lu bytes\n", written); + ret = WriteFile(output, &header, sizeof(header), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(header), "written %lu bytes\n", written); + ret = WriteFile(output, data, length, &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == length, "written %lu bytes\n", written); +} + +#define check_rgb32_data(a, b, c, d) check_rgb32_data_(__LINE__, a, b, c, d) +static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect) +{ + WCHAR output_path[MAX_PATH]; + const BYTE *expect_data; + HRSRC resource; + HANDLE output; + + GetTempPathW(ARRAY_SIZE(output_path), output_path); + lstrcatW(output_path, filename); + output = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError()); + dump_rgb32(data, length, rect, output); + trace("created %s\n", debugstr_w(output_path)); + CloseHandle(output); + + resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); + expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + + return compare_rgb32(data, &length, rect, expect_data); +} + static void set_rect(MFVideoNormalizedRect *rect, float left, float top, float right, float bottom) { rect->left = left; @@ -2912,8 +3001,8 @@ static void test_mixer_zorder(void) IMFTransform_Release(mixer); }
-static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, unsigned int width, - unsigned int height) +static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, UINT fourcc, + unsigned int width, unsigned int height) { IDirectXVideoAccelerationService *service; IDirect3DSurface9 *surface = NULL; @@ -2931,7 +3020,7 @@ static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, unsi (void **)&service); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IDirectXVideoAccelerationService_CreateSurface(service, width, height, 0, D3DFMT_A8R8G8B8, + hr = IDirectXVideoAccelerationService_CreateSurface(service, width, height, 0, fourcc, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -3080,7 +3169,7 @@ static void test_mixer_samples(void)
IMFSample_Release(sample);
- surface = create_surface(manager, 64, 64); + surface = create_surface(manager, D3DFMT_A8R8G8B8, 64, 64);
hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3229,6 +3318,176 @@ done: DestroyWindow(window); }
+static void test_presenter_orientation(const GUID *subtype) +{ + IMFTopologyServiceLookupClient *lookup_client; + static const BITMAPINFOHEADER expect_header = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 96, .biHeight = 96, + .biPlanes = 1, .biBitCount = 32, + .biCompression = BI_RGB, + .biSizeImage = 96 * 96 * 4, + }; + BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; + IMFVideoDisplayControl *display_control; + DWORD diff, data_size, frame_data_len; + IDirect3DDeviceManager9 *manager; + D3DLOCKED_RECT d3d_rect = {0}; + IMFVideoPresenter *presenter; + IDirect3DSurface9 *surface; + IMFMediaType *video_type; + const BYTE *frame_data; + struct test_host host; + IMFTransform *mixer; + LONGLONG timestamp; + IMFSample *sample; + LONG stride, ref; + HWND window; + BYTE *data; + HRESULT hr; + RECT rect; + + window = create_window(); + + hr = MFCreateVideoMixer(NULL, &IID_IDirect3DDevice9, &IID_IMFTransform, (void **)&mixer); + ok(hr == S_OK, "Failed to create a mixer, hr %#lx.\n", hr); + hr = MFCreateVideoPresenter(NULL, &IID_IDirect3DDevice9, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + init_test_host(&host, mixer, presenter); + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, &host.IMFTopologyServiceLookup_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + /* Configure device and media types. */ + + hr = MFGetService((IUnknown *)presenter, &MR_VIDEO_ACCELERATION_SERVICE, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDeviceManager9_Release(manager); + + video_type = create_video_type(subtype); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + if (broken(IsEqualGUID(subtype, &MFVideoFormat_NV12) && hr == E_FAIL)) + { + win_skip("Skipping unsupported NV12 format\n"); + IMFMediaType_Release(video_type); + goto skip_tests; + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetOutputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + load_resource(L"nv12frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header and RGB data from the dump */ + data_size = *(DWORD *)(frame_data + 2); + frame_data_len = frame_data_len - data_size; + frame_data = frame_data + data_size; + ok(frame_data_len == 13824, "got length %lu\n", frame_data_len); + } + else + { + load_resource(L"rgb32frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header from the dump */ + data_size = *(DWORD *)(frame_data + 2 + 2 * sizeof(DWORD)); + frame_data_len -= data_size; + frame_data += data_size; + ok(frame_data_len == 36864, "got length %lu\n", frame_data_len); + } + + surface = create_surface(manager, subtype->Data1, expect_header.biWidth, expect_header.biHeight); + ok(!!surface, "Failed to create input surface.\n"); + hr = IDirect3DSurface9_LockRect(surface, &d3d_rect, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + memcpy(d3d_rect.pBits, frame_data, frame_data_len); + else if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, expect_header.biWidth, &stride); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + frame_data += stride * expect_header.biHeight; + d3d_rect.pBits = (BYTE *)d3d_rect.pBits + d3d_rect.Pitch * expect_header.biHeight; + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight / 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + hr = IDirect3DSurface9_UnlockRect(surface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DSurface9_Release(surface); + + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFVideoDisplayControl, (void **)&display_control); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + if (hr == MF_E_INVALIDREQUEST) + { + Sleep(500); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFVideoDisplayControl_Release(display_control); + + ok(header.biSize == expect_header.biSize, "Unexpected biSize %#lx\n", header.biSize); + ok(header.biWidth == expect_header.biWidth, "Unexpected biWidth %#lx\n", header.biWidth); + ok(header.biHeight == expect_header.biHeight, "Unexpected biHeight %#lx\n", header.biHeight); + ok(header.biPlanes == expect_header.biPlanes, "Unexpected biPlanes %#x\n", header.biPlanes); + ok(header.biBitCount == expect_header.biBitCount, "Unexpected biBitCount %#x\n", header.biBitCount); + ok(header.biCompression == expect_header.biCompression, "Unexpected biCompression %#lx\n", header.biCompression); + ok(header.biSizeImage == expect_header.biSizeImage, "Unexpected biSizeImage %#lx\n", header.biSizeImage); + ok(header.biXPelsPerMeter == expect_header.biXPelsPerMeter, "Unexpected biXPelsPerMeter %#lx\n", header.biXPelsPerMeter); + ok(header.biYPelsPerMeter == expect_header.biYPelsPerMeter, "Unexpected biYPelsPerMeter %#lx\n", header.biYPelsPerMeter); + ok(header.biClrUsed == expect_header.biClrUsed, "Unexpected biClrUsed %#lx\n", header.biClrUsed); + ok(header.biClrImportant == expect_header.biClrImportant, "Unexpected biClrImportant %#lx\n", header.biClrImportant); + + SetRect(&rect, 0, 0, header.biWidth, header.biHeight); + diff = check_rgb32_data(L"rgb32frame-flip.bmp", data, header.biSizeImage, &rect); + todo_wine + ok(diff <= 3, "Unexpected %lu%% diff\n", diff); + CoTaskMemFree(data); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + +skip_tests: + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_ReleaseServicePointers(lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + ref = IMFTransform_Release(mixer); + ok(ref == 0, "Unexpected ref %ld\n", ref); + ref = IMFVideoPresenter_Release(presenter); + ok(ref == 0, "Unexpected ref %ld\n", ref); + + DestroyWindow(window); +} + static void test_MFIsFormatYUV(void) { static const DWORD formats[] = @@ -3332,7 +3591,7 @@ static void test_mixer_render(void) IMFMediaType_Release(output_type); IMFMediaType_Release(video_type);
- surface = create_surface(manager, 64, 64); + surface = create_surface(manager, D3DFMT_A8R8G8B8, 64, 64); ok(!!surface, "Failed to create input surface.\n");
hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); @@ -3421,6 +3680,8 @@ START_TEST(evr) test_presenter_video_window(); test_presenter_quality_control(); test_presenter_media_type(); + test_presenter_orientation(&MFVideoFormat_NV12); + test_presenter_orientation(&MFVideoFormat_RGB32); test_presenter_shutdown(); test_mixer_output_rectangle(); test_mixer_zorder(); diff --git a/dlls/evr/tests/nv12frame.bmp b/dlls/evr/tests/nv12frame.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f37bdfc4062ef20d0f017e43147767708c51c09b GIT binary patch literal 50742 zcmeI5v5g`@5JmSgm=IQ2M*<VT`D@@}osB^Zgm4f92B9F~5C93_Oa^l^w`*);lytwp zTAI@9RwG)i`c%Dr{{H&t|GfQM{q*^BI={cpkGJ>f+qAykKQEu3&%<Hl)HAr<ZliKw zU(bGKsIZ@F;1B-{4&cAXW7P%t!(VkLLmmF(e+G}$8So$fRd+Jf;r}xIzjvpRQ_n#4 zANKX^XNK_ia8!MSKm1j9GSuNe{%7!5odN&xUv(!#9sc8g29MPl@PC>9U(Vggsb`@2 z5BqxdGeh`$II2FvAO5O48S3yK|1)^3&Vc{;uey_=4*&5#gU9L&_`gj5kNs-o)H6{1 zhkZT!nIZf=9919T4}aC240ZUA{~0`1XTX2_SKY}_hyVDW!DDp>{9mU3yX#}*)H6{1 zhkZT!nIZf=9919T4}aC240ZUA{~0`1XTX2_SKY}_hyVDW!DDp>{9mU3o9!@i>KUm1 z!@i#V%n<$_j;fFFhrjAhhC2Mm{|p|hGvGh|tL|i|!+-qG;ITRb{x8%2^{^i~^$b-1 zVPDUFW(a=|N7YC8!(VkLLmmF(e+G}$8So$fRd+Jf;XnRo@K~Jz|Ci~%`gfyF`+x6n zgBuRu01n^)4&VR|-~bNb01n^)4&Xp*2cGsdP4I2mDcKcr?2F{5`fPuk@60olE?< zEuXu6mHpe}@8ri!;RBzTK>XU)pNoB!{oCU&<i||m1D}{c{My!^qkWbA+vAVq$4ub^ zpO`@W+SZ?)eU<&&<9Fo8OyL8cm_Yp6)}M`imHpe}H{{1m;RBzTK>XU)pS69J{oCW$ z<i||m1D}{c{My!^^4GXQ00IzbN8n&zW$*U*1Nkx2wtTvidzbyY)4LP-G1Inu&YgRg z{kzl89r-cSwtV`PdzbyY)B6?qG1Inut`GMv`*){bALPeO+w$2C?p^lpPTvmX$4uMu a8TRg7_U}#~_T<M*+wv)YjT;31kHBAWY55KS
literal 0 HcmV?d00001
diff --git a/dlls/evr/tests/resource.rc b/dlls/evr/tests/resource.rc new file mode 100644 index 00000000000..79b62304303 --- /dev/null +++ b/dlls/evr/tests/resource.rc @@ -0,0 +1,33 @@ +/* + * Resources for mf test suite. + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* Generated from running the mf:transform tests on Windows */ +/* @makedep: rgb32frame.bmp */ +rgb32frame.bmp RCDATA rgb32frame.bmp + +/* Generated from running the mf:transform tests on Windows */ +/* @makedep: rgb32frame-flip.bmp */ +rgb32frame-flip.bmp RCDATA rgb32frame-flip.bmp + +/* Generated from running the mf:transform tests on Windows */ +/* @makedep: nv12frame.bmp */ +nv12frame.bmp RCDATA nv12frame.bmp diff --git a/dlls/evr/tests/rgb32frame-flip.bmp b/dlls/evr/tests/rgb32frame-flip.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2a089de19287f43a1b06e1a1b83e37a24a610f1a GIT binary patch literal 36918 zcmeI4JxT*n6h^-wHd=|5KZS*YD+t)yn<m)116_ixg<|Ov)F#`}QcN!hrbuv}4|M~% z-@tG)Cvbux-0<e)<Uz(Er)R@^{oaQ4{<w1S&p-$DuX_7`{_nxxeYq|I9MAv_&;Sk4 z01eOp4bT7$&;Sjrd;<^lJqF)F^gO~%^$)&-p#Pb+1-^smJ~`Eiz;_V!-wY)19pK-0 z=yZsG{5$<*pQV5L&)%@Je)^|>r=RSz(f)5W68H|H{$I2s@Et_`AFfXYzJsX$%dLsP zcM$b2eb)=&z;%HCZX3cs{@u@T=6U+3|IGcmYo~wucN@w)AMJmvPl4|s>VH>rf$t#d z|81=Zd<Rkgj~hkcJBa%KR#VUZfa?JN-8O`O{JWpw%=7e5|C#%B*G~WR?>3Zqp8n}S zbHDD|qy4MY%OAjYfd6hg!ax4|ypPd8{nP*Qzt_=cXKfxk`w#n1n>}TFE&9*d|M^S; z-$Ath{d(CR_zt4}-^-f7cM$deTs8&1gQ)*f&wWA*4z8E~?)Ceg;lG{!@ZXNdXpi{E zf3%%dn4^FCUxkjN$3Xun`@j1b34909?_aNr9f9v4>i?)r1-^r*|En?)_zt4}Rq6?7 zupQvP+m7&$|32?y^iTivzx@AT`s}RDV`u-#x&Ms6>TlnG?I7C!-eNBB9Yp=V)r%j% zcM$deRQ-eRAnLzq8iDTs|Gq<~L;U04=_mUv{nLN;hMo1(Km9xXWS^yf`p@35v;JuR EKX0Xo-v9sr
literal 0 HcmV?d00001
diff --git a/dlls/evr/tests/rgb32frame.bmp b/dlls/evr/tests/rgb32frame.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9f2ea1e5d1b2b808f3671b09c19ed6fcd090de85 GIT binary patch literal 36918 zcmeI*u}Yg^9EI^Cp-Y{_DXoJ;g<gTswR>Gccke(i!PP-=^b)K~Zl@ik*$ag_DEVIB zs5js_AC!Oc1db^3!j~V9MuH??za3ub`F7Ype(pPd-In(IXZ`m2{g*FZJ`TemmK(IQ zCTG~^_A5ijesu<a{MVrY`X8rbw*~z1ciUNqbM#OD>(H@#ALzek|36w2%MINA@47$B z4P5_^j}KzGf$Kl}_g5@8aQ)SmVz~kSxna^F{`e>TR6k4q^k2Q<<ofBK{*!*HpLP2` zZF8~Q!1X_93$fh5_5bxa70V4=|I0r|V!46q-=BUK8^OT*|2OPMuwONd|Ns3t#vlJp zek`GX`ltW5KMrrQ*_ij;{QYy=w#9M-_wUc&Z6cN%xc+<nX>*nvxc=YoC6*hw{_2lG zEH}VEH%vOjAOEDE>SyVn{;M~fTtEHOf6`C&v-D5@)f-N(-|c^?K`b}GKQ~M|#2^2p zpXz7npZ=>ioLoQs(|^)W^|SO(|J55#uHWtd=6w^(4P5`bNq_Ad78|(!AM_xW8@T>6 z_1C^(v4QKa{_H2q4e-wmlMeC6Kk29XS^B5{>J2B?Pyh6v^i%z;+yBYVTr4+m{Xe~1 zh~);Z|4&WDas$`@LPuh`f$KkPNh~+OKQ~M|#2^2ppXz7npZ=>ioLoQs(|^)W^|NmO z3w;sG4P5_w?TY0Fu75l4?_17tgEQ~_-`jOR$8rPLpL1`2%|gsDqX8PA0UDqI8lV9h MpaB}7fpQHz0TpqG-v9sr
literal 0 HcmV?d00001