Skip to content

Commit

Permalink
Modified code for creating the dictionary of values that are computed…
Browse files Browse the repository at this point in the history
… by shortcuts.

The names of the actions that have descriptions in the keyword object for a shortcut are now stored at the same
time the lines of the shortcut are stored (i.e. when the shortcut actions are created).  When driver asks for
documentation for these components it thus gets the relevant actions from the shortcut and then looks up the corresponding
documentation strings
  • Loading branch information
Gareth Aneurin Tribello committed May 16, 2024
1 parent c1f405c commit 77a52f0
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 101 deletions.
3 changes: 0 additions & 3 deletions regtest/basic/rt-parse-only/values.json.reference
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
"phi" : {
"phi" : { "type": "scalar", "desciption": "" }
},
"shortcut_phi" : {
"phi" : { "type": "scalar", "desciption": "" }
},
"r1" : {
"r1.X" : { "type": "scalar", "description": "values from the column labelled p2.X in the file named input_colvar" }
},
Expand Down
31 changes: 2 additions & 29 deletions regtest/contour/rt-parse-only/values.json.reference
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,12 @@
"fcc_mat.y" : { "type": "matrix", "desciption": "" }
"fcc_mat.z" : { "type": "matrix", "desciption": "" }
},
"shortcut_fcc_mat" : {
"fcc_mat.w" : { "type": "matrix", "desciption": "" }
"fcc_mat.x" : { "type": "matrix", "desciption": "" }
"fcc_mat.y" : { "type": "matrix", "desciption": "" }
"fcc_mat.z" : { "type": "matrix", "desciption": "" }
},
"fcc_vfunc" : {
"fcc_vfunc" : { "type": "matrix", "desciption": "" }
},
"shortcut_fcc_vfunc" : {
"fcc_vfunc" : { "type": "matrix", "desciption": "" }
},
"fcc_wvfunc" : {
"fcc_wvfunc" : { "type": "matrix", "desciption": "" }
},
"shortcut_fcc_wvfunc" : {
"fcc_wvfunc" : { "type": "matrix", "desciption": "" }
},
"fcc_ones" : {
"fcc_ones" : { "type": "vector", "desciption": "" }
},
Expand All @@ -62,8 +50,8 @@
"fcc_n" : {
"fcc_n" : { "type": "vector", "desciption": "" }
},
"shortcut_fcc_n" : {
"fcc_n" : { "type": "vector", "desciption": "" }
"shortcut_fcc" : {
"fcc" : { "type": "vector", "desciption": "" }
},
"dens_dist" : {
"dens_dist.x" : { "type": "vector", "desciption": "" }
Expand All @@ -81,15 +69,9 @@
"dens_numer_cov" : {
"dens_numer_cov" : { "type": "vector", "desciption": "" }
},
"shortcut_dens_numer_cov" : {
"dens_numer_cov" : { "type": "vector", "desciption": "" }
},
"dens_numer_icov" : {
"dens_numer_icov" : { "type": "vector", "desciption": "" }
},
"shortcut_dens_numer_icov" : {
"dens_numer_icov" : { "type": "vector", "desciption": "" }
},
"dens_numer" : {
"dens_numer" : { "type": "grid", "desciption": "" }
},
Expand All @@ -105,24 +87,15 @@
"dens_denom_cov" : {
"dens_denom_cov" : { "type": "vector", "desciption": "" }
},
"shortcut_dens_denom_cov" : {
"dens_denom_cov" : { "type": "vector", "desciption": "" }
},
"dens_denom_icov" : {
"dens_denom_icov" : { "type": "vector", "desciption": "" }
},
"shortcut_dens_denom_icov" : {
"dens_denom_icov" : { "type": "vector", "desciption": "" }
},
"dens_denom" : {
"dens_denom" : { "type": "grid", "desciption": "" }
},
"dens" : {
"dens" : { "type": "grid", "desciption": "" }
},
"shortcut_dens" : {
"dens" : { "type": "grid", "desciption": "" }
},
"cont" : {
"cont.dens_dist.x" : { "type": "vector", "description": "a vector of coordinates for the contour along the dens_dist.x direction" },
"cont.dens_dist.y" : { "type": "vector", "description": "a vector of coordinates for the contour along the dens_dist.y direction" },
Expand Down
2 changes: 1 addition & 1 deletion regtest/multicolvar/rt-parse-only/config
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ type=driver
# this is to test automatic sizing
arg="--parse-only --natoms 10000 --shortcut-ofile shortcuts.json --valuedict-ofile values_pre.json"
function plumed_regtest_after(){
cat values_pre.json | awk '{ for(i=1;i<=NF;++i){ if($i=="\"description\":") { if(match($1, /[1-9]/)) printf("\"desciption\": \"%s\" }", $(i+2)); else printf("\"desciption\": \"\" }"); break; } printf "%s ", $i }; printf("\n");}' > values.json
cat values_pre.json | awk '{ for(i=1;i<=NF;++i){ if($i=="\"description\":") { if(match($1, /[1-9]/) && match($(i+2), /[1-9]/)) printf("\"desciption\": \"%s\" }", $(i+2)); else printf("\"desciption\": \"\" }"); break; } printf "%s ", $i }; printf("\n");}' > values.json
}
2 changes: 2 additions & 0 deletions regtest/multicolvar/rt-parse-only/plumed.dat
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ ssall: SORT ARG=dall

dallt: DISTANCE ATOMS1=7,8 ATOMS2=9,10 ATOMS3=11,12
sfinal: SORT ARG=dall,dallt

dallk: DISTANCES ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 MEAN LESS_THAN1={RATIONAL R_0=1.0} LESS_THAN2={RATIONAL R_0=1.5} LOWEST
5 changes: 5 additions & 0 deletions regtest/multicolvar/rt-parse-only/shortcuts.json.reference
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dallk" : {
"expansion" : "dallk_vatom1: CENTER ATOMS=1,2\ndallk_vatom2: CENTER ATOMS=3,4\ndallk_vatom3: CENTER ATOMS=5,6\ndallk_grp: GROUP ATOMS=dallk_vatom1,dallk_vatom2,dallk_vatom3\ndallk: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6\ndallk_lt1: LESS_THAN ARG=dallk SWITCH={RATIONAL R_0=1.0}\ndallk_lessthan-1: SUM ARG=dallk_lt1 PERIODIC=NO\ndallk_lt2: LESS_THAN ARG=dallk SWITCH={RATIONAL R_0=1.5}\ndallk_lessthan-2: SUM ARG=dallk_lt2 PERIODIC=NO\ndallk_lowest: LOWEST ARG=dallk\ndallk_mean: MEAN ARG=dallk PERIODIC=NO"
}
}
73 changes: 42 additions & 31 deletions regtest/multicolvar/rt-parse-only/values.json.reference
Original file line number Diff line number Diff line change
Expand Up @@ -21,61 +21,72 @@
"Box" : { "type": "matrix", "desciption": "" }
},
"d1" : {
"d1" : { "type": "scalar", "desciption": "DISTANCE" }
},
"shortcut_d1" : {
"d1" : { "type": "scalar", "desciption": "DISTANCE" }
"d1" : { "type": "scalar", "desciption": "" }
},
"d2" : {
"d2" : { "type": "scalar", "desciption": "DISTANCE" }
},
"shortcut_d2" : {
"d2" : { "type": "scalar", "desciption": "DISTANCE" }
"d2" : { "type": "scalar", "desciption": "" }
},
"d3" : {
"d3" : { "type": "scalar", "desciption": "DISTANCE" }
},
"shortcut_d3" : {
"d3" : { "type": "scalar", "desciption": "DISTANCE" }
"d3" : { "type": "scalar", "desciption": "" }
},
"ss" : {
"ss.1" : { "type": "scalar", "desciption": "1th" }
"ss.2" : { "type": "scalar", "desciption": "2th" }
"ss.3" : { "type": "scalar", "desciption": "3th" }
},
"shortcut_ss" : {
"ss.1" : { "type": "scalar", "desciption": "1th" }
"ss.2" : { "type": "scalar", "desciption": "2th" }
"ss.3" : { "type": "scalar", "desciption": "3th" }
},
"dall" : {
"dall" : { "type": "vector", "desciption": "" }
},
"shortcut_dall" : {
"dall" : { "type": "vector", "desciption": "" }
},
"ssall" : {
"ssall.1" : { "type": "scalar", "desciption": "1th" }
"ssall.2" : { "type": "scalar", "desciption": "2th" }
"ssall.3" : { "type": "scalar", "desciption": "3th" }
},
"shortcut_ssall" : {
"ssall.1" : { "type": "scalar", "desciption": "1th" }
"ssall.2" : { "type": "scalar", "desciption": "2th" }
"ssall.3" : { "type": "scalar", "desciption": "3th" }
},
"dallt" : {
"dallt" : { "type": "vector", "desciption": "" }
},
"shortcut_dallt" : {
"dallt" : { "type": "vector", "desciption": "" }
},
"sfinal" : {
"sfinal.1" : { "type": "scalar", "desciption": "1th" }
"sfinal.2" : { "type": "scalar", "desciption": "2th" }
},
"shortcut_sfinal" : {
"sfinal.1" : { "type": "scalar", "desciption": "1th" }
"sfinal.2" : { "type": "scalar", "desciption": "2th" }
"dallk_vatom1" : {
"dallk_vatom1" : { "type": "atoms", "desciption": "" }
},
"dallk_vatom2" : {
"dallk_vatom2" : { "type": "atoms", "desciption": "" }
},
"dallk_vatom3" : {
"dallk_vatom3" : { "type": "atoms", "desciption": "" }
},
"dallk_grp" : {
"dallk_grp" : { "type": "atoms", "desciption": "" }
},
"dallk" : {
"dallk" : { "type": "vector", "desciption": "" }
},
"dallk_lt1" : {
"dallk_lt1" : { "type": "vector", "desciption": "" }
},
"dallk_lessthan-1" : {
"dallk_lessthan-1" : { "type": "scalar", "desciption": "" }
},
"dallk_lt2" : {
"dallk_lt2" : { "type": "vector", "desciption": "" }
},
"dallk_lessthan-2" : {
"dallk_lessthan-2" : { "type": "scalar", "desciption": "" }
},
"dallk_lowest" : {
"dallk_lowest" : { "type": "scalar", "desciption": "" }
},
"dallk_mean" : {
"dallk_mean" : { "type": "scalar", "desciption": "" }
},
"shortcut_dallk" : {
"dallk" : { "type": "vector", "desciption": "" }
"dallk_lessthan-1" : { "type": "scalar", "desciption": "" }
"dallk_lessthan-2" : { "type": "scalar", "desciption": "" }
"dallk_lowest" : { "type": "scalar", "desciption": "" }
"dallk_mean" : { "type": "scalar", "desciption": "" }
}
}
12 changes: 0 additions & 12 deletions regtest/symfunc/rt-parse-only/values.json.reference
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@
"q1_mat.y" : { "type": "matrix", "desciption": "" }
"q1_mat.z" : { "type": "matrix", "desciption": "" }
},
"shortcut_q1_mat" : {
"q1_mat.w" : { "type": "matrix", "desciption": "" }
"q1_mat.x" : { "type": "matrix", "desciption": "" }
"q1_mat.y" : { "type": "matrix", "desciption": "" }
"q1_mat.z" : { "type": "matrix", "desciption": "" }
},
"q1_sh" : {
"q1_sh.rm-n1" : { "type": "matrix", "desciption": "" }
"q1_sh.rm-0" : { "type": "matrix", "desciption": "" }
Expand Down Expand Up @@ -63,15 +57,9 @@
"q1_norm2" : {
"q1_norm2" : { "type": "vector", "desciption": "" }
},
"shortcut_q1_norm2" : {
"q1_norm2" : { "type": "vector", "desciption": "" }
},
"q1_norm" : {
"q1_norm" : { "type": "vector", "desciption": "" }
},
"shortcut_q1_norm" : {
"q1_norm" : { "type": "vector", "desciption": "" }
},
"q1" : {
"q1" : { "type": "vector", "desciption": "" }
},
Expand Down
3 changes: 0 additions & 3 deletions regtest/wham/rt-parse-only/values.json.reference
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
"phi" : {
"phi" : { "type": "scalar", "desciption": "" }
},
"shortcut_phi" : {
"phi" : { "type": "scalar", "desciption": "" }
},
"rp" : {
"rp.bias" : { "type": "scalar", "desciption": "" }
"rp.force2" : { "type": "scalar", "desciption": "" }
Expand Down
41 changes: 22 additions & 19 deletions src/cltools/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,30 +804,33 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc) {
}
ActionShortcut* as=pp->castToActionShortcut();
if( as ) {
unsigned ncomponents = 0; std::vector<ActionWithValue*> val_actions;
Keywords keys; actionRegister().getKeywords( as->getName(), keys );
std::vector<std::string> cnames( keys.getOutputComponents() );
for(unsigned i=0; i<cnames.size(); ++i) {
std::string valname;
if( cnames[i]==".#!value" ) valname = as->getShortcutLabel();
else valname = as->getShortcutLabel() + "_" + cnames[i];
ActionWithValue* av = p.getActionSet().selectWithLabel<ActionWithValue*>( valname );
if( av ) val_actions.push_back(av);
}
if( val_actions.size()==0 ) continue ;
std::vector<std::string> cnames( as->getSavedOutputs() );
printf("CHECK %s %s %d \n", as->getShortcutLabel().c_str(), as->getName().c_str(), cnames.size() );
if( cnames.size()==0 ) continue ;

if( firsta ) { valuefile.printf(" \"shortcut_%s\" : {\n", as->getShortcutLabel().c_str() ); firsta=false; }
else valuefile.printf(",\n \"shortcut_%s\" : {\n", as->getShortcutLabel().c_str() );
bool firstv=true;
for(unsigned i=0; i<val_actions.size(); ++i) {
for(unsigned j=0; j<val_actions[i]->getNumberOfComponents(); ++j) {
Value* myval = val_actions[i]->copyOutput(j); std::string compname = myval->getName(), description; std::size_t dot=compname.find(".");
if( dot!=std::string::npos ) {
std::string cname = compname.substr(dot+1); description = val_actions[i]->getOutputComponentDescription( cname, keys );
} else description = keys.getOutputComponentDescription(".#!value");
if( description.find("\\")!=std::string::npos ) error("found invalid backslash character in documentation for component " + compname + " in action " + val_actions[i]->getName() + " with label " + val_actions[i]->getLabel() );
bool firstv=true; Keywords keys; actionRegister().getKeywords( as->getName(), keys );
for(unsigned i=0; i<cnames.size(); ++i) {
ActionWithValue* av2=p.getActionSet().selectWithLabel<ActionWithValue*>( cnames[i] );
if( !av2 ) plumed_merror("could not find value created by shortcut with name " + cnames[i] );
if( av2->getNumberOfComponents()==1 ) {
Value* myval = av2->copyOutput(0); std::string compname = myval->getName(), description;
if( compname==as->getShortcutLabel() ) description = keys.getOutputComponentDescription(".#!value");
else { std::size_t pp=compname.find(as->getShortcutLabel()); description = keys.getOutputComponentDescription( compname.substr(pp+as->getShortcutLabel().length()+1) ); }
if( description.find("\\")!=std::string::npos ) error("found invalid backslash character in documentation for component " + compname + " in action " + as->getName() + " with label " + as->getLabel() );
if( firstv ) { valuefile.printf(" \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() ); firstv=false; }
else valuefile.printf(",\n \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
} else {
for(unsigned j=0; j<av2->getNumberOfComponents(); ++j) {
Value* myval = av2->copyOutput(j); std::string compname = myval->getName(), description; std::size_t dot=compname.find(".");
if( dot!=std::string::npos ) {
std::string cname = compname.substr(dot+1); description = av2->getOutputComponentDescription( cname, keys );
} else plumed_merror("should not be outputting description of value from action when using shortcuts");
if( description.find("\\")!=std::string::npos ) error("found invalid backslash character in documentation for component " + compname + " in action " + av2->getName() + " with label " + av2->getLabel() );
if( firstv ) { valuefile.printf(" \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() ); firstv=false; }
else valuefile.printf(",\n \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() );
}
}
}
valuefile.printf("\n }");
Expand Down
26 changes: 26 additions & 0 deletions src/core/ActionShortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ void ActionShortcut::readInputLine( const std::string& input ) {
if( !restart ) f_input += " RESTART=NO";
}
plumed.readInputLine( f_input );
if( !founds ) {
ActionWithValue* av=NULL;
for(auto pp=plumed.getActionSet().rbegin(); pp!=plumed.getActionSet().rend(); ++pp) {
av = pp->get()->castToActionWithValue();
if( !av ) continue ;
if( std::find(savedOutputs.begin(), savedOutputs.end(), av->getLabel() )!=savedOutputs.end() ) av=NULL;
break;
}
if( av ) {
std::string av_label = av->getLabel();
if( av_label == getShortcutLabel() ) savedOutputs.push_back( av_label );
else {
for(unsigned i=0; i<keywords.cnames.size(); ++i) {
if( av_label == getShortcutLabel() + "_" + keywords.cnames[i] ) savedOutputs.push_back( av_label );
else if( keywords.getOutputComponentFlag(keywords.cnames[i])!="default" ) {
std::string thisflag = keywords.getOutputComponentFlag(keywords.cnames[i]);
if( keywords.numbered(thisflag) && av_label.find(getShortcutLabel() + "_" + keywords.cnames[i])!=std::string::npos ) savedOutputs.push_back( av_label );
}
}
}
}
}
} else error("requirement for action " + words[0] + " should be registered in registerKeywords function for shortcut action using keys.useAction");
}

Expand All @@ -105,6 +127,10 @@ std::vector<std::string> ActionShortcut::getSavedInputLines() const {
return savedInputLines;
}

std::vector<std::string> ActionShortcut::getSavedOutputs() const {
return savedOutputs;
}

std::string ActionShortcut::convertInputLineToString() {
std::string output;
for(auto p=line.begin(); p!=line.end(); ++p) {
Expand Down
3 changes: 3 additions & 0 deletions src/core/ActionShortcut.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class ActionShortcut :
private:
std::string shortcutlabel;
std::vector<std::string> savedInputLines;
std::vector<std::string> savedOutputs;
protected:
std::string getUpdateLimits() const ;
public:
Expand All @@ -53,6 +54,8 @@ class ActionShortcut :
void apply() override {}
/// Get the lines of the shortcut that were read in
std::vector<std::string> getSavedInputLines() const ;
/// Get the labels of the actions that this creates
std::vector<std::string> getSavedOutputs() const ;
/// Take everything that was input to this action and convert it to a string
std::string convertInputLineToString();
/// This sorts out the reading of arguments from shortcuts
Expand Down
2 changes: 1 addition & 1 deletion src/symfunc/CoordinationNumbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ void CoordinationNumbers::registerKeywords( Keywords& keys ) {
keys.add("compulsory","R_POWER","the power to which you want to raise the distance");
keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility");
keys.add("optional","MOMENTS","the list of moments that you would like to calculate");
keys.addOutputComponent("moment","MOMENT","the moments of the distribution");
keys.addOutputComponent("moment","MOMENTS","the moments of the distribution");
keys.needsAction("MATRIX_VECTOR_PRODUCT"); keys.needsAction("ONES"); keys.needsAction("MOMENTS");
}

Expand Down
Loading

1 comment on commit 77a52f0

@PlumedBot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found broken examples in automatic/ANGLES.tmp
Found broken examples in automatic/ANN.tmp
Found broken examples in automatic/CAVITY.tmp
Found broken examples in automatic/CLASSICAL_MDS.tmp
Found broken examples in automatic/CLUSTER_DIAMETER.tmp
Found broken examples in automatic/CLUSTER_DISTRIBUTION.tmp
Found broken examples in automatic/CLUSTER_PROPERTIES.tmp
Found broken examples in automatic/CONSTANT.tmp
Found broken examples in automatic/CONTACT_MATRIX.tmp
Found broken examples in automatic/CONTACT_MATRIX_PROPER.tmp
Found broken examples in automatic/COORDINATIONNUMBER.tmp
Found broken examples in automatic/DFSCLUSTERING.tmp
Found broken examples in automatic/DISTANCE_FROM_CONTOUR.tmp
Found broken examples in automatic/EDS.tmp
Found broken examples in automatic/EMMI.tmp
Found broken examples in automatic/ENVIRONMENTSIMILARITY.tmp
Found broken examples in automatic/FIND_CONTOUR.tmp
Found broken examples in automatic/FIND_CONTOUR_SURFACE.tmp
Found broken examples in automatic/FIND_SPHERICAL_CONTOUR.tmp
Found broken examples in automatic/FOURIER_TRANSFORM.tmp
Found broken examples in automatic/FUNCPATHGENERAL.tmp
Found broken examples in automatic/FUNCPATHMSD.tmp
Found broken examples in automatic/FUNNEL.tmp
Found broken examples in automatic/FUNNEL_PS.tmp
Found broken examples in automatic/GHBFIX.tmp
Found broken examples in automatic/GPROPERTYMAP.tmp
Found broken examples in automatic/HBOND_MATRIX.tmp
Found broken examples in automatic/INCLUDE.tmp
Found broken examples in automatic/INCYLINDER.tmp
Found broken examples in automatic/INENVELOPE.tmp
Found broken examples in automatic/INTERPOLATE_GRID.tmp
Found broken examples in automatic/LOCAL_AVERAGE.tmp
Found broken examples in automatic/MAZE_OPTIMIZER_BIAS.tmp
Found broken examples in automatic/MAZE_RANDOM_ACCELERATION_MD.tmp
Found broken examples in automatic/MAZE_SIMULATED_ANNEALING.tmp
Found broken examples in automatic/MAZE_STEERED_MD.tmp
Found broken examples in automatic/MULTICOLVARDENS.tmp
Found broken examples in automatic/OUTPUT_CLUSTER.tmp
Found broken examples in automatic/PAMM.tmp
Found broken examples in automatic/PCA.tmp
Found broken examples in automatic/PCAVARS.tmp
Found broken examples in automatic/PIV.tmp
Found broken examples in automatic/PLUMED.tmp
Found broken examples in automatic/PYCVINTERFACE.tmp
Found broken examples in automatic/PYTHONFUNCTION.tmp
Found broken examples in automatic/Q3.tmp
Found broken examples in automatic/Q4.tmp
Found broken examples in automatic/Q6.tmp
Found broken examples in automatic/QUATERNION.tmp
Found broken examples in automatic/SIZESHAPE_POSITION_LINEAR_PROJ.tmp
Found broken examples in automatic/SIZESHAPE_POSITION_MAHA_DIST.tmp
Found broken examples in automatic/SPRINT.tmp
Found broken examples in automatic/TETRAHEDRALPORE.tmp
Found broken examples in automatic/TORSIONS.tmp
Found broken examples in automatic/WHAM_WEIGHTS.tmp
Found broken examples in AnalysisPP.md
Found broken examples in CollectiveVariablesPP.md
Found broken examples in MiscelaneousPP.md

Please sign in to comment.