diff options
author | alexzhornyak <alexander.zhornyak@gmail.com> | 2017-05-13 21:39:11 (GMT) |
---|---|---|
committer | alexzhornyak <alexander.zhornyak@gmail.com> | 2017-05-13 21:39:11 (GMT) |
commit | b3c8edc7788fc6bcdd941ecdee5435957bc08366 (patch) | |
tree | 4e4238ad748c5f9e7baf28a24783bb2cccc07cdd | |
parent | 43370419fb7a9f14d85f96f39ffff86a337756d4 (diff) | |
parent | 82087b37adc295d1aab5afd51f855f8d9f0923f8 (diff) | |
download | uscxml-b3c8edc7788fc6bcdd941ecdee5435957bc08366.zip uscxml-b3c8edc7788fc6bcdd941ecdee5435957bc08366.tar.gz uscxml-b3c8edc7788fc6bcdd941ecdee5435957bc08366.tar.bz2 |
Merge branch 'Improving-EvalAsData' into Explicit-Eval
-rw-r--r-- | src/uscxml/interpreter/BasicContentExecutor.cpp | 42 | ||||
-rw-r--r-- | src/uscxml/interpreter/ContentExecutorImpl.h | 1 | ||||
-rw-r--r-- | src/uscxml/interpreter/InterpreterImpl.h | 4 | ||||
-rw-r--r-- | src/uscxml/messages/Event.h | 8 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModel.cpp | 4 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModel.h | 2 | ||||
-rw-r--r-- | src/uscxml/plugins/DataModelImpl.h | 6 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp | 127 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/lua/LuaDataModel.h | 1 | ||||
-rw-r--r-- | src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h | 1 | ||||
-rw-r--r-- | test/issues/test-issue116.scxml | 43 | ||||
-rw-r--r-- | test/w3c/lua/test562.scxml | 176 |
12 files changed, 329 insertions, 86 deletions
diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp index 7ffda91..932d579 100644 --- a/src/uscxml/interpreter/BasicContentExecutor.cpp +++ b/src/uscxml/interpreter/BasicContentExecutor.cpp @@ -67,7 +67,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { sendEvent.name = ATTR(element, kXMLCharEvent); } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element eventexpr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element eventexpr", element); } try { @@ -78,7 +78,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { target = ATTR(element, kXMLCharTarget); } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element targetexpr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element targetexpr", element); } try { @@ -89,7 +89,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { type = ATTR(element, kXMLCharType); } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element typeexpr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element typeexpr", element); } try { @@ -124,7 +124,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { } } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element idlocation", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element idlocation", element); } try { @@ -148,14 +148,14 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { } } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element delayexpr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element delayexpr", element); } try { // namelist processNameLists(sendEvent.namelist, element); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element namelist", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element namelist", element); } @@ -163,7 +163,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { // params processParams(sendEvent.params, element); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element param expr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element param expr", element); } try { @@ -173,7 +173,7 @@ void BasicContentExecutor::processSend(XERCESC_NS::DOMElement* element) { sendEvent.data = elementAsData(contents.front()); } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element content", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element content", element); } // if (sendReq->dom) { @@ -431,14 +431,14 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) { element->setUserData(kXMLCharInvokeId, (void*)invokeId, NULL); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in invoke element idlocation", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in invoke element idlocation", element); } try { // namelist processNameLists(invokeEvent.namelist, element); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element namelist", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element namelist", element); } @@ -446,7 +446,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) { // params processParams(invokeEvent.params, element); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in send element param expr", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in send element param expr", element); } try { @@ -467,7 +467,7 @@ void BasicContentExecutor::invoke(XERCESC_NS::DOMElement* element) { #endif } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in invoke element content", element); + ERROR_EXECUTION_THROW3(e,"Syntax error in invoke element content", element); } // autoforward @@ -513,7 +513,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC // namelist processNameLists(doneEvent.namelist, doneData); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in donedata element namelist", doneData); + ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element namelist", doneData); } @@ -521,7 +521,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC // params processParams(doneEvent.params, doneData); } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in donedata element param expr", doneData); + ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element param expr", doneData); } try { @@ -531,7 +531,7 @@ void BasicContentExecutor::raiseDoneEvent(XERCESC_NS::DOMElement* state, XERCESC doneEvent.data = elementAsData(contents.front()); } } catch (Event e) { - ERROR_EXECUTION_THROW2("Syntax error in donedata element content", doneData); + ERROR_EXECUTION_THROW3(e,"Syntax error in donedata element content", doneData); } } catch (ErrorEvent exc) { @@ -691,9 +691,19 @@ Data BasicContentExecutor::elementAsData(XERCESC_NS::DOMElement* element, bool a contentSS << X((*textIter)->getNodeValue()); } + // this must be handled in getAsData // test294, test562 if (LOCALNAME(element) == "content") { - return Data(spaceNormalize(contentSS.str()), Data::VERBATIM); + // need first try getAsData because how to pass 179 ? + try { + // test153, we need to throw for test150 in promela + Data d = _callbacks->getAsData(contentSS.str()); + if (!d.empty()) + return d; + } + catch (ErrorEvent &) { + return Data(spaceNormalize(contentSS.str()), Data::VERBATIM); + } } if (asExpression) // not actually used, but likely expected diff --git a/src/uscxml/interpreter/ContentExecutorImpl.h b/src/uscxml/interpreter/ContentExecutorImpl.h index 5f0acfe..fd6be89 100644 --- a/src/uscxml/interpreter/ContentExecutorImpl.h +++ b/src/uscxml/interpreter/ContentExecutorImpl.h @@ -59,6 +59,7 @@ public: uint32_t iteration) = 0; virtual Data evalAsData(const std::string& expr) = 0; + virtual void eval(const std::string& content) { evalAsData(expr); } virtual Data getAsData(const std::string& expr) = 0; virtual void assign(const std::string& location, const Data& data, const std::map<std::string, std::string>& attrs) = 0; diff --git a/src/uscxml/interpreter/InterpreterImpl.h b/src/uscxml/interpreter/InterpreterImpl.h index a68298b..fd6d393 100644 --- a/src/uscxml/interpreter/InterpreterImpl.h +++ b/src/uscxml/interpreter/InterpreterImpl.h @@ -187,6 +187,10 @@ public: return _dataModel.evalAsData(expr); } + virtual void eval(const std::string& content) { + _dataModel.eval(content); + } + virtual Data getAsData(const std::string& expr) { return _dataModel.getAsData(expr); } diff --git a/src/uscxml/messages/Event.h b/src/uscxml/messages/Event.h index b774f8a..fd9dd42 100644 --- a/src/uscxml/messages/Event.h +++ b/src/uscxml/messages/Event.h @@ -77,6 +77,14 @@ throw exc;\ } +#define ERROR_EXECUTION_THROW3(evt,caption,node) \ +{\ + auto it = evt.data.compound.find("cause"); \ + ERROR_EXECUTION2(exc,it!=evt.data.compound.end() ? it->second.atom : "",node); \ + exc.data.compound["caption"] = uscxml::Data(caption, uscxml::Data::VERBATIM); \ + throw exc;\ +} + #define ERROR_COMMUNICATION_THROW(cause) \ {\ ERROR_COMMUNICATION(exc, cause); \ diff --git a/src/uscxml/plugins/DataModel.cpp b/src/uscxml/plugins/DataModel.cpp index 07fd4b4..cf4dda2 100644 --- a/src/uscxml/plugins/DataModel.cpp +++ b/src/uscxml/plugins/DataModel.cpp @@ -42,6 +42,10 @@ Data DataModel::evalAsData(const std::string& content) { return _impl->evalAsData(content); } +void DataModel::eval(const std::string& content) { + _impl->eval(content); +} + bool DataModel::evalAsBool(const std::string& expr) { return _impl->evalAsBool(expr); } diff --git a/src/uscxml/plugins/DataModel.h b/src/uscxml/plugins/DataModel.h index 9185cc8..484f1cc 100644 --- a/src/uscxml/plugins/DataModel.h +++ b/src/uscxml/plugins/DataModel.h @@ -54,6 +54,8 @@ public: virtual Data getAsData(const std::string& content); /// @copydoc DataModelImpl::evalAsData() virtual Data evalAsData(const std::string& content); + /// @copydoc DataModelImpl::eval() + virtual void eval(const std::string& content); /// @copydoc DataModelImpl::evalAsBool() virtual bool evalAsBool(const std::string& expr); diff --git a/src/uscxml/plugins/DataModelImpl.h b/src/uscxml/plugins/DataModelImpl.h index a804ea3..62453a8 100644 --- a/src/uscxml/plugins/DataModelImpl.h +++ b/src/uscxml/plugins/DataModelImpl.h @@ -173,6 +173,12 @@ public: virtual Data evalAsData(const std::string& content) = 0; /** + * evaluating script content without return + * @param mostly used in script content. + */ + virtual void eval(const std::string& content) { evalAsData(content); } + + /** * Evaluate a given expression as a boolean. * This function is a subset of evalAsData() but saves on creating and copying a Data object. * @param expr An expression in the data-model's language. diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp index 94d2467..ea90e8c 100644 --- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp +++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.cpp @@ -79,9 +79,12 @@ static int luaEval(lua_State* luaState, const std::string& expr) { static Data getLuaAsData(lua_State* _luaState, const luabridge::LuaRef& lua) { Data data; if (lua.isFunction()) { - // TODO: this might lead to a stack-overflow - luabridge::LuaRef luaEvald = lua(); - return getLuaAsData(_luaState, luaEvald); + // we are creating __tmpFunc + // then it will be assigned to data variable + luabridge::setGlobal(_luaState, lua, "__tmpFunc"); + + data.atom = "__tmpFunc"; + data.type = Data::INTERPRETED; } else if(lua.isLightUserdata() || lua.isUserdata()) { // not sure what to do } else if(lua.isThread()) { @@ -208,17 +211,24 @@ int LuaDataModel::luaInFunction(lua_State * l) { std::shared_ptr<DataModelImpl> LuaDataModel::create(DataModelCallbacks* callbacks) { std::shared_ptr<LuaDataModel> dm(new LuaDataModel()); - dm->_callbacks = callbacks; - dm->setup(); + + dm->doCreate(callbacks); + return dm; } -void LuaDataModel::setup() { - _luaState = luaL_newstate(); - luaL_openlibs(_luaState); +LuaDataModel::~LuaDataModel() { + if (_luaState != NULL) + lua_close(_luaState); +} + +void LuaDataModel::doCreate(DataModelCallbacks* callbacks) { + this->_callbacks = callbacks; + this->_luaState = luaL_newstate(); + luaL_openlibs(this->_luaState); try { - const luabridge::LuaRef& requireFunc = luabridge::getGlobal(_luaState, "require"); + const luabridge::LuaRef& requireFunc = luabridge::getGlobal(this->_luaState, "require"); if (requireFunc.isFunction()) { const luabridge::LuaRef& resultLxp = requireFunc("lxp"); const luabridge::LuaRef& resultLxpLOM = requireFunc("lxp.lom"); @@ -226,47 +236,42 @@ void LuaDataModel::setup() { // MSVC compiler bug with implicit cast operators, see comments in LuaRef class if ((bool)resultLxp && (bool)resultLxpLOM) { _luaHasXMLParser = true; - luabridge::setGlobal(_luaState, resultLxp, "lxp"); - luabridge::setGlobal(_luaState, resultLxpLOM, "lxp.lom"); + luabridge::setGlobal(this->_luaState, resultLxp, "lxp"); + luabridge::setGlobal(this->_luaState, resultLxpLOM, "lxp.lom"); } } - } catch (luabridge::LuaException e) { - LOG(_callbacks->getLogger(), USCXML_INFO) << e.what() << std::endl; + } + catch (luabridge::LuaException e) { + LOG(this->_callbacks->getLogger(), USCXML_INFO) << e.what() << std::endl; } - luabridge::getGlobalNamespace(_luaState).beginClass<LuaDataModel>("DataModel").endClass(); - luabridge::setGlobal(_luaState, this, "__datamodel"); + luabridge::getGlobalNamespace(this->_luaState).beginClass<LuaDataModel>("DataModel").endClass(); + luabridge::setGlobal(this->_luaState, this, "__datamodel"); - luabridge::getGlobalNamespace(_luaState).addCFunction("In", luaInFunction); + luabridge::getGlobalNamespace(this->_luaState).addCFunction("In", luaInFunction); - luabridge::LuaRef ioProcTable = luabridge::newTable(_luaState); - std::map<std::string, IOProcessor> ioProcs = _callbacks->getIOProcessors(); + luabridge::LuaRef ioProcTable = luabridge::newTable(this->_luaState); + std::map<std::string, IOProcessor> ioProcs = this->_callbacks->getIOProcessors(); std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcs.begin(); - while(ioProcIter != ioProcs.end()) { + while (ioProcIter != ioProcs.end()) { Data ioProcData = ioProcIter->second.getDataModelVariables(); - ioProcTable[ioProcIter->first] = getDataAsLua(_luaState, ioProcData); + ioProcTable[ioProcIter->first] = getDataAsLua(this->_luaState, ioProcData); ioProcIter++; } - luabridge::setGlobal(_luaState, ioProcTable, "_ioprocessors"); + luabridge::setGlobal(this->_luaState, ioProcTable, "_ioprocessors"); - luabridge::LuaRef invTable = luabridge::newTable(_luaState); - std::map<std::string, Invoker> invokers = _callbacks->getInvokers(); + luabridge::LuaRef invTable = luabridge::newTable(this->_luaState); + std::map<std::string, Invoker> invokers = this->_callbacks->getInvokers(); std::map<std::string, Invoker>::const_iterator invIter = invokers.begin(); - while(invIter != invokers.end()) { + while (invIter != invokers.end()) { Data invData = invIter->second.getDataModelVariables(); - invTable[invIter->first] = getDataAsLua(_luaState, invData); + invTable[invIter->first] = getDataAsLua(this->_luaState, invData); invIter++; } - luabridge::setGlobal(_luaState, invTable, "_invokers"); - - luabridge::setGlobal(_luaState, _callbacks->getName(), "_name"); - luabridge::setGlobal(_luaState, _callbacks->getSessionId(), "_sessionid"); - -} + luabridge::setGlobal(this->_luaState, invTable, "_invokers"); -LuaDataModel::~LuaDataModel() { - if (_luaState != NULL) - lua_close(_luaState); + luabridge::setGlobal(this->_luaState, this->_callbacks->getName(), "_name"); + luabridge::setGlobal(this->_luaState, this->_callbacks->getSessionId(), "_sessionid"); } void LuaDataModel::addExtension(DataModelExtension* ext) { @@ -353,49 +358,25 @@ void LuaDataModel::setEvent(const Event& event) { Data LuaDataModel::evalAsData(const std::string& content) { Data data; - ErrorEvent originalError; std::string trimmedExpr = boost::trim_copy(content); - try { - int retVals = luaEval(_luaState, "return(" + trimmedExpr + ")"); - if (retVals == 1) { - data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1)); - } - lua_pop(_luaState, retVals); - return data; - } catch (ErrorEvent e) { - originalError = e; - } - - int retVals = 0; - try { - // evaluate again without the return() - retVals = luaEval(_luaState, trimmedExpr); - } catch (ErrorEvent e) { - throw originalError; // we will assume syntax error and throw - } - -#if 1 - // Note: Empty result is not an error test302, but how to do test488? - if (retVals == 0 && !isValidSyntax(trimmedExpr)) { - throw originalError; // we will assume syntax error and throw + int retVals = luaEval(_luaState, "return(" + trimmedExpr + ")"); + if (retVals == 1) { + data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1)); } -#endif + lua_pop(_luaState, retVals); + return data; +} - try { - if (retVals == 1) { - data = getLuaAsData(_luaState, luabridge::LuaRef::fromStack(_luaState, -1)); - } - lua_pop(_luaState, retVals); - return data; +void LuaDataModel::evalAsScript(const std::string& content) { + Data data; - } catch (ErrorEvent e) { - throw e; // we will assume syntax error and throw - } + std::string trimmedExpr = boost::trim_copy(content); + int retVals = luaEval(_luaState, trimmedExpr); - return data; + lua_pop(_luaState, retVals); } bool LuaDataModel::isValidSyntax(const std::string& expr) { @@ -508,6 +489,7 @@ void LuaDataModel::assign(const std::string& location, const Data& data, const s // JSObjectSetProperty(_ctx, JSContextGetGlobalObject(_ctx), JSStringCreateWithUTF8CString(location.c_str()), getNodeAsValue(data.node), 0, &exception); } else { +#if 0 // trigger error.execution for undefined locations, test286 test311 int retVals = luaEval(_luaState, location + " = " + location); lua_pop(_luaState, retVals); @@ -528,9 +510,14 @@ void LuaDataModel::assign(const std::string& location, const Data& data, const s if (idPath.size() == 0) return; +#endif luabridge::LuaRef lua = getDataAsLua(_luaState, data); + luabridge::setGlobal(_luaState, lua, "__tmpAssign"); + evalAsScript(location + "= __tmpAssign"); + +#if 0 if (idPath.size() == 1) { // trivial case where we reference a simple toplevel identifier luabridge::setGlobal(_luaState, lua, location.c_str()); @@ -583,7 +570,7 @@ void LuaDataModel::assign(const std::string& location, const Data& data, const s } } - +#endif // std::cout << Data::toJSON(evalAsData(location)) << std::endl; } } diff --git a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h index a43b959..93379fc 100644 --- a/src/uscxml/plugins/datamodel/lua/LuaDataModel.h +++ b/src/uscxml/plugins/datamodel/lua/LuaDataModel.h @@ -74,6 +74,7 @@ public: virtual bool evalAsBool(const std::string& expr); virtual Data evalAsData(const std::string& expr); + virtual void eval(const std::string& content); virtual Data getAsData(const std::string& content); virtual bool isDeclared(const std::string& expr); diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h index 61931c6..b030d8b 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h @@ -23,6 +23,7 @@ #include "uscxml/config.h" #include "uscxml/interpreter/InterpreterImpl.h" #include "uscxml/interpreter/BasicEventQueue.h" +#include "uscxml/interpreter/LoggingImpl.h" #include "uscxml/plugins/InvokerImpl.h" diff --git a/test/issues/test-issue116.scxml b/test/issues/test-issue116.scxml new file mode 100644 index 0000000..ca1cc56 --- /dev/null +++ b/test/issues/test-issue116.scxml @@ -0,0 +1,43 @@ +<scxml datamodel="lua" initial="StateShape1" name="ScxmlShape1" version="1.0" xmlns="http://www.w3.org/2005/07/scxml"> + <datamodel> + <data id="varFunc1">function() + print("Hello from function") +end + </data> + <data id="varFunc2">function() + return 2 +end + </data> + <data expr="nil" id="varFunc3"/> + </datamodel> + <final id="Pass"> + <onentry> + <log expr=""Pass"" label="Outcome"/> + </onentry> + </final> + <final id="Fail"> + <onentry> + <log expr=""Fail"" label="Outcome"/> + </onentry> + </final> + <state id="StateShape1"> + <onentry> + <assign expr="varFunc2" location="varFunc3"/> + <assign expr="function() + return 4 +end" location="varFunc4"/> + <log expr="''" label="Test"/> + <script>print("this is from Script!") + +print(string.format("varFunc3()==%d",varFunc3())) +print(string.format("varFunc2()==%d",varFunc2())) + +varFunc1() + +print(string.format("varFunc4()==%d",varFunc4())) + </script> + </onentry> + <transition cond="varFunc4()==4 and varFunc3()==2" target="Pass"/> + <transition target="Fail"/> + </state> +</scxml>
\ No newline at end of file diff --git a/test/w3c/lua/test562.scxml b/test/w3c/lua/test562.scxml new file mode 100644 index 0000000..3be5072 --- /dev/null +++ b/test/w3c/lua/test562.scxml @@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scxml datamodel="lua" initial="s0" name="ScxmlShape1" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" xmlns:conf="http://www.w3.org/2005/scxml-conformance"> + <state id="s0"> + <onentry> + <send event="foo"> + <content> +this is a +string + </content> + </send> + </onentry> + <transition cond="_event.data == 'this is a string'" event="foo" target="pass"/> + <transition event="*" target="fail"/> + </state> + <final id="pass"> + <onentry> + <log expr="'pass'" label="Outcome"/> + </onentry> + </final> + <final id="fail"> + <onentry> + <log expr="'fail'" label="Outcome"/> + </onentry> + </final> +</scxml><!--VFBGMAdUVHJlZUV4AARMZWZ0AhEDVG9wAhEFV2lkdGgDUgQGSGVpZ2h0A8ABCURlc2lnbmluZw +kMR3JpZC5WaXNpYmxlCQtQYWdlLkhlaWdodAMiBApQYWdlLldpZHRoAwMDD1BhZ2UuVXNlUHJpb +nRlcggVU2VsZWN0ZWQuU2Nyb2xsVG9WaWV3CA5TaG93SGludFNoYXBlcwgRVmVydFNjcm9sbEJh +ci5NYXgDCQIWVmVydFNjcm9sbEJhci5QYWdlU2l6ZQPAARVWZXJ0U2Nyb2xsQmFyLlZpc2libGU +JDVpvb20uUGVuLk1vZGUHCHBtTm90WG9yBUFsaWduBwhhbENsaWVudAhUYWJPcmRlcgIDAAtUU2 +N4bWxTaGFwZQtTY3htbFNoYXBlMQhBdXRvU2l6ZQgJUm91bmRTaXplAgoOU2hhZG93LlZpc2lib +GUIAlgwAh4CWDEDEgICWTACFAJZMQMIAghFeHBhbmRlZAkKSW1hZ2VJbmRleAcGdGlOb25lDlRl +eHQuVmVydEFsaWduBwZ2dGFUb3AMVGV4dC5TdHJpbmdzAQYLU2N4bWxTaGFwZTEAC0V4dHJhUGF +yYW1zBjV4bWxuczpjb25mPWh0dHA6Ly93d3cudzMub3JnLzIwMDUvc2N4bWwtY29uZm9ybWFuY2 +UNCglTY3htbE5hbWUGC1NjeG1sU2hhcGUxB0luaXRpYWwGAnMwCURhdGFtb2RlbAYDbHVhAAALV +FN0YXRlU2hhcGULU3RhdGVTaGFwZTEIQXV0b1NpemUIDEJvcmRlci5Db2xvcgT/gAAADEJvcmRl +ci5XaWR0aAICC0JydXNoLkNvbG9yBIDW/wAFQ29sb3IEgNb/AAlSb3VuZFNpemUCCg5TaGFkb3c +uVmlzaWJsZQgFU3R5bGUHEXRzc1JvdW5kUmVjdGFuZ2xlAlgwAjwCWDEDoAACWTACMgJZMQJkCE +V4cGFuZGVkCQpJbWFnZUluZGV4BwZ0aU5vbmUGUGFyZW50BxdUcmVlRWRpdG9yMS5TY3htbFNoY +XBlMQxUZXh0LlN0cmluZ3MBBgJzMAACSWQGAnMwCUlzSW5pdGlhbAkAABJUT25FbnRyeVN0YXRl +U2hhcGUST25FbnRyeVN0YXRlU2hhcGUxEUltYWdlLlRyYW5zcGFyZW50CQpJbWFnZS5EYXRhCvw +BAAAJVFBuZ0ltYWdliVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAA +sSAAALEgHS3X78AAAABGdBTUEAALGOfPtRkwAAAZRJREFUeNqdkk1LQkEUht9JS1PCWyC1kFZBE +AbXRWSBoLSKNkFpRAuVwF/Quh/SRl20adWuVSi0SFqkiARR2qZSy/zIvH5d7zT3cs0wbeEL7xzm +MM+ZYc4hlFKMIiKDhJBexg4fW73MvJpJMIcRQ6h7RGF+QDs4lossL1t5q2MJ0/MmCG0B6fsM0rE +nvD7m5AIuVqDcD8bdezv8zAqHTDGDWkOA0BSU2O600bhrIneTTzDQ1gPXiI/dFFz3rv6BlMjcFk +XQmAQhW/fTaxpSQK2DRDwBt7PAFQZCQqOOltjC+IcW0q0YFa+oSwH1G6TkPz7kkm+poZAsjaSB9 +qpTblzSaQU0bpLS7tE+l8ymhkJdGa5Rrl2ooGmbRGxbq85XUvgX0lQB4wOilXP1qTMe4jNbZoOt +RR0rVxkIyTK+ABMl+Itn6ufI7TAfID61YObzkzXlxn7pP4GpHBLvp7/bwcA5LzgyhojGpOfLBtY +3HYUICbomMPnFXEWCSnDlwv0DoMoSgI9tvSDqyFEGUISfTwaM3Cj6BmO5JfTInnBwAAAAAElFTk +SuQmCCDlNoYWRvdy5WaXNpYmxlCAhFeHBhbmRlZAkKSW1hZ2VJbmRleAcGdGlOb25lBlBhcmVud +AcXVHJlZUVkaXRvcjEuU3RhdGVTaGFwZTEMVGV4dC5TdHJpbmdzAQYHb25lbnRyeQAAAApUU2Vu +ZFNoYXBlClNlbmRTaGFwZTERSW1hZ2UuVHJhbnNwYXJlbnQJCkltYWdlLkRhdGEKVwMAAAlUUG5 +nSW1hZ2WJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAAJcEhZcwAACToAAAk6Af +BkkkoAAAL/SURBVHjapZNLTBNRGIXP7Uw740yhUWNViIAaogtFMFFjE1M1UagvEkGNqHHhpksX7 +twoJtYViXHRxCe28RE1LnSDCBQNCsGyIFqgtbRALbGlYk2hlnl6Oz4SF66c2dw7uef7/3P/M0TX +dfzPQ440Hz7ncGzfvaZq9YKqKtDpiz9Muvu1ZhgTpAWJ6ezq/jQ1lThrZlnJAFy72uZzOneeqqi +soocINFWDpmlUqKGoLq5NJhNkRUY8FkMwGIxQwEb2N+C+v917qLHRrelUrKmwWq1QVRX6LwjDMP +g6+wVj4Qiq165BaCQUDPS+dvAcJxsA350b3gMHDrpLSm3IZDJQaAfL7csgSwWj9cnJSYyOjmJzX +R3KylaAioOv+t78DXC59hkAQgiSySSi0Qg219YiFo8jlUpj69YtEAQBnMWCvjcDwUDglYNfxMvF +uyK+dgpocLlFaykURYJUKCAciWBiMmF0UltXC1EQQT3jRaATH8Pjg5n0zDaGZWhBA3DL29BQ7xY +WCZifyxn+S202zOfzEPkSzM3l6Slg6RI7rj++iqe9D2aG+0IOntejtCaI/+5tb/3ePe6iH0VRII +oiGFpNkVXced6GAslCUwAza0H2exriMmqjp3+4vyNymLqOkYf3/Dedzh1nOI4zfBbFLGum3eThe +dKCxRUEJp0zRsoyZpgZC0ysjtddgyP9HdFj5FLrhfObajY2C6JokmWJVRWVVRSdzeXmmZDatrK8 +Jm/RZBY/01UMlg5iIuBEFc9uTPSQixcvME1NRyzpdJpPpT+L8VjcmkxOi5mZr7by/U/aN7kWVkn +ff6aRxoSmEbDwQHgAE49acZRcueJBS8sJ5HI5SJKEOB3d7GwWobFBMi7f9JavU9bThKs0U6rNjq +qaXah+H8B4jx+NiRGEiMdzGcePtxiAAh1hEfAtO4/OPh8GPwToCEEY6mA6Cr1yA1p3nsTprttoo +Nc0Sr/hH4A5dL99gKHwS9gWA9kUEB0C7JU4WlaNOLXyjhOAxBgF/O/v/AN+1H00GUkzLwAAAABJ +RU5ErkJggg5TaGFkb3cuVmlzaWJsZQgIRXhwYW5kZWQJCkltYWdlSW5kZXgHBnRpTm9uZQZQYXJ +lbnQHHlRyZWVFZGl0b3IxLk9uRW50cnlTdGF0ZVNoYXBlMQxUZXh0LlN0cmluZ3MBBgpzZW5kIH +tmb299AAVFdmVudAYDZm9vIFByb3RvY29sQ29udHJvbEJpbmRpbmcuU2N4bWxOYW1lBgNmb28gU +HJvdG9jb2xDb250cm9sQmluZGluZy5CaW5kVHlwZXMLC3BidFN1cHBsaWVyAAAADVRDb250ZW50 +U2hhcGUNQ29udGVudFNoYXBlMRFJbWFnZS5UcmFuc3BhcmVudAkKSW1hZ2UuRGF0YQr0AgAACVR +QbmdJbWFnZYlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAABl0RVh0U29mdHdhcm +UAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKMSURBVHjajdJ/SFNRFAfw7918+6Ebc1MkFHFWbOKbF +TNGk+oPBymoFCwxCRIWaZILFgzDIvqjqBAU1KgpCQYjpIRQiUosCPGfYDTSLKk0zNwc/nxPnWm+ +7iZ7+2944MLh3nM/7533DilvbEQkJBIJZAxjpWkB9hiCIAySGEAIsTrt9iZbYWE5PUh4cX1zc+F +mV1fLdCDgJSUuV2y/9kVzsye8sZHwskwuR8/gYM+rkZE7SQzznZysrxeBZxTgeT4hoFKpUO1210 +ml0k66QI7W1IhAX3u7h+O4hIBarYbd6ayjaWe09fzKShF40929J6DE4YgD+rIyERjp7Y22ML0Cv +PxB8IuTRA9y1Ds4c0CAXrPbwvGqqjiQUVwsAv6BAc/YzDKe+NZhMeggJQQMI0GSVIJ3/iAumpNh +yk7F4YqKOKC2WkXg5/Cw57r3Ewymg+C4MPJz0+D/GoClUI+p30uY8E/i/vkj2G+zxQGZ2SwCgdF +RT8WNPqSxxzAXCiFFpYBaqQS/xMHIGvF5qB8Dd+3YV1QUB4jJFAPqVny+x6Wup0CeDcHlEAQpnb +bNbeTo8xCa+gbNwjhet16Axmy+TOs9UQAGQwy4sjY+3tHQ9hZ+PhW8TA1GJoOwtYUUZTLI6jzY5 +EV0XD2FFJZtoPUPd4GsLEChiOSueZ+v5cvMEm49n8Q/TQ60Wm1k4LEQDEK5PY8H50woyE2Hwmi8 +RutbEQ5TQKcDrWRPl5bedjocZxk6XX84gv6xMKYXtyOPgCFDgdoTmSjI1kBO30puNDbRy/cwO0u +/gU7H5lssl957vTXpWm1qwimiv/WR1/uhwe1uE+bmhujOX0KUykOSzMxq7DGEtbWJnUDgI01X6e +L/A7IW5iT2WNLlAAAAAElFTkSuQmCCDlNoYWRvdy5WaXNpYmxlCApJbWFnZUluZGV4BwZ0aU5vb +mUGUGFyZW50BxZUcmVlRWRpdG9yMS5TZW5kU2hhcGUxDFRleHQuU3RyaW5ncwEGIGNvbnRlbnQg +ew0KdGhpcyBpcyAgYSAgDQpzdHJpbmd9AAxYTUxUZXh0LlRleHQGFg0KdGhpcyBpcyAgYSAgDQp +zdHJpbmcAAAtURmluYWxTaGFwZQtGaW5hbFNoYXBlMQhBdXRvU2l6ZQgJUm91bmRTaXplAgoOU2 +hhZG93LlZpc2libGUIBVN0eWxlBwl0c3NDaXJjbGUCWDADlgACWDEDrwACWTADBAECWTEDHQEIR +XhwYW5kZWQJCkltYWdlSW5kZXgHBnRpTm9uZQZQYXJlbnQHF1RyZWVFZGl0b3IxLlNjeG1sU2hh +cGUxD1RleHQuVmVydE9mZnNldALODFRleHQuU3RyaW5ncwEGBHBhc3MAAklkBgRwYXNzAAASVE9 +uRW50cnlTdGF0ZVNoYXBlEk9uRW50cnlTdGF0ZVNoYXBlMhFJbWFnZS5UcmFuc3BhcmVudAkKSW +1hZ2UuRGF0YQr8AQAACVRQbmdJbWFnZYlQTkcNChoKAAAADUlIRFIAAAAOAAAADggGAAAAH0gt0 +QAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjnz7UZMAAAGUSURBVHjanZJNS0JBFIbf +SUtTwlsgtZBWQRAG10VkgaC0ijZBaUQLlcBf0Lof0kZdtGnVrlUotEhapIgEUdqmUsv8yLx+Xe8 +093LNMG3hC+8c5jDPmWHOIZRSjCIig4SQXsYOH1u9zLyaSTCHEUOoe0RhfkA7OJaLLC9beatjCd +PzJghtAen7DNKxJ7w+5uQCLlag3A/G3Xs7/MwKh0wxg1pDgNAUlNjutNG4ayJ3k08w0NYD14iP3 +RRc967+gZTI3BZF0JgEIVv302saUkCtg0Q8AbezwBUGQkKjjpbYwviHFtKtGBWvqEsB9Ruk5D8+ +5JJvqaGQLI2kgfaqU25c0mkFNG6S0u7RPpfMpoZCXRmuUa5dqKBpm0RsW6vOV1L4F9JUAeMDopV +z9akzHuIzW2aDrUUdK1cZCMkyvgATJfiLZ+rnyO0wHyA+tWDm85M15cZ+6T+BqRwS76e/28HAOS +84MoaIxqTnywbWNx2FCAm6JjD5xVxFgkpw5cL9A6DKEoCPbb0g6shRBlCEn08GjNwo+gZjuSX0y +J5wcAAAAABJRU5ErkJggg5TaGFkb3cuVmlzaWJsZQgIRXhwYW5kZWQJCkltYWdlSW5kZXgHBnRp +Tm9uZQZQYXJlbnQHF1RyZWVFZGl0b3IxLkZpbmFsU2hhcGUxDFRleHQuU3RyaW5ncwEGB29uZW5 +0cnkAAAAJVExvZ1NoYXBlCUxvZ1NoYXBlMRFJbWFnZS5UcmFuc3BhcmVudAkKSW1hZ2UuRGF0YQ +pBAgAACVRQbmdJbWFnZYlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAARnQU1BA +ACvyDcFiukAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAByUlEQVR42mP8 +//8/AyWAkWoGVFRUoJj07ds3hk+fPjG8f/+e4d27dwxv374Fs3/+Y2H4y8TO8PH5HUaSXRA9/4k +okDoIxOJAbLs0UeYahgvw2Wydv5jBxUybgfHfX4YDNz68+fnjuz1RLoDZbCLNoqknwcbw8fMfhl +N33jEcufpkE9yAvLy8Umw2/+cS47bImpdpoykhZijDyXDm5icGMT42hgMXHzKcu/5oGU4X/NrLK +PHsh6L7pc8Wvc+40oVVFXThmvecvsNw+uq9vb9//PTFagBQs/d/Fokt/3ktGZj4LRm+XGlk2PVr +AsN3Pi+GHcdvMJy6eHvvn9+/fR9vyfmO1YDvOxkDGUUD17GpFQI51xn+/OJneHsolmHivTaGpcc +59gKVgDXjjMav2xijmCSilrLJWjMwfDnNwMjrxPDp3imGvtX3bs+/7qkP04zTgI+bGNNYZNNm/h +e2YmBn+snw+ycbw5e7Kxme3jrib5jzeRPBpPxuHeO0N2wOmUIMzxl+vLt54e9vhst//zC8/vGNo +UOr8P9rrAbY2NisBFISwPTJmOf93NxG7t5ioKZumfj/N4nKCzDwaiWjKFAjg2Q0qk1EG0AqAAD0 +sxPNyYZgMQAAAABJRU5ErkJggg5TaGFkb3cuVmlzaWJsZQgKSW1hZ2VJbmRleAcGdGlOb25lBlB +hcmVudAceVHJlZUVkaXRvcjEuT25FbnRyeVN0YXRlU2hhcGUyDFRleHQuU3RyaW5ncwEGFGxvZy +B7T3V0Y29tZToncGFzcyd9AAVMYWJlbAYHT3V0Y29tZQRFeHByBgYncGFzcycAAAtURmluYWxTa +GFwZQtGaW5hbFNoYXBlMghBdXRvU2l6ZQgJUm91bmRTaXplAgoOU2hhZG93LlZpc2libGUIBVN0 +eWxlBwl0c3NDaXJjbGUCWDADIgECWDEDOwECWTAD6wACWTEDBAEIRXhwYW5kZWQJCkltYWdlSW5 +kZXgHBnRpTm9uZQZQYXJlbnQHF1RyZWVFZGl0b3IxLlNjeG1sU2hhcGUxD1RleHQuVmVydE9mZn +NldALODFRleHQuU3RyaW5ncwEGBGZhaWwAAklkBgRmYWlsAAASVE9uRW50cnlTdGF0ZVNoYXBlE +k9uRW50cnlTdGF0ZVNoYXBlMxFJbWFnZS5UcmFuc3BhcmVudAkKSW1hZ2UuRGF0YQr8AQAACVRQ +bmdJbWFnZYlQTkcNChoKAAAADUlIRFIAAAAOAAAADggGAAAAH0gt0QAAAAlwSFlzAAALEgAACxI +B0t1+/AAAAARnQU1BAACxjnz7UZMAAAGUSURBVHjanZJNS0JBFIbfSUtTwlsgtZBWQRAG10Vkga +C0ijZBaUQLlcBf0Lof0kZdtGnVrlUotEhapIgEUdqmUsv8yLx+Xe8093LNMG3hC+8c5jDPmWHOI +ZRSjCIig4SQXsYOH1u9zLyaSTCHEUOoe0RhfkA7OJaLLC9beatjCdPzJghtAen7DNKxJ7w+5uQC +Llag3A/G3Xs7/MwKh0wxg1pDgNAUlNjutNG4ayJ3k08w0NYD14iP3RRc967+gZTI3BZF0JgEIVv +302saUkCtg0Q8AbezwBUGQkKjjpbYwviHFtKtGBWvqEsB9Ruk5D8+5JJvqaGQLI2kgfaqU25c0m +kFNG6S0u7RPpfMpoZCXRmuUa5dqKBpm0RsW6vOV1L4F9JUAeMDopVz9akzHuIzW2aDrUUdK1cZC +MkyvgATJfiLZ+rnyO0wHyA+tWDm85M15cZ+6T+BqRwS76e/28HAOS84MoaIxqTnywbWNx2FCAm6 +JjD5xVxFgkpw5cL9A6DKEoCPbb0g6shRBlCEn08GjNwo+gZjuSX0yJ5wcAAAAABJRU5ErkJggg5 +TaGFkb3cuVmlzaWJsZQgIRXhwYW5kZWQJCkltYWdlSW5kZXgHBnRpTm9uZQZQYXJlbnQHF1RyZW +VFZGl0b3IxLkZpbmFsU2hhcGUyDFRleHQuU3RyaW5ncwEGB29uZW50cnkAAAAJVExvZ1NoYXBlC +UxvZ1NoYXBlMhFJbWFnZS5UcmFuc3BhcmVudAkKSW1hZ2UuRGF0YQpBAgAACVRQbmdJbWFnZYlQ +TkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAARnQU1BAACvyDcFiukAAAAZdEVYdFN +vZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAByUlEQVR42mP8//8/AyWAkWoGVFRUoJj07d +s3hk+fPjG8f/+e4d27dwxv374Fs3/+Y2H4y8TO8PH5HUaSXRA9/4kokDoIxOJAbLs0UeYahgvw2 +Wydv5jBxUybgfHfX4YDNz68+fnjuz1RLoDZbCLNoqknwcbw8fMfhlN33jEcufpkE9yAvLy8Umw2 +/+cS47bImpdpoykhZijDyXDm5icGMT42hgMXHzKcu/5oGU4X/NrLKPHsh6L7pc8Wvc+40oVVFXT +hmvecvsNw+uq9vb9//PTFagBQs/d/Fokt/3ktGZj4LRm+XGlk2PVrAsN3Pi+GHcdvMJy6eHvvn9 ++/fR9vyfmO1YDvOxkDGUUD17GpFQI51xn+/OJneHsolmHivTaGpcc59gKVgDXjjMav2xijmCSil +rLJWjMwfDnNwMjrxPDp3imGvtX3bs+/7qkP04zTgI+bGNNYZNNm/he2YmBn+snw+ycbw5e7Kxme +3jrib5jzeRPBpPxuHeO0N2wOmUIMzxl+vLt54e9vhst//zC8/vGNoUOr8P9rrAbY2NisBFISwPT +JmOf93NxG7t5ioKZumfj/N4nKCzDwaiWjKFAjg2Q0qk1EG0AqAAD0sxPNyYZgMQAAAABJRU5Erk +Jggg5TaGFkb3cuVmlzaWJsZQgKSW1hZ2VJbmRleAcGdGlOb25lBlBhcmVudAceVHJlZUVkaXRvc +jEuT25FbnRyeVN0YXRlU2hhcGUzDFRleHQuU3RyaW5ncwEGFGxvZyB7T3V0Y29tZTonZmFpbCd9 +AAVMYWJlbAYHT3V0Y29tZQRFeHByBgYnZmFpbCcAAA9UVHJlZUNvbm5lY3Rpb24eU3RhdGVTaGF +wZTFfT25FbnRyeVN0YXRlU2hhcGUxCUZyb21TaGFwZQcXVHJlZUVkaXRvcjEuU3RhdGVTaGFwZT +EHVG9TaGFwZQceVHJlZUVkaXRvcjEuT25FbnRyeVN0YXRlU2hhcGUxAAAPVFRyZWVDb25uZWN0a +W9uHU9uRW50cnlTdGF0ZVNoYXBlMV9TZW5kU2hhcGUxCUZyb21TaGFwZQceVHJlZUVkaXRvcjEu +T25FbnRyeVN0YXRlU2hhcGUxB1RvU2hhcGUHFlRyZWVFZGl0b3IxLlNlbmRTaGFwZTEAAA9UVHJ +lZUNvbm5lY3Rpb24YU2VuZFNoYXBlMV9Db250ZW50U2hhcGUxCUZyb21TaGFwZQcWVHJlZUVkaX +RvcjEuU2VuZFNoYXBlMQdUb1NoYXBlBxlUcmVlRWRpdG9yMS5Db250ZW50U2hhcGUxAAAPVFRyZ +WVDb25uZWN0aW9uHkZpbmFsU2hhcGUxX09uRW50cnlTdGF0ZVNoYXBlMglGcm9tU2hhcGUHF1Ry +ZWVFZGl0b3IxLkZpbmFsU2hhcGUxB1RvU2hhcGUHHlRyZWVFZGl0b3IxLk9uRW50cnlTdGF0ZVN +oYXBlMgAAD1RUcmVlQ29ubmVjdGlvbhxPbkVudHJ5U3RhdGVTaGFwZTJfTG9nU2hhcGUxCUZyb2 +1TaGFwZQceVHJlZUVkaXRvcjEuT25FbnRyeVN0YXRlU2hhcGUyB1RvU2hhcGUHFVRyZWVFZGl0b +3IxLkxvZ1NoYXBlMQAAD1RUcmVlQ29ubmVjdGlvbh5GaW5hbFNoYXBlMl9PbkVudHJ5U3RhdGVT +aGFwZTMJRnJvbVNoYXBlBxdUcmVlRWRpdG9yMS5GaW5hbFNoYXBlMgdUb1NoYXBlBx5UcmVlRWR +pdG9yMS5PbkVudHJ5U3RhdGVTaGFwZTMAAA9UVHJlZUNvbm5lY3Rpb24cT25FbnRyeVN0YXRlU2 +hhcGUzX0xvZ1NoYXBlMglGcm9tU2hhcGUHHlRyZWVFZGl0b3IxLk9uRW50cnlTdGF0ZVNoYXBlM +wdUb1NoYXBlBxVUcmVlRWRpdG9yMS5Mb2dTaGFwZTIAABdUU3RhdGVNYWNoaW5lQ29ubmVjdGlv +bg9UcmVlQ29ubmVjdGlvbjETQXJyb3dGcm9tLkJhY2tDb2xvcgcHY2xXaGl0ZRlBcnJvd0Zyb20 +uQnJ1c2guQmFja0NvbG9yBwdjbFdoaXRlDkFycm93RnJvbS5TaXplAgoPQXJyb3dGcm9tLlN0eW +xlBwljYXNDaXJjbGUMQXJyb3dUby5TaXplAgoFU3R5bGUHBmNzTGluZQlGcm9tU2hhcGUHF1RyZ +WVFZGl0b3IxLlN0YXRlU2hhcGUxB1RvU2hhcGUHF1RyZWVFZGl0b3IxLkZpbmFsU2hhcGUxClRl +eHQuQW5nbGUCWgxUZXh0LlN0cmluZ3MBBgNmb28GIV9ldmVudC5kYXRhID09ICd0aGlzIGlzIGE +gc3RyaW5nJwAFRXZlbnQGA2ZvbwlDb25kaXRpb24GIV9ldmVudC5kYXRhID09ICd0aGlzIGlzIG +Egc3RyaW5nJwZQYXJhbXMOACBQcm90b2NvbENvbnRyb2xCaW5kaW5nLlNjeG1sTmFtZQYDZm9vA +AAXVFN0YXRlTWFjaGluZUNvbm5lY3Rpb24PVHJlZUNvbm5lY3Rpb24yE0Fycm93RnJvbS5CYWNr +Q29sb3IHB2NsV2hpdGUZQXJyb3dGcm9tLkJydXNoLkJhY2tDb2xvcgcHY2xXaGl0ZQ5BcnJvd0Z +yb20uU2l6ZQIKD0Fycm93RnJvbS5TdHlsZQcJY2FzQ2lyY2xlDEFycm93VG8uU2l6ZQIKBVN0eW +xlBwZjc0xpbmUJRnJvbVNoYXBlBxdUcmVlRWRpdG9yMS5TdGF0ZVNoYXBlMQdUb1NoYXBlBxdUc +mVlRWRpdG9yMS5GaW5hbFNoYXBlMgpUZXh0LkFuZ2xlAloMVGV4dC5TdHJpbmdzAQYBKgAFRXZl +bnQGASoGUGFyYW1zDgAgUHJvdG9jb2xDb250cm9sQmluZGluZy5TY3htbE5hbWUGASoAAAA=-->
\ No newline at end of file |