diff options
author | randomdan <randomdan@localhost> | 2011-11-02 16:39:12 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2011-11-02 16:39:12 +0000 |
commit | bc034e852ebd75557418668fa946eca55cfb4958 (patch) | |
tree | a33de1084a8f2e9b04a4111905df6d249fabed65 | |
parent | Finally sort the stupid names problem in the XML lib and remove xmlMemCache f... (diff) | |
download | project2-bc034e852ebd75557418668fa946eca55cfb4958.tar.bz2 project2-bc034e852ebd75557418668fa946eca55cfb4958.tar.xz project2-bc034e852ebd75557418668fa946eca55cfb4958.zip |
Make many things use variables instead of preread values
Add support for a Boolean type
Fix flow error in exception handling
26 files changed, 151 insertions, 56 deletions
diff --git a/project2/cgi/cgiAppEngine.cpp b/project2/cgi/cgiAppEngine.cpp index 0f15f89..ceac940 100644 --- a/project2/cgi/cgiAppEngine.cpp +++ b/project2/cgi/cgiAppEngine.cpp @@ -57,7 +57,7 @@ CgiApplicationEngine::process() const currentStage = currentStage.get<0>()->run(); } catch (const CheckHost::CheckFailure & cf) { - currentStage = NextStage(new PresentStage(_env, _env->resolveScript(_env->presentRoot, cf.failedCheck->present))); + currentStage = NextStage(new PresentStage(_env, _env->resolveScript(_env->presentRoot, cf.failedCheck->present()))); } catch (const XmlScriptParser::NotFound & nf) { if (_env->notFoundPresent.empty() || triedNotFound) { diff --git a/project2/common/fileStrmVarWriter.cpp b/project2/common/fileStrmVarWriter.cpp index a6ae728..c38c71b 100644 --- a/project2/common/fileStrmVarWriter.cpp +++ b/project2/common/fileStrmVarWriter.cpp @@ -19,6 +19,9 @@ FileStreamVariableWriter::~FileStreamVariableWriter() void FileStreamVariableWriter::operator()(const Null &) const { fprintf(out, "<null>"); } +void FileStreamVariableWriter::operator()(const Boolean & i) const { + fprintf(out, i.value ? "true" : "false"); +} void FileStreamVariableWriter::operator()(const long long int & i) const { fprintf(out, "%lld", i); } diff --git a/project2/common/fileStrmVarWriter.h b/project2/common/fileStrmVarWriter.h index b98691b..a6a5a45 100644 --- a/project2/common/fileStrmVarWriter.h +++ b/project2/common/fileStrmVarWriter.h @@ -19,6 +19,7 @@ class FileStreamVariableWriter : public boost::static_visitor<> { void operator()(const short unsigned int & i) const; void operator()(const float & i) const; void operator()(const double & i) const; + void operator()(const Boolean & i) const; void operator()(const Glib::ustring & i) const; void operator()(const boost::posix_time::ptime & i) const; diff --git a/project2/common/library.cpp b/project2/common/library.cpp index 103cb4e..476df56 100644 --- a/project2/common/library.cpp +++ b/project2/common/library.cpp @@ -9,7 +9,7 @@ SimpleMessageException(UnloadLibraryFailed); Library::Library(const xmlpp::Element * p) : SourceObject(p), - handle(dlopen(p->get_attribute_value("path").c_str(), RTLD_NOW)) + handle(dlopen(Variable(p, "path")(), RTLD_NOW)) { if (!handle) { throw LoadLibraryFailed(dlerror()); diff --git a/project2/common/paramChecker.cpp b/project2/common/paramChecker.cpp index 164d7a3..ad61b3a 100644 --- a/project2/common/paramChecker.cpp +++ b/project2/common/paramChecker.cpp @@ -6,7 +6,7 @@ ParamChecker::ParamChecker(const xmlpp::Element * p) : SourceObject(p), message(p, "message", false, "Check failed"), group(p, "group", false, "default"), - present(p->get_attribute_value("present")) + present(p, "present", false, "") { } diff --git a/project2/common/paramChecker.h b/project2/common/paramChecker.h index d013fc4..b0940c9 100644 --- a/project2/common/paramChecker.h +++ b/project2/common/paramChecker.h @@ -15,7 +15,7 @@ class ParamChecker : public SourceObject { const Variable message; const Variable group; - const std::string present; + const Variable present; }; typedef boost::intrusive_ptr<const ParamChecker> ParamCheckerCPtr; diff --git a/project2/common/rowView.cpp b/project2/common/rowView.cpp index 08f96b1..7173c19 100644 --- a/project2/common/rowView.cpp +++ b/project2/common/rowView.cpp @@ -14,8 +14,8 @@ RowView::RowView(const xmlpp::Element * p) : SourceObject(p), View(p), RowProcessor(p), - rootName(p->get_attribute_value("rootname")), - recordName(p->get_attribute_value("recordname")) + rootName(p, "rootname"), + recordName(p, "recordname") { BOOST_FOREACH(xmlpp::Node * node, p->find("columns/*")) { if (const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node)) { @@ -40,7 +40,7 @@ RowView::loadComplete(const CommonObjects * co) void RowView::rowReady(const RowState * rs) const { - presenter->pushSub(recordName); + presenter->pushSub(recordName()); if (viewColumns.empty()) { rs->foreachColumn(boost::bind(&Presenter::addField, presenter, _2, _3)); } @@ -57,7 +57,7 @@ void RowView::execute(const Presenter * p) const { presenter = p; - presenter->pushSub(rootName); + presenter->pushSub(rootName()); ScopeObject pres(boost::bind(&Presenter::popSub, p)); RowProcessor::execute(); } diff --git a/project2/common/rowView.h b/project2/common/rowView.h index c065414..2bab953 100644 --- a/project2/common/rowView.h +++ b/project2/common/rowView.h @@ -16,8 +16,8 @@ class RowView : public View, public RowProcessor { void execute(const Presenter *) const; void rowReady(const RowState *) const; - const Glib::ustring rootName; - const Glib::ustring recordName; + const Variable rootName; + const Variable recordName; protected: typedef std::map<Glib::ustring, Variable> Columns; diff --git a/project2/common/structExceptHandling.cpp b/project2/common/structExceptHandling.cpp index 56b3108..5b5f1f5 100644 --- a/project2/common/structExceptHandling.cpp +++ b/project2/common/structExceptHandling.cpp @@ -43,6 +43,8 @@ StructuredExceptionHandler::execute() const catch (...) { try { run(catches); + run(finallies); + return; } catch (...) { } diff --git a/project2/common/variableConvert.cpp b/project2/common/variableConvert.cpp index f0e42c9..7eb16cf 100644 --- a/project2/common/variableConvert.cpp +++ b/project2/common/variableConvert.cpp @@ -121,7 +121,7 @@ class ConvertVisitorUCharStar : public boost::static_visitor<const unsigned char private: const VariableType * var; }; -// Convert to generic type +// Convert to numeric type template <typename DestType> class ConvertVisitor : public boost::static_visitor<DestType> { public: @@ -136,6 +136,9 @@ class ConvertVisitor : public boost::static_visitor<DestType> { DestType operator()(const Null &) const { throw NullVariable(); } + DestType operator()(const Boolean & b) const { + return b.value ? 1 : 0; + } template <typename T> DestType operator()(const T & r) const { return boost::numeric_cast<DestType>(r); @@ -164,6 +167,30 @@ class ConvertVisitorDateTime : public boost::static_visitor<const boost::posix_t private: const VariableType * var; }; +// Convert to boolean +class ConvertVisitorBool : public boost::static_visitor<bool> { + public: + ConvertVisitorBool(const VariableType * v) : var(v) { + } + bool operator()(const Glib::ustring & s) const { + const char * str = s.c_str(); + if (strcasecmp(str, "true") == 0 || strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0) return true; + if (strcasecmp(str, "false") == 0 || strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0) return false; + throw InvalidConversionTo("bool"); + } + bool operator()(const boost::posix_time::ptime &) const { + throw InvalidConversionTo("bool"); + } + bool operator()(const Null &) const { + throw NullVariable(); + } + template <typename T> + bool operator()(const T & t) const { + return (t != 0); + } + private: + const VariableType * var; +}; VariableType::operator const Glib::ustring &() const { return boost::apply_visitor(ConvertVisitorGlibUstring(this), *this); @@ -196,3 +223,7 @@ VariableType::operator const boost::posix_time::ptime &() const { return boost::apply_visitor(ConvertVisitorDateTime(this), *this); } +VariableType::operator bool() const +{ + return boost::apply_visitor(ConvertVisitorBool(this), *this); +} diff --git a/project2/common/variables.cpp b/project2/common/variables.cpp index 18ddbde..261e942 100644 --- a/project2/common/variables.cpp +++ b/project2/common/variables.cpp @@ -24,6 +24,27 @@ bool Null::operator<(const Null &) const return false; } +bool Boolean::operator<(const Boolean & b) const +{ + return ((this->value == false) && (b.value == true)); +} +Boolean::operator bool() const +{ + return this->value; +} +std::basic_ostream<char> & +operator<<(std::basic_ostream<char> & os, const Boolean & b) +{ + os << (b.value ? "true" : "false"); + return os; +} +std::basic_ostream<unsigned char> & +operator<<(std::basic_ostream<unsigned char> & os, const Boolean & b) +{ + os << (b.value ? "true" : "false"); + return os; +} + enum VT_typeID { DefaultType, String, @@ -92,6 +113,20 @@ VariableType::VariableType() : { } +VariableType::VariableType(char * t) : + _VT(Glib::ustring(t)), + convertCache(NULL), + freer(NULL) +{ +} + +VariableType::VariableType(const char * t) : + _VT(Glib::ustring(t)), + convertCache(NULL), + freer(NULL) +{ +} + VariableType::VariableType(const VariableType & vt) : _VT(*((const _VT *)&vt)), convertCache(NULL), diff --git a/project2/common/variables.h b/project2/common/variables.h index 6dbbf2b..84715d4 100644 --- a/project2/common/variables.h +++ b/project2/common/variables.h @@ -17,8 +17,21 @@ class Null { public: bool operator<(const Null &) const; }; + +class Boolean { + public: + Boolean(bool v); + bool operator<(const Boolean &) const; + operator bool() const; + bool value; +}; +std::basic_ostream<char> & operator<<(std::basic_ostream<char> &, const Boolean &); +std::basic_ostream<unsigned char> & operator<<(std::basic_ostream<unsigned char> &, const Boolean &); + typedef boost::variant< + // Other Null, + Boolean, // Strings Glib::ustring, // Numbers @@ -32,13 +45,15 @@ typedef boost::variant< short int, double, float, - // DateTimes + // Date and Times boost::posix_time::ptime > _VT; class VariableType : public _VT { public: typedef void(*Freer)(const void*); + VariableType(char * t); + VariableType(const char * t); template<typename T> VariableType(const T & t) : _VT(t), convertCache(NULL), freer(NULL) { } VariableType(); @@ -55,6 +70,8 @@ class VariableType : public _VT { operator int32_t() const; operator double() const; operator const boost::posix_time::ptime &() const; + operator bool() const; + template <typename T> T as() const { return *this; } template <typename T> const T * get() const { return boost::get<T>(this); } private: diff --git a/project2/json/conversion.cpp b/project2/json/conversion.cpp index d13a324..1fae0d3 100644 --- a/project2/json/conversion.cpp +++ b/project2/json/conversion.cpp @@ -11,10 +11,10 @@ json::Value Project2ToJson::operator()(const Null & c) const { json::Value Project2ToJson::operator()(const Glib::ustring & c) const { return c; } - -VariableType JsonToProject2::operator()(const json::Boolean &) const { - throw ConversionNotSupported(); +json::Value Project2ToJson::operator()(const Boolean & c) const { + return c; } + VariableType JsonToProject2::operator()(const json::Object &) const { throw ConversionNotSupported(); } diff --git a/project2/json/conversion.h b/project2/json/conversion.h index acd22fb..31bfc8c 100644 --- a/project2/json/conversion.h +++ b/project2/json/conversion.h @@ -8,6 +8,7 @@ class Project2ToJson : public boost::static_visitor<json::Value> { json::Value operator()(const boost::posix_time::ptime & i) const; json::Value operator()(const Null & c) const; json::Value operator()(const Glib::ustring & c) const; + json::Value operator()(const Boolean & c) const; template <class Numeric> json::Value operator()(const Numeric & i) const { return boost::numeric_cast<json::Number>(i); @@ -16,7 +17,6 @@ class Project2ToJson : public boost::static_visitor<json::Value> { class JsonToProject2 : public boost::static_visitor<VariableType> { public: - VariableType operator()(const json::Boolean &) const; VariableType operator()(const json::Object &) const; VariableType operator()(const json::Array &) const; template <class Copyable> diff --git a/project2/mail/sendmailTask.cpp b/project2/mail/sendmailTask.cpp index 73afb20..e335d30 100644 --- a/project2/mail/sendmailTask.cpp +++ b/project2/mail/sendmailTask.cpp @@ -51,7 +51,7 @@ SendMailTask::SendMailTask(const xmlpp::Element * p) : subject(p, "subject"), from(p, "from"), server(p, "server", defaultMailServer.empty(), defaultMailServer), - present(p->get_attribute_value("present").raw()) + present(p, "present") { } @@ -221,7 +221,7 @@ SendMailTask::execute() const parts->parts.insert(new Header("Content-Transfer-Encoding", "binary")); parts->parts.insert(new BoundaryEnd()); - ViewHostPtr vsp = new ViewHost(Environment::getCurrent()->resolveScript("emails", present)); + ViewHostPtr vsp = new ViewHost(Environment::getCurrent()->resolveScript("emails", present())); vsp->executeViews(boost::bind(&SendMailTask::createDefaultPresenter, this, _1)); vsp->doTransforms(); part = parts->parts.begin(); diff --git a/project2/mail/sendmailTask.h b/project2/mail/sendmailTask.h index fa8427f..8c427dd 100644 --- a/project2/mail/sendmailTask.h +++ b/project2/mail/sendmailTask.h @@ -41,7 +41,7 @@ class SendMailTask : public Task { const Variable subject; const Variable from; const Variable server; - const std::string present; + const Variable present; private: static const char * writeMailWrapper(void ** buf, int * len, void * arg); diff --git a/project2/sql/sqlMergeTask.cpp b/project2/sql/sqlMergeTask.cpp index fd9ae96..30d3a59 100644 --- a/project2/sql/sqlMergeTask.cpp +++ b/project2/sql/sqlMergeTask.cpp @@ -49,9 +49,9 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : SourceObject(p), Task(p), updateWhere(p, "updatewhere", false), - patchOrder(p->get_attribute_value("patchorder")), - earlyKeys(p->get_attribute_value("earlykeys") == "yes"), - useView(p->get_attribute_value("useview") == "yes"), + patchOrder(p, "patchorder", false), + earlyKeys(p, "earlykeys", false, false), + useView(p, "useview", false, false), tempTableCreated(false), insCmd(NULL), destdb(NULL), @@ -63,7 +63,7 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : loader.supportedStorers.insert(Storer::into(&sources)); loader.collectAll(p, true); - if (!sources.empty() && useView) { + if (!sources.empty() && useView()) { throw NotSupported("useview not supported with iterate fillers"); } @@ -72,7 +72,7 @@ SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) : TargetColumnPtr tcp(new TargetColumn(e->get_child_text()->get_content())); tcp->maptable = e->get_attribute_value("maptable"); if (!tcp->maptable.empty()) { - if (useView) { + if (useView()) { throw NotSupported("useview not supported with mapped columns"); } tcp->mapcolumn = e->get_attribute_value("mapcolumn"); @@ -118,7 +118,7 @@ void SqlMergeTask::execute() const { createTempTable(); - if (earlyKeys) { + if (earlyKeys()) { createTempKey(); copyToTempTable(); } @@ -134,14 +134,14 @@ SqlMergeTask::execute() const BOOST_FOREACH(const Keys::value_type & k, keys) { tp.addKey(k); } - tp.patch(updateWhere(), patchOrder.c_str()); + tp.patch(updateWhere(), patchOrder()); dropTempTable(); } void SqlMergeTask::createTempTable() const { - if (useView) { + if (useView()) { DB::ModifyCommand * cv = destdb->newModifyCommand(stringf( "CREATE VIEW %s AS %s", dtablet.c_str(), @@ -174,7 +174,7 @@ SqlMergeTask::dropTempTable() const { if (tempTableCreated) { DB::ModifyCommand * d; - if (useView) { + if (useView()) { d = destdb->newModifyCommand("DROP VIEW " + dtablet); } else { @@ -187,7 +187,7 @@ SqlMergeTask::dropTempTable() const void SqlMergeTask::createTempKey() const { - if (useView) return; + if (useView()) return; /* Primary key */ Buffer idx; idx.appendf("ALTER TABLE %s ADD CONSTRAINT pk_%s PRIMARY KEY(%s)", @@ -285,7 +285,7 @@ attach(boost::intrusive_ptr<IHaveSubTasks> i, DB::ModifyCommand * insert) void SqlMergeTask::copyToTempTable() const { - if (useView) return; + if (useView()) return; BOOST_FOREACH(const Sources::value_type & i, sources) { i->execute(); } diff --git a/project2/sql/sqlMergeTask.h b/project2/sql/sqlMergeTask.h index c9e206c..41d1269 100644 --- a/project2/sql/sqlMergeTask.h +++ b/project2/sql/sqlMergeTask.h @@ -47,9 +47,9 @@ class SqlMergeTask : public Task { Keys keys; Keys indexes; const Variable updateWhere; - const std::string patchOrder; - const bool earlyKeys; - const bool useView; + const Variable patchOrder; + const Variable earlyKeys; + const Variable useView; private: virtual void copyToTempTable() const; diff --git a/project2/sql/sqlVariableBinder.cpp b/project2/sql/sqlVariableBinder.cpp index 169fe2c..1ff8170 100644 --- a/project2/sql/sqlVariableBinder.cpp +++ b/project2/sql/sqlVariableBinder.cpp @@ -70,9 +70,13 @@ SqlVariableBinder::operator()(const float & i) const cmd->bindParamF(idx, i); } void +SqlVariableBinder::operator()(const Boolean & i) const +{ + cmd->bindParamI(idx, i.value ? 1 : 0); +} +void SqlVariableBinder::operator()(const boost::posix_time::ptime & i) const { struct tm tm(boost::posix_time::to_tm(i)); cmd->bindParamT(idx, &tm); } - diff --git a/project2/sql/sqlVariableBinder.h b/project2/sql/sqlVariableBinder.h index df3879a..3d68773 100644 --- a/project2/sql/sqlVariableBinder.h +++ b/project2/sql/sqlVariableBinder.h @@ -14,6 +14,7 @@ class SqlVariableBinder : public boost::static_visitor<> { public: SqlVariableBinder(DB::Command * c, unsigned int i); void operator()(const Null & i) const; + void operator()(const Boolean & i) const; void operator()(const Glib::ustring & i) const; void operator()(const long long unsigned int & i) const; void operator()(const long unsigned int & i) const; diff --git a/project2/xml/xmlDocumentPrefetch.cpp b/project2/xml/xmlDocumentPrefetch.cpp index f2ff4d0..cfb5191 100644 --- a/project2/xml/xmlDocumentPrefetch.cpp +++ b/project2/xml/xmlDocumentPrefetch.cpp @@ -9,8 +9,8 @@ XmlDocumentPrefetch::XmlDocumentPrefetch(const xmlpp::Element * p) : View(p), Task(p), VariableCurlHelper(p), - html(p->get_attribute_value("html") == "true"), - warnings(p->get_attribute_value("warnings") != "false"), + html(p, "html", false, false), + warnings(p, "warnings", false, true), encoding(p, "encoding", false) { } @@ -46,12 +46,12 @@ XmlDocumentPrefetch::newCurl() const bool XmlDocumentPrefetch::asHtml() const { - return html; + return html(); } bool XmlDocumentPrefetch::withWarnings() const { - return warnings; + return warnings(); } diff --git a/project2/xml/xmlDocumentPrefetch.h b/project2/xml/xmlDocumentPrefetch.h index e6ccbec..902b7be 100644 --- a/project2/xml/xmlDocumentPrefetch.h +++ b/project2/xml/xmlDocumentPrefetch.h @@ -17,8 +17,8 @@ class XmlDocumentPrefetch : public View, public Task, XmlDocumentCache, Variable void execute() const; void loadComplete(const CommonObjects *); - const bool html; - const bool warnings; + const Variable html; + const Variable warnings; const Variable encoding; CurlPtr newCurl() const; diff --git a/project2/xml/xmlRows.cpp b/project2/xml/xmlRows.cpp index 182da6a..71cf06c 100644 --- a/project2/xml/xmlRows.cpp +++ b/project2/xml/xmlRows.cpp @@ -16,15 +16,17 @@ DECLARE_LOADER("xmlrows", XmlRows); XmlRows::XmlRows(const xmlpp::Element * p) : RowSet(p), - recordRoot(p->get_attribute_value("recordroot")), - recordTrigger(p->get_attribute_value("recordtrigger")), - filename(p->get_attribute_value("filename")), + recordRoot(p, "recordroot"), + recordTrigger(p, "recordtrigger"), + filename(p, "filename"), anyInterestingAttributes(false) { typedef boost::split_iterator<Glib::ustring::iterator> ssi; - boost::split(root, recordRoot, boost::is_any_of("/")); - boost::split(trigger, recordTrigger, boost::is_any_of("/")); + Glib::ustring rR = recordRoot(); + boost::split(root, rR, boost::is_any_of("/")); + Glib::ustring rT = recordTrigger(); + boost::split(trigger, rT, boost::is_any_of("/")); unsigned int col = 0; BOOST_FOREACH(const xmlpp::Node * node, p->find("fields/field")) { @@ -68,7 +70,7 @@ store(const XmlRows::Path & position, RowState::FieldValues & values, const XmlR void XmlRows::execute(const Glib::ustring &, const RowProcessor * rp) const { - xmlTextReaderPtr reader = xmlReaderForFile(filename.c_str(), NULL, 0); + xmlTextReaderPtr reader = xmlReaderForFile(filename(), NULL, 0); if (reader == NULL) { throw std::runtime_error("Failed to open file"); } diff --git a/project2/xml/xmlRows.h b/project2/xml/xmlRows.h index 3ab889e..6e74377 100644 --- a/project2/xml/xmlRows.h +++ b/project2/xml/xmlRows.h @@ -18,9 +18,9 @@ class XmlRows : public RowSet { void execute(const Glib::ustring &, const RowProcessor *) const; virtual void loadComplete(const CommonObjects *); - const Glib::ustring recordRoot; - const Glib::ustring recordTrigger; - const std::string filename; + const Variable recordRoot; + const Variable recordTrigger; + const Variable filename; private: class XmlState : public RowState { diff --git a/project2/xml/xpathRows.cpp b/project2/xml/xpathRows.cpp index 24283dd..71a2ce2 100644 --- a/project2/xml/xpathRows.cpp +++ b/project2/xml/xpathRows.cpp @@ -20,8 +20,8 @@ SimpleMessageException(XpathEvalError); XPathRows::XPathRows(const xmlpp::Element * p) : RowSet(p), VariableCurlHelper(p), - html(p->get_attribute_value("html") == "true"), - warnings(p->get_attribute_value("warnings") != "false"), + html(p, "html", false, false), + warnings(p, "warnings", false, true), encoding(p, "encoding", false) { BOOST_FOREACH(const xmlpp::Node * node, p->find("filterview")) { @@ -51,13 +51,13 @@ XPathRows::loadComplete(const CommonObjects *) bool XPathRows::asHtml() const { - return html; + return html(); } bool XPathRows::withWarnings() const { - return warnings; + return warnings(); } CurlPtr diff --git a/project2/xml/xpathRows.h b/project2/xml/xpathRows.h index 4b9e008..4f1db39 100644 --- a/project2/xml/xpathRows.h +++ b/project2/xml/xpathRows.h @@ -20,9 +20,6 @@ class XPathRows : public RowSet, XmlDocumentCache, VariableCurlHelper { void execute(const Glib::ustring &, const RowProcessor *) const; virtual void loadComplete(const CommonObjects *); - const bool html; - const bool warnings; - private: class FilterViewColumn : public Column { public: @@ -57,6 +54,8 @@ class XPathRows : public RowSet, XmlDocumentCache, VariableCurlHelper { private: const FilterViewCPtr fv; }; + const Variable html; + const Variable warnings; const Variable encoding; }; |