Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
March 2018
- 90 participants
- 1704 messages
[PATCH v3 4/6] quartz/tests: Simply test_render_with_multithread().
by Zebediah Figura
Use CoCreateInstance directly, and try to run the graph on a real file.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/quartz/tests/filtergraph.c | 67 ++++++++---------------------------------
1 file changed, 12 insertions(+), 55 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 6c33414..8444456 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -587,78 +587,35 @@ static void test_render_run(const WCHAR *file)
static DWORD WINAPI call_RenderFile_multithread(LPVOID lParam)
{
- IFilterGraph2 *filter_graph = lParam;
+ WCHAR *filename = load_resource(avifile);
+ IFilterGraph2 *graph = lParam;
HRESULT hr;
- WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0};
- HANDLE handle;
- handle = CreateFileW(mp3file, 0, 0, NULL, CREATE_ALWAYS, 0, NULL);
- if (handle == INVALID_HANDLE_VALUE)
- {
- skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(mp3file));
- return 1;
- }
- CloseHandle(handle);
+ hr = IFilterGraph2_RenderFile(graph, filename, NULL);
+todo_wine
+ ok(SUCCEEDED(hr), "RenderFile failed: %x\n", hr);
- hr = IFilterGraph2_RenderFile(filter_graph, mp3file, NULL);
- todo_wine ok(hr == VFW_E_CANNOT_RENDER || /* xp or older + DirectX 9 */
- hr == VFW_E_NO_TRANSPORT || /* win7 or newer */
- broken(hr == CLASS_E_CLASSNOTAVAILABLE), /* xp or older + DirectX 8 or older */
- "Expected 0x%08x or 0x%08x, returned 0x%08x\n", VFW_E_CANNOT_RENDER, VFW_E_NO_TRANSPORT, hr);
+ if (SUCCEEDED(hr))
+ rungraph(graph);
- DeleteFileW(mp3file);
return 0;
}
static void test_render_with_multithread(void)
{
- HRESULT hr;
- HMODULE hmod;
- static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID rclsid, REFIID riid, void **out);
- IClassFactory *classfactory = NULL;
- static IGraphBuilder *graph_builder;
- static IFilterGraph2 *filter_graph;
+ IFilterGraph2 *graph;
HANDLE thread;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- hmod = LoadLibraryA("quartz.dll");
- if (!hmod)
- {
- skip("Fail to load quartz.dll.\n");
- return;
- }
+ graph = create_graph();
- pDllGetClassObject = (void*)GetProcAddress(hmod, "DllGetClassObject");
- if (!pDllGetClassObject)
- {
- skip("Fail to get DllGetClassObject.\n");
- return;
- }
+ thread = CreateThread(NULL, 0, call_RenderFile_multithread, graph, 0, NULL);
- hr = pDllGetClassObject(&CLSID_FilterGraph, &IID_IClassFactory, (void **)&classfactory);
- ok(hr == S_OK, "DllGetClassObject failed 0x%08x\n", hr);
- if (FAILED(hr))
- {
- skip("Can't create IClassFactory 0x%08x.\n", hr);
- return;
- }
-
- hr = IClassFactory_CreateInstance(classfactory, NULL, &IID_IUnknown, (LPVOID*)&graph_builder);
- ok(hr == S_OK, "IClassFactory_CreateInstance failed 0x%08x\n", hr);
-
- hr = IGraphBuilder_QueryInterface(graph_builder, &IID_IFilterGraph2, (void**)&filter_graph);
- ok(hr == S_OK, "IGraphBuilder_QueryInterface failed 0x%08x\n", hr);
-
- thread = CreateThread(NULL, 0, call_RenderFile_multithread, filter_graph, 0, NULL);
-
- WaitForSingleObject(thread, 1000);
- IFilterGraph2_Release(filter_graph);
- IGraphBuilder_Release(graph_builder);
- IClassFactory_Release(classfactory);
+ ok(WaitForSingleObject(thread, 1000) == WAIT_OBJECT_0, "wait failed\n");
+ IFilterGraph2_Release(graph);
CloseHandle(thread);
CoUninitialize();
- return;
}
static void test_graph_builder(void)
--
2.7.4
March 1, 2018
[PATCH v3 3/6] quartz/tests: Expand and separate media event tests.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/quartz/tests/filtergraph.c | 125 ++++++++++++++++++++++++++++------------
1 file changed, 87 insertions(+), 38 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index bf3c98f..6c33414 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -398,49 +398,98 @@ static void test_state_change(IFilterGraph2 *graph)
IMediaControl_Release(control);
}
+static void test_media_event(IFilterGraph2 *graph)
+{
+ IMediaEvent *media_event;
+ IMediaSeeking *seeking;
+ IMediaControl *control;
+ IMediaFilter *filter;
+ LONG_PTR lparam1, lparam2;
+ LONGLONG current, stop;
+ OAFilterState state;
+ int got_eos = 0;
+ HANDLE event;
+ HRESULT hr;
+ LONG code;
+
+ hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
+ ok(hr == S_OK, "QueryInterface(IMediaFilter) failed: %#x\n", hr);
+
+ hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+ ok(hr == S_OK, "QueryInterface(IMediaControl) failed: %#x\n", hr);
+
+ hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&media_event);
+ ok(hr == S_OK, "QueryInterface(IMediaEvent) failed: %#x\n", hr);
+
+ hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaSeeking, (void **)&seeking);
+ ok(hr == S_OK, "QueryInterface(IMediaEvent) failed: %#x\n", hr);
+
+ hr = IMediaControl_Stop(control);
+ ok(SUCCEEDED(hr), "Stop() failed: %#x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() timed out\n");
+
+ hr = IMediaSeeking_GetDuration(seeking, &stop);
+ ok(hr == S_OK, "GetDuration() failed: %#x\n", hr);
+ current = 0;
+ hr = IMediaSeeking_SetPositions(seeking, ¤t, AM_SEEKING_AbsolutePositioning, &stop, AM_SEEKING_AbsolutePositioning);
+ ok(hr == S_OK, "SetPositions() failed: %#x\n", hr);
+
+ hr = IMediaFilter_SetSyncSource(filter, NULL);
+ ok(hr == S_OK, "SetSyncSource() failed: %#x\n", hr);
+
+ hr = IMediaEvent_GetEventHandle(media_event, (OAEVENT *)&event);
+ ok(hr == S_OK, "GetEventHandle() failed: %#x\n", hr);
+
+ /* flush existing events */
+ while ((hr = IMediaEvent_GetEvent(media_event, &code, &lparam1, &lparam2, 0)) == S_OK);
+
+ ok(WaitForSingleObject(event, 0) == WAIT_TIMEOUT, "event should not be signaled\n");
+
+ hr = IMediaControl_Run(control);
+ ok(SUCCEEDED(hr), "Run() failed: %#x\n", hr);
+
+ while (!got_eos)
+ {
+ if (WaitForSingleObject(event, 1000) == WAIT_TIMEOUT)
+ break;
+
+ while ((hr = IMediaEvent_GetEvent(media_event, &code, &lparam1, &lparam2, 0)) == S_OK)
+ {
+ if (code == EC_COMPLETE)
+ {
+ got_eos = 1;
+ break;
+ }
+ }
+ }
+ ok(got_eos, "didn't get EOS\n");
+
+ hr = IMediaSeeking_GetCurrentPosition(seeking, ¤t);
+ ok(hr == S_OK, "GetCurrentPosition() failed: %#x\n", hr);
+todo_wine
+ ok(current == stop, "expected %s, got %s\n", wine_dbgstr_longlong(stop), wine_dbgstr_longlong(current));
+
+ hr = IMediaControl_Stop(control);
+ ok(SUCCEEDED(hr), "Run() failed: %#x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() timed out\n");
+
+ hr = IFilterGraph2_SetDefaultSyncSource(graph);
+ ok(hr == S_OK, "SetDefaultSinkSource() failed: %#x\n", hr);
+
+ IMediaSeeking_Release(seeking);
+ IMediaEvent_Release(media_event);
+ IMediaControl_Release(control);
+ IMediaFilter_Release(filter);
+}
+
static void rungraph(IFilterGraph2 *graph)
{
- HRESULT hr;
- IMediaControl* pmc;
- IMediaEvent* pme;
- IMediaFilter* pmf;
- HANDLE hEvent;
-
test_basic_video(graph);
test_mediacontrol(graph);
test_state_change(graph);
-
- hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&pmc);
- ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
-
- hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&pmf);
- ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
-
- IMediaControl_Stop(pmc);
-
- IMediaFilter_SetSyncSource(pmf, NULL);
-
- IMediaFilter_Release(pmf);
-
- hr = IMediaControl_Run(pmc);
- ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
-
- hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (LPVOID*)&pme);
- ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
-
- hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
- ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
-
- ok(WaitForSingleObject(hEvent, 2000) == WAIT_OBJECT_0, "Wait failed\n");
-
- hr = IMediaEvent_Release(pme);
- ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
-
- hr = IMediaControl_Stop(pmc);
- ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
-
- hr = IMediaControl_Release(pmc);
- ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
+ test_media_event(graph);
}
static HRESULT test_graph_builder_connect(WCHAR *filename)
--
2.7.4
March 1, 2018
[PATCH v3 2/6] quartz/tests: Expand and separate state change tests.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
v2: fix test failures
dlls/quartz/tests/filtergraph.c | 100 ++++++++++++++++++++++------------------
1 file changed, 56 insertions(+), 44 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 7116283..bf3c98f 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -346,6 +346,58 @@ static void test_mediacontrol(IFilterGraph2 *graph)
IMediaFilter_Release(filter);
}
+static void test_state_change(IFilterGraph2 *graph)
+{
+ IMediaControl *control;
+ OAFilterState state;
+ HRESULT hr;
+
+ hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+ ok(hr == S_OK, "QueryInterface(IMediaControl) failed: %x\n", hr);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Stopped, "wrong state %d\n", state);
+
+ hr = IMediaControl_Run(control);
+ ok(SUCCEEDED(hr), "Run() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, INFINITE, &state);
+ ok(SUCCEEDED(hr), "GetState() failed: %x\n", hr);
+ ok(state == State_Running, "wrong state %d\n", state);
+
+ hr = IMediaControl_Stop(control);
+ ok(SUCCEEDED(hr), "Stop() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Stopped, "wrong state %d\n", state);
+
+ hr = IMediaControl_Pause(control);
+ ok(SUCCEEDED(hr), "Pause() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Paused, "wrong state %d\n", state);
+
+ hr = IMediaControl_Run(control);
+ ok(SUCCEEDED(hr), "Run() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Running, "wrong state %d\n", state);
+
+ hr = IMediaControl_Pause(control);
+ ok(SUCCEEDED(hr), "Pause() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Paused, "wrong state %d\n", state);
+
+ hr = IMediaControl_Stop(control);
+ ok(SUCCEEDED(hr), "Stop() failed: %x\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "GetState() failed: %x\n", hr);
+ ok(state == State_Stopped, "wrong state %d\n", state);
+
+ IMediaControl_Release(control);
+}
+
static void rungraph(IFilterGraph2 *graph)
{
HRESULT hr;
@@ -354,6 +406,10 @@ static void rungraph(IFilterGraph2 *graph)
IMediaFilter* pmf;
HANDLE hEvent;
+ test_basic_video(graph);
+ test_mediacontrol(graph);
+ test_state_change(graph);
+
hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&pmc);
ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
@@ -366,53 +422,9 @@ static void rungraph(IFilterGraph2 *graph)
IMediaFilter_Release(pmf);
- test_basic_video(graph);
- test_mediacontrol(graph);
-
hr = IMediaControl_Run(pmc);
ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
- Sleep(10);
- /* Crash fun */
- trace("run -> stop\n");
- hr = IMediaControl_Stop(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
-
- IFilterGraph2_SetDefaultSyncSource(graph);
-
- Sleep(10);
- trace("stop -> pause\n");
- hr = IMediaControl_Pause(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
-
- Sleep(10);
- trace("pause -> run\n");
- hr = IMediaControl_Run(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
-
- Sleep(10);
- trace("run -> pause\n");
- hr = IMediaControl_Pause(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
-
- Sleep(10);
- trace("pause -> stop\n");
- hr = IMediaControl_Stop(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
-
- Sleep(10);
- trace("pause -> run\n");
- hr = IMediaControl_Run(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
-
- trace("run -> stop\n");
- hr = IMediaControl_Stop(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
-
- trace("stop -> run\n");
- hr = IMediaControl_Run(pmc);
- ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
-
hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (LPVOID*)&pme);
ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
--
2.7.4
March 1, 2018
[PATCH v3 1/6] quartz: Always return VFW_E_CANNOT_CONNECT from Connect() if no filter was found.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
v3: Fix test failures; sorry about the spam.
dlls/quartz/filtergraph.c | 2 +-
dlls/quartz/tests/filtergraph.c | 30 +++++++++++++++++++-----------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c
index d1643c3..60c7374 100644
--- a/dlls/quartz/filtergraph.c
+++ b/dlls/quartz/filtergraph.c
@@ -1193,7 +1193,7 @@ out:
--This->recursioncount;
LeaveCriticalSection(&This->cs);
TRACE("--> %08x\n", hr);
- return SUCCEEDED(hr) ? S_OK : hr;
+ return SUCCEEDED(hr) ? S_OK : VFW_E_CANNOT_CONNECT;
}
static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 8e9d17e..7116283 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -431,7 +431,7 @@ static void rungraph(IFilterGraph2 *graph)
ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
}
-static void test_graph_builder_connect(WCHAR *filename)
+static HRESULT test_graph_builder_connect(WCHAR *filename)
{
static const WCHAR outputW[] = {'O','u','t','p','u','t',0};
static const WCHAR inW[] = {'I','n',0};
@@ -460,11 +460,8 @@ static void test_graph_builder_connect(WCHAR *filename)
ok(hr == S_OK, "FindPin failed: %#x\n", hr);
hr = IFilterGraph2_Connect(graph, pin_out, pin_in);
- if (hr != VFW_E_NO_ACCEPTABLE_TYPES)
- {
- ok(SUCCEEDED(hr), "Connect failed: %#x\n", hr);
+ if (SUCCEEDED(hr))
rungraph(graph);
- }
IPin_Release(pin_in);
IPin_Release(pin_out);
@@ -472,6 +469,8 @@ static void test_graph_builder_connect(WCHAR *filename)
IBaseFilter_Release(video_filter);
IVideoWindow_Release(window);
IFilterGraph2_Release(graph);
+
+ return hr;
}
static void test_render_run(const WCHAR *file)
@@ -495,19 +494,28 @@ static void test_render_run(const WCHAR *file)
graph = create_graph();
hr = IFilterGraph2_RenderFile(graph, filename, NULL);
- if (hr == VFW_E_CANNOT_RENDER)
+ if (FAILED(hr))
+ {
skip("%s: codec not supported; skipping test\n", wine_dbgstr_w(file));
+
+ refs = IFilterGraph2_Release(graph);
+ ok(!refs, "Graph has %u references\n", refs);
+
+ hr = test_graph_builder_connect(filename);
+ ok(hr == VFW_E_CANNOT_CONNECT, "got %#x\n", hr);
+ }
else
{
ok(hr == S_OK || hr == VFW_S_AUDIO_NOT_RENDERED, "RenderFile failed: %x\n", hr);
rungraph(graph);
+
+ refs = IFilterGraph2_Release(graph);
+ ok(!refs, "Graph has %u references\n", refs);
+
+ hr = test_graph_builder_connect(filename);
+ ok(hr == S_OK || hr == VFW_S_PARTIAL_RENDER, "got %#x\n", hr);
}
- refs = IFilterGraph2_Release(graph);
- ok(!refs, "Graph has %u references\n", refs);
-
- test_graph_builder_connect(filename);
-
/* check reference leaks */
h = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
ok(h != INVALID_HANDLE_VALUE, "CreateFile failed: err=%d\n", GetLastError());
--
2.7.4
March 1, 2018