| 1 | #pragma once
|
|---|
| 2 |
|
|---|
| 3 | namespace parsers {
|
|---|
| 4 | namespace where {
|
|---|
| 5 | namespace operator_impl {
|
|---|
| 6 | template<typename THandler>
|
|---|
| 7 | struct simple_bool_binary_operator_impl : public binary_operator_impl<THandler> {
|
|---|
| 8 | expression_ast<THandler> evaluate(THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 9 | value_type ltype = left.get_type();
|
|---|
| 10 | value_type rtype = right.get_type();
|
|---|
| 11 |
|
|---|
| 12 | if ( (ltype != rtype) && (rtype != type_tbd) ) {
|
|---|
| 13 | handler.error(_T("Invalid types (not same) for binary operator"));
|
|---|
| 14 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 15 | }
|
|---|
| 16 | value_type type = left.get_type();
|
|---|
| 17 | if (type_is_int(type))
|
|---|
| 18 | return eval_int(type, handler, left, right)?expression_ast<THandler>(int_value(TRUE)):expression_ast<THandler>(int_value(FALSE));
|
|---|
| 19 | if (type == type_string)
|
|---|
| 20 | return eval_string(type, handler, left, right)?expression_ast<THandler>(int_value(TRUE)):expression_ast<THandler>(int_value(FALSE));
|
|---|
| 21 | handler.error(_T("missing impl for simple bool binary operator"));
|
|---|
| 22 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 23 | }
|
|---|
| 24 | virtual bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const = 0;
|
|---|
| 25 | virtual bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const = 0;
|
|---|
| 26 | };
|
|---|
| 27 |
|
|---|
| 28 | template<typename THandler>
|
|---|
| 29 | struct operator_and : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 30 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 31 | return left.get_int(handler) && right.get_int(handler);
|
|---|
| 32 | }
|
|---|
| 33 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 34 | handler.error(_T("missing impl for and binary operator"));
|
|---|
| 35 | // TODO convert strings
|
|---|
| 36 | return false;
|
|---|
| 37 | };
|
|---|
| 38 | };
|
|---|
| 39 | template<typename THandler>
|
|---|
| 40 | struct operator_or : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 41 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 42 | return left.get_int(handler) || right.get_int(handler);
|
|---|
| 43 | }
|
|---|
| 44 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 45 | handler.error(_T("missing impl for or binary operator"));
|
|---|
| 46 | // TODO convert strings
|
|---|
| 47 | return false;
|
|---|
| 48 | };
|
|---|
| 49 | };
|
|---|
| 50 | template<typename THandler>
|
|---|
| 51 | struct operator_eq : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 52 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 53 | return left.get_int(handler) == right.get_int(handler);
|
|---|
| 54 | }
|
|---|
| 55 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 56 | return left.get_string(handler) == right.get_string(handler);
|
|---|
| 57 | };
|
|---|
| 58 | };
|
|---|
| 59 | template<typename THandler>
|
|---|
| 60 | struct operator_ne : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 61 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 62 | return left.get_int(handler) != right.get_int(handler);
|
|---|
| 63 | }
|
|---|
| 64 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 65 | return left.get_string(handler) != right.get_string(handler);
|
|---|
| 66 | };
|
|---|
| 67 | };
|
|---|
| 68 | template<typename THandler>
|
|---|
| 69 | struct operator_gt : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 70 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 71 | return left.get_int(handler) > right.get_int(handler);
|
|---|
| 72 | }
|
|---|
| 73 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 74 | return left.get_string(handler) > right.get_string(handler);
|
|---|
| 75 | };
|
|---|
| 76 | };
|
|---|
| 77 | template<typename THandler>
|
|---|
| 78 | struct operator_lt : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 79 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 80 | return left.get_int(handler) < right.get_int(handler);
|
|---|
| 81 | }
|
|---|
| 82 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 83 | return left.get_string(handler) < right.get_string(handler);
|
|---|
| 84 | };
|
|---|
| 85 | };
|
|---|
| 86 | template<typename THandler>
|
|---|
| 87 | struct operator_le : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 88 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 89 | return left.get_int(handler) <= right.get_int(handler);
|
|---|
| 90 | }
|
|---|
| 91 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 92 | return left.get_string(handler) <= right.get_string(handler);
|
|---|
| 93 | };
|
|---|
| 94 | };
|
|---|
| 95 | template<typename THandler>
|
|---|
| 96 | struct operator_ge : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 97 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 98 | return left.get_int(handler) >= right.get_int(handler);
|
|---|
| 99 | }
|
|---|
| 100 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 101 | return left.get_string(handler) >= right.get_string(handler);
|
|---|
| 102 | };
|
|---|
| 103 | };
|
|---|
| 104 | template<typename THandler>
|
|---|
| 105 | struct operator_like : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 106 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 107 | return false;
|
|---|
| 108 | }
|
|---|
| 109 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 110 | std::wstring s1 = left.get_string(handler);
|
|---|
| 111 | std::wstring s2 = right.get_string(handler);
|
|---|
| 112 | bool res;
|
|---|
| 113 | if (s1.size() > s2.size() && s2.size() > 0)
|
|---|
| 114 | return s1.find(s2) != std::wstring::npos;
|
|---|
| 115 | return s2.find(s1) != std::wstring::npos;
|
|---|
| 116 | //if (res)
|
|---|
| 117 | // std::wcout << _T("Found: ") << s1 << _T(" in ") << s2 << std::endl;
|
|---|
| 118 | return res;
|
|---|
| 119 | };
|
|---|
| 120 | };
|
|---|
| 121 | template<typename THandler>
|
|---|
| 122 | struct operator_not_like : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 123 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 124 | return false;
|
|---|
| 125 | }
|
|---|
| 126 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 127 | std::wstring s1 = left.get_string(handler);
|
|---|
| 128 | std::wstring s2 = right.get_string(handler);
|
|---|
| 129 | bool res;
|
|---|
| 130 | if (s1.size() > s2.size() && s2.size() > 0)
|
|---|
| 131 | return s1.find(s2) == std::wstring::npos;
|
|---|
| 132 | return s2.find(s1) == std::wstring::npos;
|
|---|
| 133 | //if (res)
|
|---|
| 134 | // std::wcout << _T("Found: ") << s1 << _T(" in ") << s2 << std::endl;
|
|---|
| 135 | return res;
|
|---|
| 136 | };
|
|---|
| 137 | };
|
|---|
| 138 | template<typename THandler>
|
|---|
| 139 | struct operator_not_in : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 140 |
|
|---|
| 141 | typedef typename expression_ast<THandler>::list_type list_type;
|
|---|
| 142 | typedef typename expression_ast<THandler> list_item_type;
|
|---|
| 143 | typename expression_ast<THandler>::list_type list;
|
|---|
| 144 | operator_not_in(const expression_ast<THandler> &subject) : list(subject.get_list()) {}
|
|---|
| 145 |
|
|---|
| 146 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 147 | long long val = left.get_int(handler);
|
|---|
| 148 | BOOST_FOREACH(list_item_type itm, list) {
|
|---|
| 149 | if (itm.get_int(handler) == val)
|
|---|
| 150 | return false;
|
|---|
| 151 | }
|
|---|
| 152 | return true;
|
|---|
| 153 | }
|
|---|
| 154 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 155 | std::wstring val = left.get_string(handler);
|
|---|
| 156 | BOOST_FOREACH(list_item_type itm, list) {
|
|---|
| 157 | if (itm.get_string(handler) == val)
|
|---|
| 158 | return false;
|
|---|
| 159 | }
|
|---|
| 160 | return true;
|
|---|
| 161 | };
|
|---|
| 162 | };
|
|---|
| 163 | template<typename THandler>
|
|---|
| 164 | struct operator_in : public simple_bool_binary_operator_impl<THandler> {
|
|---|
| 165 |
|
|---|
| 166 | typedef typename expression_ast<THandler>::list_type list_type;
|
|---|
| 167 | typedef typename expression_ast<THandler> list_item_type;
|
|---|
| 168 | typename expression_ast<THandler>::list_type list;
|
|---|
| 169 | operator_in(const expression_ast<THandler> &subject) : list(subject.get_list()) {}
|
|---|
| 170 |
|
|---|
| 171 | bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 172 | long long val = left.get_int(handler);
|
|---|
| 173 | BOOST_FOREACH(list_item_type itm, list) {
|
|---|
| 174 | if (itm.get_int(handler) == val)
|
|---|
| 175 | return true;
|
|---|
| 176 | }
|
|---|
| 177 | return false;
|
|---|
| 178 | }
|
|---|
| 179 | bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 180 | std::wstring val = left.get_string(handler);
|
|---|
| 181 | BOOST_FOREACH(list_item_type itm, list) {
|
|---|
| 182 | if (itm.get_string(handler) == val)
|
|---|
| 183 | return true;
|
|---|
| 184 | }
|
|---|
| 185 | return false;
|
|---|
| 186 | };
|
|---|
| 187 | };
|
|---|
| 188 | template<typename THandler>
|
|---|
| 189 | struct operator_false : public binary_operator_impl<THandler>, unary_operator_impl<THandler>, binary_function_impl<THandler> {
|
|---|
| 190 | expression_ast<THandler> evaluate(THandler &handler, const expression_ast<THandler> &left, const expression_ast<THandler> & right) const {
|
|---|
| 191 | handler.error(_T("missing impl for FALSE"));
|
|---|
| 192 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 193 | }
|
|---|
| 194 | expression_ast<THandler> evaluate(THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 195 | handler.error(_T("missing impl for FALSE"));
|
|---|
| 196 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 197 | }
|
|---|
| 198 | expression_ast<THandler> evaluate(parsers::where::value_type type,THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 199 | handler.error(_T("missing impl for FALSE"));
|
|---|
| 200 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 201 | }
|
|---|
| 202 | };
|
|---|
| 203 |
|
|---|
| 204 | template<typename THandler>
|
|---|
| 205 | struct function_convert : public binary_function_impl<THandler> {
|
|---|
| 206 | typename expression_ast<THandler> list_entry;
|
|---|
| 207 | typedef typename expression_ast<THandler>::list_type list_type;
|
|---|
| 208 | typename expression_ast<THandler>::list_type list;
|
|---|
| 209 | bool single_item;
|
|---|
| 210 | function_convert(const expression_ast<THandler> &subject) : list(subject.get_list()), single_item(list.size()==1) {}
|
|---|
| 211 | expression_ast<THandler> evaluate(value_type type, THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 212 | if (single_item) {
|
|---|
| 213 | if (type_is_int(type)) {
|
|---|
| 214 | return expression_ast<THandler>(int_value(list.front().get_int(handler)));
|
|---|
| 215 | }
|
|---|
| 216 | if (type == type_string) {
|
|---|
| 217 | return expression_ast<THandler>(string_value(list.front().get_string(handler)));
|
|---|
| 218 | }
|
|---|
| 219 | handler.error(_T("1:Failed to handle type: ") + to_string(type));
|
|---|
| 220 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 221 | }
|
|---|
| 222 | if (list.size()==2) {
|
|---|
| 223 | list_type::const_iterator item = list.begin();
|
|---|
| 224 | list_type::const_iterator unit = item;
|
|---|
| 225 | std::advance(unit, 1);
|
|---|
| 226 | if (type == type_date) {
|
|---|
| 227 | return expression_ast<THandler>(int_value(parse_time((*item).get_int(handler), (*unit).get_string(handler))));
|
|---|
| 228 | }
|
|---|
| 229 | handler.error(_T("m:Failed to handle type: ") + to_string(type) + _T(" ") + (*item).to_string() + _T(", ") + (*unit).to_string());
|
|---|
| 230 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 231 | }
|
|---|
| 232 | std::wcout << _T("----------------------------------------------\n");
|
|---|
| 233 | std::wcout << list.size() << _T("\n");
|
|---|
| 234 | std::wcout << subject.to_string() << _T("\n");
|
|---|
| 235 | std::wcout << _T("----------------------------------------------\n");
|
|---|
| 236 | handler.error(_T("Missing implementation for convert function"));
|
|---|
| 237 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 238 | }
|
|---|
| 239 |
|
|---|
| 240 | inline long long parse_time(unsigned int value, std::wstring unit) const {
|
|---|
| 241 | long long now = constants::get_now();
|
|---|
| 242 | if (unit.empty())
|
|---|
| 243 | return now + value;
|
|---|
| 244 | else if ( (unit == _T("s")) || (unit == _T("S")) )
|
|---|
| 245 | return now + (value);
|
|---|
| 246 | else if ( (unit == _T("m")) || (unit == _T("M")) )
|
|---|
| 247 | return now + (value * 60);
|
|---|
| 248 | else if ( (unit == _T("h")) || (unit == _T("H")) )
|
|---|
| 249 | return now + (value * 60 * 60);
|
|---|
| 250 | else if ( (unit == _T("d")) || (unit == _T("D")) )
|
|---|
| 251 | return now + (value * 24 * 60 * 60);
|
|---|
| 252 | else if ( (unit == _T("w")) || (unit == _T("W")) )
|
|---|
| 253 | return now + (value * 7 * 24 * 60 * 60);
|
|---|
| 254 | return now + value;
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | };
|
|---|
| 258 |
|
|---|
| 259 |
|
|---|
| 260 | template<typename THandler>
|
|---|
| 261 | struct simple_bool_unary_operator_impl : public unary_operator_impl<THandler> {
|
|---|
| 262 | expression_ast<THandler> evaluate(THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 263 | value_type type = subject.get_type();
|
|---|
| 264 | if (type_is_int(type))
|
|---|
| 265 | return eval_int(type, handler, subject)?expression_ast<THandler>(int_value(TRUE)):expression_ast<THandler>(int_value(FALSE));
|
|---|
| 266 | if (type == type_string)
|
|---|
| 267 | return eval_string(type, handler, subject)?expression_ast<THandler>(int_value(TRUE)):expression_ast<THandler>(int_value(FALSE));
|
|---|
| 268 | handler.error(_T("missing impl for bool unary operator"));
|
|---|
| 269 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 270 | }
|
|---|
| 271 | virtual bool eval_int(value_type type, THandler &handler, const expression_ast<THandler> &subject) const = 0;
|
|---|
| 272 | virtual bool eval_string(value_type type, THandler &handler, const expression_ast<THandler> &subject) const = 0;
|
|---|
| 273 | };
|
|---|
| 274 |
|
|---|
| 275 | template<typename THandler>
|
|---|
| 276 | struct operator_not : public unary_operator_impl<THandler>, binary_function_impl<THandler> {
|
|---|
| 277 | operator_not(const expression_ast<THandler> &subject) {}
|
|---|
| 278 | operator_not() {}
|
|---|
| 279 | expression_ast<THandler> evaluate(THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 280 | return evaluate(subject.get_type(), handler, subject);
|
|---|
| 281 | }
|
|---|
| 282 | expression_ast<THandler> evaluate(value_type type, THandler &handler, const expression_ast<THandler> &subject) const {
|
|---|
| 283 | if (type == type_bool)
|
|---|
| 284 | return subject.get_int(handler)?expression_ast<THandler>(int_value(TRUE)):expression_ast<THandler>(int_value(FALSE));
|
|---|
| 285 | if (type == type_int)
|
|---|
| 286 | return expression_ast<THandler>(int_value(-subject.get_int(handler)));
|
|---|
| 287 | if (type == type_date) {
|
|---|
| 288 | long long now = constants::get_now();
|
|---|
| 289 | long long val = now - (subject.get_int(handler) - now);
|
|---|
| 290 | return expression_ast<THandler>(int_value(val));
|
|---|
| 291 | }
|
|---|
| 292 | handler.error(_T("missing impl for NOT operator"));
|
|---|
| 293 | return expression_ast<THandler>(int_value(FALSE));
|
|---|
| 294 | }
|
|---|
| 295 | };
|
|---|
| 296 | }
|
|---|
| 297 | template<typename THandler>
|
|---|
| 298 | typename factory<THandler>::bin_op_type factory<THandler>::get_binary_operator(operators op, const expression_ast<THandler> &left, const expression_ast<THandler> &right) {
|
|---|
| 299 | // op_in, op_nin
|
|---|
| 300 | if (op == op_eq)
|
|---|
| 301 | return bin_op_type(new operator_impl::operator_eq<THandler>());
|
|---|
| 302 | if (op == op_gt)
|
|---|
| 303 | return bin_op_type(new operator_impl::operator_gt<THandler>());
|
|---|
| 304 | if (op == op_lt)
|
|---|
| 305 | return bin_op_type(new operator_impl::operator_lt<THandler>());
|
|---|
| 306 | if (op == op_le)
|
|---|
| 307 | return bin_op_type(new operator_impl::operator_le<THandler>());
|
|---|
| 308 | if (op == op_ge)
|
|---|
| 309 | return bin_op_type(new operator_impl::operator_ge<THandler>());
|
|---|
| 310 | if (op == op_ne)
|
|---|
| 311 | return bin_op_type(new operator_impl::operator_ne<THandler>());
|
|---|
| 312 | if (op == op_like)
|
|---|
| 313 | return bin_op_type(new operator_impl::operator_like<THandler>());
|
|---|
| 314 | if (op == op_not_like)
|
|---|
| 315 | return bin_op_type(new operator_impl::operator_not_like<THandler>());
|
|---|
| 316 |
|
|---|
| 317 | if (op == op_and)
|
|---|
| 318 | return bin_op_type(new operator_impl::operator_and<THandler>());
|
|---|
| 319 | if (op == op_or)
|
|---|
| 320 | return bin_op_type(new operator_impl::operator_or<THandler>());
|
|---|
| 321 | if (op == op_in)
|
|---|
| 322 | return bin_op_type(new operator_impl::operator_in<THandler>(right));
|
|---|
| 323 | if (op == op_nin)
|
|---|
| 324 | return bin_op_type(new operator_impl::operator_not_in<THandler>(right));
|
|---|
| 325 | std::cout << "======== UNHANDLED OPERATOR\n";
|
|---|
| 326 | return bin_op_type(new operator_impl::operator_false<THandler>());
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | template<typename THandler>
|
|---|
| 330 | typename factory<THandler>::bin_fun_type factory<THandler>::get_binary_function(std::wstring name, const expression_ast<THandler> &subject) {
|
|---|
| 331 | if (name == _T("convert"))
|
|---|
| 332 | return bin_fun_type(new operator_impl::function_convert<THandler>(subject));
|
|---|
| 333 | if (name == _T("auto_convert"))
|
|---|
| 334 | return bin_fun_type(new operator_impl::function_convert<THandler>(subject));
|
|---|
| 335 | if (name == _T("neg"))
|
|---|
| 336 | return bin_fun_type(new operator_impl::operator_not<THandler>(subject));
|
|---|
| 337 | std::wcout << _T("======== UNDEFINED FUNCTION: ") << name << std::endl;
|
|---|
| 338 | return bin_fun_type(new operator_impl::operator_false<THandler>());
|
|---|
| 339 | }
|
|---|
| 340 | template<typename THandler>
|
|---|
| 341 | typename factory<THandler>::un_op_type factory<THandler>::get_unary_operator(operators op) {
|
|---|
| 342 | // op_inv, op_not
|
|---|
| 343 | if (op == op_not)
|
|---|
| 344 | return un_op_type(new operator_impl::operator_not<THandler>());
|
|---|
| 345 | std::cout << "======== UNHANDLED OPERATOR\n";
|
|---|
| 346 | return un_op_type(new operator_impl::operator_false<THandler>());
|
|---|
| 347 | }
|
|---|
| 348 | }
|
|---|
| 349 | }
|
|---|