blob: 346b642913de52b5c6e432a0bd5b28d08d06865e [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Lei Zhanga6d9f0e2015-06-13 00:48:38 -07004
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07005// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../include/javascript/JavaScript.h"
8#include "../../include/javascript/IJavaScript.h"
9#include "../../include/javascript/JS_EventHandler.h"
10#include "../../include/javascript/JS_Runtime.h"
11#include "../../include/javascript/JS_Context.h"
12#include "../../include/javascript/JS_Define.h"
13#include "../../include/javascript/JS_Object.h"
14#include "../../include/javascript/JS_Value.h"
15#include "../../include/javascript/Document.h"
16#include "../../include/javascript/app.h"
17#include "../../include/javascript/color.h"
18#include "../../include/javascript/Consts.h"
19#include "../../include/javascript/Document.h"
20#include "../../include/javascript/event.h"
21#include "../../include/javascript/Field.h"
22#include "../../include/javascript/Icon.h"
23#include "../../include/javascript/PublicMethods.h"
24#include "../../include/javascript/report.h"
25#include "../../include/javascript/util.h"
26#include "../../include/javascript/JS_GlobalData.h"
27#include "../../include/javascript/global.h"
28#include "../../include/javascript/console.h"
Bo Xufdc00a72014-10-28 23:03:33 -070029#include "../../include/fpdfxfa/fpdfxfa_app.h"
Bo Xufdc00a72014-10-28 23:03:33 -070030#include "../../../xfa/src/fxjse/src/value.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070031
32CJS_RuntimeFactory::~CJS_RuntimeFactory()
33{
34}
35
Tom Sepez2f2ffec2015-07-23 14:42:09 -070036IFXJS_Runtime* CJS_RuntimeFactory::NewJSRuntime(CPDFDoc_Environment* pApp)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070037{
38 if (!m_bInit)
39 {
40 JS_Initial();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070041 m_bInit = TRUE;
42 }
43 return new CJS_Runtime(pApp);
44}
Tom Sepez2f2ffec2015-07-23 14:42:09 -070045void CJS_RuntimeFactory::AddRef()
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070046{
Tom Sepez2f2ffec2015-07-23 14:42:09 -070047 //to do.Should be implemented as atom manipulation.
48 m_nRef++;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070049}
Tom Sepez2f2ffec2015-07-23 14:42:09 -070050void CJS_RuntimeFactory::Release()
Lei Zhanga6d9f0e2015-06-13 00:48:38 -070051{
Tom Sepez2f2ffec2015-07-23 14:42:09 -070052 if(m_bInit)
53 {
54 //to do.Should be implemented as atom manipulation.
55 if (--m_nRef == 0)
56 {
57 JS_Release();
58 ReleaseGlobalData();
59 m_bInit = FALSE;
60 }
61 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070062}
63
Tom Sepez2f2ffec2015-07-23 14:42:09 -070064void CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070065{
Lei Zhang796c9082015-07-16 18:45:22 -070066 delete (CJS_Runtime*)pRuntime;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070067}
68
Tom Sepez2f2ffec2015-07-23 14:42:09 -070069CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070070{
Tom Sepez2f2ffec2015-07-23 14:42:09 -070071 if (m_pGlobalData)
72 {
73 m_nGlobalDataCount++;
74 return m_pGlobalData;
75 }
76 m_nGlobalDataCount = 1;
77 m_pGlobalData = new CJS_GlobalData(pApp);
78 return m_pGlobalData;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070079}
80
81void CJS_RuntimeFactory::ReleaseGlobalData()
82{
Tom Sepez2f2ffec2015-07-23 14:42:09 -070083 m_nGlobalDataCount--;
Lei Zhanga6d9f0e2015-06-13 00:48:38 -070084
Tom Sepez2f2ffec2015-07-23 14:42:09 -070085 if (m_nGlobalDataCount <= 0)
86 {
87 delete m_pGlobalData;
88 m_pGlobalData = NULL;
89 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070090}
91
Tom Sepezd2cc1b92015-04-30 15:19:03 -070092void* CJS_ArrayBufferAllocator::Allocate(size_t length) {
93 return calloc(1, length);
94}
95
96void* CJS_ArrayBufferAllocator::AllocateUninitialized(size_t length) {
97 return malloc(length);
98}
99
100void CJS_ArrayBufferAllocator::Free(void* data, size_t length) {
101 free(data);
102}
103
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700104/* ------------------------------ CJS_Runtime ------------------------------ */
Jochen Eisingerdfa2c992015-05-19 00:38:00 +0200105extern v8::Global<v8::ObjectTemplate>& _getGlobalObjectTemplate(IJS_Runtime* pJSRuntime);
Bo Xufdc00a72014-10-28 23:03:33 -0700106CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp) :
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700107 m_pApp(pApp),
108 m_pDocument(NULL),
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700109 m_bBlocking(FALSE),
Tom Sepezd2cc1b92015-04-30 15:19:03 -0700110 m_pFieldEventPath(NULL)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700111{
Tom Sepezbdeeb8a2015-05-27 12:25:00 -0700112 if (CPDFXFA_App::GetInstance()->GetJSERuntime()) {
113 m_isolate = (v8::Isolate*)CPDFXFA_App::GetInstance()->GetJSERuntime();
Tom Sepezd2cc1b92015-04-30 15:19:03 -0700114 } else {
115 m_pArrayBufferAllocator.reset(new CJS_ArrayBufferAllocator());
116 v8::Isolate::CreateParams params;
117 params.array_buffer_allocator = m_pArrayBufferAllocator.get();
118 m_isolate = v8::Isolate::New(params);
119 }
120
Bo Xufdc00a72014-10-28 23:03:33 -0700121 v8::Isolate* isolate = m_isolate;
122 v8::Isolate::Scope isolate_scope(isolate);
123 v8::Locker locker(isolate);
124 v8::HandleScope handle_scope(isolate);
Tom Sepezbdeeb8a2015-05-27 12:25:00 -0700125 if (CPDFXFA_App::GetInstance()->InitRuntime(FALSE)) {
Bo Xufdc00a72014-10-28 23:03:33 -0700126 CJS_Context * pContext = (CJS_Context*)NewContext();
127 JS_InitialRuntime(*this, this, pContext, m_context);
128 ReleaseContext(pContext);
129 return;
130 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700131
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700132 InitJSObjects();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700133
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700134 CJS_Context * pContext = (CJS_Context*)NewContext();
135 JS_InitialRuntime(*this, this, pContext, m_context);
136 ReleaseContext(pContext);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700137}
138
139CJS_Runtime::~CJS_Runtime()
140{
Bo Xufdc00a72014-10-28 23:03:33 -0700141 int size = m_ContextArray.GetSize();
142 for (int i=0;i < size; i++)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700143 delete m_ContextArray.GetAt(i);
144
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700145 m_ContextArray.RemoveAll();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700146
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700147 RemoveEventsInLoop(m_pFieldEventPath);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700148
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700149 m_pApp = NULL;
150 m_pDocument = NULL;
151 m_pFieldEventPath = NULL;
152 m_context.Reset();
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700153
Bo Xufdc00a72014-10-28 23:03:33 -0700154 m_isolate = NULL;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700155}
156
157FX_BOOL CJS_Runtime::InitJSObjects()
158{
159 v8::Isolate::Scope isolate_scope(GetIsolate());
Bo Xufdc00a72014-10-28 23:03:33 -0700160 v8::Locker locker(GetIsolate());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700161 v8::HandleScope handle_scope(GetIsolate());
Jochen Eisingerdfa2c992015-05-19 00:38:00 +0200162 v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700163 v8::Context::Scope context_scope(context);
164 //0 - 8
165 if (CJS_Border::Init(*this, JS_STATIC) < 0) return FALSE;
166 if (CJS_Display::Init(*this, JS_STATIC) < 0) return FALSE;
167 if (CJS_Font::Init(*this, JS_STATIC) < 0) return FALSE;
168 if (CJS_Highlight::Init(*this, JS_STATIC) < 0) return FALSE;
169 if (CJS_Position::Init(*this, JS_STATIC) < 0) return FALSE;
170 if (CJS_ScaleHow::Init(*this, JS_STATIC) < 0) return FALSE;
171 if (CJS_ScaleWhen::Init(*this, JS_STATIC) < 0) return FALSE;
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700172 if (CJS_Style::Init(*this, JS_STATIC) < 0) return FALSE;
173 if (CJS_Zoomtype::Init(*this, JS_STATIC) < 0) return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700174
175 //9 - 11
176 if (CJS_App::Init(*this, JS_STATIC) < 0) return FALSE;
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700177 if (CJS_Color::Init(*this, JS_STATIC) < 0) return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700178 if (CJS_Console::Init(*this, JS_STATIC) < 0) return FALSE;
179
180 //12 - 14
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700181 if (CJS_Document::Init(*this, JS_DYNAMIC) < 0) return FALSE;
182 if (CJS_Event::Init(*this, JS_STATIC) < 0) return FALSE;
183 if (CJS_Field::Init(*this, JS_DYNAMIC) < 0) return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700184
185 //15 - 17
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700186 if (CJS_Global::Init(*this, JS_STATIC) < 0) return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700187 if (CJS_Icon::Init(*this, JS_DYNAMIC) < 0) return FALSE;
188 if (CJS_Util::Init(*this, JS_STATIC) < 0) return FALSE;
189
190 if (CJS_PublicMethods::Init(*this) < 0) return FALSE;
191 if (CJS_GlobalConsts::Init(*this) < 0) return FALSE;
192 if (CJS_GlobalArrays::Init(*this) < 0) return FALSE;
193
194 if (CJS_TimerObj::Init(*this, JS_DYNAMIC) < 0) return FALSE;
195 if (CJS_PrintParamsObj::Init(*this, JS_DYNAMIC) <0) return FALSE;
196
197 return TRUE;
198}
199
200IFXJS_Context* CJS_Runtime::NewContext()
201{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700202 CJS_Context * p = new CJS_Context(this);
203 m_ContextArray.Add(p);
204 return p;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700205}
206
207void CJS_Runtime::ReleaseContext(IFXJS_Context * pContext)
208{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700209 CJS_Context* pJSContext = (CJS_Context*)pContext;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700210
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700211 for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
212 {
213 if (pJSContext == m_ContextArray.GetAt(i))
214 {
215 delete pJSContext;
216 m_ContextArray.RemoveAt(i);
217 break;
218 }
219 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700220}
221
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700222IFXJS_Context* CJS_Runtime::GetCurrentContext()
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700223{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700224 if(!m_ContextArray.GetSize())
225 return NULL;
226 return m_ContextArray.GetAt(m_ContextArray.GetSize()-1);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700227}
228
229void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc)
230{
231 if (m_pDocument != pReaderDoc)
232 {
233 v8::Isolate::Scope isolate_scope(m_isolate);
Bo Xufdc00a72014-10-28 23:03:33 -0700234 v8::Locker locker(m_isolate);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700235 v8::HandleScope handle_scope(m_isolate);
236 v8::Local<v8::Context> context =v8::Local<v8::Context>::New(m_isolate, m_context);
237 v8::Context::Scope context_scope(context);
238
239 m_pDocument = pReaderDoc;
240
241 if (pReaderDoc)
242 {
243 JSObject pThis = JS_GetThisObj(*this);
244 if(!pThis.IsEmpty())
245 {
246 if (JS_GetObjDefnID(pThis) == JS_GetObjDefnID(*this, L"Document"))
247 {
248 if (CJS_Document* pJSDocument = (CJS_Document*)JS_GetPrivate(pThis))
249 {
250 if (Document * pDocument = (Document*)pJSDocument->GetEmbedObject())
251 pDocument->AttachDoc(pReaderDoc);
252 }
253 }
254 }
255 JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"Document"));
256 }
257 else
258 {
259 JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"app"));
260 }
261 }
262}
263
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700264FX_BOOL CJS_Runtime::AddEventToLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700265{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700266 if (m_pFieldEventPath == NULL)
267 {
268 m_pFieldEventPath = new CJS_FieldEvent;
269 m_pFieldEventPath->sTargetName = sTargetName;
270 m_pFieldEventPath->eEventType = eEventType;
271 m_pFieldEventPath->pNext = NULL;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700272
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700273 return TRUE;
274 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700275
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700276 //to search
277 CJS_FieldEvent* p = m_pFieldEventPath;
278 CJS_FieldEvent* pLast = m_pFieldEventPath;
279 while (p)
280 {
281 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
282 return FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700283
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700284 pLast = p;
285 p = p->pNext;
286 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700287
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700288 //to add
289 CJS_FieldEvent* pNew = new CJS_FieldEvent;
290 pNew->sTargetName = sTargetName;
291 pNew->eEventType = eEventType;
292 pNew->pNext = NULL;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700293
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700294 pLast->pNext = pNew;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700295
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700296 return TRUE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700297}
298
299void CJS_Runtime::RemoveEventInLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
300{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700301 FX_BOOL bFind = FALSE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700302
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700303 CJS_FieldEvent* p = m_pFieldEventPath;
304 CJS_FieldEvent* pLast = NULL;
305 while (p)
306 {
307 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
308 {
309 bFind = TRUE;
310 break;
311 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700312
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700313 pLast = p;
314 p = p->pNext;
315 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700316
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700317 if (bFind)
318 {
319 RemoveEventsInLoop(p);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700320
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700321 if (p == m_pFieldEventPath)
322 m_pFieldEventPath = NULL;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700323
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700324 if (pLast)
325 pLast->pNext = NULL;
326 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700327}
328
329void CJS_Runtime::RemoveEventsInLoop(CJS_FieldEvent* pStart)
330{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700331 CJS_FieldEvent* p = pStart;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700332
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700333 while (p)
334 {
335 CJS_FieldEvent* pOld = p;
336 p = pOld->pNext;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700337
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700338 delete pOld;
339 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700340}
341
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700342v8::Local<v8::Context> CJS_Runtime::NewJSContext()
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700343{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700344 return v8::Local<v8::Context>::New(m_isolate, m_context);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700345}
346
347CFX_WideString ChangeObjName(const CFX_WideString& str)
348{
Tom Sepez2f2ffec2015-07-23 14:42:09 -0700349 CFX_WideString sRet = str;
350 sRet.Replace(L"_", L".");
351 return sRet;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700352}
Tom Sepezca3ac5e2015-06-10 17:38:11 -0700353FX_BOOL CJS_Runtime::GetHValueByName(const CFX_ByteStringC& utf8Name, FXJSE_HVALUE hValue)
Bo Xufdc00a72014-10-28 23:03:33 -0700354{
Tom Sepezd7e5cc72015-06-10 14:33:37 -0700355 const FX_CHAR* name = utf8Name.GetCStr();
Bo Xufdc00a72014-10-28 23:03:33 -0700356
357 v8::Locker lock(GetIsolate());
358 v8::Isolate::Scope isolate_scope(GetIsolate());
359 v8::HandleScope handle_scope(GetIsolate());
360 v8::Local<v8::Context> context =
361 v8::Local<v8::Context>::New(GetIsolate(), m_context);
362 v8::Context::Scope context_scope(context);
363
364
365 //v8::Local<v8::Context> tmpCotext = v8::Local<v8::Context>::New(GetIsolate(), m_context);
366 v8::Local<v8::Value> propvalue = context->Global()->Get(v8::String::NewFromUtf8(GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength()));
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700367
Bo Xufdc00a72014-10-28 23:03:33 -0700368 if (propvalue.IsEmpty()) {
369 FXJSE_Value_SetUndefined(hValue);
370 return FALSE;
371 }
372 ((CFXJSE_Value*)hValue)->ForceSetValue(propvalue);
373
374 return TRUE;
375}
Tom Sepezca3ac5e2015-06-10 17:38:11 -0700376FX_BOOL CJS_Runtime::SetHValueByName(const CFX_ByteStringC& utf8Name, FXJSE_HVALUE hValue)
Bo Xufdc00a72014-10-28 23:03:33 -0700377{
378 if (utf8Name.IsEmpty() || hValue == NULL)
379 return FALSE;
Tom Sepezd7e5cc72015-06-10 14:33:37 -0700380 const FX_CHAR* name = utf8Name.GetCStr();
Bo Xufdc00a72014-10-28 23:03:33 -0700381 v8::Isolate* pIsolate = GetIsolate();
382 v8::Locker lock(pIsolate);
383 v8::Isolate::Scope isolate_scope(pIsolate);
384 v8::HandleScope handle_scope(pIsolate);
385 v8::Local<v8::Context> context =
386 v8::Local<v8::Context>::New(pIsolate, m_context);
387 v8::Context::Scope context_scope(context);
388
389 //v8::Local<v8::Context> tmpCotext = v8::Local<v8::Context>::New(GetIsolate(), m_context);
390 v8::Local<v8::Value> propvalue = v8::Local<v8::Value>::New(GetIsolate(),((CFXJSE_Value*)hValue)->DirectGetValue());
391 context->Global()->Set(v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString, utf8Name.GetLength()), propvalue);
Lei Zhanga6d9f0e2015-06-13 00:48:38 -0700392
Bo Xufdc00a72014-10-28 23:03:33 -0700393 return TRUE;
394}