Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ResfileReader.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/pack/task/ResfileReader.cc
11 /// @brief implementation of resfile reader and its command classes
12 /// @author Steven Lewis (smlewi@unc.edu)
13 /// @author Andrew Leaver-Fay
14 
15 // Unit Headers
17 
18 // Package Headers
21 #include <core/pose/Pose.hh>
22 #include <core/pose/PDBInfo.hh>
23 
24 // Project Headers
27 
28 // Utility Headers
29 #include <utility/io/izstream.hh>
30 #include <utility/exit.hh>
31 #include <utility/assert.hh> //ASSERT_ONLY makes release build happy
32 #include <utility/string_util.hh>
33 #include <basic/Tracer.hh>
34 #include <basic/options/option.hh>
35 // AUTO-REMOVED #include <basic/options/util.hh>
36 #include <basic/options/keys/packing.OptionKeys.gen.hh>
37 
38 // AUTO-REMOVED #include <core/pack/task/TaskFactory.hh>
39 
40 using basic::T;
41 using basic::Error;
42 using basic::Warning;
43 
44 //STL headers
45 #include <string>
46 //#include <iostream> //need this for debugging
47 #include <fstream>
48 #include <sstream> //automatic checking string to int conversion
49 #ifdef WIN32
50 #include <cctype> //for split_lines to handle '\t' tab characters
51 #endif
52 
53 #include <algorithm>
54 
55 // option key includes
56 
57 #include <basic/options/keys/run.OptionKeys.gen.hh>
58 
59 #include <utility/vector1.hh>
60 
61 
62 
63 
64 namespace core {
65 namespace pack {
66 namespace task {
67 
68 /// @details Auto-generated virtual destructor
70 
71 static basic::Tracer TR("core.pack.task.ResfileReader");
72 
73 using std::string;
74 using std::endl;
75 using std::istream;
76 using std::istringstream;
77 using std::map;
78 using std::stringstream;
79 using utility::vector1;
80 using core::pose::Pose;
81 
83  Pose const & pose,
84  istream & resfile ) :
85  commands_( pose.total_residue() )
86 {
87  using namespace std;
88 
89  map< string, ResfileCommandOP > command_map = create_command_map();
90  bool have_read_start_token = false;
91 
92  // save the RANGE and CHAIN commands and apply them at the end
94  vector1< std::list< ResfileCommandOP > > residue_range_commands(pose.total_residue(), std::list< ResfileCommandOP >());
95  vector1< std::list< ResfileCommandOP > > residue_chain_commands(pose.total_residue(), std::list< ResfileCommandOP >());
96 
97  uint lineno = 0;
98  while ( resfile ) {
99  vector1< string > tokens( tokenize_line( resfile ));
100  ++lineno;
101 
102  if (!tokens.size()) continue;
103  if (comment_begin(tokens,1)) continue; // ignore the rest of this line
104 
105  if (!have_read_start_token) {
106  parse_header_line(tokens, command_map, lineno, have_read_start_token);
107  } else {
108  parse_body_line(pose, tokens, command_map, lineno,
109  residue_range_commands, residue_chain_commands);
110  }
111  }
112 
113  if (!have_read_start_token) {
114  TR.Warning
115  << "Reached the end of resfile without finding a 'START' token." << endl
116  << "No residue-specific behavior specified in resfile." << endl;
117  }
118 
119  // apply the RANGE and CHAIN commands
120  for(Size i = 1; i <= pose.total_residue(); ++i){
121  if(commands_[i].empty()){
122  if(!residue_range_commands[i].empty()){
123  commands_[i].assign(
124  residue_range_commands[i].begin(), residue_range_commands[i].end());
125  } else if(!residue_chain_commands[i].empty()){
126  commands_[i].assign(
127  residue_chain_commands[i].begin(), residue_chain_commands[i].end());
128  }
129  }
130  }
131 }
132 
133 
135 
136 std::list< ResfileCommandCOP > const &
138 {
139  return default_commands_;
140 }
141 
142 
143 bool
145 {
146  if ( resid > commands_.size() || resid == 0 ) {
147  utility_exit_with_message( "Residue index out of bounds: resid=" +
148  utility::to_string( resid ) + " with only " +
149  utility::to_string( commands_.size() ) + " residues total." );
150  }
151  return ! commands_[ resid ].empty();
152 }
153 
154 std::list< ResfileCommandCOP > const &
156 {
157  if ( resid > commands_.size() || resid == 0 ) {
158  utility_exit_with_message( "Residue index out of bounds: resid=" +
159  utility::to_string( resid ) + " with only " +
160  utility::to_string( commands_.size() ) + " residues total." );
161  }
162  return commands_[ resid ];
163 }
164 
165 void
167  vector1< string > const & tokens,
168  map< string, ResfileCommandOP > const & command_map,
169  Size const lineno,
170  bool & have_read_start_token
171 ) {
172  // read in default behaviors, store them, process them later
173  if ( get_token( 1, tokens) == "START" ) {
174  have_read_start_token = true;
175  } else {
176  Size which_token = 1, ntokens = tokens.size();
177  while(which_token <= ntokens){
178  if (comment_begin(tokens, which_token)) break;
179 
180  ResfileCommandOP command(
181  locate_command(which_token, tokens, command_map, lineno));
182  command->initialize_from_tokens(tokens, which_token, 0);
183  default_commands_.push_back(command);
184  }
185  }
186 }
187 
188 
189 ///@ details Parse body line in resfile
190 /// expected formats:
191 /// <residue identifier> <chain identifier> <commands*>
192 /// <residue identifier> - <residue identifier> <chain identifier> <commands*>
193 /// * <chain identifer> <commands*>
194 ///
195 /// The here is how a residue specification is resolved if it is
196 /// specified multiple times:
197 ///
198 /// 1) If a residue is specified by multiple commands of the same level (SINGLE, RANGE, or CHAIN), then this is an error
199 /// 2) If a residue is specified by multiple commands of different levels then the more restricted level takes precidence, SINGLE over RANGE and CHAIN, and RANGE over CHAIN
200 void
202  pose::Pose const & pose,
203  vector1< string > const & tokens,
204  map< string, ResfileCommandOP > const & command_map,
205  Size const lineno,
206  vector1< std::list<ResfileCommandOP > > & residue_range_commands,
207  vector1< std::list<ResfileCommandOP > > & residue_chain_commands
208 ) {
209  Size which_token = 1, ntokens(tokens.size());
210  int PDBnum, PDBnum_end;
211  char icode, icode_end, chain;
212  residue_identifier_type id_type;
213 
214  parse_resid( which_token, tokens, lineno,
215  PDBnum, PDBnum_end, icode, icode_end, chain, id_type);
216 
217  bool found_commands(false);
218 
219  if(id_type == ResfileContents::SINGLE_RESID){
220  Size const resid(locate_resid(pose, chain, PDBnum, icode, lineno));
221 
222  while (which_token <= ntokens) {
223  if (comment_begin(tokens, which_token)) break;
224 
225  ResfileCommandOP command(
226  locate_command(which_token, tokens, command_map, lineno));
227  command->initialize_from_tokens( tokens, which_token, resid );
228  commands_[ resid ].push_back( command );
229  found_commands = true;
230  }
231  } else if (id_type == ResfileContents::RANGE_RESID) {
232  Size const resid_start(locate_resid(pose, chain, PDBnum, icode, lineno));
233  Size const resid_end(locate_resid(pose, chain, PDBnum_end, icode_end, lineno));
234  if(resid_start >= resid_end){
235  stringstream err_msg;
236  err_msg
237  << "On line " << lineno << ", "
238  << "the start residue (PDBnum=" << PDBnum;
239  if(icode != ' '){
240  err_msg << ", icode=" << icode;
241  }
242  err_msg
243  << ", chain=" << (chain == ' ' ? '_' : chain) << ") "
244  << "does not come before the end residue "
245  << "(PDBnum=" << PDBnum_end;
246  if(icode_end != ' '){
247  err_msg << ", icode=" << icode_end;
248  }
249  err_msg
250  << ", chain=" << (chain == ' ' ? '_' : chain) << ").";
251  onError(err_msg.str());
252  }
253 
254  while ( which_token <= ntokens ) {
255  if (comment_begin(tokens, which_token)) break;
256 
257  ResfileCommandOP command(
258  locate_command(which_token, tokens, command_map, lineno));
259  Size const saved_which_token(which_token);
260  Size which_token_i;
261  // The number in pdb files is not straight
262  for(Size i = resid_start; i <= resid_end; ++i){
263  which_token_i = saved_which_token;
264  ResfileCommandOP command_i(command->clone());
265  command_i->initialize_from_tokens(tokens, which_token_i, i);
266  residue_range_commands[i].push_back(command_i);
267  }
268  which_token = which_token_i;
269  found_commands = true;
270  }
271  } else if (id_type == ResfileContents::CHAIN_RESID) {
272  if(!pose.pdb_info()) {
273  stringstream err_msg;
274  err_msg
275  << "On line " << lineno << ", "
276  << "attemting to set task for all residues in a chain, however the pose does not have a PdbInfo object, which is used to look up which residues are part of which chain. Often the PdbInfo object is setup when the pose is intialized. Please check your protocol.";
277  utility_exit_with_message(err_msg.str());
278  }
279  bool found_a_residue_on_chain(false);
280  while ( which_token <= ntokens ) {
281  if (comment_begin(tokens, which_token)) break;
282 
283  ResfileCommandOP command(
284  locate_command(which_token, tokens, command_map, lineno));
285  Size const saved_which_token(which_token);
286  Size which_token_i;
287  for(Size i=1; i <= pose.total_residue(); ++i){
288  if(pose.pdb_info()->chain(i) == chain){
289  found_a_residue_on_chain = true;
290  which_token_i = saved_which_token;
291  ResfileCommandOP command_i(command->clone());
292  command_i->initialize_from_tokens(tokens, which_token_i, i);
293  residue_chain_commands[i].push_back(command_i);
294  }
295  }
296  which_token = which_token_i;
297  found_commands = true;
298  }
299  if(!found_a_residue_on_chain){
300  stringstream err_msg;
301  err_msg
302  << "On line " << lineno << ", "
303  << "there are no residues with chain '"
304  << (chain == ' ' ? '_' : chain) << "'.";
305  onError(err_msg.str());
306  }
307 
308  } else {
309  // unrecongized id type
310  runtime_assert(false);
311  }
312 
313  if(!found_commands){
314  stringstream err_msg;
315  err_msg
316  << "On line " << lineno << ", "
317  << "no commands are specified.";
318  onError(err_msg.str());
319  }
320 }
321 
322 
323 void
325  Size & which_token,
326  vector1< string > const & tokens,
327  Size const lineno,
328  int & PDBnum,
329  int & PDBnum_end, // only defined for RANGE id_type
330  char & icode,
331  char & icode_end, // only defined for RANGE id_type
332  char & chain,
333  residue_identifier_type & id_type) const {
334 
335  string token(get_token(which_token, tokens));
336  ++which_token;
337  if(*token.begin() == '*'){
338  // apply task all residues on the chain
340 
341  if(token.length() > 1){
342  stringstream err_msg;
343  err_msg
344  << "On line " << lineno << ", "
345  << "malformed residue identifier specification involving '*'";
346  onError(err_msg.str());
347  }
348 
349  } else {
350 
352 
353  // this may turn out to be a range specification but we have to
354  // wait to the next token to figure that out.
355 
356  parse_PDBnum_icode(token, lineno, PDBnum, icode);
357  }
358 
359  token = get_token(which_token, tokens);
360  ++which_token;
361 
362  if(token == "-"){
363 
364  if(id_type == ResfileContents::CHAIN_RESID){
365  // In this case we've already encountered a '*' to it can't be a
366  // range specification
367  stringstream err_msg;
368  err_msg
369  << "On line " << lineno << ", "
370  << "malformed residue identifier.";
371  onError(err_msg.str());
372  }
373 
375 
376  token = get_token( which_token, tokens );
377  ++which_token;
378 
379  parse_PDBnum_icode(token, lineno, PDBnum_end, icode_end);
380 
381  // advance token counter in preparation for getting the chain
382  // token "again".
383  ++which_token;
384  }
385 
386  // The pdb format is case insensitive everwhere except for the chain
387  // specifier! Get the token again but this time do not change it to
388  // upper case
389  token = get_token(which_token-1, tokens, false);
390  if (token.length() != 1){
391  stringstream err_msg;
392  err_msg
393  << "On line " << lineno << ", "
394  << "the chain identifier '" << token << "' "
395  << "must be just a single character in [_A-Za-z] "
396  << "(note the chain identifier is case sensitive).";
397  onError(err_msg.str());
398  }
399  chain = token[0];
400  if (chain == '_') chain = ' ';
401  if(core::pose::chr_chains.find(chain) == std::string::npos){
402  stringstream err_msg;
403  err_msg
404  << "On line " << lineno << ", "
405  << "The chain identifier '" << chain << "' "
406  << "is not in [_A-Za-z] "
407  << "(note the chain identifier is case sensitive).";
408  onError(err_msg.str());
409  }
410 }
411 
412 void
414  string const & token,
415  Size const lineno,
416  int & PDBnum,
417  char & icode) const {
418 
419  istringstream PDBnum_s;
420  if ( std::isalpha( *token.rbegin() ) ) {
421  PDBnum_s.str(token.substr(0, token.length() - 1));
422  icode = *token.rbegin();
423  } else {
424  PDBnum_s.str(token);
425  icode = ' ';
426  }
427 
428  char remaining;
429  if(!(PDBnum_s >> PDBnum) || PDBnum_s.get(remaining)){
430  stringstream err_msg;
431  err_msg
432  << "On line " << lineno << ", "
433  << "the token '" << token << "' "
434  << "is not a valid <PDBNUM>[<ICODE>] identifier.";
435  onError(err_msg.str());
436  }
437 
438 }
439 
440 Size
442  Pose const & pose,
443  char const chain,
444  Size const PDBnum,
445  char const icode,
446  Size const lineno
447 ) const {
448 
449  Size resid(0);
450  if(pose.pdb_info() == 0){
451  if(1 <= PDBnum && PDBnum <= pose.total_residue()){
452  resid = PDBnum;
453  }
454  } else {
455  resid = pose.pdb_info()->pdb2pose().find( chain, PDBnum, icode );
456  }
457 
458  if(resid == 0){
459  std::stringstream err_msg;
460  err_msg << "On line " << lineno << ", the pose does not have residue with chain=" << chain << ", PDBnum=" << PDBnum;
461  if(icode != ' '){
462  err_msg << ", icode=" << icode;
463  }
464  err_msg << ".";
465  onError(err_msg.str());
466  }
467  return resid;
468 }
469 
470 
471 
474  Size const which_token,
475  vector1< string > const & tokens,
476  std::map< string, ResfileCommandOP > const & command_map,
477  Size const lineno
478 ) const {
479 
480  std::map< string, ResfileCommandOP >::const_iterator command(
481  command_map.find(get_token(which_token, tokens)));
482 
483  if (command == command_map.end()) {
484  std::stringstream err_msg;
485  err_msg
486  << "On line " << lineno
487  << " command '" << get_token(which_token, tokens) <<"' is not recognized.";
488  onError(err_msg.str());
489  }
490  return(command->second->clone());
491 }
492 
493 
494 ///////////////////////////////////////////////////////////////////////
495 ///@brief NATRO disables packing and designing at a position, the residue
496 ///will be totally unchanged
497 void
499  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
500  Size & which_token,
501  Size /*resid*/
502 )
503 {
504  assert( get_token( which_token, tokens ) == name() );
505  ++which_token;
506 }
507 
508 void
510  PackerTask & task,
511  Size resid
512 ) const
513 {
515 }
516 
517 ///////////////////////////////////////////////////////////////////////
518 ///@brief NATAA allows repacking but no sequence changes (all rotamers are of the original residue)
519 void
521  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
522  Size & which_token,
523  Size /*resid*/
524 )
525 {
526  assert( get_token( which_token, tokens ) == name() );
527  ++which_token;
528 }
529 
530 void
532  PackerTask & task,
533  Size resid
534 ) const
535 {
537 }
538 
539 ///////////////////////////////////////////////////////////////////////
540 ///@brief ALLAA is deprecated; allows repacking and designing to any canonical residue (default state of PackerTask)
541 void
543 #ifdef NDEBUG
545 #else
546  utility::vector1< std::string > const & tokens,
547 #endif
548  Size & which_token,
549  Size /*resid*/
550 )
551 {
552  assert( get_token( which_token, tokens ) == name() );
553  ++which_token;
554 }
555 
556 void
558  PackerTask & task,
559  Size resid
560 ) const
561 {
562  //warn user not to use ALLAA to mean ALLAAxc. This repeats for every line on purpose!
563  // disable warning with command -nowarn_ALLAA
564  // this warning is /really/ not necessary -- people ought to know that cys is an amino acid!
565 // T("core.pack.task.ResfileReader") << "RESFILE WARNING: " << ALLAA::name() << " is deprecated. Use "
566 // << ALLAAxc::name() << " to exclude cysteine, or "
567 // << ALLAAwc::name() << " to include cysteine. Substituting "
568 // << ALLAAwc::name() << " behavior." << std::endl;
569 
570  //as in warning, pass to ALLAAwc
571  ALLAAwc allaawc;
572  allaawc.residue_action(task,resid);
573 
574 }
575 
576 
577 ///////////////////////////////////////////////////////////////////////
578 ///@brief ALLAAxc allows repacking and designing to any canonical noncysteine residue
579 void
581  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
582  Size & which_token,
583  Size /*resid*/
584 )
585 {
586  assert( get_token( which_token, tokens ) == name() );
587  ++which_token;
588 }
589 
590 void
592  PackerTask & task,
593  Size resid
594 ) const
595 {
597  keep_aas[ chemical::aa_cys ] = false;
598  std::string const mode( "ALLAAxc" );
599  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_aas, mode );
600 }
601 
602 
603 ///////////////////////////////////////////////////////////////////////
604 ///@brief allows repacking and designing to any canonical residue (default state of PackerTask)
605 void
607  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
608  Size & which_token,
609  Size /*resid*/
610 )
611 {
612  assert( get_token( which_token, tokens ) == name() || get_token( which_token, tokens ) == ALLAA::name() );
613  ++which_token;
614 }
615 
616 void
618  PackerTask & /*task*/,
619  Size /*resid*/
620 ) const
621 {
622  //do not change anything, default packerTask behavior is to design with everything
623 }
624 
625 
626 ///////////////////////////////////////////////////////////////////////
627 ///@brief PIKAA allows residues specifed in a following string and packing
628 ///the string should be formatted ALLCAPS with no spaces between residues
629 ///using the standard single letter codes
630 void
632  utility::vector1< std::string > const & tokens,
633  Size & which_token,
634  Size resid
635 )
636 {
637  using namespace chemical;
638  using utility::vector1;
639 
640  assert( get_token( which_token, tokens ) == name() );
641  keep_canonical_aas_.resize( chemical::num_canonical_aas, false );
642 
643  if ( which_token == tokens.size() ) {
644  std::stringstream err_msg;
645  err_msg << "PIKAA must be followed by a string of allowed amino acids.";
646  onError(err_msg.str());
647  }
648  ++which_token;
649  std::string const & aas_to_keep = get_token( which_token, tokens );
650 
651 
652  // note: stl uses an index-by-0 convention so the for-loop initialization statment
653  // and its boundary check are not in the rosetta standard.
654  for ( Size ii = 0; ii < aas_to_keep.size(); ++ii ) {
655  if ( oneletter_code_specifies_aa( aas_to_keep[ ii ] ) ) {
656  AA aa( aa_from_oneletter_code( aas_to_keep[ ii ] ) );
657  if ( size_t(aa) <= keep_canonical_aas_.size() ) {
658  keep_canonical_aas_[ aa ] = true;
659  }
660  // allow use of PIKAA for DNA types (letters a,c,g,t)
661  else if ( aa == na_ade || aa == na_cyt || aa == na_gua || aa == na_thy ) {
662  na_allowed_.push_back( aa );
663  }
664  } else {
665  TR << "Ignoring unknown one-letter amino acid code " << aas_to_keep[ ii ] << " while parsing PIKAA mode for residue " << resid << "." << std::endl;
666 
667  }
668  }
669 
670  ++which_token;
671 }
672 
673 void
675  PackerTask & task,
676  Size resid
677 ) const
678 {
679  if ( keep_canonical_aas_.size() != chemical::num_canonical_aas ) {
680  utility_exit_with_message( "PIKAA Resfile Command used uninitialized" );
681  }
682  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_canonical_aas_ );
683  for ( std::list< chemical::AA >::const_iterator
684  iter = na_allowed_.begin(), iter_end = na_allowed_.end();
685  iter != iter_end; ++iter ) {
686  task.nonconst_residue_task(resid).allow_noncanonical_aa( *iter );
687  }
688 }
689 
690 ///////////////////////////////////////////////////////////////////////
691 ///@brief PIKNA allows nucleic acid residues specifed in a following string
692 /// uses a string of single letter codes
693 void
695  utility::vector1< std::string > const & tokens,
696  Size & which_token,
697  Size resid
698 )
699 {
700  using namespace chemical;
701  using utility::vector1;
702 
703  assert( get_token( which_token, tokens ) == name() );
704 
705  if ( which_token == tokens.size() ) {
706  std::stringstream err_msg;
707  err_msg << "PIKNA must be followed by nucleic acids in one-letter format.";
708  onError(err_msg.str());
709  }
710  ++which_token;
711  std::string const & nas_string( get_token( which_token, tokens ) );
712 
713  // note: stl uses an index-by-0 convention so the for-loop initialization statment
714  // and its boundary check are not in the rosetta standard.
715  for ( std::string::const_iterator letter( nas_string.begin() );
716  letter != nas_string.end(); ++letter ) {
717  // custom conversion from single letter to aa enum
718  AA na( aa_unk );
719  if ( *letter == 'A' || *letter == 'a' ) na = na_ade;
720  else if ( *letter == 'C' || *letter == 'c' ) na = na_cyt;
721  else if ( *letter == 'G' || *letter == 'g' ) na = na_gua;
722  else if ( *letter == 'T' || *letter == 't' ) na = na_thy;
723  else {
724  std::stringstream err_msg;
725  TR << "Ignoring unknown one-letter nucleic acid code. " << *letter <<" while parsing PIKNA option for residue " << resid << ".";
726  //onError(err_msg.str());
727  }
728  keep_nas_.push_back( na );
729  }
730  ++which_token;
731 }
732 
733 void
735  PackerTask & task,
736  Size resid
737 ) const
738 {
739  task.nonconst_residue_task(resid).restrict_absent_nas( keep_nas_ );
740 }
741 
742 ///////////////////////////////////////////////////////////////////////
743 ///@brief PIKNA allows nucleic acid residues specifed in a following string
744 /// uses a string of single letter codes
745 void
747  utility::vector1< std::string > const & tokens,
748  Size & which_token,
749  Size resid
750 )
751 {
752  using namespace chemical;
753  using utility::vector1;
754 
755  assert( tokens[ which_token ] == name() );
756  if ( which_token == tokens.size() ) {
757  TR.Error << "RESFILE ERROR: PIKRNA must be followed by a string of allowed "
758  << "nucleic acids in single-letter format" << std::endl;
759  utility_exit();
760  }
761  std::string const & nas_string( tokens[ ++which_token ] );
762 
763  // note: stl uses an index-by-0 convention so the for-loop initialization statment
764  // and its boundary check are not in the rosetta standard.
765  for ( std::string::const_iterator letter( nas_string.begin() );
766  letter != nas_string.end(); ++letter ) {
767  // custom conversion from single letter to aa enum
768  AA na( aa_unk );
769  if ( *letter == 'A' || *letter == 'a' ) na = na_rad;
770  else if ( *letter == 'C' || *letter == 'c' ) na = na_rcy;
771  else if ( *letter == 'G' || *letter == 'g' ) na = na_rgu;
772  else if ( *letter == 'U' || *letter == 'u' ) na = na_ura;
773  else {
774  TR.Error << "RESFILE ERROR: unknown one-letter nucleic acid code " << *letter
775  << " while parsing PIKRNA option for residue " << resid << std::endl;
776  utility_exit();
777  }
778  keep_rnas_.push_back( na );
779  }
780 
781  ++which_token;
782 }
783 
784 void
786  PackerTask & task,
787  Size resid
788 ) const
789 {
790  for ( Size ii = 1; ii <= keep_rnas_.size(); ++ii ) {
791  task.nonconst_residue_task(resid).allow_aa( keep_rnas_[ ii ] );
792  }
793 }
794 
795 ///////////////////////////////////////////////////////////////////////
796 ///@brief NOTAA disallows residues specified in a following string, and allows packing
797 ///the string should be formatted ALLCAPS with no spaces between residues
798 ///using the standard single letter codes
799 void
801  utility::vector1< std::string > const & tokens,
802  Size & which_token,
803  Size resid
804 )
805 {
806  using namespace chemical;
807 
808  assert( get_token( which_token, tokens ) == name() );
809  keep_aas_.resize( chemical::num_canonical_aas, true );
810 
811  ++which_token;
812  std::string const & aas_to_exclude = get_token( which_token, tokens );
813 
814  // note: stl uses an index-by-0 convention so the for-loop initialization statment
815  // and its boundary check are not in the rosetta standard.
816  for ( Size ii = 0; ii < aas_to_exclude.size(); ++ii ) {
817  if ( oneletter_code_specifies_aa( aas_to_exclude[ ii ] ) &&
818  aa_from_oneletter_code(aas_to_exclude[ii]) <= chemical::num_canonical_aas ) {
819  keep_aas_[ aa_from_oneletter_code( aas_to_exclude[ ii ] ) ] = false;
820  } else {
821  std::stringstream err_msg;
822  TR << "Ignoring Unknown one-letter amino acid code "<< aas_to_exclude[ ii ] << " while parsing NOTAA option for residue " << resid << ".";
823  //onError(err_msg.str()); // keep parsing on error
824  }
825  }
826 
827  ++which_token;
828 }
829 
830 void
832  PackerTask & task,
833  Size resid
834 ) const
835 {
836  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_aas_ );
837 }
838 
839 ///////////////////////////////////////////////////////////////////////
840 ///@brief EMPTY disallows canonical residues but leaves packing and designing unchanged
841 ///this is intended for use with noncanonical residues
842 ///it will act like NOTAA QWERTYIPASDFGHKLCVNM (all residues), which essentially prevents repacking; PIKAA with no argument raises error
843 void
845  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
846  Size & which_token,
847  Size /*resid*/
848 )
849 {
850  assert( get_token( which_token, tokens ) == name() );
851  ++which_token;
852 }
853 
854 void
856  PackerTask & task,
857  Size resid
858 ) const
859 {
860  //vector is expected format for PackerTask, but false at all positions
862  std::string mode( "EMPTY" );
863  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_aas, mode );
864 }
865 
866 ///////////////////////////////////////////////////////////////////////
867 ///@brief POLAR allows polar residues and packing
868 ///polar-ness is ultimately determined in residue parameter file
869 void
871  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
872  Size & which_token,
873  Size /*resid*/
874 )
875 {
876  assert( get_token( which_token, tokens ) == name() );
877  ++which_token;
878 }
879 
880 void
882  PackerTask & task,
883  Size resid
884 ) const
885 {
886  using namespace chemical;
887 
889 
891  restype_iter = task.residue_task( resid ).allowed_residue_types_begin(),
892  restype_iter_end = task.residue_task( resid ).allowed_residue_types_end();
893  restype_iter != restype_iter_end; ++restype_iter ) {
894  if ( (*restype_iter)->aa() > num_canonical_aas ) {
895  std::stringstream err_msg;
896  err_msg << "POLAR mode read for residue " << resid << " which has been instructed to use non-canonical amino acids.";
897  onError(err_msg.str());
898  continue;
899  }
900  if ( (*restype_iter)->is_polar() ) {
901  keep_aas[ (*restype_iter)->aa() ] = true;
902  }
903  }
904  std::string mode( "POLAR");
905  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_aas, mode );
906 
907 }
908 
909 ///////////////////////////////////////////////////////////////////////
910 ///@brief APOLAR allows nonpolar residues and packing
911 ///apolarity is (ultimately) determined by the lack of a POLAR flag in the residue parameter file
912 void
914  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
915  Size & which_token,
916  Size /*resid*/
917 )
918 {
919  assert( get_token( which_token, tokens ) == name() );
920  ++which_token;
921 
922 }
923 void
925  PackerTask & task,
926  Size resid
927 ) const
928 {
929  using namespace chemical;
930 
932 
934  restype_iter = task.residue_task( resid ).allowed_residue_types_begin(),
935  restype_iter_end = task.residue_task( resid ).allowed_residue_types_end();
936  restype_iter != restype_iter_end; ++restype_iter ) {
937  if ( (*restype_iter)->aa() > num_canonical_aas ) {
938  std::stringstream err_msg;
939  err_msg << "APOLAR mode read for residue " << resid << " which has been instructed to use non-canonical amino acids.";
940  onError(err_msg.str());
941  continue;
942  }
943  if ( ! (*restype_iter)->is_polar() ) {
944  keep_aas[ (*restype_iter)->aa() ] = true;
945  }
946  }
947  std::string mode( "APOLAR" );
948  task.nonconst_residue_task(resid).restrict_absent_canonical_aas( keep_aas, mode );
949 
950 }
951 
952 ///////////////////////////////////////////////////////////////////////
953 ///@brief APOLA is deprecated, it calls APOLAR to allow nonpolar residues and packing
954 void
956 #ifdef NDEBUG
958 #else
959  utility::vector1< std::string > const & tokens,
960 #endif
961  Size & which_token,
962  Size /*resid*/
963 )
964 {
965  assert( get_token( which_token, tokens ) == name() );
966  TR << "RESFILE NOTE: APOLA command deprecated. Use APOLAR command instead. Treating as APOLAR command." << std::endl;
967  ++which_token;
968 }
969 
970 void
972  PackerTask & task,
973  Size resid
974 ) const
975 {
976  APOLAR apolar_command;
977  apolar_command.residue_action( task, resid );
978 }
979 
980 ///////////////////////////////////////////////////////////////////////
981 ///@brief EX handles extrachi options. one EX command is necessary for each
982 ///chi and sampling level you wish to turn on, so multiple EX commands may
983 ///appear on a line. EX must be followed by an integer (which chi)
984 ///EX recognizes an optional subcommand LEVEL following the chi integer
985 ///LEVEL must be followed by a second integer for the level you want
986 void
988  utility::vector1< std::string > const & tokens,
989  Size & which_token,
990  Size resid
991 )
992 {
993  assert( get_token( which_token, tokens ) == name() );
994 
995  if ( which_token == tokens.size() ) {
996  std::stringstream err_msg;
997  err_msg << "EX command must be followe by a chi-id or \"ARO\" for reside " << resid << ".";
998  onError(err_msg.str());
999  }
1000 
1001  aro_specified_ = false;
1002  if ( get_token( which_token + 1, tokens ) == "ARO" ) {
1003  aro_specified_ = true;
1004  ++which_token;
1005  if ( which_token == tokens.size() ) {
1006  std::stringstream err_msg;
1007  err_msg << "EX ARO command must be followed by a chi-id for residue " << resid << ".";
1008  onError(err_msg.str());
1009  }
1010  }
1011  ++which_token;
1012  which_chi_ = atoi( get_token( which_token, tokens ).c_str() );
1013  Size which_chi_token = which_token;
1014  chi_sample_level_ = EX_ONE_STDDEV;
1015  if ( which_token != tokens.size() ) {
1016  if ( get_token( which_token + 1, tokens ) == "LEVEL" ) {
1017  ++which_token;
1018 
1019  ++which_token;
1020  chi_sample_level_ = static_cast< ExtraRotSample> (atoi( get_token( which_token, tokens ).c_str() ));
1021  if ( chi_sample_level_ >= ExtraRotSampleCardinality || chi_sample_level_ < 0 ) {
1022  std::stringstream err_msg;
1023  err_msg << "Extra rotamer sample level " << get_token( which_token, tokens ) << " is not in the range [0-" << ExtraRotSampleCardinality <<"] for residue " << resid << ".";
1024  onError(err_msg.str());
1025  }
1026  }
1027  }
1028 
1029  if ( which_chi_ > 2 && aro_specified_ ) {
1030  std::stringstream err_msg;
1031  err_msg << "The token following EX ARO, " << get_token( which_chi_token, tokens ) << ", should be a valid chi-id level, eg a '1' or a '2' for residue " << resid << ".";
1032  onError(err_msg.str());
1033  }
1034  else if ( which_chi_ > 4 ) {
1035  std::stringstream err_msg;
1036  err_msg << "The given chi-id, '" << get_token( which_chi_token, tokens ) << "' must either be an integer [1-4] or 'ARO' for residue " << resid << ".";
1037  onError(err_msg.str());
1038  }
1039  ++which_token;
1040 }
1041 
1042 void
1044  PackerTask & task,
1045  Size resid
1046 ) const
1047 {
1048  if ( which_chi_ == 1 ) {
1049  if ( aro_specified_ ) {
1050  task.nonconst_residue_task( resid ).or_ex1aro_sample_level( chi_sample_level_ );
1051  } else {
1052  task.nonconst_residue_task( resid ).or_ex1_sample_level( chi_sample_level_ );
1053  }
1054  } else if ( which_chi_ == 2 ) {
1055  if ( aro_specified_ ) {
1056  task.nonconst_residue_task( resid ).or_ex2aro_sample_level( chi_sample_level_ );
1057  } else {
1058  task.nonconst_residue_task( resid ).or_ex2_sample_level( chi_sample_level_ );
1059  }
1060  } else if ( which_chi_ == 3 ) {
1061  task.nonconst_residue_task( resid ).or_ex3_sample_level( chi_sample_level_ );
1062  } else if ( which_chi_ == 4 ) {
1063  task.nonconst_residue_task( resid ).or_ex4_sample_level( chi_sample_level_ );
1064  }
1065 }
1066 
1067 ////////////////////////////////////////////////////////////////////
1068 ///@brief NC allows a noncanonical residue; use one NC command per noncanonical
1069 void
1071  utility::vector1< std::string > const & tokens,
1072  Size & which_token,
1073  Size /*resid*/
1074 )
1075 {
1076  assert( get_token( which_token, tokens ) == name() );
1077  ++which_token;
1078  nc_to_include_ = get_token( which_token, tokens );
1079  ++which_token;
1080 }//end NC
1081 
1082 void
1084  PackerTask & task,
1085  Size resid
1086 ) const
1087 {
1088 
1089  core::chemical::ResidueTypeSet const & residue_set = task.residue_task( resid ).get_original_residue_set();
1090  if ( residue_set.has_name( nc_to_include_ )){
1091  task.nonconst_residue_task(resid).allow_noncanonical_aa( nc_to_include_ );
1092  } else {
1093  std::stringstream err_msg;
1094  err_msg << "Unable to add non-canonical amino acid " << nc_to_include_ << " because it is not in the ResidueTypeSet for residue " << resid << ".";
1095  onError(err_msg.str());
1096  }
1097 }//end NC
1098 
1099 /////////////////////////////////////////////////////////////////
1100 ///@brief EX_CUTOFF allows setting of the extrachi_cutoff (for determining burial for extra rotamers)
1101 void
1103  utility::vector1< std::string > const & tokens,
1104  Size & which_token,
1105  Size resid
1106 )
1107 {
1108  assert( get_token( which_token, tokens ) == name() );
1109 
1110  //check that next token is an integer value
1111  //stringstreams provide type safety! yay!
1112  ++which_token;
1113  std::istringstream ex_cutoff_ss( get_token( which_token, tokens ) );
1114 
1115  if (( ex_cutoff_ss >> ex_cutoff_ ).fail() ) { //convert string to Size and check error
1116  std::stringstream err_msg;
1117  err_msg << "The leve given for EX_CUTOFF, " << get_token( which_token-1, tokens) << ", must be an integer in the range [0-18] where 18 is the default for residue " << resid << ".";
1118  onError(err_msg.str());
1119  }//end error if
1120 
1121  ++which_token;
1122 }//end EX_CUTOFF
1123 
1124 void
1126  PackerTask & task,
1127  Size resid
1128 ) const
1129 {
1130  task.nonconst_residue_task(resid).and_extrachi_cutoff(ex_cutoff_);
1131 }//end EX_CUTOFF
1132 
1133 ///////////////////////////////////////////////////////////
1134 ///@brief USE_INPUT_SC turns on inclusion of the current rotamer for the packer
1135 void
1137  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
1138  Size & which_token,
1139  Size /*resid*/
1140 )
1141 {
1142  assert( get_token( which_token, tokens ) == name() );
1143  ++which_token;
1144 }//end USE_INPUT_SC
1145 
1146 void
1148  PackerTask & task,
1149  Size resid
1150 ) const
1151 {
1152  task.nonconst_residue_task(resid).or_include_current(true);
1153 }//end USE_INPUT_SC
1154 
1155 ///////////////////////////////////////////////////////////
1156 ///@brief AUTO
1157 void
1159  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
1160  Size & which_token,
1161  Size /*resid*/
1162 )
1163 {
1164  assert( get_token( which_token, tokens ) == name() );
1165  ++which_token;
1166 }
1167 
1168 void
1170  PackerTask & task,
1171  Size resid
1172 ) const
1173 {
1174  task.nonconst_residue_task(resid).add_behavior( name() );
1175 }//end AUTO
1176 
1177 ///////////////////////////////////////////////////////////
1178 ///@brief SCAN
1179 void
1181  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
1182  Size & which_token,
1183  Size /*resid*/
1184 )
1185 {
1186  assert( get_token( which_token, tokens ) == name() );
1187  ++which_token;
1188 }
1189 
1190 void
1192  PackerTask & task,
1193  Size resid
1194 ) const
1195 {
1196  task.nonconst_residue_task(resid).add_behavior( name() );
1197 }
1198 //end SCAN
1199 
1200 ///////////////////////////////////////////////////////////
1201 ///@brief TARGET
1202 void
1204  utility::vector1< std::string > const & tokens,
1205  Size & which_token,
1206  Size resid
1207 )
1208 {
1209  assert( get_token( which_token, tokens ) == name() );
1210 
1211  if ( which_token == tokens.size() ) {
1212  std::stringstream err_msg;
1213  err_msg << "TARGET must be followed by a character or string that identifies a target type. Use '_' if no target type is desired; for residue " << resid << ".";
1214  onError(err_msg.str());
1215  }
1216  ++which_token;
1217  argstring_ = get_token( which_token, tokens );
1218  ++which_token;
1219 }
1220 void
1222  PackerTask & task,
1223  Size resid
1224 ) const
1225 {
1226  using namespace chemical;
1227  using utility::vector1;
1228 
1229  ResidueLevelTask & rtask( task.nonconst_residue_task(resid) );
1230  task.nonconst_residue_task(resid).add_behavior( name() );
1231 
1232  if ( argstring_.size() == 1 ) {
1233  char letter( argstring_[0] );
1234  if ( letter == '_' ) { return; } // dummy character
1236  rtask.target_type( aa_from_oneletter_code( letter ) );
1237  } else {
1238  std::stringstream err_msg;
1239  err_msg << "Unknown one-letter code '"<< letter << "' for TARGET command for residue " << resid << ".";
1240  onError(err_msg.str());
1241  }
1242  }
1243  else rtask.target_type( argstring_ );
1244 }
1245 //end TARGET
1246 
1247 ///////////////////////////////////////////////////////////
1248 ///@brief NO_ADDUCTS
1249 void
1251  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
1252  Size & which_token,
1253  Size /*resid*/
1254 )
1255 {
1256  assert( get_token( which_token, tokens ) == name() );
1257  ++which_token;
1258 }
1259 
1260 void
1262  PackerTask & task,
1263  Size resid
1264 ) const
1265 {
1266  task.nonconst_residue_task(resid).or_adducts(false);
1267 }
1268 //end NO_ADDUCTS
1269 
1270 ///////////////////////////////////////////////////////////
1271 ///@brief FIX_HIS_TAUTOMER
1272 void
1274  utility::vector1< std::string > const & ASSERT_ONLY(tokens),
1275  Size & which_token,
1276  Size /*resid*/
1277 )
1278 {
1279  assert( tokens[ which_token ] == name() );
1280  ++which_token;
1281 }
1282 
1283 void
1285  PackerTask & task,
1286  Size resid
1287 ) const
1288 {
1289  task.nonconst_residue_task(resid).or_fix_his_tautomer(true); //call is safe against not-histidine
1290 }
1291 //end FIX_HIS_TAUTOMER
1292 
1293 ///@details this creates a map linking the parsed strings from the resfile
1294 ///to the command objects. NEW COMMANDS MUST BE ADDED HERE, HARD CODED
1295 ///note that it uses the command object name() method, not hard coded strings
1296 ///(of course, the name() method has hard coded strings...)
1297 std::map< std::string, ResfileCommandOP >
1299 {
1300  using namespace std;
1301 
1302  map< string, ResfileCommandOP > command_map;
1303  command_map[ NATRO::name() ] = new NATRO;
1304  command_map[ NATAA::name() ] = new NATAA;
1305  command_map[ ALLAA::name() ] = new ALLAA;
1306  command_map[ ALLAAxc::name() ] = new ALLAAxc;
1307  command_map[ ALLAAwc::name() ] = new ALLAAwc;
1308  command_map[ PIKAA::name() ] = new PIKAA;
1309  command_map[ PIKNA::name() ] = new PIKNA;
1310  command_map[ PIKRNA::name() ] = new PIKRNA;
1311  command_map[ NOTAA::name() ] = new NOTAA;
1312  command_map[ EMPTY::name() ] = new EMPTY;
1313  command_map[ POLAR::name() ] = new POLAR;
1314  command_map[ APOLAR::name() ] = new APOLAR;
1315  command_map[ APOLA::name() ] = new APOLA;
1316  command_map[ EX::name() ] = new EX;
1317  command_map[ EX_CUTOFF::name() ] = new EX_CUTOFF;
1318  command_map[ NC::name() ] = new NC;
1319  command_map[ USE_INPUT_SC::name() ] = new USE_INPUT_SC;
1320  command_map[ AUTO::name() ] = new AUTO;
1321  command_map[ SCAN::name() ] = new SCAN;
1322  command_map[ TARGET::name() ] = new TARGET;
1323  command_map[ NO_ADDUCTS::name() ] = new NO_ADDUCTS;
1324  command_map[ FIX_HIS_TAUTOMER::name() ] = new FIX_HIS_TAUTOMER;
1325 
1326  return command_map;
1327 }
1328 ///@brief utility function for resfile reader (checks for a leading # signaling a comment)
1329 bool
1331 {
1332  return get_token( which_token, tokens )[ 0 ] == '#';
1333 }
1334 
1335 ///@details resfile parser applies a resfile filename to a PackerTask
1336 ///each line of the resfile is broken into whitespace-delimited tokens
1337 ///whenever it reads a comment token, it ignores the rest of the line
1338 ///commands read before a "start" token are stored for application
1339 ///later as defaults lines after the start token alter specific
1340 ///ResidueLevelTasks in the PackerTask currently the reader assumes
1341 ///residue ID = PDB ID at the end, any residues not explicitly
1342 ///specified have the default actions performed on them
1343 
1344 void
1346  pose::Pose const & pose,
1347  PackerTask & the_task)
1348 {
1349  parse_resfile(pose, the_task, basic::options::option[basic::options::OptionKeys::packing::resfile].value().at(1));
1350 }
1351 
1352 
1353 void
1355  pose::Pose const & pose,
1356  PackerTask & the_task,
1358 {
1359 
1360  std::string resfile;
1361  utility::io::izstream file( filename );
1362  if (!file) {
1363  TR << "File:" << filename << " not found!\n";
1364  utility_exit_with_message( "Cannot open file " + filename );
1365  } else {
1366  //T() << "read file: " << filename << "\n";
1367  }
1368  utility::slurp( file, resfile );
1369  try{
1370  parse_resfile_string( pose, the_task, resfile );
1371  } catch (ResfileReaderException &) {
1372  if (basic::options::option[ basic::options::OptionKeys::run::interactive ].user()){
1373  throw;
1374  } else {
1375  utility_exit();
1376  }
1377  }
1378 }
1379 
1380 
1381 
1382 
1383  // question: if no chain is supplied should it be accepted?
1384  // yes just pass ' ' for the chain
1385  // how if a symbol is a chain or not?
1386  // all commands begin with something in the command map, if it's not a command treat it as a chain
1387 
1388 void
1390  pose::Pose const & pose,
1391  PackerTask & the_task,
1392  std::string const & resfile_string ) throw(ResfileReaderException)
1393 {
1394  using namespace std;
1395  istringstream resfile(resfile_string);
1396  ResfileContents contents( pose, resfile );
1397 
1398  for ( Size ii = 1; ii <= pose.total_residue(); ++ii ) {
1399 
1400  std::list< ResfileCommandCOP > const & ii_command_list(
1402  contents.commands_for_residue( ii ) : contents.default_commands() );
1403 
1404  for ( std::list< ResfileCommandCOP >::const_iterator
1405  iter = ii_command_list.begin(), iter_end = ii_command_list.end();
1406  iter != iter_end; ++iter ) {
1407  (*iter)->residue_action( the_task, ii );
1408  }
1409  }
1410 }
1411 
1412 
1413 /// @details utility function to increment next token to be parsed
1414 ///
1415 /// The PDB specification is case insensitive everywhere except for
1416 /// the chain identifiers. By default get_tokens makes everything
1417 /// upper case. To handle this special case, get_tokens optionally
1418 /// allows it to not convert it to upper case.
1421  const Size which_token,
1422  const utility::vector1<std::string> & tokens,
1423  bool make_upper_case) {
1424 
1425  if (which_token > tokens.size() ){
1426  if (which_token == 1){
1427  std::stringstream err_msg;
1428  err_msg << "Resfile does not specify anything.";
1429  onError(err_msg.str());
1430  } else {
1431  std::stringstream err_msg;
1432  err_msg << "After token " << tokens[ which_token -1 ] << " another token is expected.";
1433  onError(err_msg.str());
1434  }
1435  }
1436  std::string token = tokens[ which_token ];
1437  if(make_upper_case){
1438 
1439  std::transform(token.begin(), token.end(), token.begin(), (int(*)(int)) std::toupper);
1440  }
1441  return token;
1442 }
1443 
1445 tokenize_line( std::istream & inputstream )
1446 {
1447 
1449  std::string input_line;
1450  std::getline( inputstream, input_line );
1451 
1452  unsigned int llength = input_line.size();
1453  unsigned int processing = 0;
1454  unsigned int token_start_char = 0;
1455 
1456  while ( processing < llength ) {
1457  if ( std::isspace( input_line[ processing ] ) ) { // == ' ') {
1458  if ( !( std::isspace(input_line[ token_start_char ] ) ) ) { // != ' ' ) {
1459  std::string token = input_line.substr( token_start_char, processing - token_start_char);
1460  tokens.push_back( token );
1461  }
1462  ++processing;
1463  token_start_char = processing;
1464  } else {
1465  ++processing;
1466  }
1467  }
1468  if ( processing != token_start_char ) { // last token on the line
1469  std::string token = input_line.substr( token_start_char, processing - token_start_char + 1 );
1470  tokens.push_back( token );
1471  }
1472 
1473  /*
1474  for ( Size ii = 1; ii <= tokens.size(); ++ii ) {
1475  std::cout << "token: " << ii << ": \"" << tokens[ ii ] << "\"" << std::endl;
1476  }
1477  */
1478 
1479  return tokens;
1480 }
1481 
1482 void onError( std::string message){
1483  static bool interactive = basic::options::option[ basic::options::OptionKeys::run::interactive ].value();
1484  TR << message << std::endl;
1485  if (interactive){
1486  throw ResfileReaderException(message);
1487  } else {
1488  utility_exit();
1489  }
1490 }
1491 
1492 
1493 } //namespace task
1494 } //namespace pack
1495 } //namespace core