本文整理汇总了C++中BSONObj::firstElementFieldName方法的典型用法代码示例。如果您正苦于以下问题:C++ BSONObj::firstElementFieldName方法的具体用法?C++ BSONObj::firstElementFieldName怎么用?C++ BSONObj::firstElementFieldName使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类BSONObj
的用法示例。
在下文中一共展示了BSONObj::firstElementFieldName方法的10个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: init
void Projection::init( const BSONObj& o ) {
massert( 10371 , "can only add to Projection once", _source.isEmpty());
_source = o;
BSONObjIterator i( o );
int true_false = -1;
while ( i.more() ) {
BSONElement e = i.next();
if ( ! e.isNumber() )
_hasNonSimple = true;
if (e.type() == Object) {
BSONObj obj = e.embeddedObject();
BSONElement e2 = obj.firstElement();
if ( mongoutils::str::equals( e2.fieldName(), "$slice" ) ) {
if (e2.isNumber()) {
int i = e2.numberInt();
if (i < 0)
add(e.fieldName(), i, -i); // limit is now positive
else
add(e.fieldName(), 0, i);
}
else if (e2.type() == Array) {
BSONObj arr = e2.embeddedObject();
uassert(13099, "$slice array wrong size", arr.nFields() == 2 );
BSONObjIterator it(arr);
int skip = it.next().numberInt();
int limit = it.next().numberInt();
uassert(13100, "$slice limit must be positive", limit > 0 );
add(e.fieldName(), skip, limit);
}
else {
uassert(13098, "$slice only supports numbers and [skip, limit] arrays", false);
}
}
else if ( mongoutils::str::equals( e2.fieldName(), "$elemMatch" ) ) {
// validate $elemMatch arguments and dependencies
uassert( 16342, "elemMatch: invalid argument. object required.",
e2.type() == Object );
uassert( 16343, "Cannot specify positional operator and $elemMatch"
" (currently unsupported).",
_arrayOpType != ARRAY_OP_POSITIONAL );
uassert( 16344, "Cannot use $elemMatch projection on a nested field"
" (currently unsupported).",
! mongoutils::str::contains( e.fieldName(), '.' ) );
_arrayOpType = ARRAY_OP_ELEM_MATCH;
// initialize new Matcher object(s)
_matchers.insert( make_pair( mongoutils::str::before( e.fieldName(), '.' ),
boost::make_shared<Matcher>( e.wrap(), true ) ) );
add( e.fieldName(), true );
}
else {
uasserted(13097, string("Unsupported projection option: ") +
obj.firstElementFieldName() );
}
}
else if (!strcmp(e.fieldName(), "_id") && !e.trueValue()) {
_includeID = false;
}
else {
add( e.fieldName(), e.trueValue() );
// validate input
if (true_false == -1) {
true_false = e.trueValue();
_include = !e.trueValue();
}
else {
uassert( 10053 , "You cannot currently mix including and excluding fields. "
"Contact us if this is an issue." ,
(bool)true_false == e.trueValue() );
}
}
if ( mongoutils::str::contains( e.fieldName(), ".$" ) ) {
// positional op found; verify dependencies
uassert( 16345, "Cannot exclude array elements with the positional operator"
" (currently unsupported).", e.trueValue() );
uassert( 16346, "Cannot specify more than one positional array element per query"
" (currently unsupported).", _arrayOpType != ARRAY_OP_POSITIONAL );
uassert( 16347, "Cannot specify positional operator and $elemMatch"
" (currently unsupported).", _arrayOpType != ARRAY_OP_ELEM_MATCH );
_arrayOpType = ARRAY_OP_POSITIONAL;
}
}
}
示例2: parse
Status UpdateDriver::parse(const BSONObj& updateExpr, const bool multi) {
clear();
// Check if the update expression is a full object replacement.
if (*updateExpr.firstElementFieldName() != '$') {
if (multi) {
return Status(ErrorCodes::FailedToParse, "multi update only works with $ operators");
}
// Modifiers expect BSONElements as input. But the input to object replace is, by
// definition, an object. We wrap the 'updateExpr' as the mod is expecting. Note
// that the wrapper is temporary so the object replace mod should make a copy of
// the object.
unique_ptr<ModifierObjectReplace> mod(new ModifierObjectReplace);
BSONObj wrapper = BSON("dummy" << updateExpr);
Status status = mod->init(wrapper.firstElement(), _modOptions);
if (!status.isOK()) {
return status;
}
_mods.push_back(mod.release());
// Register the fact that this driver will only do full object replacements.
_replacementMode = true;
return Status::OK();
}
// The update expression is made of mod operators, that is
// { <$mod>: {...}, <$mod>: {...}, ... }
BSONObjIterator outerIter(updateExpr);
while (outerIter.more()) {
BSONElement outerModElem = outerIter.next();
// Check whether this is a valid mod type.
modifiertable::ModifierType modType = modifiertable::getType(outerModElem.fieldName());
if (modType == modifiertable::MOD_UNKNOWN) {
return Status(ErrorCodes::FailedToParse,
str::stream() << "Unknown modifier: " << outerModElem.fieldName());
}
// Check whether there is indeed a list of mods under this modifier.
if (outerModElem.type() != Object) {
return Status(ErrorCodes::FailedToParse,
str::stream() << "Modifiers operate on fields but we found type "
<< typeName(outerModElem.type())
<< " instead. For example: {$mod: {<field>: ...}}"
<< " not {"
<< outerModElem.toString()
<< "}");
}
// Check whether there are indeed mods under this modifier.
if (outerModElem.embeddedObject().isEmpty()) {
return Status(ErrorCodes::FailedToParse,
str::stream() << "'" << outerModElem.fieldName()
<< "' is empty. You must specify a field like so: "
"{"
<< outerModElem.fieldName()
<< ": {<field>: ...}}");
}
BSONObjIterator innerIter(outerModElem.embeddedObject());
while (innerIter.more()) {
BSONElement innerModElem = innerIter.next();
Status status = addAndParse(modType, innerModElem);
if (!status.isOK()) {
return status;
}
}
}
// Register the fact that there will be only $mod's in this driver -- no object
// replacement.
_replacementMode = false;
return Status::OK();
}
示例3: validateNS
//.........这里部分代码省略.........
set<DiskLoc> recs;
if( scanData ) {
shared_ptr<Cursor> c = theDataFileMgr.findAll(ns);
int n = 0;
int nInvalid = 0;
long long len = 0;
long long nlen = 0;
int outOfOrder = 0;
DiskLoc cl_last;
while ( c->ok() ) {
n++;
DiskLoc cl = c->currLoc();
if ( n < 1000000 )
recs.insert(cl);
if ( d->isCapped() ) {
if ( cl < cl_last )
outOfOrder++;
cl_last = cl;
}
Record *r = c->_current();
len += r->lengthWithHeaders();
nlen += r->netLength();
if (full){
BSONObj obj = BSONObj::make(r);
if (!obj.isValid() || !obj.valid()){ // both fast and deep checks
valid = false;
if (nInvalid == 0) // only log once;
errors << "invalid bson object detected (see logs for more info)";
nInvalid++;
if (strcmp("_id", obj.firstElementFieldName()) == 0){
try {
obj.firstElement().validate(); // throws on error
log() << "Invalid bson detected in " << ns << " with _id: " << obj.firstElement().toString(false) << endl;
}
catch(...){
log() << "Invalid bson detected in " << ns << " with corrupt _id" << endl;
}
}
else {
log() << "Invalid bson detected in " << ns << " and couldn't find _id" << endl;
}
}
}
c->advance();
}
if ( d->isCapped() && !d->capLooped() ) {
result.append("cappedOutOfOrder", outOfOrder);
if ( outOfOrder > 1 ) {
valid = false;
errors << "too many out of order records";
}
}
result.append("objectsFound", n);
if (full) {
result.append("invalidObjects", nInvalid);
}
result.appendNumber("bytesWithHeaders", len);
result.appendNumber("bytesWithoutHeaders", nlen);
}
示例4: validateNS
//.........这里部分代码省略.........
}
Record *r = cl.rec();
len += r->lengthWithHeaders();
nlen += r->netLength();
if ( r->lengthWithHeaders() ==
NamespaceDetails::quantizeAllocationSpace
( r->lengthWithHeaders() ) ) {
// Count the number of records having a size consistent with
// the quantizeAllocationSpace quantization implementation.
++nQuantizedSize;
}
if ( r->lengthWithHeaders() ==
NamespaceDetails::quantizePowerOf2AllocationSpace
( r->lengthWithHeaders() - 1 ) ) {
// Count the number of records having a size consistent with the
// quantizePowerOf2AllocationSpace quantization implementation.
// Because of SERVER-8311, power of 2 quantization is not idempotent and
// r->lengthWithHeaders() - 1 must be checked instead of the record
// length itself.
++nPowerOf2QuantizedSize;
}
if (full){
BSONObj obj = BSONObj::make(r);
if (!obj.isValid() || !obj.valid()){ // both fast and deep checks
valid = false;
if (nInvalid == 0) // only log once;
errors << "invalid bson object detected (see logs for more info)";
nInvalid++;
if (strcmp("_id", obj.firstElementFieldName()) == 0){
try {
obj.firstElement().validate(); // throws on error
log() << "Invalid bson detected in " << ns << " with _id: " << obj.firstElement().toString(false) << endl;
}
catch(...){
log() << "Invalid bson detected in " << ns << " with corrupt _id" << endl;
}
}
else {
log() << "Invalid bson detected in " << ns << " and couldn't find _id" << endl;
}
}
else {
bsonLen += obj.objsize();
}
}
}
if (Runner::RUNNER_EOF != state) {
// TODO: more descriptive logging.
warning() << "Internal error while reading collection " << ns << endl;
}
if ( nsd->isCapped() && !nsd->capLooped() ) {
result.append("cappedOutOfOrder", outOfOrder);
if ( outOfOrder > 1 ) {
valid = false;
errors << "too many out of order records";
}
}
result.append("objectsFound", n);
if (full) {
result.append("invalidObjects", nInvalid);
示例5: updateShardChunks
Status updateShardChunks(OperationContext* opCtx,
const NamespaceString& nss,
const std::vector<ChunkType>& chunks,
const OID& currEpoch) {
invariant(!chunks.empty());
NamespaceString chunkMetadataNss(ChunkType::ShardNSPrefix + nss.ns());
try {
DBDirectClient client(opCtx);
/**
* Here are examples of the operations that can happen on the config server to update
* the config.chunks collection. 'chunks' only includes the chunks that result from the
* operations, which can be read from the config server, not any that were removed, so
* we must delete any chunks that overlap with the new 'chunks'.
*
* CollectionVersion = 10.3
*
* moveChunk
* {_id: 3, max: 5, version: 10.1} --> {_id: 3, max: 5, version: 11.0}
*
* splitChunk
* {_id: 3, max: 9, version 10.3} --> {_id: 3, max: 5, version 10.4}
* {_id: 5, max: 8, version 10.5}
* {_id: 8, max: 9, version 10.6}
*
* mergeChunk
* {_id: 10, max: 14, version 4.3} --> {_id: 10, max: 22, version 10.4}
* {_id: 14, max: 19, version 7.1}
* {_id: 19, max: 22, version 2.0}
*
*/
for (auto& chunk : chunks) {
// Check for a different epoch.
if (!chunk.getVersion().hasEqualEpoch(currEpoch)) {
return Status{ErrorCodes::ConflictingOperationInProgress,
str::stream() << "Invalid chunks found when reloading '"
<< nss.toString()
<< "'. Previous collection epoch was '"
<< currEpoch.toString()
<< "', but unexpectedly found a new epoch '"
<< chunk.getVersion().epoch().toString()
<< "'. Collection was dropped and recreated."};
}
// Delete any overlapping chunk ranges. Overlapping chunks will have a min value
// ("_id") between (chunk.min, chunk.max].
//
// query: { "_id" : {"$gte": chunk.min, "$lt": chunk.max}}
auto deleteDocs(stdx::make_unique<BatchedDeleteDocument>());
deleteDocs->setQuery(BSON(ChunkType::minShardID << BSON(
"$gte" << chunk.getMin() << "$lt" << chunk.getMax())));
deleteDocs->setLimit(0);
auto deleteRequest(stdx::make_unique<BatchedDeleteRequest>());
deleteRequest->addToDeletes(deleteDocs.release());
BatchedCommandRequest batchedDeleteRequest(deleteRequest.release());
batchedDeleteRequest.setNS(chunkMetadataNss);
const BSONObj deleteCmdObj = batchedDeleteRequest.toBSON();
rpc::UniqueReply deleteCommandResponse =
client.runCommandWithMetadata(chunkMetadataNss.db().toString(),
deleteCmdObj.firstElementFieldName(),
rpc::makeEmptyMetadata(),
deleteCmdObj);
auto deleteStatus =
getStatusFromCommandResult(deleteCommandResponse->getCommandReply());
if (!deleteStatus.isOK()) {
return deleteStatus;
}
// Now the document can be expected to cleanly insert without overlap.
auto insert(stdx::make_unique<BatchedInsertRequest>());
insert->addToDocuments(chunk.toShardBSON());
BatchedCommandRequest insertRequest(insert.release());
insertRequest.setNS(chunkMetadataNss);
const BSONObj insertCmdObj = insertRequest.toBSON();
rpc::UniqueReply commandResponse =
client.runCommandWithMetadata(chunkMetadataNss.db().toString(),
insertCmdObj.firstElementFieldName(),
rpc::makeEmptyMetadata(),
insertCmdObj);
auto insertStatus = getStatusFromCommandResult(commandResponse->getCommandReply());
if (!insertStatus.isOK()) {
return insertStatus;
}
}
return Status::OK();
} catch (const DBException& ex) {
return ex.toStatus();
}
}
示例6: processObj
bool processObj(const BSONObj &obj) {
if (obj.hasField("$err")) {
log() << "error getting oplog: " << obj << endl;
return false;
}
static const char *names[] = {"ts", "op", "ns", "o", "b"};
BSONElement fields[5];
obj.getFields(5, names, fields);
BSONElement &tsElt = fields[0];
if (!tsElt.ok()) {
log() << "oplog format error: " << obj << " missing 'ts' field." << endl;
return false;
}
if (tsElt.type() != Date && tsElt.type() != Timestamp) {
log() << "oplog format error: " << obj << " wrong 'ts' field type." << endl;
return false;
}
_thisTime = OpTime(tsElt.date());
BSONElement &opElt = fields[1];
if (!opElt.ok()) {
log() << "oplog format error: " << obj << " missing 'op' field." << endl;
return false;
}
StringData op = opElt.Stringdata();
// nop
if (op == "n") {
if (!_insertBuf.empty()) {
flushInserts();
}
_maxOpTimeSynced = _thisTime;
_thisTime = OpTime();
return true;
}
// "presence of a database"
if (op == "db") {
if (!_insertBuf.empty()) {
flushInserts();
}
_maxOpTimeSynced = _thisTime;
_thisTime = OpTime();
return true;
}
if (op != "c" && op != "i" && op != "u" && op != "d") {
log() << "oplog format error: " << obj << " has an invalid 'op' field of '" << op << "'." << endl;
return false;
}
if (op != "i" && !_insertBuf.empty()) {
flushInserts();
}
BSONElement &nsElt = fields[2];
if (!nsElt.ok()) {
log() << "oplog format error: " << obj << " missing 'ns' field." << endl;
return false;
}
StringData ns = nsElt.Stringdata();
size_t i = ns.find('.');
if (i == string::npos) {
log() << "oplog format error: invalid namespace '" << ns << "' in op " << obj << "." << endl;
return false;
}
StringData dbname = ns.substr(0, i);
StringData collname = ns.substr(i + 1);
BSONElement &oElt = fields[3];
if (!oElt.ok()) {
log() << "oplog format error: " << obj << " missing 'o' field." << endl;
return false;
}
BSONObj o = obj["o"].Obj();
if (op == "c") {
if (collname != "$cmd") {
log() << "oplog format error: invalid namespace '" << ns << "' for command in op " << obj << "." << endl;
return false;
}
BSONObj info;
bool ok = _conn.runCommand(dbname.toString(), o, info);
if (!ok) {
StringData fieldName = o.firstElementFieldName();
BSONElement errmsgElt = info["errmsg"];
StringData errmsg = errmsgElt.type() == String ? errmsgElt.Stringdata() : "";
bool isDropIndexes = (fieldName == "dropIndexes" || fieldName == "deleteIndexes");
if (((fieldName == "drop" || isDropIndexes) && errmsg == "ns not found") ||
(isDropIndexes && (errmsg == "index not found" || errmsg.find("can't find index with key:") == 0))) {
// This is actually ok. We don't mind dropping something that's not there.
LOG(1) << "Tried to replay " << o << ", got " << info << ", ignoring." << endl;
}
else {
log() << "replay of command " << o << " failed: " << info << endl;
return false;
}
}
}
else {
//.........这里部分代码省略.........
示例7: init
void Projection::init( const BSONObj& o ) {
massert( 10371 , "can only add to Projection once", _source.isEmpty());
_source = o;
BSONObjIterator i( o );
int true_false = -1;
while ( i.more() ) {
BSONElement e = i.next();
if ( ! e.isNumber() )
_hasNonSimple = true;
if (e.type() == Object) {
BSONObj obj = e.embeddedObject();
BSONElement e2 = obj.firstElement();
if ( strcmp(e2.fieldName(), "$slice") == 0 ) {
if (e2.isNumber()) {
int i = e2.numberInt();
if (i < 0)
add(e.fieldName(), i, -i); // limit is now positive
else
add(e.fieldName(), 0, i);
}
else if (e2.type() == Array) {
BSONObj arr = e2.embeddedObject();
uassert(13099, "$slice array wrong size", arr.nFields() == 2 );
BSONObjIterator it(arr);
int skip = it.next().numberInt();
int limit = it.next().numberInt();
uassert(13100, "$slice limit must be positive", limit > 0 );
add(e.fieldName(), skip, limit);
}
else {
uassert(13098, "$slice only supports numbers and [skip, limit] arrays", false);
}
}
else {
uassert(13097, string("Unsupported projection option: ") + obj.firstElementFieldName(), false);
}
}
else if (!strcmp(e.fieldName(), "_id") && !e.trueValue()) {
_includeID = false;
}
else {
add (e.fieldName(), e.trueValue());
// validate input
if (true_false == -1) {
true_false = e.trueValue();
_include = !e.trueValue();
}
else {
uassert( 10053 , "You cannot currently mix including and excluding fields. Contact us if this is an issue." ,
(bool)true_false == e.trueValue() );
}
}
}
}
示例8: isDocReplacement
bool UpdateDriver::isDocReplacement(const BSONObj& updateExpr) {
return *updateExpr.firstElementFieldName() != '$';
}
示例9: _updateObjects
UpdateResult _updateObjects( bool su,
const char* ns,
const BSONObj& updateobj,
const BSONObj& patternOrig,
bool upsert,
bool multi,
bool logop ,
OpDebug& debug,
RemoveSaver* rs,
bool fromMigrate,
const QueryPlanSelectionPolicy& planPolicy ) {
DEBUGUPDATE( "update: " << ns
<< " update: " << updateobj
<< " query: " << patternOrig
<< " upsert: " << upsert << " multi: " << multi );
Client& client = cc();
int profile = client.database()->profile;
debug.updateobj = updateobj;
// The idea with these here it to make them loop invariant for
// multi updates, and thus be a bit faster for that case. The
// pointers may be left invalid on a failed or terminal yield
// recovery.
NamespaceDetails* d = nsdetails(ns); // can be null if an upsert...
NamespaceDetailsTransient* nsdt = &NamespaceDetailsTransient::get(ns);
auto_ptr<ModSet> mods;
bool isOperatorUpdate = updateobj.firstElementFieldName()[0] == '$';
int modsIsIndexed = false; // really the # of indexes
if ( isOperatorUpdate ) {
if( d && d->indexBuildInProgress ) {
set<string> bgKeys;
d->inProgIdx().keyPattern().getFieldNames(bgKeys);
mods.reset( new ModSet(updateobj, nsdt->indexKeys(), &bgKeys) );
}
else {
mods.reset( new ModSet(updateobj, nsdt->indexKeys()) );
}
modsIsIndexed = mods->isIndexed();
}
if( planPolicy.permitOptimalIdPlan() && !multi && isSimpleIdQuery(patternOrig) && d &&
!modsIsIndexed ) {
int idxNo = d->findIdIndex();
if( idxNo >= 0 ) {
debug.idhack = true;
UpdateResult result = _updateById( isOperatorUpdate,
idxNo,
mods.get(),
profile,
d,
nsdt,
su,
ns,
updateobj,
patternOrig,
logop,
debug,
fromMigrate);
if ( result.existing || ! upsert ) {
return result;
}
else if ( upsert && ! isOperatorUpdate && ! logop) {
// this handles repl inserts
checkNoMods( updateobj );
debug.upsert = true;
BSONObj no = updateobj;
theDataFileMgr.insertWithObjMod(ns, no, su);
return UpdateResult( 0 , 0 , 1 , no );
}
}
}
int numModded = 0;
debug.nscanned = 0;
shared_ptr<Cursor> c =
NamespaceDetailsTransient::getCursor( ns, patternOrig, BSONObj(), planPolicy );
d = nsdetails(ns);
nsdt = &NamespaceDetailsTransient::get(ns);
bool autoDedup = c->autoDedup();
if( c->ok() ) {
set<DiskLoc> seenObjects;
MatchDetails details;
auto_ptr<ClientCursor> cc;
do {
if ( cc.get() == 0 &&
client.allowedToThrowPageFaultException() &&
! c->currLoc().isNull() &&
! c->currLoc().rec()->likelyInPhysicalMemory() ) {
throw PageFaultException( c->currLoc().rec() );
}
bool atomic = c->matcher() && c->matcher()->docMatcher().atomic();
//.........这里部分代码省略.........
示例10: run
bool CmdExplain::run(OperationContext* txn,
const string& dbname,
BSONObj& cmdObj, int options,
string& errmsg,
BSONObjBuilder& result,
bool fromRepl) {
// Should never get explain commands issued from replication.
if (fromRepl) {
Status commandStat(ErrorCodes::IllegalOperation,
"explain command should not be from repl");
appendCommandStatus(result, commandStat);
return false;
}
// Get the verbosity. We use the executionStats verbosity by default.
Explain::Verbosity verbosity = Explain::EXEC_STATS;
if (!cmdObj["verbosity"].eoo()) {
const char* verbStr = cmdObj["verbosity"].valuestrsafe();
if (mongoutils::str::equals(verbStr, "queryPlanner")) {
verbosity = Explain::QUERY_PLANNER;
}
else if (mongoutils::str::equals(verbStr, "allPlansExecution")) {
verbosity = Explain::EXEC_ALL_PLANS;
}
else if (mongoutils::str::equals(verbStr, "full")) {
verbosity = Explain::FULL;
}
else if (!mongoutils::str::equals(verbStr, "executionStats")) {
Status commandStat(ErrorCodes::BadValue,
"verbosity string must be one of "
"{'queryPlanner', 'executionStats', 'allPlansExecution'}");
appendCommandStatus(result, commandStat);
return false;
}
}
if (Object != cmdObj.firstElement().type()) {
Status commandStat(ErrorCodes::BadValue,
"explain command requires a nested object");
appendCommandStatus(result, commandStat);
return false;
}
// This is the nested command which we are explaining.
BSONObj explainObj = cmdObj.firstElement().Obj();
Command* commToExplain = Command::findCommand(explainObj.firstElementFieldName());
if (NULL == commToExplain) {
mongoutils::str::stream ss;
ss << "unknown command: " << explainObj.firstElementFieldName();
Status explainStatus(ErrorCodes::CommandNotFound, ss);
return appendCommandStatus(result, explainStatus);
}
// Check whether the child command is allowed to run here. TODO: this logic is
// copied from Command::execCommand and should be abstracted. Until then, make
// sure to keep it up to date.
repl::ReplicationCoordinator* replCoord = repl::getGlobalReplicationCoordinator();
bool canRunHere =
replCoord->canAcceptWritesForDatabase(dbname) ||
commToExplain->slaveOk() ||
(commToExplain->slaveOverrideOk() && (options & QueryOption_SlaveOk));
if (!canRunHere) {
mongoutils::str::stream ss;
ss << "Explain's child command cannot run on this node. "
<< "Are you explaining a write command on a secondary?";
appendCommandStatus(result, false, ss);
return false;
}
// Actually call the nested command's explain(...) method.
Status explainStatus = commToExplain->explain(txn, dbname, explainObj, verbosity, &result);
if (!explainStatus.isOK()) {
return appendCommandStatus(result, explainStatus);
}
return true;
}