The code from https://github.com/vpcola/Nucleo
JsonParser.cpp@0:5464d5e415e5, 2014-10-08 (annotated)
- Committer:
- sinrab
- Date:
- Wed Oct 08 11:00:24 2014 +0000
- Revision:
- 0:5464d5e415e5
The code from https://github.com/vpcola/Nucleo
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
sinrab | 0:5464d5e415e5 | 1 | /* |
sinrab | 0:5464d5e415e5 | 2 | * |
sinrab | 0:5464d5e415e5 | 3 | * Compact JSON format parsing lib (native cross-platform c++) |
sinrab | 0:5464d5e415e5 | 4 | * |
sinrab | 0:5464d5e415e5 | 5 | * Copyright (C) 2013 Victor Laskin (victor.laskin@gmail.com) |
sinrab | 0:5464d5e415e5 | 6 | * Details: http://vitiy.info/?p=102 |
sinrab | 0:5464d5e415e5 | 7 | * |
sinrab | 0:5464d5e415e5 | 8 | * Redistribution and use in source and binary forms, with or without |
sinrab | 0:5464d5e415e5 | 9 | * modification, are permitted provided that the following conditions |
sinrab | 0:5464d5e415e5 | 10 | * are met: |
sinrab | 0:5464d5e415e5 | 11 | * 1. Redistributions of source code must retain the above copyright |
sinrab | 0:5464d5e415e5 | 12 | * notice, this list of conditions and the following disclaimer. |
sinrab | 0:5464d5e415e5 | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
sinrab | 0:5464d5e415e5 | 14 | * notice, this list of conditions and the following disclaimer in |
sinrab | 0:5464d5e415e5 | 15 | * the documentation and/or other materials provided with the |
sinrab | 0:5464d5e415e5 | 16 | * distribution. |
sinrab | 0:5464d5e415e5 | 17 | * 3. The names of the authors may not be used to endorse or promote |
sinrab | 0:5464d5e415e5 | 18 | * products derived from this software without specific prior |
sinrab | 0:5464d5e415e5 | 19 | * written permission. |
sinrab | 0:5464d5e415e5 | 20 | * |
sinrab | 0:5464d5e415e5 | 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS |
sinrab | 0:5464d5e415e5 | 22 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
sinrab | 0:5464d5e415e5 | 23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
sinrab | 0:5464d5e415e5 | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
sinrab | 0:5464d5e415e5 | 25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
sinrab | 0:5464d5e415e5 | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
sinrab | 0:5464d5e415e5 | 27 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
sinrab | 0:5464d5e415e5 | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
sinrab | 0:5464d5e415e5 | 29 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
sinrab | 0:5464d5e415e5 | 30 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
sinrab | 0:5464d5e415e5 | 31 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
sinrab | 0:5464d5e415e5 | 32 | * |
sinrab | 0:5464d5e415e5 | 33 | */ |
sinrab | 0:5464d5e415e5 | 34 | |
sinrab | 0:5464d5e415e5 | 35 | #include "JsonParser.h" |
sinrab | 0:5464d5e415e5 | 36 | |
sinrab | 0:5464d5e415e5 | 37 | namespace JSON { |
sinrab | 0:5464d5e415e5 | 38 | |
sinrab | 0:5464d5e415e5 | 39 | |
sinrab | 0:5464d5e415e5 | 40 | MVJSONReader::MVJSONReader(const string & source) { |
sinrab | 0:5464d5e415e5 | 41 | root = parse(source); |
sinrab | 0:5464d5e415e5 | 42 | } |
sinrab | 0:5464d5e415e5 | 43 | |
sinrab | 0:5464d5e415e5 | 44 | MVJSONReader::~MVJSONReader() { |
sinrab | 0:5464d5e415e5 | 45 | if (root != NULL) |
sinrab | 0:5464d5e415e5 | 46 | delete root; |
sinrab | 0:5464d5e415e5 | 47 | } |
sinrab | 0:5464d5e415e5 | 48 | |
sinrab | 0:5464d5e415e5 | 49 | MVJSONNode::~MVJSONNode() { |
sinrab | 0:5464d5e415e5 | 50 | if (values.size() > 0) |
sinrab | 0:5464d5e415e5 | 51 | for (int i = 0; i < values.size(); i++) |
sinrab | 0:5464d5e415e5 | 52 | delete values.at(i); |
sinrab | 0:5464d5e415e5 | 53 | } |
sinrab | 0:5464d5e415e5 | 54 | |
sinrab | 0:5464d5e415e5 | 55 | |
sinrab | 0:5464d5e415e5 | 56 | |
sinrab | 0:5464d5e415e5 | 57 | MVJSONNode* MVJSONReader::parse(string text) |
sinrab | 0:5464d5e415e5 | 58 | { |
sinrab | 0:5464d5e415e5 | 59 | string s = trim(text); |
sinrab | 0:5464d5e415e5 | 60 | if (s.length() < 2) return NULL; |
sinrab | 0:5464d5e415e5 | 61 | |
sinrab | 0:5464d5e415e5 | 62 | // object |
sinrab | 0:5464d5e415e5 | 63 | if ((s[0] == '{') && (s[s.length() - 1] == '}')) |
sinrab | 0:5464d5e415e5 | 64 | { |
sinrab | 0:5464d5e415e5 | 65 | // erase last and first symbols |
sinrab | 0:5464d5e415e5 | 66 | s.erase(0, 1); |
sinrab | 0:5464d5e415e5 | 67 | s.erase(s.length() - 1, 1); |
sinrab | 0:5464d5e415e5 | 68 | |
sinrab | 0:5464d5e415e5 | 69 | vector<string> parts; |
sinrab | 0:5464d5e415e5 | 70 | splitList(s, parts); |
sinrab | 0:5464d5e415e5 | 71 | |
sinrab | 0:5464d5e415e5 | 72 | MVJSONNode* node = new MVJSONNode(); |
sinrab | 0:5464d5e415e5 | 73 | |
sinrab | 0:5464d5e415e5 | 74 | for (int i = 0; i < parts.size(); i++) |
sinrab | 0:5464d5e415e5 | 75 | node->values.push_back(parseValue(parts.at(i), false)); |
sinrab | 0:5464d5e415e5 | 76 | |
sinrab | 0:5464d5e415e5 | 77 | return node; |
sinrab | 0:5464d5e415e5 | 78 | } |
sinrab | 0:5464d5e415e5 | 79 | |
sinrab | 0:5464d5e415e5 | 80 | return NULL; |
sinrab | 0:5464d5e415e5 | 81 | } |
sinrab | 0:5464d5e415e5 | 82 | |
sinrab | 0:5464d5e415e5 | 83 | |
sinrab | 0:5464d5e415e5 | 84 | |
sinrab | 0:5464d5e415e5 | 85 | |
sinrab | 0:5464d5e415e5 | 86 | MVJSONValue* MVJSONReader::parseValue(string text, bool hasNoName) |
sinrab | 0:5464d5e415e5 | 87 | { |
sinrab | 0:5464d5e415e5 | 88 | string key; |
sinrab | 0:5464d5e415e5 | 89 | string s; |
sinrab | 0:5464d5e415e5 | 90 | splitInHalf(text, ":", key, s); |
sinrab | 0:5464d5e415e5 | 91 | key = trim(key); |
sinrab | 0:5464d5e415e5 | 92 | s = trim(s); |
sinrab | 0:5464d5e415e5 | 93 | if (key.length() > 2) |
sinrab | 0:5464d5e415e5 | 94 | { |
sinrab | 0:5464d5e415e5 | 95 | // strip " |
sinrab | 0:5464d5e415e5 | 96 | key.erase(0, 1); |
sinrab | 0:5464d5e415e5 | 97 | key.erase(key.length() - 1, 1); |
sinrab | 0:5464d5e415e5 | 98 | } |
sinrab | 0:5464d5e415e5 | 99 | |
sinrab | 0:5464d5e415e5 | 100 | if (hasNoName) |
sinrab | 0:5464d5e415e5 | 101 | { |
sinrab | 0:5464d5e415e5 | 102 | s = text; |
sinrab | 0:5464d5e415e5 | 103 | key = ""; |
sinrab | 0:5464d5e415e5 | 104 | } |
sinrab | 0:5464d5e415e5 | 105 | |
sinrab | 0:5464d5e415e5 | 106 | |
sinrab | 0:5464d5e415e5 | 107 | if (s == "false") // bool |
sinrab | 0:5464d5e415e5 | 108 | return new MVJSONValue(key, false); |
sinrab | 0:5464d5e415e5 | 109 | |
sinrab | 0:5464d5e415e5 | 110 | if (s == "true") // bool |
sinrab | 0:5464d5e415e5 | 111 | return new MVJSONValue(key, true); |
sinrab | 0:5464d5e415e5 | 112 | |
sinrab | 0:5464d5e415e5 | 113 | if (s == "null") // null |
sinrab | 0:5464d5e415e5 | 114 | return new MVJSONValue(key, MVJSON_TYPE_NULL); |
sinrab | 0:5464d5e415e5 | 115 | |
sinrab | 0:5464d5e415e5 | 116 | char first = s[0]; |
sinrab | 0:5464d5e415e5 | 117 | |
sinrab | 0:5464d5e415e5 | 118 | if (first == '"') // string |
sinrab | 0:5464d5e415e5 | 119 | return new MVJSONValue(key, s.substr(1, s.length() - 2)); |
sinrab | 0:5464d5e415e5 | 120 | |
sinrab | 0:5464d5e415e5 | 121 | if (first == '{') // object |
sinrab | 0:5464d5e415e5 | 122 | return new MVJSONValue(key, parse(s)); |
sinrab | 0:5464d5e415e5 | 123 | |
sinrab | 0:5464d5e415e5 | 124 | if (first == '[') // array |
sinrab | 0:5464d5e415e5 | 125 | { |
sinrab | 0:5464d5e415e5 | 126 | s.erase(0, 1); |
sinrab | 0:5464d5e415e5 | 127 | s.erase(s.length() - 1, 1); |
sinrab | 0:5464d5e415e5 | 128 | vector<string> parts; |
sinrab | 0:5464d5e415e5 | 129 | splitList(s, parts); |
sinrab | 0:5464d5e415e5 | 130 | |
sinrab | 0:5464d5e415e5 | 131 | MVJSONValue* val = new MVJSONValue(key, MVJSON_TYPE_ARRAY); |
sinrab | 0:5464d5e415e5 | 132 | for (int i = 0; i < parts.size(); i++) |
sinrab | 0:5464d5e415e5 | 133 | val->arrayValue.push_back(parseValue(parts.at(i), true)); |
sinrab | 0:5464d5e415e5 | 134 | return val; |
sinrab | 0:5464d5e415e5 | 135 | } |
sinrab | 0:5464d5e415e5 | 136 | |
sinrab | 0:5464d5e415e5 | 137 | // else its number! |
sinrab | 0:5464d5e415e5 | 138 | if (s.find(".") == string::npos) |
sinrab | 0:5464d5e415e5 | 139 | return new MVJSONValue(key, stringToInt(s)); |
sinrab | 0:5464d5e415e5 | 140 | else |
sinrab | 0:5464d5e415e5 | 141 | return new MVJSONValue(key, stringToDouble(s)); |
sinrab | 0:5464d5e415e5 | 142 | |
sinrab | 0:5464d5e415e5 | 143 | } |
sinrab | 0:5464d5e415e5 | 144 | |
sinrab | 0:5464d5e415e5 | 145 | MVJSONValue::~MVJSONValue() |
sinrab | 0:5464d5e415e5 | 146 | { |
sinrab | 0:5464d5e415e5 | 147 | if (objValue != NULL) |
sinrab | 0:5464d5e415e5 | 148 | delete objValue; |
sinrab | 0:5464d5e415e5 | 149 | if (arrayValue.size() > 0) |
sinrab | 0:5464d5e415e5 | 150 | for (int i = 0; i < arrayValue.size(); i++) |
sinrab | 0:5464d5e415e5 | 151 | delete arrayValue.at(i); |
sinrab | 0:5464d5e415e5 | 152 | } |
sinrab | 0:5464d5e415e5 | 153 | |
sinrab | 0:5464d5e415e5 | 154 | void MVJSONValue::init(MVJSON_TYPE valueType) |
sinrab | 0:5464d5e415e5 | 155 | { |
sinrab | 0:5464d5e415e5 | 156 | this->valueType = valueType; |
sinrab | 0:5464d5e415e5 | 157 | objValue = NULL; |
sinrab | 0:5464d5e415e5 | 158 | name = ""; |
sinrab | 0:5464d5e415e5 | 159 | } |
sinrab | 0:5464d5e415e5 | 160 | |
sinrab | 0:5464d5e415e5 | 161 | MVJSONValue::MVJSONValue(string name, MVJSON_TYPE valueType) |
sinrab | 0:5464d5e415e5 | 162 | { |
sinrab | 0:5464d5e415e5 | 163 | init(valueType); |
sinrab | 0:5464d5e415e5 | 164 | this->name = name; |
sinrab | 0:5464d5e415e5 | 165 | } |
sinrab | 0:5464d5e415e5 | 166 | |
sinrab | 0:5464d5e415e5 | 167 | MVJSONValue::MVJSONValue(string name, bool value) |
sinrab | 0:5464d5e415e5 | 168 | { |
sinrab | 0:5464d5e415e5 | 169 | init(MVJSON_TYPE_BOOL); |
sinrab | 0:5464d5e415e5 | 170 | this->name = name; |
sinrab | 0:5464d5e415e5 | 171 | boolValue = value; |
sinrab | 0:5464d5e415e5 | 172 | } |
sinrab | 0:5464d5e415e5 | 173 | |
sinrab | 0:5464d5e415e5 | 174 | MVJSONValue::MVJSONValue(string name, string value) |
sinrab | 0:5464d5e415e5 | 175 | { |
sinrab | 0:5464d5e415e5 | 176 | init(MVJSON_TYPE_STRING); |
sinrab | 0:5464d5e415e5 | 177 | this->name = name; |
sinrab | 0:5464d5e415e5 | 178 | |
sinrab | 0:5464d5e415e5 | 179 | stringValue = value; |
sinrab | 0:5464d5e415e5 | 180 | |
sinrab | 0:5464d5e415e5 | 181 | // here we switch back special chars |
sinrab | 0:5464d5e415e5 | 182 | // \" \\ \/ \b \f \n \r \t \u four-hex-digits |
sinrab | 0:5464d5e415e5 | 183 | replace(stringValue, "\\\"", "\""); |
sinrab | 0:5464d5e415e5 | 184 | replace(stringValue, "\\\\", "\\"); |
sinrab | 0:5464d5e415e5 | 185 | replace(stringValue, "\\/", "/"); |
sinrab | 0:5464d5e415e5 | 186 | replace(stringValue, "\\b", "\b"); |
sinrab | 0:5464d5e415e5 | 187 | replace(stringValue, "\\f", "\f"); |
sinrab | 0:5464d5e415e5 | 188 | replace(stringValue, "\\n", "\n"); |
sinrab | 0:5464d5e415e5 | 189 | replace(stringValue, "\\r", "\r"); |
sinrab | 0:5464d5e415e5 | 190 | replace(stringValue, "\\t", "\t"); |
sinrab | 0:5464d5e415e5 | 191 | |
sinrab | 0:5464d5e415e5 | 192 | // TODO - \u four-hex-digits |
sinrab | 0:5464d5e415e5 | 193 | // SS::replace(stringValue, "\\\\", "\\"); |
sinrab | 0:5464d5e415e5 | 194 | |
sinrab | 0:5464d5e415e5 | 195 | } |
sinrab | 0:5464d5e415e5 | 196 | |
sinrab | 0:5464d5e415e5 | 197 | MVJSONValue::MVJSONValue(string name, int value) |
sinrab | 0:5464d5e415e5 | 198 | { |
sinrab | 0:5464d5e415e5 | 199 | init(MVJSON_TYPE_INT); |
sinrab | 0:5464d5e415e5 | 200 | this->name = name; |
sinrab | 0:5464d5e415e5 | 201 | intValue = value; |
sinrab | 0:5464d5e415e5 | 202 | } |
sinrab | 0:5464d5e415e5 | 203 | |
sinrab | 0:5464d5e415e5 | 204 | MVJSONValue::MVJSONValue(string name, double value) |
sinrab | 0:5464d5e415e5 | 205 | { |
sinrab | 0:5464d5e415e5 | 206 | init(MVJSON_TYPE_DOUBLE); |
sinrab | 0:5464d5e415e5 | 207 | this->name = name; |
sinrab | 0:5464d5e415e5 | 208 | doubleValue = value; |
sinrab | 0:5464d5e415e5 | 209 | } |
sinrab | 0:5464d5e415e5 | 210 | |
sinrab | 0:5464d5e415e5 | 211 | MVJSONValue::MVJSONValue(string name, MVJSONNode* value) |
sinrab | 0:5464d5e415e5 | 212 | { |
sinrab | 0:5464d5e415e5 | 213 | init(MVJSON_TYPE_OBJECT); |
sinrab | 0:5464d5e415e5 | 214 | this->name = name; |
sinrab | 0:5464d5e415e5 | 215 | objValue = value; |
sinrab | 0:5464d5e415e5 | 216 | } |
sinrab | 0:5464d5e415e5 | 217 | |
sinrab | 0:5464d5e415e5 | 218 | bool MVJSONNode::hasField(string name) |
sinrab | 0:5464d5e415e5 | 219 | { |
sinrab | 0:5464d5e415e5 | 220 | if (values.size() == 0) return false; |
sinrab | 0:5464d5e415e5 | 221 | for (int i = 0; i < values.size(); i++) |
sinrab | 0:5464d5e415e5 | 222 | if (values.at(i)->name == name) |
sinrab | 0:5464d5e415e5 | 223 | return true; |
sinrab | 0:5464d5e415e5 | 224 | return false; |
sinrab | 0:5464d5e415e5 | 225 | } |
sinrab | 0:5464d5e415e5 | 226 | |
sinrab | 0:5464d5e415e5 | 227 | MVJSONValue* MVJSONNode::getField(string name) |
sinrab | 0:5464d5e415e5 | 228 | { |
sinrab | 0:5464d5e415e5 | 229 | if (values.size() == 0) return NULL; |
sinrab | 0:5464d5e415e5 | 230 | for (int i = 0; i < values.size(); i++) |
sinrab | 0:5464d5e415e5 | 231 | if (values.at(i)->name == name) |
sinrab | 0:5464d5e415e5 | 232 | return values.at(i); |
sinrab | 0:5464d5e415e5 | 233 | return NULL; |
sinrab | 0:5464d5e415e5 | 234 | } |
sinrab | 0:5464d5e415e5 | 235 | |
sinrab | 0:5464d5e415e5 | 236 | |
sinrab | 0:5464d5e415e5 | 237 | double MVJSONNode::getFieldDouble(string name) |
sinrab | 0:5464d5e415e5 | 238 | { |
sinrab | 0:5464d5e415e5 | 239 | MVJSONValue* value = getField(name); |
sinrab | 0:5464d5e415e5 | 240 | if (value == NULL) return 0; |
sinrab | 0:5464d5e415e5 | 241 | if (value->valueType == MVJSON_TYPE_INT) return value->intValue; |
sinrab | 0:5464d5e415e5 | 242 | if (value->valueType == MVJSON_TYPE_DOUBLE) return value->doubleValue; |
sinrab | 0:5464d5e415e5 | 243 | return 0; |
sinrab | 0:5464d5e415e5 | 244 | } |
sinrab | 0:5464d5e415e5 | 245 | |
sinrab | 0:5464d5e415e5 | 246 | int MVJSONNode::getFieldInt(string name) |
sinrab | 0:5464d5e415e5 | 247 | { |
sinrab | 0:5464d5e415e5 | 248 | MVJSONValue* value = getField(name); |
sinrab | 0:5464d5e415e5 | 249 | if (value == NULL) return 0; |
sinrab | 0:5464d5e415e5 | 250 | if (value->valueType == MVJSON_TYPE_INT) return value->intValue; |
sinrab | 0:5464d5e415e5 | 251 | return 0; |
sinrab | 0:5464d5e415e5 | 252 | } |
sinrab | 0:5464d5e415e5 | 253 | |
sinrab | 0:5464d5e415e5 | 254 | string MVJSONNode::getFieldString(string name) |
sinrab | 0:5464d5e415e5 | 255 | { |
sinrab | 0:5464d5e415e5 | 256 | MVJSONValue* value = getField(name); |
sinrab | 0:5464d5e415e5 | 257 | if (value == NULL) return ""; |
sinrab | 0:5464d5e415e5 | 258 | if (value->valueType == MVJSON_TYPE_STRING) return value->stringValue; |
sinrab | 0:5464d5e415e5 | 259 | return ""; |
sinrab | 0:5464d5e415e5 | 260 | } |
sinrab | 0:5464d5e415e5 | 261 | |
sinrab | 0:5464d5e415e5 | 262 | bool MVJSONNode::getFieldBool(string name) |
sinrab | 0:5464d5e415e5 | 263 | { |
sinrab | 0:5464d5e415e5 | 264 | MVJSONValue* value = getField(name); |
sinrab | 0:5464d5e415e5 | 265 | if (value == NULL) return false; |
sinrab | 0:5464d5e415e5 | 266 | if (value->valueType == MVJSON_TYPE_INT) return (bool)value->intValue; |
sinrab | 0:5464d5e415e5 | 267 | if (value->valueType == MVJSON_TYPE_BOOL) return value->boolValue; |
sinrab | 0:5464d5e415e5 | 268 | return false; |
sinrab | 0:5464d5e415e5 | 269 | } |
sinrab | 0:5464d5e415e5 | 270 | |
sinrab | 0:5464d5e415e5 | 271 | double MVJSONValue::getFieldDouble(string name) |
sinrab | 0:5464d5e415e5 | 272 | { |
sinrab | 0:5464d5e415e5 | 273 | if (objValue == NULL) return 0; |
sinrab | 0:5464d5e415e5 | 274 | return objValue->getFieldDouble(name); |
sinrab | 0:5464d5e415e5 | 275 | } |
sinrab | 0:5464d5e415e5 | 276 | |
sinrab | 0:5464d5e415e5 | 277 | int MVJSONValue::getFieldInt(string name) |
sinrab | 0:5464d5e415e5 | 278 | { |
sinrab | 0:5464d5e415e5 | 279 | if (objValue == NULL) return 0; |
sinrab | 0:5464d5e415e5 | 280 | return objValue->getFieldInt(name); |
sinrab | 0:5464d5e415e5 | 281 | } |
sinrab | 0:5464d5e415e5 | 282 | |
sinrab | 0:5464d5e415e5 | 283 | string MVJSONValue::getFieldString(string name) |
sinrab | 0:5464d5e415e5 | 284 | { |
sinrab | 0:5464d5e415e5 | 285 | if (objValue == NULL) return ""; |
sinrab | 0:5464d5e415e5 | 286 | return objValue->getFieldString(name); |
sinrab | 0:5464d5e415e5 | 287 | } |
sinrab | 0:5464d5e415e5 | 288 | |
sinrab | 0:5464d5e415e5 | 289 | bool MVJSONValue::getFieldBool(string name) |
sinrab | 0:5464d5e415e5 | 290 | { |
sinrab | 0:5464d5e415e5 | 291 | if (objValue == NULL) return false; |
sinrab | 0:5464d5e415e5 | 292 | return objValue->getFieldBool(name); |
sinrab | 0:5464d5e415e5 | 293 | } |
sinrab | 0:5464d5e415e5 | 294 | |
sinrab | 0:5464d5e415e5 | 295 | |
sinrab | 0:5464d5e415e5 | 296 | } /* namespace F2 */ |
sinrab | 0:5464d5e415e5 | 297 |