/* * This function checks to see if the current YAML::Node contains only keys * that we care about. Unknown keys should cause PLFS to spit out an error * rather than being silently ignored. * This is a bit nasty as it drills through the entire tree recursively * but it will catch any unknowns in one pass * * Returns true if all keys are valid * * Returns false if unknown keys are found and sets bad_key to an error * message that points out what key is invalid */ bool is_valid_node(const YAML::Node node, string** bad_key) { set<string> key_list(Valid_Keys, Valid_Keys + (sizeof(Valid_Keys) / sizeof(Valid_Keys[0])) ); string key; string err = "\nBad key or value in plfsrc: "; if(node.IsMap()) { for(YAML::const_iterator it=node.begin();it!=node.end();it++) { if(!it->first.IsNull()) { key = it->first.as<string>(); if(!is_valid_node(node[key],bad_key)) // recurse return false; if(key_list.find(key) == key_list.end()) { err.append(key); *bad_key = new string (err); return false; // this is an unknown key } } } } else if (node.IsSequence()) { for(unsigned int i = 0; i < node.size(); i++) if(!is_valid_node(node[i],bad_key)) // recurse return false; } else if (node.IsScalar() && node.as<string>().find(" ") != string::npos) { err.append(node.as<string>()); *bad_key = new string (err); return false; // no spaces in values allowed } return true; // all keys are valid }
bool AreDetailsEqual(const YAML::Node& lhs, const YAML::Node& rhs) { //We want to check for plugin order and messages. if (lhs.IsSequence() && rhs.IsSequence()) { std::list<std::string> lhs_names, rhs_names; std::list<Message> lhs_messages, rhs_messages; for (YAML::const_iterator it = lhs.begin(); it != lhs.end(); ++it) { if ((*it)["name"]) lhs_names.push_back((*it)["name"].as<std::string>()); if ((*it)["messages"]) { std::list<Message> messages = (*it)["messages"].as< std::list<Message> >(); lhs_messages.insert(lhs_messages.end(), messages.begin(), messages.end()); } } for (YAML::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { if ((*it)["name"]) rhs_names.push_back((*it)["name"].as<std::string>()); if ((*it)["messages"]) { std::list<Message> messages = (*it)["messages"].as< std::list<Message> >(); rhs_messages.insert(rhs_messages.end(), messages.begin(), messages.end()); } } return lhs_names == rhs_names && lhs_messages == rhs_messages; } else return false; }
bool Sampler::parseConfig(const string &config_string) { YAML::Node node = YAML::Load(config_string); for (YAML::const_iterator it = node.begin(); it != node.end(); ++it) { string sample_name = it->first.as<string>(); ui << sample_name << "\n"; YAML::Node sample_data = it->second; if (!sample_data["file"]) { ui << "file is required for each sample\n"; continue; } string file(sample_data["file"].as<string>()); float pan = 0.; if (sample_data["pan"]) { pan = sample_data["pan"].as<float>(); } midi_data_t midi_data = sample_data["midi"].as<int>(); addSample(midi_data, file, pan); } return true; }
/** reads all the regular expressions from the database. and compile them */ void RegexManager::load_config(YAML::Node cfg) { try { TSDebug(BANJAX_PLUGIN_NAME, "Setting regex re2 options"); RE2::Options opt; opt.set_log_errors(false); opt.set_perl_classes(true); opt.set_posix_syntax(true); TSDebug(BANJAX_PLUGIN_NAME, "Loading regex manager conf"); //now we compile all of them and store them for later use for(YAML::const_iterator it = cfg.begin(); it != cfg.end(); ++it) { string cur_rule = (const char*) (*it)["rule"].as<std::string>().c_str(); TSDebug(BANJAX_PLUGIN_NAME, "initiating rule %s", cur_rule.c_str()); unsigned int observation_interval = (*it)["interval"].as<unsigned int>(); unsigned int threshold = (*it)["hits_per_interval"].as<unsigned int>(); rated_banning_regexes.push_back(new RatedRegex(cur_rule, new RE2((const char*)((*it)["regex"].as<std::string>().c_str()), opt), observation_interval * 1000, threshold /(double)(observation_interval* 1000))); } } catch(YAML::RepresentationException& e) { TSDebug(BANJAX_PLUGIN_NAME, "Error loading regex manager conf [%s].", e.what()); return; } TSDebug(BANJAX_PLUGIN_NAME, "Done loading regex manager conf"); }
//============================================================================== /// Parse the converted units list from a document. /// /// \param [in] unit_list The list of converted units. /// void DefinitionParser::ParseConvertedUnits( const YAML::Node& unit_list ) { for ( YAML::Iterator it = unit_list.begin(); it != unit_list.end(); ++it ) { ParseConvertedUnit( *it ); } }
TEST ForceInsertIntoMap() { YAML::Node node; node["a"] = "b"; node.force_insert("x", "y"); node.force_insert("a", 5); YAML_ASSERT(node.size() == 3); YAML_ASSERT(node.Type() == YAML::NodeType::Map); bool ab = false; bool a5 = false; bool xy = false; for(YAML::const_iterator it=node.begin();it!=node.end();++it) { if(it->first.as<std::string>() == "a") { if(it->second.as<std::string>() == "b") ab = true; else if(it->second.as<std::string>() == "5") a5 = true; } else if(it->first.as<std::string>() == "x" && it->second.as<std::string>() == "y") xy = true; } YAML_ASSERT(ab); YAML_ASSERT(a5); YAML_ASSERT(xy); return true; }
YAML::Node MergeYaml( const YAML::Node& a, const YAML::Node& b ) { // Short circuit cases if( a.IsNull() ) { return b; } else if( b.IsNull() ) { return a; } if( !a.IsMap() || !b.IsMap() ) { throw std::runtime_error( "Cannot merge non-map nodes." ); } YAML::Node node; CopyYaml( a, node ); YAML::Node::const_iterator iter; // Cycle through b and add all fields to node for( iter = b.begin(); iter != b.end(); iter++ ) { std::string key = iter->first.as<std::string>(); // If both a and b have a key we have to merge them if( node[key] ) { node[key] = MergeYaml( node[key], iter->second ); } // Otherwise we just add it else { node[key] = iter->second; } } return node; }
void kul::yaml::File::validate(const YAML::Node& n, const std::vector<NodeValidator>& nvs) throw(Exception) { kul::hash::set::String keys; for(const auto& nv : nvs) if(nv.name() == "*") return; for(YAML::const_iterator it = n.begin(); it != n.end(); ++it){ const std::string& key(it->first.as<std::string>()); if(keys.count(key)) KEXCEPTION("Duplicate key detected: " + key + "\n" + this->f); keys.insert(key); bool f = 0; for(const auto& nv : nvs){ if(nv.name() != key) continue; f = 1; if(nv.type() == 1 && it->second.Type() != 2) KEXCEPTION("String expected: " + nv.name() + "\n" + this->f); if(nv.type() == 2 && it->second.Type() != 3) KEXCEPTION("List expected: " + nv.name() + "\n" + this->f); if(nv.type() == 3 && it->second.Type() != 4) KEXCEPTION("Map expected: " + nv.name() + "\n" + this->f); if(nv.type() == 2) for(size_t i = 0; i < it->second.size(); i++) validate(it->second[i], nv.children()); if(nv.type() == 3) validate(it->second, nv.children()); } if(!f) KEXCEPTION("Unexpected key: " + key + "\n" + this->f); } for(const auto& nv : nvs){ if(nv.mandatory() && !keys.count(nv.name())) KEXCEPTION("Key mandatory: : " + nv.name() + "\n" + this->f); } }
bool get_fields(doid_t do_id, const vector<const Field*> &fields, map_t &values) { m_log->trace() << "Getting fields on obj-" << do_id << endl; YAML::Node document; if(!load(do_id, document)) { return false; } // Get the fields from the file that are not being updated for(auto it = fields.begin(); it != fields.end(); ++it) { const Field* field = *it; m_log->trace() << "Searching for field: " << field->get_name() << endl; YAML::Node existing = document["fields"]; for(auto it2 = existing.begin(); it2 != existing.end(); ++it2) { if(it2->first.as<string>() == field->get_name()) { vector<uint8_t> value = read_yaml_field(field, it2->second, do_id); if(value.size() > 0) { values[*it] = value; m_log->trace() << "Found requested field: " + field->get_name() << endl; } } } } return true; }
void FileBundle::Import(const YAML::Node& config) { switch (config.Type()) { case YAML::NodeType::Scalar: ImportScalarNode(config); break; case YAML::NodeType::Sequence: for (auto i = config.begin(); i != config.end(); ++i) { const YAML::Node& node = *i; switch(node.Type()) { case YAML::NodeType::Scalar: ImportScalarNode(node); break; case YAML::NodeType::Map: for (auto k = node.begin(); k != node.end(); ++k) { auto file = ImportScalarNode(k->second); file->name = k->first.as<string>(); } break; } } break; case YAML::NodeType::Map: ImportCompositeBundle(config); break; } }
int main(int argc, char* argv[]) { try { YAML::Node config = YAML::LoadFile(argv[1]); YAML::const_iterator iter =config.begin(); yaml::ConfigNodePtr np; while( iter != config.end()) { const YAML::Node& node = *iter; std::string module_name = node["module_name"].as<std::string>(); np = yaml::NodeFactory::Instance().Create( module_name ); np->Decode(node); np->Print(std::cout); ++iter; } } catch ( YAML::ParserException& e ) { std::cout << e.what(); } return 0; }
void set_field(doid_t do_id, const Field* field, const val_t &value) { m_log->trace() << "Setting field on obj-" << do_id << endl; YAML::Node document; if(!load(do_id, document)) { return; } // Get the fields from the file that are not being updated const Class* dcc = g_dcf->get_class_by_name(document["class"].as<string>()); ObjectData dbo(dcc->get_id()); YAML::Node existing = document["fields"]; for(auto it = existing.begin(); it != existing.end(); ++it) { const Field* field = dcc->get_field_by_name(it->first.as<string>()); if(!field) { m_log->warning() << "Field '" << it->first.as<string>() << "', loaded from '" << filename(do_id) << "', does not exist." << endl; continue; } vector<uint8_t> value = read_yaml_field(field, it->second, do_id); if(value.size() > 0) { dbo.fields[field] = value; } } dbo.fields[field] = value; write_yaml_object(do_id, dcc, dbo); }
/** * LoadDevices * * Loads devices from configuration object(YAML::Node) */ void InsteonNetwork::loadDevices() { YAML::Node device = config_["DEVICES"]; for (auto it = device.begin(); it != device.end(); ++it) { addDevice(it->first.as<int>(0)); } }
/** * Loads the map data set from a YAML file. * @param node YAML node. */ void MapDataSet::load(const YAML::Node &node) { for (YAML::const_iterator i = node.begin(); i != node.end(); ++i) { _name = i->as<std::string>(_name); } }
void WorldYamlSource::loadPropertySystems() { // iterate through each section (each section is a system) std::vector<YAML::Node> nodes = YAML::LoadAllFromFile(dir + "PropertySystems.yaml"); for (size_t i = 0; i < nodes.size(); i++) { YamlWrapper yaml(nodes[i]); // parse which system this section is for String typeName = yaml.read<String>("Which", "NONE", "Invalid property system."); ThingType type = ThingType::fromString(typeName); // create the system propertySystems[type].reset(new PropertySystem()); PropertySystem& system = *propertySystems[type]; // parse the properties of the system YAML::Node propertiesNode = yaml["Properties"].getNode(); for (auto iter = propertiesNode.begin(); iter != propertiesNode.end(); ++iter) { YamlWrapper propertyYaml(*iter); String name = propertyYaml.read<String>("Name", "", "Property name not given."); Type type = Type::fromString(propertyYaml.read<String>("Type")); Variant def = readVariant(propertyYaml["Default"].getNode(), type); bool mainKey = propertyYaml.read<bool>("MainKey", false); system.add(name, type, def, mainKey); } } }
void WorldYamlSource::loadItems() { if (!propertySystems[ThingType::ITEM]) return; PropertySystem& itemSys = *propertySystems[ThingType::ITEM]; std::vector<YAML::Node> nodes = YAML::LoadAllFromFile(dir + "Items.yaml"); for (size_t i = 0; i < nodes.size(); i++) { YamlWrapper yaml(nodes[i]); // read base String baseName = yaml.read<String>("Base", "", "Item lacks a base."); if (baseName == "") continue; auto iter = itemBaseNameMap.find(baseName); if (iter == itemBaseNameMap.end()) { LOG(ERROR) << "'" << baseName << "' is not an existing item base."; continue; } BaseThing& base = *iter->second; items.emplace_back(new Item(base, items.size() + 1)); Item& item = *items.back(); // read location if (yaml["Location"]->IsSequence()) { item.moveTo(yaml.read<Coord>("Location", Coord())); } // read properties YAML::Node propertiesNode = yaml["Properties"].getNode(); for (auto iter = propertiesNode.begin(); iter != propertiesNode.end(); ++iter) { const Property& property = itemSys[iter->first.as<String>()]; item.setValue(property, readVariant(iter->second, property.type)); } } }
bool KnobSerialization::checkForValueNode(const YAML::Node& node, const std::string& nodeType) { if (!node[nodeType]) { return false; } // We need to figure out of the knob is multi-view and if multi-dimensional YAML::Node valueNode = node[nodeType]; _dataType = dataTypeFromString(nodeType); // If the "Value" is a map, this can be either a multi-view knob or a single-view // and single-dimensional knob with animation. // Check to find any of the keys of a single dimension map. If we find it, that means // this is not the multi-view map and that this is a single-dimensional knob if (!valueNode.IsMap()) { decodeValueNode("Main", valueNode); } else { if (valueNode["Curve"] || valueNode["pyMultiExpr"] || valueNode["pyExpr"] || valueNode["exprtk"] || valueNode["N"] || valueNode["T"] || valueNode["K"] || valueNode["D"] || valueNode["V"]) { decodeValueNode("Main", valueNode); } else { // Multi-view for (YAML::const_iterator it = valueNode.begin(); it != valueNode.end(); ++it) { decodeValueNode(it->first.as<std::string>(), it->second); } } } return true; }
//============================================================================== /// Parse the derived dimension list from a document. /// /// \param [in] dim_list The YAML list node for the dimensions. /// void DefinitionParser::ParseDerivedDimensions( const YAML::Node& dim_list ) { for ( YAML::Iterator it = dim_list.begin(); it != dim_list.end(); ++it ) { ParseDerivedDimension( *it ); } }
Program::Program(const YAML::Node& fns) { for (YAML::Iterator it = fns.begin(); it != fns.end(); ++it) { std::string name; it.first() >> name; ReadFn(name, it.second()); } }
QList<AbstractListEntry*>* SettingsDBManager::getAllElements(int* state) { if (!config["settings-groups"]) return nullptr; //ошибка конфига! YAML::Node settingsSet = config["settings-groups"]; if (!config["time-dictionary"]) return nullptr; //ошибка конфига! YAML::Node timeInf = config["time-dictionary"]; QList<AbstractListEntry*> * settings = new QList<AbstractListEntry*>; for (YAML::iterator groupIter = settingsSet.begin(); groupIter != settingsSet.end(); ++groupIter) { YAML::Node settingsGroup = groupIter->second; std::string title(settingsGroup["group-title"]["title"].as<std::string>()); settings->append(new SettingsEntry(QString::fromStdString(title))); // qDebug() << QString::fromStdString(groupIter->first.as<std::string>()); for (YAML::iterator settingsIter = settingsGroup.begin(); settingsIter != settingsGroup.end(); ++settingsIter) { YAML::Node settingsInf = settingsIter->second; if (settingsInf["type"].as<std::string>() == "radio-button"){ ListSettingsEntry* settingsEntry = new ListSettingsEntry(); settingsEntry->name = settingsIter->first.as<std::string>(); createSettingsEntry(settingsInf, timeInf, *settingsEntry); settings->append(settingsEntry); } if (settingsInf["type"].as<std::string>() == "switcher") { OffOnSettingsEntry* settingsEntry = new OffOnSettingsEntry(); settingsEntry->name = settingsIter->first.as<std::string>(); createSettingsEntry(settingsInf, *settingsEntry); settings->append(settingsEntry); } } } return settings; }
/** * Load the Ufopaedia from YAML * @param node YAML node. * @param rule Pointer to Ruleset. */ void UfopaediaSaved::load(const YAML::Node& node, Ruleset *rule) { for (YAML::Iterator it = node.begin (); it != node.end (); ++it) { std::string id; *it >> id; insertArticle(rule->getUfopaediaArticle(id)); } }
/** * Loads a ruleset's contents from a YAML file. * @param filename YAML filename. */ void Ruleset::load(const std::string &filename) { std::string s = Options::getDataFolder() + "Ruleset/" + filename + ".rul"; std::ifstream fin(s.c_str()); if (!fin) { throw Exception("Failed to load ruleset"); } YAML::Parser parser(fin); YAML::Node doc; parser.GetNextDocument(doc); for (YAML::Iterator i = doc.begin(); i != doc.end(); ++i) { std::string key; i.first() >> key; if (key == "countries") { for (YAML::Iterator j = i.second().begin(); j != i.second().end(); ++j) { std::string type; j.second()["type"] >> type; RuleCountry *rule; if (_countries.find(type) != _countries.end()) { rule = _countries[type]; } else { rule = new RuleCountry(type); _countries[type] = rule; _countriesIndex.push_back(type); } rule->load(j.second()); } } else if (key == "regions") { for (YAML::Iterator j = i.second().begin(); j != i.second().end(); ++j) { std::string type; j.second()["type"] >> type; RuleRegion *rule; if (_regions.find(type) != _regions.end()) { rule = _regions[type]; } else { rule = new RuleRegion(type); _regions[type] = rule; _regionsIndex.push_back(type); } rule->load(j.second()); } } else if (key == "facilities")
static void IF_VALUEDATER(const maiken::Application& a, const YAML::Node& n, const std::string& s, const std::vector<std::string>& lefts){ kul::hash::set::String keys; for(YAML::const_iterator it= n.begin(); it != n.end(); ++it){ if(std::find(lefts.begin(), lefts.end(), it->first.Scalar()) == lefts.end()) KEXCEPT(maiken::Exception, "malformed "+s+" key, \n"+a.project().dir().path()); if(keys.count(it->first.Scalar())) KEXCEPT(maiken::Exception, "Duplicate "+s+"key detected: "+it->first.Scalar()+"\n"+a.project().dir().path()); keys.insert(it->first.Scalar()); } }
/** * Add the weighted options from a YAML::Node to a WeightedOptions. * The weight option list is not replaced, only values in @a nd will be added / * changed. * @param nd The YAML node (containing a map) with the new values. */ void WeightedOptions::load(const YAML::Node &nd) { for (YAML::const_iterator val = nd.begin(); val != nd.end(); ++val) { std::string id = val->first.as<std::string>(); size_t w = val->second.as<size_t>(); set(id, w); } }
bool loadFromYAMLNode(const YAML::Node& node, Writer& config) { for(YAML::const_iterator it = node.begin(); it != node.end(); ++it) { std::string key = it->first.as<std::string>(); const YAML::Node& n = it->second; switch (n.Type()) { case YAML::NodeType::Scalar: { std::string error; Variant v = yamlScalarToVariant(n, error); if (v.valid()) config.setValue(key, v); else config.addError("While reading key '" + key +"': " + error); break; } case YAML::NodeType::Sequence: { config.writeArray(key); for(YAML::const_iterator it2 = n.begin(); it2 != n.end(); ++it2) { const YAML::Node& n2 = *it2; if (n2.Type() != YAML::NodeType::Map) { config.addError("Sequences must only contains maps"); return false; } else { config.addArrayItem(); loadFromYAMLNode(n2, config); config.endArrayItem(); } } config.endArray(); break; } case YAML::NodeType::Map: config.writeGroup(key); loadFromYAMLNode(n, config); config.endGroup(); break; case YAML::NodeType::Null: break; } } return true; }
YAML::Node expandDefaults(const YAML::Node& node) { YAML::Node result = YAML::Clone(node); if (node.IsMap() && node["DEFAULT"]) { const YAML::Node& default_node = result["DEFAULT"]; for (auto field = result.begin(); field != result.end(); ++field) { std::string fieldname = field->first.as<std::string>(); if (fieldname != "DEFAULT") { result[fieldname] = applyDefaults(result[fieldname], default_node); } } } if (result.IsMap() || result.IsSequence()) { for (auto child = result.begin(); child != result.end(); ++child) { std::string child_name = child->first.as<std::string>(); result[child_name] = expandDefaults(child->second); } } return result; }
Optimizer( ros::NodeHandle& nodeHandle, ros::NodeHandle& ph ) : privHandle( ph ), rxInitialized( false ), epsInitialized( false ), lastSeq( 0 ) { GetParam<double>( privHandle, "feature_cache_time", _featureCacheTime, 1.0 ); // Number of info updates to store max unsigned int infoBufferSize; GetParam<unsigned int>( privHandle, "info_buffer_size", infoBufferSize, 0 ); _dataBuffer.SetMaxSize( infoBufferSize ); std::string logPath; if( GetParam( privHandle, "output_log_path", logPath ) ) { _logOutFile.open( logPath ); } // Iterate over all models WriteLock lock( _initMutex ); XmlRpc::XmlRpcValue modelsXml; GetParam( privHandle, "models", modelsXml ); YAML::Node modelsYaml = XmlToYaml( modelsXml ); YAML::Node::const_iterator iter; for( iter = modelsYaml.begin(); iter != modelsYaml.end(); ++iter ) { const std::string& modelName = iter->first.as<std::string>(); YAML::Node modelYaml = iter->second; RegisterModel( modelName, modelYaml ); } if( _estRegistry.count( "transition" ) == 0 ) { ROS_ERROR_STREAM( "Must specify transition model." ); exit( -1 ); } InnovationClipParameters clipParams; GetParam<unsigned int>( privHandle, "max_eps_length", clipParams.maxEpisodeLength, 100 ); // GetParam<unsigned int>( privHandle, "max_eps_to_keep", clipParams.numEpisodesToKeep, 50 ); GetParam<double>( privHandle, "l2_weight", clipParams.l2Weight, 1E-6 ); GetParam<unsigned int>( privHandle, "batch_size", clipParams.batchSize, 30 ); CovarianceEstimator& transReg = *(_estRegistry["transition"].estimator); _clipOptimizer = std::make_shared<InnovationClipOptimizer>( transReg, clipParams ); // _clipOptimizer = std::make_shared<InnovationClipOptimizer>( clipParams ); // TODO Iterate and add all non-transition regs to the optimizer typedef EstimatorRegistry::value_type Item; BOOST_FOREACH( Item& item, _estRegistry ) { _clipOptimizer->AddObservationReg( *item.second.estimator, item.first ); }
/** * Add the weighted options from a YAML::Node to a WeightedOptions. * The weight option list is not replaced, only values in @a nd will be added / * changed. * @param nd The YAML node (containing a map) with the new values. * @param wo The list to change. */ void WeightedOptions::load(const YAML::Node &nd) { for (YAML::Iterator val = nd.begin(); val != nd.end(); ++val) { std::string id; unsigned w; val.first() >> id; val.second() >> w; set(id, w); } }
void Config::parseCommand(const YAML::Node& node, iCommandConfig& config) { //std::cerr << "Under active development!" << '\n'; //return; if(node.size() >= 1 && node.IsMap()) for (YAML::const_iterator iter=node.begin();iter!=node.end();++iter) { std::string key = iter->first.as<std::string>(); YAML::Node value = iter->second; Util::lowercase(key); //std::cout << key << std::endl; if(key == "command") { if(value.IsScalar()) { LOG(logger, DEBUG, "Proc: %s", value.as<std::string>().c_str()); config.command = Util::parseCommand(value.as<std::string>()); #if 0 // TODO: We need to take quotes from the user and send them all as // a single argument instead of multiple arguments. std::string cnfval = value.as<std::string>(); char* cmd = new char[cnfval.size() + 1]; cmd[cnfval.size()] = 0; memcpy(cmd, cnfval.c_str(), cnfval.size()); size_t size = 1; for(size_t i=0; i<cnfval.size(); i++) if(cmd[i] == ' ') size++; config.command = new char*[size+1]; config.command[size] = 0; config.command[0] = cmd; size_t csize = 0; for(size_t i=0; i<cnfval.size(); i++) { if(cmd[i] == ' ') { cmd[i] = 0; if(csize < size && (i + 1) < cnfval.size()) { config.command[++csize] = cmd+(unsigned int)i+1; } } } #endif } } else if( key == "enabled" ) { config.enabled = value.as<bool>(); } } //for(size_t i=0;config.command[i]; i++) //{ // std::cout << "==" << config.command[i] << '\n'; //} }
void ExtraSprites::load(const YAML::Node &node) { for (YAML::Iterator i = node.begin(); i != node.end(); ++i) { std::string key; i.first() >> key; if (key == "width") { i.second() >> _width; } else if (key == "height")