/* TM-score: superposition of two protein structures by assuming * correspondence between residues with the same residue number and identify * the best superposition with the highest TM-score. Please report issues * to zhanglab@zhanggroup.org * * References to cite: * Y Zhang, J Skolnick. Proteins, 57:702-10 (2004) * * DISCLAIMER: * Permission to use, copy, modify, and distribute the Software for any * purpose, with or without fee, is hereby granted, provided that the * notices on the head, the reference information, and this copyright * notice appear in all copies or substantial portions of the Software. * It is provided "as is" without express or implied warranty. * * ========================== * How to install the program * ========================== * The following command compiles the program in your Linux computer: * * g++ -static -O3 -ffast-math -lm -o TMscore TMscore.cpp * * The '-static' flag should be removed on Mac OS, which does not support * building static executables. * * ====================== * How to use the program * ====================== * You can run the program without argument to obtain the document. * Briefly, you can compare two structures by: * * ./TMscore structure1.pdb structure2.pdb * * ============== * Update history * ============== * 2019/04/07: A C/C++ code of TM-score was constructed by Chengxin Zhang * 2019/07/24: Several updates to match the output format of TMscore.f: * (1) Add rasmol format output by "-o" option * (2) Add GDT score and MaxSub score output * (3) Fixed bug in the calculation of 'the residue pairs of * distance < 5.0 Angstrom)' * 2019/08/18: Add TM-score REMARK in rasmol output. * 2019/08/20: Clarify PyMOL syntax. * 2019/08/22: Add 4 more PyMOL scripts. * 2019/11/25: Remove unused functions. Fix minor memory leak. * 2021/01/07: Fix bug in -c. * 2021/02/24: Fix file format issue for new pymol. * 2022/02/27: Add -seq for TM-score superimposition guided by sequence * alignment. */ using namespace std; #define MAX(A,B) ((A)>(B)?(A):(B)) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void print_version() { cout << "\n" " *************************************************************************\n" " * TM-SCORE *\n" " * A scoring function to assess the similarity of protein structures *\n" " * Based on statistics: *\n" " * 0.0 < TM-score < 0.17, random structural similarity *\n" " * 0.5 < TM-score < 1.00, in about the same fold *\n" " * Reference: Yang Zhang and Jeffrey Skolnick, Proteins 2004 57: 702-710 *\n" " * For comments, please email to: zhanglab@zhanggroup.org *\n" " *************************************************************************" << endl; } void print_extra_help() { cout << "Additional options:\n" " -a TM-score normalized by the average length of two structures\n" " T or F, (default F)\n" "\n" " -m Output TM-score rotation matrix\n" "\n" " -d TM-score scaled by an assigned d0, e.g. 5 Angstroms\n" "\n" " -fast Fast but slightly inaccurate alignment\n" "\n" " -dir Perform all-against-all alignment among the list of PDB\n" " chains listed by 'chain_list' under 'chain_folder'. Note\n" " that the slash is necessary.\n" " $ TMscore -dir chain_folder/ chain_list\n" "\n" " -dir1 Use chain2 to search a list of PDB chains listed by 'chain1_list'\n" " under 'chain1_folder'. Note that the slash is necessary.\n" " $ TMscore -dir1 chain1_folder/ chain1_list chain2\n" "\n" " -dir2 Use chain1 to search a list of PDB chains listed by 'chain2_list'\n" " under 'chain2_folder'\n" " $ TMscore chain1 -dir2 chain2_folder/ chain2_list\n" "\n" " -suffix (Only when -dir1 and/or -dir2 are set, default is empty)\n" " add file name suffix to files listed by chain1_list or chain2_list\n" "\n" " -atom 4-character atom name used to represent a residue.\n" " Default is \" C3'\" for RNA/DNA and \" CA \" for proteins\n" " (note the spaces before and after CA).\n" "\n" " -mol Molecule type: RNA or protein\n" " Default is detect molecule type automatically\n" "\n" " -ter Strings to mark the end of a chain\n" " 3: (default) TER, ENDMDL, END or different chain ID\n" " 2: ENDMDL, END, or different chain ID\n" " 1: ENDMDL or END\n" " 0: (default in the first C++ TMalign) end of file\n" "\n" " -split Whether to split PDB file into multiple chains\n" " 0: (default) treat the whole structure as one single chain\n" " 1: treat each MODEL as a separate chain (-ter should be 0)\n" " 2: treat each chain as a seperate chain (-ter should be <=1)\n" "\n" " -outfmt Output format\n" " 0: (default) full output\n" " 1: fasta format compact output\n" " 2: tabular format very compact output\n" " -1: full output, but without version or citation information\n" "\n" " -mirror Whether to align the mirror image of input structure\n" " 0: (default) do not align mirrored structure\n" " 1: align mirror of chain1 to origin chain2\n" "\n" " -het Whether to align residues marked as 'HETATM' in addition to 'ATOM '\n" " 0: (default) only align 'ATOM ' residues\n" " 1: align both 'ATOM ' and 'HETATM' residues\n" "\n" " -infmt1 Input format for chain1\n" " -infmt2 Input format for chain2\n" " -1: (default) automatically detect PDB or PDBx/mmCIF format\n" " 0: PDB format\n" " 1: SPICKER format\n" " 2: xyz format\n" " 3: PDBx/mmCIF format\n" < #include #include #include #include #include #include // for min() #include // for errno #include // for size_t, NULL #include // for exit() #include // for pid_t #include // for waitpid() #include // for ioctl() and FIONREAD #if defined(__sun) # include // for FIONREAD on Solaris 2.5 #endif #include // for pipe() fork() exec() and filedes functions #include // for kill() #include // for fcntl() #if REDI_EVISCERATE_PSTREAMS # include // for FILE, fdopen() #endif /// The library version. #define PSTREAMS_VERSION 0x0101 // 1.0.1 /** * @namespace redi * @brief All PStreams classes are declared in namespace redi. * * Like the standard iostreams, PStreams is a set of class templates, * taking a character type and traits type. As with the standard streams * they are most likely to be used with @c char and the default * traits type, so typedefs for this most common case are provided. * * The @c pstream_common class template is not intended to be used directly, * it is used internally to provide the common functionality for the * other stream classes. */ namespace redi { /// Common base class providing constants and typenames. struct pstreams { /// Type used to specify how to connect to the process. typedef std::ios_base::openmode pmode; /// Type used to hold the arguments for a command. typedef std::vector argv_type; /// Type used for file descriptors. typedef int fd_type; static const pmode pstdin = std::ios_base::out; ///< Write to stdin static const pmode pstdout = std::ios_base::in; ///< Read from stdout static const pmode pstderr = std::ios_base::app; ///< Read from stderr /// Create a new process group for the child process. static const pmode newpg = std::ios_base::trunc; protected: enum { bufsz = 32 }; ///< Size of pstreambuf buffers. enum { pbsz = 2 }; ///< Number of putback characters kept. }; /// Class template for stream buffer. template > class basic_pstreambuf : public std::basic_streambuf , public pstreams { public: // Type definitions for dependent types typedef CharT char_type; typedef Traits traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::off_type off_type; typedef typename traits_type::pos_type pos_type; /** @deprecated use pstreams::fd_type instead. */ typedef fd_type fd_t; /// Default constructor. basic_pstreambuf(); /// Constructor that initialises the buffer with @a cmd. basic_pstreambuf(const std::string& cmd, pmode mode); /// Constructor that initialises the buffer with @a file and @a argv. basic_pstreambuf( const std::string& file, const argv_type& argv, pmode mode ); /// Destructor. ~basic_pstreambuf(); /// Initialise the stream buffer with @a cmd. basic_pstreambuf* open(const std::string& cmd, pmode mode); /// Initialise the stream buffer with @a file and @a argv. basic_pstreambuf* open(const std::string& file, const argv_type& argv, pmode mode); /// Close the stream buffer and wait for the process to exit. basic_pstreambuf* close(); /// Send a signal to the process. basic_pstreambuf* kill(int signal = SIGTERM); /// Send a signal to the process' process group. basic_pstreambuf* killpg(int signal = SIGTERM); /// Close the pipe connected to the process' stdin. void peof(); /// Change active input source. bool read_err(bool readerr = true); /// Report whether the stream buffer has been initialised. bool is_open() const; /// Report whether the process has exited. bool exited(); #if REDI_EVISCERATE_PSTREAMS /// Obtain FILE pointers for each of the process' standard streams. std::size_t fopen(FILE*& in, FILE*& out, FILE*& err); #endif /// Return the exit status of the process. int status() const; /// Return the error number (errno) for the most recent failed operation. int error() const; protected: /// Transfer characters to the pipe when character buffer overflows. int_type overflow(int_type c); /// Transfer characters from the pipe when the character buffer is empty. int_type underflow(); /// Make a character available to be returned by the next extraction. int_type pbackfail(int_type c = traits_type::eof()); /// Write any buffered characters to the stream. int sync(); /// Insert multiple characters into the pipe. std::streamsize xsputn(const char_type* s, std::streamsize n); /// Insert a sequence of characters into the pipe. std::streamsize write(const char_type* s, std::streamsize n); /// Extract a sequence of characters from the pipe. std::streamsize read(char_type* s, std::streamsize n); /// Report how many characters can be read from active input without blocking. std::streamsize showmanyc(); protected: /// Enumerated type to indicate whether stdout or stderr is to be read. enum buf_read_src { rsrc_out = 0, rsrc_err = 1 }; /// Initialise pipes and fork process. pid_t fork(pmode mode); /// Wait for the child process to exit. int wait(bool nohang = false); /// Return the file descriptor for the output pipe. fd_type& wpipe(); /// Return the file descriptor for the active input pipe. fd_type& rpipe(); /// Return the file descriptor for the specified input pipe. fd_type& rpipe(buf_read_src which); void create_buffers(pmode mode); void destroy_buffers(pmode mode); /// Writes buffered characters to the process' stdin pipe. bool empty_buffer(); bool fill_buffer(bool non_blocking = false); /// Return the active input buffer. char_type* rbuffer(); buf_read_src switch_read_buffer(buf_read_src); private: basic_pstreambuf(const basic_pstreambuf&); basic_pstreambuf& operator=(const basic_pstreambuf&); void init_rbuffers(); pid_t ppid_; // pid of process fd_type wpipe_; // pipe used to write to process' stdin fd_type rpipe_[2]; // two pipes to read from, stdout and stderr char_type* wbuffer_; char_type* rbuffer_[2]; char_type* rbufstate_[3]; /// Index into rpipe_[] to indicate active source for read operations. buf_read_src rsrc_; int status_; // hold exit status of child process int error_; // hold errno if fork() or exec() fails }; /// Class template for common base class. template > class pstream_common : virtual public std::basic_ios , virtual public pstreams { protected: typedef basic_pstreambuf streambuf_type; typedef pstreams::pmode pmode; typedef pstreams::argv_type argv_type; /// Default constructor. pstream_common(); /// Constructor that initialises the stream by starting a process. pstream_common(const std::string& cmd, pmode mode); /// Constructor that initialises the stream by starting a process. pstream_common(const std::string& file, const argv_type& argv, pmode mode); /// Pure virtual destructor. virtual ~pstream_common() = 0; /// Start a process. void do_open(const std::string& cmd, pmode mode); /// Start a process. void do_open(const std::string& file, const argv_type& argv, pmode mode); public: /// Close the pipe. void close(); /// Report whether the stream's buffer has been initialised. bool is_open() const; /// Return the command used to initialise the stream. const std::string& command() const; /// Return a pointer to the stream buffer. streambuf_type* rdbuf() const; #if REDI_EVISCERATE_PSTREAMS /// Obtain FILE pointers for each of the process' standard streams. std::size_t fopen(FILE*& in, FILE*& out, FILE*& err); #endif protected: std::string command_; ///< The command used to start the process. streambuf_type buf_; ///< The stream buffer. }; /** * @class basic_ipstream * @brief Class template for Input PStreams. * * Reading from an ipstream reads the command's standard output and/or * standard error (depending on how the ipstream is opened) * and the command's standard input is the same as that of the process * that created the object, unless altered by the command itself. */ template > class basic_ipstream : public std::basic_istream , public pstream_common , virtual public pstreams { typedef std::basic_istream istream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope // Ensure a basic_ipstream will read from at least one pipe pmode readable(pmode mode) { if (!(mode & (pstdout|pstderr))) mode |= pstdout; return mode; } public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_ipstream() : istream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_ipstream(const std::string& cmd, pmode mode = pstdout) : istream_type(NULL), pbase_type(cmd, readable(mode)) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_ipstream( const std::string& file, const argv_type& argv, pmode mode = pstdout ) : istream_type(NULL), pbase_type(file, argv, readable(mode)) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode|pstdout) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_ipstream(const argv_type& argv, pmode mode = pstdout) : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode)) { } #if __cplusplus >= 201103L template explicit basic_ipstream(std::initializer_list args, pmode mode = pstdout) : basic_ipstream(argv_type(args.begin(), args.end()), mode) { } #endif /** * @brief Destructor. * * Closes the stream and waits for the child to exit. */ ~basic_ipstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode|pstdout ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout) { this->do_open(cmd, readable(mode)); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode|pstdout ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout ) { this->do_open(file, argv, readable(mode)); } /** * @brief Set streambuf to read from process' @c stdout. * @return @c *this */ basic_ipstream& out() { this->buf_.read_err(false); return *this; } /** * @brief Set streambuf to read from process' @c stderr. * @return @c *this */ basic_ipstream& err() { this->buf_.read_err(true); return *this; } }; /** * @class basic_opstream * @brief Class template for Output PStreams. * * Writing to an open opstream writes to the standard input of the command; * the command's standard output is the same as that of the process that * created the pstream object, unless altered by the command itself. */ template > class basic_opstream : public std::basic_ostream , public pstream_common , virtual public pstreams { typedef std::basic_ostream ostream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_opstream() : ostream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_opstream(const std::string& cmd, pmode mode = pstdin) : ostream_type(NULL), pbase_type(cmd, mode|pstdin) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_opstream( const std::string& file, const argv_type& argv, pmode mode = pstdin ) : ostream_type(NULL), pbase_type(file, argv, mode|pstdin) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode|pstdin) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_opstream(const argv_type& argv, pmode mode = pstdin) : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param args a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_opstream(std::initializer_list args, pmode mode = pstdin) : basic_opstream(argv_type(args.begin(), args.end()), mode) { } #endif /** * @brief Destructor * * Closes the stream and waits for the child to exit. */ ~basic_opstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode|pstdin ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdin) { this->do_open(cmd, mode|pstdin); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode|pstdin ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdin) { this->do_open(file, argv, mode|pstdin); } }; /** * @class basic_pstream * @brief Class template for Bidirectional PStreams. * * Writing to a pstream opened with @c pmode @c pstdin writes to the * standard input of the command. * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr * reads the command's standard output and/or standard error. * Any of the process' @c stdin, @c stdout or @c stderr that is not * connected to the pstream (as specified by the @c pmode) * will be the same as the process that created the pstream object, * unless altered by the command itself. */ template > class basic_pstream : public std::basic_iostream , public pstream_common , virtual public pstreams { typedef std::basic_iostream iostream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_pstream() : iostream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin) : iostream_type(NULL), pbase_type(cmd, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_pstream( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) : iostream_type(NULL), pbase_type(file, argv, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin) : iostream_type(NULL), pbase_type(argv.at(0), argv, mode) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param l a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_pstream(std::initializer_list l, pmode mode = pstdout|pstdin) : basic_pstream(argv_type(l.begin(), l.end()), mode) { } #endif /** * @brief Destructor * * Closes the stream and waits for the child to exit. */ ~basic_pstream() { } /** * @brief Start a process. * * Calls do_open( @a cnd , @a mode ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout|pstdin) { this->do_open(cmd, mode); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) { this->do_open(file, argv, mode); } /** * @brief Set streambuf to read from process' @c stdout. * @return @c *this */ basic_pstream& out() { this->buf_.read_err(false); return *this; } /** * @brief Set streambuf to read from process' @c stderr. * @return @c *this */ basic_pstream& err() { this->buf_.read_err(true); return *this; } }; /** * @class basic_rpstream * @brief Class template for Restricted PStreams. * * Writing to an rpstream opened with @c pmode @c pstdin writes to the * standard input of the command. * It is not possible to read directly from an rpstream object, to use * an rpstream as in istream you must call either basic_rpstream::out() * or basic_rpstream::err(). This is to prevent accidental reads from * the wrong input source. If the rpstream was not opened with @c pmode * @c pstderr then the class cannot read the process' @c stderr, and * basic_rpstream::err() will return an istream that reads from the * process' @c stdout, and vice versa. * Reading from an rpstream opened with @c pmode @c pstdout and/or * @c pstderr reads the command's standard output and/or standard error. * Any of the process' @c stdin, @c stdout or @c stderr that is not * connected to the pstream (as specified by the @c pmode) * will be the same as the process that created the pstream object, * unless altered by the command itself. */ template > class basic_rpstream : public std::basic_ostream , private std::basic_istream , private pstream_common , virtual public pstreams { typedef std::basic_ostream ostream_type; typedef std::basic_istream istream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_rpstream() : ostream_type(NULL), istream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin) : ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_rpstream( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin) : ostream_type(NULL), istream_type(NULL), pbase_type(argv.at(0), argv, mode) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param l a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_rpstream(std::initializer_list l, pmode mode = pstdout|pstdin) : basic_rpstream(argv_type(l.begin(), l.end()), mode) { } #endif /// Destructor ~basic_rpstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout|pstdin) { this->do_open(cmd, mode); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) { this->do_open(file, argv, mode); } /** * @brief Obtain a reference to the istream that reads * the process' @c stdout. * @return @c *this */ istream_type& out() { this->buf_.read_err(false); return *this; } /** * @brief Obtain a reference to the istream that reads * the process' @c stderr. * @return @c *this */ istream_type& err() { this->buf_.read_err(true); return *this; } }; /// Type definition for common template specialisation. typedef basic_pstreambuf pstreambuf; /// Type definition for common template specialisation. typedef basic_ipstream ipstream; /// Type definition for common template specialisation. typedef basic_opstream opstream; /// Type definition for common template specialisation. typedef basic_pstream pstream; /// Type definition for common template specialisation. typedef basic_rpstream rpstream; /** * When inserted into an output pstream the manipulator calls * basic_pstreambuf::peof() to close the output pipe, * causing the child process to receive the end-of-file indicator * on subsequent reads from its @c stdin stream. * * @brief Manipulator to close the pipe connected to the process' stdin. * @param s An output PStream class. * @return The stream object the manipulator was invoked on. * @see basic_pstreambuf::peof() * @relates basic_opstream basic_pstream basic_rpstream */ template inline std::basic_ostream& peof(std::basic_ostream& s) { typedef basic_pstreambuf pstreambuf_type; if (pstreambuf_type* p = dynamic_cast(s.rdbuf())) p->peof(); return s; } /* * member definitions for pstreambuf */ /** * @class basic_pstreambuf * Provides underlying streambuf functionality for the PStreams classes. */ /** Creates an uninitialised stream buffer. */ template inline basic_pstreambuf::basic_pstreambuf() : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); } /** * Initialises the stream buffer by calling open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see open() */ template inline basic_pstreambuf::basic_pstreambuf(const std::string& cmd, pmode mode) : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); open(cmd, mode); } /** * Initialises the stream buffer by calling open() with the supplied * arguments. * * @param file a string containing the name of a program to execute. * @param argv a vector of argument strings passsed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see open() */ template inline basic_pstreambuf::basic_pstreambuf( const std::string& file, const argv_type& argv, pmode mode ) : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); open(file, argv, mode); } /** * Closes the stream by calling close(). * @see close() */ template inline basic_pstreambuf::~basic_pstreambuf() { close(); } /** * Starts a new process by passing @a command to the shell (/bin/sh) * and opens pipes to the process with the specified @a mode. * * If @a mode contains @c pstdout the initial read source will be * the child process' stdout, otherwise if @a mode contains @c pstderr * the initial read source will be the child's stderr. * * Will duplicate the actions of the shell in searching for an * executable file if the specified file name does not contain a slash (/) * character. * * @warning * There is no way to tell whether the shell command succeeded, this * function will always succeed unless resource limits (such as * memory usage, or number of processes or open files) are exceeded. * This means is_open() will return true even if @a command cannot * be executed. * Use pstreambuf::open(const std::string&, const argv_type&, pmode) * if you need to know whether the command failed to execute. * * @param command a string containing a shell command. * @param mode a bitwise OR of one or more of @c out, @c in, @c err. * @return NULL if the shell could not be started or the * pipes could not be opened, @c this otherwise. * @see execl(3) */ template basic_pstreambuf* basic_pstreambuf::open(const std::string& command, pmode mode) { const char * shell_path = "/bin/sh"; #if 0 const std::string argv[] = { "sh", "-c", command }; return this->open(shell_path, argv_type(argv, argv+3), mode); #else basic_pstreambuf* ret = NULL; if (!is_open()) { switch(fork(mode)) { case 0 : // this is the new process, exec command ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL); // can only reach this point if exec() failed // parent can get exit code from waitpid() ::_exit(errno); // using std::exit() would make static dtors run twice case -1 : // couldn't fork, error already handled in pstreambuf::fork() break; default : // this is the parent process // activate buffers create_buffers(mode); ret = this; } } return ret; #endif } /** * @brief Helper function to close a file descriptor. * * Inspects @a fd and calls close(3) if it has a non-negative value. * * @param fd a file descriptor. * @relates basic_pstreambuf */ inline void close_fd(pstreams::fd_type& fd) { if (fd >= 0 && ::close(fd) == 0) fd = -1; } /** * @brief Helper function to close an array of file descriptors. * * Calls @c close_fd() on each member of the array. * The length of the array is determined automatically by * template argument deduction to avoid errors. * * @param fds an array of file descriptors. * @relates basic_pstreambuf */ template inline void close_fd_array(pstreams::fd_type (&fds)[N]) { for (std::size_t i = 0; i < N; ++i) close_fd(fds[i]); } /** * Starts a new process by executing @a file with the arguments in * @a argv and opens pipes to the process with the specified @a mode. * * By convention @c argv[0] should be the file name of the file being * executed. * * If @a mode contains @c pstdout the initial read source will be * the child process' stdout, otherwise if @a mode contains @c pstderr * the initial read source will be the child's stderr. * * Will duplicate the actions of the shell in searching for an * executable file if the specified file name does not contain a slash (/) * character. * * Iff @a file is successfully executed then is_open() will return true. * Otherwise, pstreambuf::error() can be used to obtain the value of * @c errno that was set by execvp(3) in the child process. * * The exit status of the new process will be returned by * pstreambuf::status() after pstreambuf::exited() returns true. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode a bitwise OR of one or more of @c out, @c in and @c err. * @return NULL if a pipe could not be opened or if the program could * not be executed, @c this otherwise. * @see execvp(3) */ template basic_pstreambuf* basic_pstreambuf::open( const std::string& file, const argv_type& argv, pmode mode ) { basic_pstreambuf* ret = NULL; if (!is_open()) { // constants for read/write ends of pipe enum { RD, WR }; // open another pipe and set close-on-exec fd_type ck_exec[] = { -1, -1 }; if (-1 == ::pipe(ck_exec) || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC) || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC)) { error_ = errno; close_fd_array(ck_exec); } else { switch(fork(mode)) { case 0 : // this is the new process, exec command { char** arg_v = new char*[argv.size()+1]; for (std::size_t i = 0; i < argv.size(); ++i) { const std::string& src = argv[i]; char*& dest = arg_v[i]; dest = new char[src.size()+1]; dest[ src.copy(dest, src.size()) ] = '\0'; } arg_v[argv.size()] = NULL; ::execvp(file.c_str(), arg_v); // can only reach this point if exec() failed // parent can get error code from ck_exec pipe error_ = errno; while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1 && errno == EINTR) { } ::close(ck_exec[WR]); ::close(ck_exec[RD]); ::_exit(error_); // using std::exit() would make static dtors run twice } case -1 : // couldn't fork, error already handled in pstreambuf::fork() close_fd_array(ck_exec); break; default : // this is the parent process // check child called exec() successfully ::close(ck_exec[WR]); switch (::read(ck_exec[RD], &error_, sizeof(error_))) { case 0: // activate buffers create_buffers(mode); ret = this; break; case -1: error_ = errno; break; default: // error_ contains error code from child // call wait() to clean up and set ppid_ to 0 this->wait(); break; } ::close(ck_exec[RD]); } } } return ret; } /** * Creates pipes as specified by @a mode and calls @c fork() to create * a new process. If the fork is successful the parent process stores * the child's PID and the opened pipes and the child process replaces * its standard streams with the opened pipes. * * If an error occurs the error code will be set to one of the possible * errors for @c pipe() or @c fork(). * See your system's documentation for these error codes. * * @param mode an OR of pmodes specifying which of the child's * standard streams to connect to. * @return On success the PID of the child is returned in the parent's * context and zero is returned in the child's context. * On error -1 is returned and the error code is set appropriately. */ template pid_t basic_pstreambuf::fork(pmode mode) { pid_t pid = -1; // Three pairs of file descriptors, for pipes connected to the // process' stdin, stdout and stderr // (stored in a single array so close_fd_array() can close all at once) fd_type fd[] = { -1, -1, -1, -1, -1, -1 }; fd_type* const pin = fd; fd_type* const pout = fd+2; fd_type* const perr = fd+4; // constants for read/write ends of pipe enum { RD, WR }; // N.B. // For the pstreambuf pin is an output stream and // pout and perr are input streams. if (!error_ && mode&pstdin && ::pipe(pin)) error_ = errno; if (!error_ && mode&pstdout && ::pipe(pout)) error_ = errno; if (!error_ && mode&pstderr && ::pipe(perr)) error_ = errno; if (!error_) { pid = ::fork(); switch (pid) { case 0 : { // this is the new process // for each open pipe close one end and redirect the // respective standard stream to the other end if (*pin >= 0) { ::close(pin[WR]); ::dup2(pin[RD], STDIN_FILENO); ::close(pin[RD]); } if (*pout >= 0) { ::close(pout[RD]); ::dup2(pout[WR], STDOUT_FILENO); ::close(pout[WR]); } if (*perr >= 0) { ::close(perr[RD]); ::dup2(perr[WR], STDERR_FILENO); ::close(perr[WR]); } #ifdef _POSIX_JOB_CONTROL if (mode&newpg) ::setpgid(0, 0); // Change to a new process group #endif break; } case -1 : { // couldn't fork for some reason error_ = errno; // close any open pipes close_fd_array(fd); break; } default : { // this is the parent process, store process' pid ppid_ = pid; // store one end of open pipes and close other end if (*pin >= 0) { wpipe_ = pin[WR]; ::close(pin[RD]); } if (*pout >= 0) { rpipe_[rsrc_out] = pout[RD]; ::close(pout[WR]); } if (*perr >= 0) { rpipe_[rsrc_err] = perr[RD]; ::close(perr[WR]); } } } } else { // close any pipes we opened before failure close_fd_array(fd); } return pid; } /** * Closes all pipes and calls wait() to wait for the process to finish. * If an error occurs the error code will be set to one of the possible * errors for @c waitpid(). * See your system's documentation for these errors. * * @return @c this on successful close or @c NULL if there is no * process to close or if an error occurs. */ template basic_pstreambuf* basic_pstreambuf::close() { const bool running = is_open(); sync(); // this might call wait() and reap the child process // rather than trying to work out whether or not we need to clean up // just do it anyway, all cleanup functions are safe to call twice. destroy_buffers(pstdin|pstdout|pstderr); // close pipes before wait() so child gets EOF/SIGPIPE close_fd(wpipe_); close_fd_array(rpipe_); do { error_ = 0; } while (wait() == -1 && error() == EINTR); return running ? this : NULL; } /** * Called on construction to initialise the arrays used for reading. */ template inline void basic_pstreambuf::init_rbuffers() { rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL; rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL; } template void basic_pstreambuf::create_buffers(pmode mode) { if (mode & pstdin) { delete[] wbuffer_; wbuffer_ = new char_type[bufsz]; this->setp(wbuffer_, wbuffer_ + bufsz); } if (mode & pstdout) { delete[] rbuffer_[rsrc_out]; rbuffer_[rsrc_out] = new char_type[bufsz]; rsrc_ = rsrc_out; this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz); } if (mode & pstderr) { delete[] rbuffer_[rsrc_err]; rbuffer_[rsrc_err] = new char_type[bufsz]; if (!(mode & pstdout)) { rsrc_ = rsrc_err; this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz); } } } template void basic_pstreambuf::destroy_buffers(pmode mode) { if (mode & pstdin) { this->setp(NULL, NULL); delete[] wbuffer_; wbuffer_ = NULL; } if (mode & pstdout) { if (rsrc_ == rsrc_out) this->setg(NULL, NULL, NULL); delete[] rbuffer_[rsrc_out]; rbuffer_[rsrc_out] = NULL; } if (mode & pstderr) { if (rsrc_ == rsrc_err) this->setg(NULL, NULL, NULL); delete[] rbuffer_[rsrc_err]; rbuffer_[rsrc_err] = NULL; } } template typename basic_pstreambuf::buf_read_src basic_pstreambuf::switch_read_buffer(buf_read_src src) { if (rsrc_ != src) { char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()}; this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]); for (std::size_t i = 0; i < 3; ++i) rbufstate_[i] = tmpbufstate[i]; rsrc_ = src; } return rsrc_; } /** * Suspends execution and waits for the associated process to exit, or * until a signal is delivered whose action is to terminate the current * process or to call a signal handling function. If the process has * already exited (i.e. it is a "zombie" process) then wait() returns * immediately. Waiting for the child process causes all its system * resources to be freed. * * error() will return EINTR if wait() is interrupted by a signal. * * @param nohang true to return immediately if the process has not exited. * @return 1 if the process has exited and wait() has not yet been called. * 0 if @a nohang is true and the process has not exited yet. * -1 if no process has been started or if an error occurs, * in which case the error can be found using error(). */ template int basic_pstreambuf::wait(bool nohang) { int child_exited = -1; if (is_open()) { int exit_status; switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0)) { case 0 : // nohang was true and process has not exited child_exited = 0; break; case -1 : error_ = errno; break; default : // process has exited ppid_ = 0; status_ = exit_status; child_exited = 1; // Close wpipe, would get SIGPIPE if we used it. destroy_buffers(pstdin); close_fd(wpipe_); // Must free read buffers and pipes on destruction // or next call to open()/close() break; } } return child_exited; } /** * Sends the specified signal to the process. A signal can be used to * terminate a child process that would not exit otherwise. * * If an error occurs the error code will be set to one of the possible * errors for @c kill(). See your system's documentation for these errors. * * @param signal A signal to send to the child process. * @return @c this or @c NULL if @c kill() fails. */ template inline basic_pstreambuf* basic_pstreambuf::kill(int signal) { basic_pstreambuf* ret = NULL; if (is_open()) { if (::kill(ppid_, signal)) error_ = errno; else { #if 0 // TODO call exited() to check for exit and clean up? leave to user? if (signal==SIGTERM || signal==SIGKILL) this->exited(); #endif ret = this; } } return ret; } /** * Sends the specified signal to the process group of the child process. * A signal can be used to terminate a child process that would not exit * otherwise, or to kill the process and its own children. * * If an error occurs the error code will be set to one of the possible * errors for @c getpgid() or @c kill(). See your system's documentation * for these errors. If the child is in the current process group then * NULL will be returned and the error code set to EPERM. * * @param signal A signal to send to the child process. * @return @c this on success or @c NULL on failure. */ template inline basic_pstreambuf* basic_pstreambuf::killpg(int signal) { basic_pstreambuf* ret = NULL; #ifdef _POSIX_JOB_CONTROL if (is_open()) { pid_t pgid = ::getpgid(ppid_); if (pgid == -1) error_ = errno; else if (pgid == ::getpgrp()) error_ = EPERM; // Don't commit suicide else if (::killpg(pgid, signal)) error_ = errno; else ret = this; } #else error_ = ENOTSUP; #endif return ret; } /** * This function can call pstreambuf::wait() and so may change the * object's state if the child process has already exited. * * @return True if the associated process has exited, false otherwise. * @see basic_pstreambuf::wait() */ template inline bool basic_pstreambuf::exited() { return ppid_ == 0 || wait(true)==1; } /** * @return The exit status of the child process, or -1 if wait() * has not yet been called to wait for the child to exit. * @see basic_pstreambuf::wait() */ template inline int basic_pstreambuf::status() const { return status_; } /** * @return The error code of the most recently failed operation, or zero. */ template inline int basic_pstreambuf::error() const { return error_; } /** * Closes the output pipe, causing the child process to receive the * end-of-file indicator on subsequent reads from its @c stdin stream. */ template inline void basic_pstreambuf::peof() { sync(); destroy_buffers(pstdin); close_fd(wpipe_); } /** * Unlike pstreambuf::exited(), this function will not call wait() and * so will not change the object's state. This means that once a child * process is executed successfully this function will continue to * return true even after the process exits (until wait() is called.) * * @return true if a previous call to open() succeeded and wait() has * not been called and determined that the process has exited, * false otherwise. */ template inline bool basic_pstreambuf::is_open() const { return ppid_ > 0; } /** * Toggle the stream used for reading. If @a readerr is @c true then the * process' @c stderr output will be used for subsequent extractions, if * @a readerr is false the the process' stdout will be used. * @param readerr @c true to read @c stderr, @c false to read @c stdout. * @return @c true if the requested stream is open and will be used for * subsequent extractions, @c false otherwise. */ template inline bool basic_pstreambuf::read_err(bool readerr) { buf_read_src src = readerr ? rsrc_err : rsrc_out; if (rpipe_[src]>=0) { switch_read_buffer(src); return true; } return false; } /** * Called when the internal character buffer is not present or is full, * to transfer the buffer contents to the pipe. * * @param c a character to be written to the pipe. * @return @c traits_type::eof() if an error occurs, otherwise if @a c * is not equal to @c traits_type::eof() it will be buffered and * a value other than @c traits_type::eof() returned to indicate * success. */ template typename basic_pstreambuf::int_type basic_pstreambuf::overflow(int_type c) { if (!empty_buffer()) return traits_type::eof(); else if (!traits_type::eq_int_type(c, traits_type::eof())) return this->sputc(c); else return traits_type::not_eof(c); } template int basic_pstreambuf::sync() { return !exited() && empty_buffer() ? 0 : -1; } /** * @param s character buffer. * @param n buffer length. * @return the number of characters written. */ template std::streamsize basic_pstreambuf::xsputn(const char_type* s, std::streamsize n) { std::streamsize done = 0; while (done < n) { if (std::streamsize nbuf = this->epptr() - this->pptr()) { nbuf = std::min(nbuf, n - done); traits_type::copy(this->pptr(), s + done, nbuf); this->pbump(nbuf); done += nbuf; } else if (!empty_buffer()) break; } return done; } /** * @return true if the buffer was emptied, false otherwise. */ template bool basic_pstreambuf::empty_buffer() { const std::streamsize count = this->pptr() - this->pbase(); if (count > 0) { const std::streamsize written = this->write(this->wbuffer_, count); if (written > 0) { if (const std::streamsize unwritten = count - written) traits_type::move(this->pbase(), this->pbase()+written, unwritten); this->pbump(-written); return true; } } return false; } /** * Called when the internal character buffer is is empty, to re-fill it * from the pipe. * * @return The first available character in the buffer, * or @c traits_type::eof() in case of failure. */ template typename basic_pstreambuf::int_type basic_pstreambuf::underflow() { if (this->gptr() < this->egptr() || fill_buffer()) return traits_type::to_int_type(*this->gptr()); else return traits_type::eof(); } /** * Attempts to make @a c available as the next character to be read by * @c sgetc(). * * @param c a character to make available for extraction. * @return @a c if the character can be made available, * @c traits_type::eof() otherwise. */ template typename basic_pstreambuf::int_type basic_pstreambuf::pbackfail(int_type c) { if (this->gptr() != this->eback()) { this->gbump(-1); if (!traits_type::eq_int_type(c, traits_type::eof())) *this->gptr() = traits_type::to_char_type(c); return traits_type::not_eof(c); } else return traits_type::eof(); } template std::streamsize basic_pstreambuf::showmanyc() { int avail = 0; if (sizeof(char_type) == 1) avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1; #ifdef FIONREAD else { if (::ioctl(rpipe(), FIONREAD, &avail) == -1) avail = -1; else if (avail) avail /= sizeof(char_type); } #endif return std::streamsize(avail); } /** * @return true if the buffer was filled, false otherwise. */ template bool basic_pstreambuf::fill_buffer(bool non_blocking) { const std::streamsize pb1 = this->gptr() - this->eback(); const std::streamsize pb2 = pbsz; const std::streamsize npb = std::min(pb1, pb2); char_type* const rbuf = rbuffer(); if (npb) traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb); std::streamsize rc = -1; if (non_blocking) { const int flags = ::fcntl(rpipe(), F_GETFL); if (flags != -1) { const bool blocking = !(flags & O_NONBLOCK); if (blocking) ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking error_ = 0; rc = read(rbuf + pbsz, bufsz - pbsz); if (rc == -1 && error_ == EAGAIN) // nothing available rc = 0; else if (rc == 0) // EOF rc = -1; if (blocking) ::fcntl(rpipe(), F_SETFL, flags); // restore } } else rc = read(rbuf + pbsz, bufsz - pbsz); if (rc > 0 || (rc == 0 && non_blocking)) { this->setg( rbuf + pbsz - npb, rbuf + pbsz, rbuf + pbsz + rc ); return true; } else { this->setg(NULL, NULL, NULL); return false; } } /** * Writes up to @a n characters to the pipe from the buffer @a s. * * @param s character buffer. * @param n buffer length. * @return the number of characters written. */ template inline std::streamsize basic_pstreambuf::write(const char_type* s, std::streamsize n) { std::streamsize nwritten = 0; if (wpipe() >= 0) { nwritten = ::write(wpipe(), s, n * sizeof(char_type)); if (nwritten == -1) error_ = errno; else nwritten /= sizeof(char_type); } return nwritten; } /** * Reads up to @a n characters from the pipe to the buffer @a s. * * @param s character buffer. * @param n buffer length. * @return the number of characters read. */ template inline std::streamsize basic_pstreambuf::read(char_type* s, std::streamsize n) { std::streamsize nread = 0; if (rpipe() >= 0) { nread = ::read(rpipe(), s, n * sizeof(char_type)); if (nread == -1) error_ = errno; else nread /= sizeof(char_type); } return nread; } /** @return a reference to the output file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::wpipe() { return wpipe_; } /** @return a reference to the active input file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::rpipe() { return rpipe_[rsrc_]; } /** @return a reference to the specified input file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::rpipe(buf_read_src which) { return rpipe_[which]; } /** @return a pointer to the start of the active input buffer area. */ template inline typename basic_pstreambuf::char_type* basic_pstreambuf::rbuffer() { return rbuffer_[rsrc_]; } /* * member definitions for pstream_common */ /** * @class pstream_common * Abstract Base Class providing common functionality for basic_ipstream, * basic_opstream and basic_pstream. * pstream_common manages the basic_pstreambuf stream buffer that is used * by the derived classes to initialise an iostream class. */ /** Creates an uninitialised stream. */ template inline pstream_common::pstream_common() : std::basic_ios(NULL) , command_() , buf_() { this->std::basic_ios::rdbuf(&buf_); } /** * Initialises the stream buffer by calling * do_open( @a command , @a mode ) * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ template inline pstream_common::pstream_common(const std::string& cmd, pmode mode) : std::basic_ios(NULL) , command_(cmd) , buf_() { this->std::basic_ios::rdbuf(&buf_); do_open(cmd, mode); } /** * Initialises the stream buffer by calling * do_open( @a file , @a argv , @a mode ) * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template inline pstream_common::pstream_common( const std::string& file, const argv_type& argv, pmode mode ) : std::basic_ios(NULL) , command_(file) , buf_() { this->std::basic_ios::rdbuf(&buf_); do_open(file, argv, mode); } /** * This is a pure virtual function to make @c pstream_common abstract. * Because it is the destructor it will be called by derived classes * and so must be defined. It is also protected, to discourage use of * the PStreams classes through pointers or references to the base class. * * @sa If defining a pure virtual seems odd you should read * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!) */ template inline pstream_common::~pstream_common() { } /** * Calls rdbuf()->open( @a command , @a mode ) * and sets @c failbit on error. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see basic_pstreambuf::open(const std::string&, pmode) */ template inline void pstream_common::do_open(const std::string& cmd, pmode mode) { if (!buf_.open((command_=cmd), mode)) this->setstate(std::ios_base::failbit); } /** * Calls rdbuf()->open( @a file, @a argv, @a mode ) * and sets @c failbit on error. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see basic_pstreambuf::open(const std::string&, const argv_type&, pmode) */ template inline void pstream_common::do_open( const std::string& file, const argv_type& argv, pmode mode ) { if (!buf_.open((command_=file), argv, mode)) this->setstate(std::ios_base::failbit); } /** Calls rdbuf->close() and sets @c failbit on error. */ template inline void pstream_common::close() { if (!buf_.close()) this->setstate(std::ios_base::failbit); } /** * @return rdbuf()->is_open(). * @see basic_pstreambuf::is_open() */ template inline bool pstream_common::is_open() const { return buf_.is_open(); } /** @return a string containing the command used to initialise the stream. */ template inline const std::string& pstream_common::command() const { return command_; } /** @return a pointer to the private stream buffer member. */ // TODO document behaviour if buffer replaced. template inline typename pstream_common::streambuf_type* pstream_common::rdbuf() const { return const_cast(&buf_); } #if REDI_EVISCERATE_PSTREAMS /** * @def REDI_EVISCERATE_PSTREAMS * If this macro has a non-zero value then certain internals of the * @c basic_pstreambuf template class are exposed. In general this is * a Bad Thing, as the internal implementation is largely undocumented * and may be subject to change at any time, so this feature is only * provided because it might make PStreams useful in situations where * it is necessary to do Bad Things. */ /** * @warning This function exposes the internals of the stream buffer and * should be used with caution. It is the caller's responsibility * to flush streams etc. in order to clear any buffered data. * The POSIX.1 function fdopen(3) is used to obtain the * @c FILE pointers from the streambuf's private file descriptor * members so consult your system's documentation for * fdopen(3). * * @param in A FILE* that will refer to the process' stdin. * @param out A FILE* that will refer to the process' stdout. * @param err A FILE* that will refer to the process' stderr. * @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr. * * For each open stream shared with the child process a @c FILE* is * obtained and assigned to the corresponding parameter. For closed * streams @c NULL is assigned to the parameter. * The return value can be tested to see which parameters should be * @c !NULL by masking with the corresponding @c pmode value. * * @see fdopen(3) */ template std::size_t basic_pstreambuf::fopen(FILE*& in, FILE*& out, FILE*& err) { in = out = err = NULL; std::size_t open_files = 0; if (wpipe() > -1) { if ((in = ::fdopen(wpipe(), "w"))) { open_files |= pstdin; } } if (rpipe(rsrc_out) > -1) { if ((out = ::fdopen(rpipe(rsrc_out), "r"))) { open_files |= pstdout; } } if (rpipe(rsrc_err) > -1) { if ((err = ::fdopen(rpipe(rsrc_err), "r"))) { open_files |= pstderr; } } return open_files; } /** * @warning This function exposes the internals of the stream buffer and * should be used with caution. * * @param in A FILE* that will refer to the process' stdin. * @param out A FILE* that will refer to the process' stdout. * @param err A FILE* that will refer to the process' stderr. * @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr. * @see basic_pstreambuf::fopen() */ template inline std::size_t pstream_common::fopen(FILE*& fin, FILE*& fout, FILE*& ferr) { return buf_.fopen(fin, fout, ferr); } #endif // REDI_EVISCERATE_PSTREAMS } // namespace redi /** * @mainpage PStreams Reference * @htmlinclude mainpage.html */ #endif // REDI_PSTREAM_H_SEEN #endif // WIN32 void PrintErrorAndQuit(const string sErrorString) { cout << sErrorString << endl; exit(1); } template inline T getmin(const T &a, const T &b) { return b void NewArray(A *** array, int Narray1, int Narray2) { *array=new A* [Narray1]; for(int i=0; i void DeleteArray(A *** array, int Narray) { for(int i=0; i &line_vec, const char delimiter=' ') { bool within_word = false; for (size_t pos=0;pos= 0 && idxEnd >= 0) result = inputString.substr(idxBegin, idxEnd + 1 - idxBegin); return result; } size_t get_PDB_lines(const string filename, vector >&PDB_lines, vector &chainID_list, vector &mol_vec, const int ter_opt, const int infmt_opt, const string atom_opt, const int split_opt, const int het_opt) { size_t i=0; // resi i.e. atom index string line; char chainID=0; string resi=""; bool select_atom=false; size_t model_idx=0; vector tmp_str_vec; int compress_type=0; // uncompressed file ifstream fin; #ifndef REDI_PSTREAM_H_SEEN ifstream fin_gz; #else redi::ipstream fin_gz; // if file is compressed if (filename.size()>=3 && filename.substr(filename.size()-3,3)==".gz") { fin_gz.open("gunzip -c '"+filename+"'"); compress_type=1; } else if (filename.size()>=4 && filename.substr(filename.size()-4,4)==".bz2") { fin_gz.open("bzcat '"+filename+"'"); compress_type=2; } else #endif { if (filename=="-") compress_type=-1; else fin.open(filename.c_str()); } if (infmt_opt==0||infmt_opt==-1) // PDB format { while ((compress_type==-1)?cin.good():(compress_type?fin_gz.good():fin.good())) { if (compress_type==-1) getline(cin, line); else if (compress_type) getline(fin_gz, line); else getline(fin, line); if (infmt_opt==-1 && line.compare(0,5,"loop_")==0) // PDBx/mmCIF return get_PDB_lines(filename,PDB_lines,chainID_list, mol_vec, ter_opt, 3, atom_opt, split_opt,het_opt); if (i > 0) { if (ter_opt>=1 && line.compare(0,3,"END")==0) break; else if (ter_opt>=3 && line.compare(0,3,"TER")==0) break; } if (split_opt && line.compare(0,3,"END")==0) chainID=0; if (line.size()>=54 && (line[16]==' ' || line[16]=='A') && ( (line.compare(0, 6, "ATOM ")==0) || (line.compare(0, 6, "HETATM")==0 && het_opt==1) || (line.compare(0, 6, "HETATM")==0 && het_opt==2 && line.compare(17,3, "MSE")==0))) { if (atom_opt=="auto") { if (line[17]==' ' && (line[18]=='D'||line[18]==' ')) select_atom=(line.compare(12,4," C3'")==0); else select_atom=(line.compare(12,4," CA ")==0); } else select_atom=(line.compare(12,4,atom_opt)==0); if (select_atom) { if (!chainID) { chainID=line[21]; model_idx++; stringstream i8_stream; i=0; if (split_opt==2) // split by chain { if (chainID==' ') { if (ter_opt>=1) i8_stream << ":_"; else i8_stream<<':'<=1) i8_stream << ':' << chainID; else i8_stream<<':'<=2 && chainID!=line[21]) break; if (split_opt==2 && chainID!=line[21]) { chainID=line[21]; i=0; stringstream i8_stream; if (chainID==' ') { if (ter_opt>=1) i8_stream << ":_"; else i8_stream<<':'<=1) i8_stream << ':' << chainID; else i8_stream<<':'<>L>>x>>y>>z; getline(cin, line); if (!cin.good()) break; } else if (compress_type) { fin_gz>>L>>x>>y>>z; getline(fin_gz, line); if (!fin_gz.good()) break; } else { fin >>L>>x>>y>>z; getline(fin, line); if (!fin.good()) break; } model_idx++; stringstream i8_stream; i8_stream << ':' << model_idx; chainID_list.push_back(i8_stream.str()); PDB_lines.push_back(tmp_str_vec); mol_vec.push_back(0); for (i=0;i>x>>y>>z; else if (compress_type) fin_gz>>x>>y>>z; else fin >>x>>y>>z; i8_stream<<"ATOM "<='a' && line[0]<='z') mol_vec.back()++; // RNA else mol_vec.back()--; } } } else if (infmt_opt==3) // PDBx/mmCIF format { bool loop_ = false; // not reading following content map _atom_site; int atom_site_pos; vector line_vec; string alt_id="."; // alternative location indicator string asym_id="."; // this is similar to chainID, except that // chainID is char while asym_id is a string // with possibly multiple char string prev_asym_id=""; string AA=""; // residue name string atom=""; string prev_resi=""; string model_index=""; // the same as model_idx but type is string stringstream i8_stream; while ((compress_type==-1)?cin.good():(compress_type?fin_gz.good():fin.good())) { if (compress_type==-1) getline(cin, line); else if (compress_type) getline(fin_gz, line); else getline(fin, line); if (line.size()==0) continue; if (loop_) loop_ = (line.size()>=2)?(line.compare(0,2,"# ")):(line.compare(0,1,"#")); if (!loop_) { if (line.compare(0,5,"loop_")) continue; while(1) { if (compress_type==-1) { if (cin.good()) getline(cin, line); else PrintErrorAndQuit("ERROR! Unexpected end of -"); } else if (compress_type) { if (fin_gz.good()) getline(fin_gz, line); else PrintErrorAndQuit("ERROR! Unexpected end of "+filename); } else { if (fin.good()) getline(fin, line); else PrintErrorAndQuit("ERROR! Unexpected end of "+filename); } if (line.size()) break; } if (line.compare(0,11,"_atom_site.")) continue; loop_=true; _atom_site.clear(); atom_site_pos=0; _atom_site[Trim(line.substr(11))]=atom_site_pos; while(1) { if (compress_type==-1) getline(cin, line); else if (compress_type) getline(fin_gz, line); else getline(fin, line); if (line.size()==0) continue; if (line.compare(0,11,"_atom_site.")) break; _atom_site[Trim(line.substr(11))]=++atom_site_pos; } if (_atom_site.count("group_PDB")* _atom_site.count("label_atom_id")* _atom_site.count("label_comp_id")* (_atom_site.count("auth_asym_id")+ _atom_site.count("label_asym_id"))* (_atom_site.count("auth_seq_id")+ _atom_site.count("label_seq_id"))* _atom_site.count("Cartn_x")* _atom_site.count("Cartn_y")* _atom_site.count("Cartn_z")==0) { loop_ = false; cerr<<"Warning! Missing one of the following _atom_site data items: group_PDB, label_atom_id, label_comp_id, auth_asym_id/label_asym_id, auth_seq_id/label_seq_id, Cartn_x, Cartn_y, Cartn_z"<=5) continue; AA=line_vec[_atom_site["label_comp_id"]]; // residue name if (AA.size()==1) AA=" "+AA; else if (AA.size()==2) AA=" " +AA; else if (AA.size()>=4) continue; if (atom_opt=="auto") { if (AA[0]==' ' && (AA[1]=='D'||AA[1]==' ')) // DNA || RNA select_atom=(atom==" C3'"); else select_atom=(atom==" CA "); } else select_atom=(atom==atom_opt); if (!select_atom) continue; if (_atom_site.count("auth_asym_id")) asym_id=line_vec[_atom_site["auth_asym_id"]]; else asym_id=line_vec[_atom_site["label_asym_id"]]; if (asym_id==".") asym_id=" "; if (_atom_site.count("pdbx_PDB_model_num") && model_index!=line_vec[_atom_site["pdbx_PDB_model_num"]]) { model_index=line_vec[_atom_site["pdbx_PDB_model_num"]]; if (PDB_lines.size() && ter_opt>=1) break; if (PDB_lines.size()==0 || split_opt>=1) { PDB_lines.push_back(tmp_str_vec); mol_vec.push_back(0); prev_asym_id=asym_id; if (split_opt==1 && ter_opt==0) chainID_list.push_back( ':'+model_index); else if (split_opt==2 && ter_opt==0) chainID_list.push_back(':'+model_index+','+asym_id); else //if (split_opt==2 && ter_opt==1) chainID_list.push_back(':'+asym_id); //else //chainID_list.push_back(""); } } if (prev_asym_id!=asym_id) { if (prev_asym_id!="" && ter_opt>=2) break; if (split_opt>=2) { PDB_lines.push_back(tmp_str_vec); mol_vec.push_back(0); if (split_opt==1 && ter_opt==0) chainID_list.push_back( ':'+model_index); else if (split_opt==2 && ter_opt==0) chainID_list.push_back(':'+model_index+','+asym_id); else //if (split_opt==2 && ter_opt==1) chainID_list.push_back(':'+asym_id); //else //chainID_list.push_back(""); } } if (prev_asym_id!=asym_id) prev_asym_id=asym_id; if (AA[0]==' ' && (AA[1]=='D'||AA[1]==' ')) mol_vec.back()++; else mol_vec.back()--; if (_atom_site.count("auth_seq_id")) resi=line_vec[_atom_site["auth_seq_id"]]; else resi=line_vec[_atom_site["label_seq_id"]]; if (_atom_site.count("pdbx_PDB_ins_code") && line_vec[_atom_site["pdbx_PDB_ins_code"]]!="?") resi+=line_vec[_atom_site["pdbx_PDB_ins_code"]][0]; else resi+=" "; if (prev_resi==resi) cerr<<"Warning! Duplicated residue "<=1) fin_gz.close(); else if (compress_type==0) fin.close(); line.clear(); if (!split_opt) chainID_list.push_back(""); return PDB_lines.size(); } int read_PDB(const vector &PDB_lines, double **a, char *seq, vector &resi_vec, const int read_resi) { size_t i; for (i=0;i=2) resi_vec.push_back(PDB_lines[i].substr(22,5)+ PDB_lines[i][21]); if (read_resi==1) resi_vec.push_back(PDB_lines[i].substr(22,5)); } seq[i]='\0'; return i; } double dist(double x[3], double y[3]) { double d1=x[0]-y[0]; double d2=x[1]-y[1]; double d3=x[2]-y[2]; return (d1*d1 + d2*d2 + d3*d3); } double dot(double *a, double *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); } void transform(double t[3], double u[3][3], double *x, double *x1) { x1[0]=t[0]+dot(&u[0][0], x); x1[1]=t[1]+dot(&u[1][0], x); x1[2]=t[2]+dot(&u[2][0], x); } void do_rotation(double **x, double **x1, int len, double t[3], double u[3][3]) { for(int i=0; i&chain_list, const string &name, const string &dir_opt, const string &suffix_opt) { ifstream fp(name.c_str()); if (! fp.is_open()) PrintErrorAndQuit(("Can not open file: "+name+'\n').c_str()); string line; while (fp.good()) { getline(fp, line); if (! line.size()) continue; chain_list.push_back(dir_opt+Trim(line)+suffix_opt); } fp.close(); line.clear(); } /* These functions implement d0 normalization. The d0 for final TM-score * output is implemented by parameter_set4final. For both RNA alignment * and protein alignment, using d0 set by parameter_set4search yields * slightly better results during initial alignment-superposition iteration. */ void parameter_set4search(const int xlen, const int ylen, double &D0_MIN, double &Lnorm, double &score_d8, double &d0, double &d0_search, double &dcu0) { //parameter initialization for searching: D0_MIN, Lnorm, d0, d0_search, score_d8 D0_MIN=0.5; dcu0=4.25; //update 3.85-->4.25 Lnorm=getmin(xlen, ylen); //normalize TMscore by this in searching if (Lnorm<=19) //update 15-->19 d0=0.168; //update 0.5-->0.168 else d0=(1.24*pow((Lnorm*1.0-15), 1.0/3)-1.8); D0_MIN=d0+0.8; //this should be moved to above d0=D0_MIN; //update: best for search d0_search=d0; if (d0_search>8) d0_search=8; if (d0_search<4.5) d0_search=4.5; score_d8=1.5*pow(Lnorm*1.0, 0.3)+3.5; //remove pairs with dis>d8 during search & final } void parameter_set4final_C3prime(const double len, double &D0_MIN, double &Lnorm, double &d0, double &d0_search) { D0_MIN=0.3; Lnorm=len; //normalize TMscore by this in searching if(Lnorm<=11) d0=0.3; else if(Lnorm>11&&Lnorm<=15) d0=0.4; else if(Lnorm>15&&Lnorm<=19) d0=0.5; else if(Lnorm>19&&Lnorm<=23) d0=0.6; else if(Lnorm>23&&Lnorm<30) d0=0.7; else d0=(0.6*pow((Lnorm*1.0-0.5), 1.0/2)-2.5); d0_search=d0; if (d0_search>8) d0_search=8; if (d0_search<4.5) d0_search=4.5; } void parameter_set4final(const double len, double &D0_MIN, double &Lnorm, double &d0, double &d0_search, const int mol_type) { if (mol_type>0) // RNA { parameter_set4final_C3prime(len, D0_MIN, Lnorm, d0, d0_search); return; } D0_MIN=0.5; Lnorm=len; //normalize TMscore by this in searching if (Lnorm<=21) d0=0.5; else d0=(1.24*pow((Lnorm*1.0-15), 1.0/3)-1.8); if (d08) d0_search=8; if (d0_search<4.5) d0_search=4.5; } void parameter_set4scale(const int len, const double d_s, double &Lnorm, double &d0, double &d0_search) { d0=d_s; Lnorm=len; //normalize TMscore by this in searching d0_search=d0; if (d0_search>8) d0_search=8; if (d0_search<4.5) d0_search=4.5; } /************************************************************************** Implemetation of Kabsch algoritm for finding the best rotation matrix --------------------------------------------------------------------------- x - x(i,m) are coordinates of atom m in set x (input) y - y(i,m) are coordinates of atom m in set y (input) n - n is number of atom pairs (input) mode - 0:calculate rms only (input) 1:calculate u,t only (takes medium) 2:calculate rms,u,t (takes longer) rms - sum of w*(ux+t-y)**2 over all atom pairs (output) u - u(i,j) is rotation matrix for best superposition (output) t - t(i) is translation vector for best superposition (output) **************************************************************************/ bool Kabsch(double **x, double **y, int n, int mode, double *rms, double t[3], double u[3][3]) { int i, j, m, m1, l, k; double e0, rms1, d, h, g; double cth, sth, sqrth, p, det, sigma; double xc[3], yc[3]; double a[3][3], b[3][3], r[3][3], e[3], rr[6], ss[6]; double sqrt3 = 1.73205080756888, tol = 0.01; int ip[] = { 0, 1, 3, 1, 2, 4, 3, 4, 5 }; int ip2312[] = { 1, 2, 0, 1 }; int a_failed = 0, b_failed = 0; double epsilon = 0.00000001; //initialization *rms = 0; rms1 = 0; e0 = 0; double c1[3], c2[3]; double s1[3], s2[3]; double sx[3], sy[3], sz[3]; for (i = 0; i < 3; i++) { s1[i] = 0.0; s2[i] = 0.0; sx[i] = 0.0; sy[i] = 0.0; sz[i] = 0.0; } for (i = 0; i<3; i++) { xc[i] = 0.0; yc[i] = 0.0; t[i] = 0.0; for (j = 0; j<3; j++) { u[i][j] = 0.0; r[i][j] = 0.0; a[i][j] = 0.0; if (i == j) { u[i][j] = 1.0; a[i][j] = 1.0; } } } if (n<1) return false; //compute centers for vector sets x, y for (i = 0; i0) { d = spur*spur; h = d - cof; g = (spur*cof - det) / 2.0 - spur*h; if (h>0) { sqrth = sqrt(h); d = h*h*h - g*g; if (d<0.0) d = 0.0; d = atan2(sqrt(d), -g) / 3.0; cth = sqrth * cos(d); sth = sqrth*sqrt3*sin(d); e[0] = (spur + cth) + cth; e[1] = (spur - cth) + sth; e[2] = (spur - cth) - sth; if (mode != 0) {//compute a for (l = 0; l<3; l = l + 2) { d = e[l]; ss[0] = (d - rr[2]) * (d - rr[5]) - rr[4] * rr[4]; ss[1] = (d - rr[5]) * rr[1] + rr[3] * rr[4]; ss[2] = (d - rr[0]) * (d - rr[5]) - rr[3] * rr[3]; ss[3] = (d - rr[2]) * rr[3] + rr[1] * rr[4]; ss[4] = (d - rr[0]) * rr[4] + rr[1] * rr[3]; ss[5] = (d - rr[0]) * (d - rr[2]) - rr[1] * rr[1]; if (fabs(ss[0]) <= epsilon) ss[0] = 0.0; if (fabs(ss[1]) <= epsilon) ss[1] = 0.0; if (fabs(ss[2]) <= epsilon) ss[2] = 0.0; if (fabs(ss[3]) <= epsilon) ss[3] = 0.0; if (fabs(ss[4]) <= epsilon) ss[4] = 0.0; if (fabs(ss[5]) <= epsilon) ss[5] = 0.0; if (fabs(ss[0]) >= fabs(ss[2])) { j = 0; if (fabs(ss[0]) < fabs(ss[5])) j = 2; } else if (fabs(ss[2]) >= fabs(ss[5])) j = 1; else j = 2; d = 0.0; j = 3 * j; for (i = 0; i<3; i++) { k = ip[i + j]; a[i][l] = ss[k]; d = d + ss[k] * ss[k]; } //if( d > 0.0 ) d = 1.0 / sqrt(d); if (d > epsilon) d = 1.0 / sqrt(d); else d = 0.0; for (i = 0; i<3; i++) a[i][l] = a[i][l] * d; }//for l d = a[0][0] * a[0][2] + a[1][0] * a[1][2] + a[2][0] * a[2][2]; if ((e[0] - e[1]) >(e[1] - e[2])) { m1 = 2; m = 0; } else { m1 = 0; m = 2; } p = 0; for (i = 0; i<3; i++) { a[i][m1] = a[i][m1] - d*a[i][m]; p = p + a[i][m1] * a[i][m1]; } if (p <= tol) { p = 1.0; for (i = 0; i<3; i++) { if (p < fabs(a[i][m])) continue; p = fabs(a[i][m]); j = i; } k = ip2312[j]; l = ip2312[j + 1]; p = sqrt(a[k][m] * a[k][m] + a[l][m] * a[l][m]); if (p > tol) { a[j][m1] = 0.0; a[k][m1] = -a[l][m] / p; a[l][m1] = a[k][m] / p; } else a_failed = 1; }//if p<=tol else { p = 1.0 / sqrt(p); for (i = 0; i<3; i++) a[i][m1] = a[i][m1] * p; }//else p<=tol if (a_failed != 1) { a[0][1] = a[1][2] * a[2][0] - a[1][0] * a[2][2]; a[1][1] = a[2][2] * a[0][0] - a[2][0] * a[0][2]; a[2][1] = a[0][2] * a[1][0] - a[0][0] * a[1][2]; } }//if(mode!=0) }//h>0 //compute b anyway if (mode != 0 && a_failed != 1)//a is computed correctly { //compute b for (l = 0; l<2; l++) { d = 0.0; for (i = 0; i<3; i++) { b[i][l] = r[i][0] * a[0][l] + r[i][1] * a[1][l] + r[i][2] * a[2][l]; d = d + b[i][l] * b[i][l]; } //if( d > 0 ) d = 1.0 / sqrt(d); if (d > epsilon) d = 1.0 / sqrt(d); else d = 0.0; for (i = 0; i<3; i++) b[i][l] = b[i][l] * d; } d = b[0][0] * b[0][1] + b[1][0] * b[1][1] + b[2][0] * b[2][1]; p = 0.0; for (i = 0; i<3; i++) { b[i][1] = b[i][1] - d*b[i][0]; p += b[i][1] * b[i][1]; } if (p <= tol) { p = 1.0; for (i = 0; i<3; i++) { if (p tol) { b[j][1] = 0.0; b[k][1] = -b[l][0] / p; b[l][1] = b[k][0] / p; } else b_failed = 1; }//if( p <= tol ) else { p = 1.0 / sqrt(p); for (i = 0; i<3; i++) b[i][1] = b[i][1] * p; } if (b_failed != 1) { b[0][2] = b[1][0] * b[2][1] - b[1][1] * b[2][0]; b[1][2] = b[2][0] * b[0][1] - b[2][1] * b[0][0]; b[2][2] = b[0][0] * b[1][1] - b[0][1] * b[1][0]; //compute u for (i = 0; i<3; i++) for (j = 0; j<3; j++) u[i][j] = b[i][0] * a[j][0] + b[i][1] * a[j][1] + b[i][2] * a[j][2]; } //compute t for (i = 0; i<3; i++) t[i] = ((yc[i] - u[i][0] * xc[0]) - u[i][1] * xc[1]) - u[i][2] * xc[2]; }//if(mode!=0 && a_failed!=1) }//spur>0 else //just compute t and errors { //compute t for (i = 0; i<3; i++) t[i] = ((yc[i] - u[i][0] * xc[0]) - u[i][1] * xc[1]) - u[i][2] * xc[2]; }//else spur>0 //compute rms for (i = 0; i<3; i++) { if (e[i] < 0) e[i] = 0; e[i] = sqrt(e[i]); } d = e[2]; if (sigma < 0.0) d = -d; d = (d + e[1]) + e[0]; if (mode == 2 || mode == 0) { rms1 = (e0 - d) - d; if (rms1 < 0.0) rms1 = 0.0; } *rms = rms1; return true; } /* This matrix contains two scoring matrices: * [1] BLOSUM62 for protein is defined for upper case letters: * ABCDEFGHIKLMNOPQRSTVWXYZ* excluding J * The original BLOSUM does not have O (PYL) and U (SEC). * In this matrix, OU values are copied from K and C, respectively. * [2] BLASTN for RNA/DNA is defined for lower case letters: * acgtu where matching (including t vs u) is 2 and mismatching is -3 */ const int BLOSUM[128][128]={ //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 51 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 //0 \a \b \t \n \v \f \t ' ' | " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ DEL { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//0 '\0' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//1 SOH { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//2 STX { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//3 ETX { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//4 EOT { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//5 ENQ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//6 ACK { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//7 '\a' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//8 '\b' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//9 '\t' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//10 '\n' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//11 '\v' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//12 '\f' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//13 '\r' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//14 SO { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//15 SI { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//16 DLE { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//17 DC1 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//18 DC2 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//19 DC3 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//20 DC4 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//21 NAK { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//22 SYN { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//23 ETB { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//24 CAN { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//25 EM { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//26 SUB { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//27 ESC { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//28 FS { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//29 GS { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//30 RS { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//31 US { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//32 ' ' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//33 ! { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//34 " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//35 # { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//36 $ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//37 % { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//38 & { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//39 ' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//40 ( { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//41 ) { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-4,-4,-4,-4,-4,-4,-4,-4, 0,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//42 * { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//43 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//44 , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//45 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//46 . { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//47 / { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//48 0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//49 1 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//50 2 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//51 3 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//52 4 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//53 5 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//54 6 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//55 7 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//56 8 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//57 9 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//58 : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//59 ; { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//60 < { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//61 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//62 > { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//63 ? { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//64 @ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-2, 0,-2,-1,-2, 0,-2,-1, 0,-1,-1,-1,-2,-1,-1,-1,-1, 1, 0, 0, 0,-3, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//65 A { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 4,-3, 4, 1,-3,-1, 0,-3, 0, 0,-4,-3, 3, 0,-2, 0,-1, 0,-1,-3,-3,-4,-1,-3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//66 B { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 9,-3,-4,-2,-3,-3,-1, 0,-3,-1,-1,-3,-3,-3,-3,-3,-1,-1, 9,-1,-2,-2,-2,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//67 C { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 4,-3, 6, 2,-3,-1,-1,-3, 0,-1,-4,-3, 1,-1,-1, 0,-2, 0,-1,-3,-3,-4,-1,-3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//68 D { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 1,-4, 2, 5,-3,-2, 0,-3, 0, 1,-3,-2, 0, 1,-1, 2, 0, 0,-1,-4,-2,-3,-1,-2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//69 E { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-3,-2,-3,-3, 6,-3,-1, 0, 0,-3, 0, 0,-3,-3,-4,-3,-3,-2,-2,-2,-1, 1,-1, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//70 F { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-3,-1,-2,-3, 6,-2,-4, 0,-2,-4,-3, 0,-2,-2,-2,-2, 0,-2,-3,-3,-2,-1,-3,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//71 G { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-3,-1, 0,-1,-2, 8,-3, 0,-1,-3,-2, 1,-1,-2, 0, 0,-1,-2,-3,-3,-2,-1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//72 H { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-3,-1,-3,-3, 0,-4,-3, 4, 0,-3, 2, 1,-3,-3,-3,-3,-3,-2,-1,-1, 3,-3,-1,-1,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//73 I { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//74 J { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0,-3,-1, 1,-3,-2,-1,-3, 0, 5,-2,-1, 0, 5,-1, 1, 2, 0,-1,-3,-2,-3,-1,-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//75 K { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-4,-1,-4,-3, 0,-4,-3, 2, 0,-2, 4, 2,-3,-2,-3,-2,-2,-2,-1,-1, 1,-2,-1,-1,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//76 L { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-3,-1,-3,-2, 0,-3,-2, 1, 0,-1, 2, 5,-2,-1,-2, 0,-1,-1,-1,-1, 1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//77 M { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 3,-3, 1, 0,-3, 0, 1,-3, 0, 0,-3,-2, 6, 0,-2, 0, 0, 1, 0,-3,-3,-4,-1,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//78 N { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0,-3,-1, 1,-3,-2,-1,-3, 0, 5,-2,-1, 0, 5,-1, 1, 2, 0,-1,-3,-2,-3,-1,-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//79 O { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-2,-3,-1,-1,-4,-2,-2,-3, 0,-1,-3,-2,-2,-1, 7,-1,-2,-1,-1,-3,-2,-4,-2,-3,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//80 P { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0,-3, 0, 2,-3,-2, 0,-3, 0, 1,-2, 0, 0, 1,-1, 5, 1, 0,-1,-3,-2,-2,-1,-1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//81 Q { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-3,-2, 0,-3,-2, 0,-3, 0, 2,-2,-1, 0, 2,-2, 1, 5,-1,-1,-3,-3,-3,-1,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//82 R { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0,-2, 0,-1,-2, 0, 0,-2,-1, 1, 0,-1, 0,-1, 4, 1,-1,-2,-3, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//83 S { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-2,-2,-2,-1, 0,-1,-1,-1, 0,-1,-1,-1,-1, 1, 5,-1, 0,-2, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//84 T { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 9,-3,-4,-2,-3,-3,-1, 0,-3,-1,-1,-3,-3,-3,-3,-3,-1,-1, 9,-1,-2,-2,-2,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//85 U { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-1,-3,-2,-1,-3,-3, 3, 0,-2, 1, 1,-3,-2,-2,-2,-3,-2, 0,-1, 4,-3,-1,-1,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//86 V { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-4,-2,-4,-3, 1,-2,-2,-3, 0,-3,-2,-1,-4,-3,-4,-2,-3,-3,-2,-2,-3,11,-2, 2,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//87 W { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1,-2,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-2,-1,-1, 0, 0,-2,-1,-2,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//88 X { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-3,-2,-3,-2, 3,-3, 2,-1, 0,-2,-1,-1,-2,-2,-3,-1,-2,-2,-2,-2,-1, 2,-1, 7,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//89 Y { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 1,-3, 1, 4,-3,-2, 0,-3, 0, 1,-3,-1, 0, 1,-1, 3, 0, 0,-1,-3,-2,-3,-1,-2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//90 Z { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//91 [ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//92 '\' { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//93 ] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//94 ^ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//95 _ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//96 ` { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-3, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//97 a { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//98 b { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 2, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//99 c { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//100 d { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//101 e { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//102 f { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//103 g { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//104 h { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//105 i { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//106 j { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//107 k { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//108 l { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//109 m { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//110 n { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//111 o { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//112 p { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//113 q { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//114 r { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//115 s { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//116 t { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 0, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//117 u { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//118 v { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//119 w { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//120 x { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//121 y { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//122 z { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//123 { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//124 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//125 } { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//126 ~ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},//127 DEL }; const int gapopen_blosum62=-11; const int gapext_blosum62=-1; const int gapopen_blastn=-15; //-5; const int gapext_blastn =-4; //-2; /* initialize matrix in gotoh algorithm */ void init_gotoh_mat(int **S, int **JumpH, int **JumpV, int **P, int **H, int **V, const int xlen, const int ylen, const int gapopen, const int gapext, const int glocal=0, const int alt_init=1) { // fill first row/colum of JumpH,jumpV and path matrix P int i,j; for (i=0;i=aln_score) { max_aln_i=i; max_aln_j=j; aln_score=S[i][j]; } } } // reset all path after [max_aln_i][max_aln_j] for (i=max_aln_i+1;i0 * 1 : \ match-mismatch * 2 : | vertical gap (insertion) * 4 : - horizontal gap (deletion) * JumpH - horizontal long gap number. * JumpV - vertical long gap number. * all matrices are in the size of [len(seqx)+1]*[len(seqy)+1] * * glocal - global or local alignment * 0 : global alignment (Needleman-Wunsch dynamic programming) * 1 : glocal-query alignment * 2 : glocal-both alignment * 3 : local alignment (Smith-Waterman dynamic programming) * * alt_init - whether to adopt alternative matrix initialization * 1 : use wei zheng's matrix initialization * 0 : use yang zhang's matrix initialization, does NOT work * for glocal alignment */ int calculate_score_gotoh(const int xlen,const int ylen, int **S, int** JumpH, int** JumpV, int **P, const int gapopen,const int gapext, const int glocal=0, const int alt_init=1) { int **H; int **V; NewArray(&H,xlen+1,ylen+1); // penalty score for horizontal long gap NewArray(&V,xlen+1,ylen+1); // penalty score for vertical long gap // fill first row/colum of JumpH,jumpV and path matrix P int i,j; init_gotoh_mat(S, JumpH, JumpV, P, H, V, xlen, ylen, gapopen, gapext, glocal, alt_init); // fill S and P int diag_score,left_score,up_score; for (i=1;i=3) { H[i][j]=MAX(S[i][j-1]+gapopen,H[i][j-1]+gapext); JumpH[i][j]=(H[i][j]==H[i][j-1]+gapext)?(JumpH[i][j-1]+1):1; } else { H[i][j]=MAX(S[i][j-1],H[i][j-1]); JumpH[i][j]=(H[i][j]==H[i][j-1])?(JumpH[i][j-1]+1):1; } // penalty of consective insertion if (glocal<2 || j=3) { V[i][j]=MAX(S[i-1][j]+gapopen,V[i-1][j]+gapext); JumpV[i][j]=(V[i][j]==V[i-1][j]+gapext)?(JumpV[i-1][j]+1):1; } else { V[i][j]=MAX(S[i-1][j],V[i-1][j]); JumpV[i][j]=(V[i][j]==V[i-1][j])?(JumpV[i-1][j]+1):1; } diag_score=S[i-1][j-1]+S[i][j]; // match-mismatch '\' left_score=H[i][j]; // deletion '-' up_score =V[i][j]; // insertion '|' if (diag_score>=left_score && diag_score>=up_score) { S[i][j]=diag_score; P[i][j]+=1; } if (up_score>=diag_score && up_score>=left_score) { S[i][j]=up_score; P[i][j]+=2; } if (left_score>=diag_score && left_score>=up_score) { S[i][j]=left_score; P[i][j]+=4; } if (glocal>=3 && S[i][j]<0) { S[i][j]=0; P[i][j]=0; H[i][j]=0; V[i][j]=0; JumpH[i][j]=0; JumpV[i][j]=0; } } } int aln_score=S[xlen][ylen]; // re-fill first row/column of path matrix P for back-tracing for (i=1;i0) P[i][0]=2; // | for (j=1;j0) P[0][j]=4; // - // calculate alignment score and alignment path for swalign if (glocal>=3) find_highest_align_score(S,P,aln_score,xlen,ylen); // release memory DeleteArray(&H,xlen+1); DeleteArray(&V,xlen+1); return aln_score; // final alignment score } /* trace back dynamic programming path to diciper pairwise alignment */ void trace_back_gotoh(const char *seqx, const char *seqy, int ** JumpH, int ** JumpV, int ** P, string& seqxA, string& seqyA, const int xlen, const int ylen, int *invmap, const int invmap_only=1) { int i,j; int gaplen,p; char *buf=NULL; if (invmap_only) for (j = 0; j < ylen; j++) invmap[j] = -1; if (invmap_only!=1) buf=new char [MAX(xlen,ylen)+1]; i=xlen; j=ylen; while(i+j) { gaplen=0; if (P[i][j]>=4) { gaplen=JumpH[i][j]; j-=gaplen; if (invmap_only==1) continue; strncpy(buf,seqy+j,gaplen); buf[gaplen]=0; seqyA=buf+seqyA; for (p=0;p= 2) { gaplen=JumpV[i][j]; i-=gaplen; if (invmap_only==1) continue; strncpy(buf,seqx+i,gaplen); buf[gaplen]=0; seqxA=buf+seqxA; for (p=0;p=0;i--) { for (j=ylen;j>=0;j--) { if (P[i][j]!=0) { found_start_cell=true; break; } } if (found_start_cell) break; } /* copy C terminal sequence */ if (invmap_only!=1) { for (p=0;p=4) { gaplen=JumpH[i][j]; j-=gaplen; if (invmap_only==1) continue; strncpy(buf,seqy+j,gaplen); buf[gaplen]=0; seqyA=buf+seqyA; for (p=0;p= 2) { gaplen=JumpV[i][j]; i-=gaplen; if (invmap_only==1) continue; strncpy(buf,seqx+i,gaplen); buf[gaplen]=0; seqxA=buf+seqxA; for (p=0;p0) // RNA or DNA { gapopen=gapopen_blastn; gapext =gapext_blastn; if (glocal==3) { gapopen=-5; gapext =-2; } } for (i=0;i &sequence, char *seqx, char *seqy, const vector resi_vec1, const vector resi_vec2, const int byresi_opt) { sequence.clear(); sequence.push_back(""); sequence.push_back(""); int i1=0; // positions in resi_vec1 int i2=0; // positions in resi_vec2 int xlen=resi_vec1.size(); int ylen=resi_vec2.size(); if (byresi_opt==4 || byresi_opt==5) // global or glocal sequence alignment { int *invmap; int glocal=0; if (byresi_opt==5) glocal=2; int mol_type=0; for (i1=0;i1 chainID_map1; map chainID_map2; if (byresi_opt==3) { vector chainID_vec; string chainID; stringstream ss; int i; for (i=0;i().swap(chainID_vec); } string chainID1=""; string chainID2=""; string chainID1_prev=""; string chainID2_prev=""; while(i1 atoi(resi_vec2[i2].substr(0,4).c_str())) { sequence[0]+='-'; sequence[1]+=seqy[i2++]; } else { sequence[0]+=seqx[i1++]; sequence[1]+=seqy[i2++]; } chainID1_prev=chainID1; chainID2_prev=chainID2; } else { if (chainID1_prev==chainID1 && chainID2_prev!=chainID2) { sequence[0]+=seqx[i1++]; sequence[1]+='-'; chainID1_prev=chainID1; } else if (chainID1_prev!=chainID1 && chainID2_prev==chainID2) { sequence[0]+='-'; sequence[1]+=seqy[i2++]; chainID2_prev=chainID2; } else { sequence[0]+=seqx[i1++]; sequence[1]+=seqy[i2++]; chainID1_prev=chainID1; chainID2_prev=chainID2; } } } map().swap(chainID_map1); map().swap(chainID_map2); chainID1.clear(); chainID2.clear(); chainID1_prev.clear(); chainID2_prev.clear(); return sequence[0].size(); } // 1, collect those residues with dis3) { inc++; double dinc=(d+inc*0.5); d_tmp = dinc * dinc; } else break; } *score1=score_sum/Lnorm; return n_cut; } int score_fun8_standard(double **xa, double **ya, int n_ali, double d, int i_ali[], double *score1, int score_sum_method, double score_d8, double d0) { double score_sum = 0, di; double d_tmp = d*d; double d02 = d0*d0; double score_d8_cut = score_d8*score_d8; int i, n_cut, inc = 0; while (1) { n_cut = 0; score_sum = 0; for (i = 0; i3) { inc++; double dinc = (d + inc*0.5); d_tmp = dinc * dinc; } else break; } *score1 = score_sum / n_ali; return n_cut; } double TMscore8_search(double **r1, double **r2, double **xtm, double **ytm, double **xt, int Lali, double t0[3], double u0[3][3], int simplify_step, int score_sum_method, double *Rcomm, double local_d0_search, double Lnorm, double score_d8, double d0) { int i, m; double score_max, score, rmsd; const int kmax=Lali; int k_ali[kmax], ka, k; double t[3]; double u[3][3]; double d; //iterative parameters int n_it=20; //maximum number of iterations int n_init_max=6; //maximum number of different fragment length int L_ini[n_init_max]; //fragment lengths, Lali, Lali/2, Lali/4 ... 4 int L_ini_min=4; if(Laliscore_max) { score_max=score; //save the rotation matrix for(k=0; k<3; k++) { t0[k]=t[k]; u0[k][0]=u[k][0]; u0[k][1]=u[k][1]; u0[k][2]=u[k][2]; } } //try to extend the alignment iteratively d = local_d0_search + 1; for(int it=0; itscore_max) { score_max=score; //save the rotation matrix for(k=0; k<3; k++) { t0[k]=t[k]; u0[k][0]=u[k][0]; u0[k][1]=u[k][1]; u0[k][2]=u[k][2]; } } //check if it converges if(n_cut==ka) { for(k=0; kiL_max) i=iL_max; //do this to use the last missed fragment } else if(i>=iL_max) break; }//while(1) //end of one fragment }//for(i_init return score_max; } double TMscore8_search_standard( double **r1, double **r2, double **xtm, double **ytm, double **xt, int Lali, double t0[3], double u0[3][3], int simplify_step, int score_sum_method, double *Rcomm, double local_d0_search, double score_d8, double d0) { int i, m; double score_max, score, rmsd; const int kmax = Lali; int k_ali[kmax], ka, k; double t[3]; double u[3][3]; double d; //iterative parameters int n_it = 20; //maximum number of iterations int n_init_max = 6; //maximum number of different fragment length int L_ini[n_init_max]; //fragment lengths, Lali, Lali/2, Lali/4 ... 4 int L_ini_min = 4; if (Laliscore_max) { score_max = score; //save the rotation matrix for (k = 0; k<3; k++) { t0[k] = t[k]; u0[k][0] = u[k][0]; u0[k][1] = u[k][1]; u0[k][2] = u[k][2]; } } //try to extend the alignment iteratively d = local_d0_search + 1; for (int it = 0; itscore_max) { score_max = score; //save the rotation matrix for (k = 0; k<3; k++) { t0[k] = t[k]; u0[k][0] = u[k][0]; u0[k][1] = u[k][1]; u0[k][2] = u[k][2]; } } //check if it converges if (n_cut == ka) { for (k = 0; kiL_max) i = iL_max; //do this to use the last missed fragment } else if (i >= iL_max) break; }//while(1) //end of one fragment }//for(i_init return score_max; } double detailed_search_standard( double **r1, double **r2, double **xtm, double **ytm, double **xt, double **x, double **y, int xlen, int ylen, int invmap0[], double t[3], double u[3][3], int simplify_step, int score_sum_method, double local_d0_search, const bool& bNormalize, double Lnorm, double score_d8, double d0) { //x is model, y is template, try to superpose onto y int i, j, k; double tmscore; double rmsd; k=0; for(i=0; i=0) //aligned { xtm[k][0]=x[j][0]; xtm[k][1]=x[j][1]; xtm[k][2]=x[j][2]; ytm[k][0]=y[i][0]; ytm[k][1]=y[i][1]; ytm[k][2]=y[i][2]; k++; } } //detailed search 40-->1 tmscore = TMscore8_search_standard( r1, r2, xtm, ytm, xt, k, t, u, simplify_step, score_sum_method, &rmsd, local_d0_search, score_d8, d0); if (bNormalize)// "-i", to use standard_TMscore, then bNormalize=true, else bNormalize=false; tmscore = tmscore * k / Lnorm; return tmscore; } void smooth(int *sec, int len) { int i, j; //smooth single --x-- => ----- for (i=2; i ------ for (i=0; i&resi_vec1, const vector&resi_vec2, const string chainID1, const string chainID2) { int compress_type=0; // uncompressed file ifstream fin; #ifndef REDI_PSTREAM_H_SEEN ifstream fin_gz; #else redi::ipstream fin_gz; // if file is compressed if (xname.size()>=3 && xname.substr(xname.size()-3,3)==".gz") { fin_gz.open("gunzip -c "+xname); compress_type=1; } else if (xname.size()>=4 && xname.substr(xname.size()-4,4)==".bz2") { fin_gz.open("bzcat "+xname); compress_type=2; } else #endif fin.open(xname.c_str()); stringstream buf; stringstream buf_pymol; string line; double x[3]; // before transform double x1[3]; // after transform /* for PDBx/mmCIF only */ map _atom_site; size_t atom_site_pos; vector line_vec; int infmt=-1; // 0 - PDB, 3 - PDBx/mmCIF while (compress_type?fin_gz.good():fin.good()) { if (compress_type) getline(fin_gz, line); else getline(fin, line); if (line.compare(0, 6, "ATOM ")==0 || line.compare(0, 6, "HETATM")==0) // PDB format { infmt=0; x[0]=atof(line.substr(30,8).c_str()); x[1]=atof(line.substr(38,8).c_str()); x[2]=atof(line.substr(46,8).c_str()); if (mirror_opt) x[2]=-x[2]; transform(t, u, x, x1); buf<=1 && line.compare(0,3,"END")==0) break; } } if (compress_type) fin_gz.close(); else fin.close(); string fname_super_full=fname_super; if (infmt==0) fname_super_full+=".pdb"; else if (infmt==3) fname_super_full+=".cif"; ofstream fp; fp.open(fname_super_full.c_str()); fp<=1) // align one chain from model 1 { chain1_sele=" and c. "+chainID1.substr(1); chain2_sele=" and c. "+chainID2.substr(1); } else if (split_opt==2 && ter_opt==0) // align one chain from each model { for (i=1;i pml_list; pml_list.push_back(fname_super+""); pml_list.push_back(fname_super+"_atm"); pml_list.push_back(fname_super+"_all"); pml_list.push_back(fname_super+"_all_atm"); pml_list.push_back(fname_super+"_all_atm_lig"); for (int p=0;p&resi_vec1, const vector&resi_vec2, const string chainID1, const string chainID2, const int xlen, const int ylen, const double d0A, const int n_ali8, const double rmsd, const double TM1, const double Liden) { stringstream buf; stringstream buf_all; stringstream buf_atm; stringstream buf_all_atm; stringstream buf_all_atm_lig; //stringstream buf_pdb; stringstream buf_tm; string line; double x[3]; // before transform double x1[3]; // after transform bool after_ter; // true if passed the "TER" line in PDB string asym_id; // chain ID buf_tm<<"REMARK US-align" <<"\nREMARK Structure 1:"<=1) // align one chain from model 1 { chain1_sele=chainID1.substr(1); chain2_sele=chainID2.substr(1); } else if (split_opt==2 && ter_opt==0) // align one chain from each model { for (i=1;i _atom_site; int atom_site_pos; vector line_vec; string atom; // 4-character atom name string AA; // 3-character residue name string resi; // 4-character residue sequence number string inscode; // 1-character insertion code string model_index; // model index bool is_mmcif=false; /* used for CONECT record of chain1 */ int ca_idx1=0; // all CA atoms int lig_idx1=0; // all atoms vector idx_vec; /* used for CONECT record of chain2 */ int ca_idx2=0; // all CA atoms int lig_idx2=0; // all atoms /* extract aligned region */ vector resi_aln1; vector resi_aln2; int i1=-1; int i2=-1; if (!mm_opt) { for (i=0;i=3 && line.compare(0,3,"TER")==0) after_ter=true; if (is_mmcif==false && line.size()>=54 && (line.compare(0, 6, "ATOM ")==0 || line.compare(0, 6, "HETATM")==0)) // PDB format { if (line[16]!='A' && line[16]!=' ') continue; x[0]=atof(line.substr(30,8).c_str()); x[1]=atof(line.substr(38,8).c_str()); x[2]=atof(line.substr(46,8).c_str()); if (mirror_opt) x[2]=-x[2]; transform(t, u, x, x1); //buf_pdb<=2) { if (ca_idx1 && asym_id.size() && asym_id!=line.substr(21,1)) { after_ter=true; continue; } asym_id=line[21]; } buf_all_atm<<"ATOM "<=5) atom=atom.substr(0,4); AA=line_vec[_atom_site["label_comp_id"]]; // residue name if (AA.size()==1) AA=" "+AA; else if (AA.size()==2) AA=" " +AA; else if (AA.size()>=4) AA=AA.substr(0,3); if (_atom_site.count("auth_seq_id")) resi=line_vec[_atom_site["auth_seq_id"]]; else resi=line_vec[_atom_site["label_seq_id"]]; while (resi.size()<4) resi=' '+resi; if (resi.size()>4) resi=resi.substr(0,4); inscode=' '; if (_atom_site.count("pdbx_PDB_ins_code") && line_vec[_atom_site["pdbx_PDB_ins_code"]]!="?") inscode=line_vec[_atom_site["pdbx_PDB_ins_code"]][0]; if (_atom_site.count("auth_asym_id")) { if (chain1_sele.size()) after_ter =line_vec[_atom_site["auth_asym_id"]]!=chain1_sele; else if (ter_opt>=2 && ca_idx1 && asym_id.size() && asym_id!=line_vec[_atom_site["auth_asym_id"]]) after_ter=true; asym_id=line_vec[_atom_site["auth_asym_id"]]; } else if (_atom_site.count("label_asym_id")) { if (chain1_sele.size()) after_ter =line_vec[_atom_site["label_asym_id"]]!=chain1_sele; if (ter_opt>=2 && ca_idx1 && asym_id.size() && asym_id!=line_vec[_atom_site["label_asym_id"]]) after_ter=true; asym_id=line_vec[_atom_site["label_asym_id"]]; } //buf_pdb<=1 && line.compare(0,3,"END")==0) break; } } fin.close(); if (!mm_opt) buf<<"TER\n"; buf_all<<"TER\n"; if (!mm_opt) buf_atm<<"TER\n"; buf_all_atm<<"TER\n"; buf_all_atm_lig<<"TER\n"; for (i=1;i=3 && line.compare(0,3,"TER")==0) after_ter=true; if (line.size()>=54 && (line.compare(0, 6, "ATOM ")==0 || line.compare(0, 6, "HETATM")==0)) // PDB format { if (line[16]!='A' && line[16]!=' ') continue; if (after_ter && line.compare(0,6,"ATOM ")==0) continue; lig_idx2++; buf_all_atm_lig<=2) { if (ca_idx2 && asym_id.size() && asym_id!=line.substr(21,1)) { after_ter=true; continue; } asym_id=line[21]; } buf_all_atm<<"ATOM "<=5) atom=atom.substr(0,4); AA=line_vec[_atom_site["label_comp_id"]]; // residue name if (AA.size()==1) AA=" "+AA; else if (AA.size()==2) AA=" " +AA; else if (AA.size()>=4) AA=AA.substr(0,3); if (_atom_site.count("auth_seq_id")) resi=line_vec[_atom_site["auth_seq_id"]]; else resi=line_vec[_atom_site["label_seq_id"]]; while (resi.size()<4) resi=' '+resi; if (resi.size()>4) resi=resi.substr(0,4); inscode=' '; if (_atom_site.count("pdbx_PDB_ins_code") && line_vec[_atom_site["pdbx_PDB_ins_code"]]!="?") inscode=line_vec[_atom_site["pdbx_PDB_ins_code"]][0]; if (_atom_site.count("auth_asym_id")) { if (chain2_sele.size()) after_ter =line_vec[_atom_site["auth_asym_id"]]!=chain2_sele; if (ter_opt>=2 && ca_idx2 && asym_id.size() && asym_id!=line_vec[_atom_site["auth_asym_id"]]) after_ter=true; asym_id=line_vec[_atom_site["auth_asym_id"]]; } else if (_atom_site.count("label_asym_id")) { if (chain2_sele.size()) after_ter =line_vec[_atom_site["label_asym_id"]]!=chain2_sele; if (ter_opt>=2 && ca_idx2 && asym_id.size() && asym_id!=line_vec[_atom_site["label_asym_id"]]) after_ter=true; asym_id=line_vec[_atom_site["label_asym_id"]]; } if (after_ter==false || line_vec[_atom_site["group_PDB"]]=="HETATM") { lig_idx2++; buf_all_atm_lig<=1 && line.compare(0,3,"END")==0) break; } } fin.close(); if (!mm_opt) buf<<"TER\n"; buf_all<<"TER\n"; if (!mm_opt) buf_atm<<"TER\n"; buf_all_atm<<"TER\n"; buf_all_atm_lig<<"TER\n"; for (i=ca_idx1+1;i pml_list; pml_list.push_back(fname_super+""); pml_list.push_back(fname_super+"_atm"); pml_list.push_back(fname_super+"_all"); pml_list.push_back(fname_super+"_all_atm"); pml_list.push_back(fname_super+"_all_atm_lig"); for (i=0;i0) // RNA { if (Lnorm<=11) d0=0.3; else if(Lnorm>11 && Lnorm<=15) d0=0.4; else if(Lnorm>15 && Lnorm<=19) d0=0.5; else if(Lnorm>19 && Lnorm<=23) d0=0.6; else if(Lnorm>23 && Lnorm<30) d0=0.7; else d0=(0.6*pow((Lnorm*1.0-0.5), 1.0/2)-2.5); } else { if (Lnorm > 21) d0=(1.24*pow((Lnorm*1.0-15), 1.0/3) -1.8); else d0 = D0_MIN; if (d0 < D0_MIN) d0 = D0_MIN; } double d0_input = d0;// Scaled by seq_min double tmscore;// collected alined residues from invmap int n_al = 0; int i; for (int j = 0; j= 0) { xtm[n_al][0] = x[i][0]; xtm[n_al][1] = x[i][1]; xtm[n_al][2] = x[i][2]; ytm[n_al][0] = y[j][0]; ytm[n_al][1] = y[j][1]; ytm[n_al][2] = y[j][2]; r1[n_al][0] = x[i][0]; r1[n_al][1] = x[i][1]; r1[n_al][2] = x[i][2]; r2[n_al][0] = y[j][0]; r2[n_al][1] = y[j][1]; r2[n_al][2] = y[j][2]; n_al++; } else if (i != -1) PrintErrorAndQuit("Wrong map!\n"); } L_ali = n_al; Kabsch(r1, r2, n_al, 0, &RMSD, t, u); RMSD = sqrt( RMSD/(1.0*n_al) ); int temp_simplify_step = 1; int temp_score_sum_method = 0; d0_search = d0_input; double rms = 0.0; tmscore = TMscore8_search_standard(r1, r2, xtm, ytm, xt, n_al, t, u, temp_simplify_step, temp_score_sum_method, &rms, d0_input, score_d8, d0); tmscore = tmscore * n_al / (1.0*Lnorm); return tmscore; } /* calculate approximate TM-score given rotation matrix */ double approx_TM(const int xlen, const int ylen, const int a_opt, double **xa, double **ya, double t[3], double u[3][3], const int invmap0[], const int mol_type) { double Lnorm_0=ylen; // normalized by the second protein if (a_opt==-2 && xlen>ylen) Lnorm_0=xlen; // longer else if (a_opt==-1 && xlen=0)//aligned { transform(t, u, &xa[i][0], &xtmp[0]); d=sqrt(dist(&xtmp[0], &ya[j][0])); TMtmp+=1/(1+(d/d0)*(d/d0)); //if (d <= score_d8) TMtmp+=1/(1+(d/d0)*(d/d0)); } } TMtmp/=Lnorm_0; return TMtmp; } void clean_up_after_approx_TM(int *invmap0, int *invmap, double **score, bool **path, double **val, double **xtm, double **ytm, double **xt, double **r1, double **r2, const int xlen, const int minlen) { delete [] invmap0; delete [] invmap; DeleteArray(&score, xlen+1); DeleteArray(&path, xlen+1); DeleteArray(&val, xlen+1); DeleteArray(&xtm, minlen); DeleteArray(&ytm, minlen); DeleteArray(&xt, xlen); DeleteArray(&r1, minlen); DeleteArray(&r2, minlen); return; } int score_fun8( double **xa, double **ya, int n_ali, double d, int i_ali[], double *score1, int score_sum_method, const double Lnorm, const double score_d8, const double d0, double GDT_list_tmp[5], double &maxsub_tmp) { double score_sum=0, di; double d_tmp=d*d; double d02=d0*d0; double score_d8_cut = score_d8*score_d8; int i, n_cut, inc=0; while(1) { for (i=0;i<5;i++) GDT_list_tmp[i]=0; maxsub_tmp=0; n_cut=0; score_sum=0; for(i=0; i3) { inc++; double dinc=(d+inc*0.5); d_tmp = dinc * dinc; } else break; } *score1=score_sum/Lnorm; return n_cut; } int score_fun8_standard(double **xa, double **ya, int n_ali, double d, int i_ali[], double *score1, int score_sum_method, double score_d8, double d0, double GDT_list_tmp[5], double &maxsub_tmp) { double score_sum = 0, di; double d_tmp = d*d; double d02 = d0*d0; double score_d8_cut = score_d8*score_d8; int i, n_cut, inc = 0; while (1) { for (i=0;i<5;i++) GDT_list_tmp[i]=0; maxsub_tmp=0; n_cut = 0; score_sum = 0; for (i = 0; i3) { inc++; double dinc = (d + inc*0.5); d_tmp = dinc * dinc; } else break; } *score1 = score_sum / n_ali; return n_cut; } double TMscore8_search(double **r1, double **r2, double **xtm, double **ytm, double **xt, int Lali, double t0[3], double u0[3][3], int simplify_step, int score_sum_method, double *Rcomm, double local_d0_search, double Lnorm, double score_d8, double d0, double GDT_list[5], double &maxsub) { double GDT_list_tmp[5]={0,0,0,0,0}; double maxsub_tmp=0; int i, m; double score_max, score, rmsd; const int kmax=Lali; int k_ali[kmax], ka, k; double t[3]; double u[3][3]; double d; //iterative parameters int n_it=20; //maximum number of iterations int n_init_max=6; //maximum number of different fragment length int L_ini[n_init_max]; //fragment lengths, Lali, Lali/2, Lali/4 ... 4 int L_ini_min=4; if(Laliscore_max) { score_max=score; //save the rotation matrix for(k=0; k<3; k++) { t0[k]=t[k]; u0[k][0]=u[k][0]; u0[k][1]=u[k][1]; u0[k][2]=u[k][2]; } } if (maxsub_tmp>maxsub) maxsub=maxsub_tmp; for (k=0;k<5;k++) if (GDT_list_tmp[k]>GDT_list[k]) GDT_list[k]=GDT_list_tmp[k]; //try to extend the alignment iteratively d = local_d0_search + 1; for(int it=0; itscore_max) { score_max=score; //save the rotation matrix for(k=0; k<3; k++) { t0[k]=t[k]; u0[k][0]=u[k][0]; u0[k][1]=u[k][1]; u0[k][2]=u[k][2]; } } if (maxsub_tmp>maxsub) maxsub=maxsub_tmp; for (k=0;k<5;k++) if (GDT_list_tmp[k]>GDT_list[k]) GDT_list[k]=GDT_list_tmp[k]; //check if it converges if(n_cut==ka) { for(k=0; kiL_max) i=iL_max; //do this to use the last missed fragment } else if(i>=iL_max) break; }//while(1) //end of one fragment }//for(i_init return score_max; } double TMscore8_search_standard( double **r1, double **r2, double **xtm, double **ytm, double **xt, int Lali, double t0[3], double u0[3][3], int simplify_step, int score_sum_method, double *Rcomm, double local_d0_search, double score_d8, double d0, double GDT_list[5], double &maxsub) { double GDT_list_tmp[5]={0,0,0,0,0}; double maxsub_tmp=0; int i, m; double score_max, score, rmsd; const int kmax = Lali; int k_ali[kmax], ka, k; double t[3]; double u[3][3]; double d; //iterative parameters int n_it = 20; //maximum number of iterations int n_init_max = 6; //maximum number of different fragment length int L_ini[n_init_max]; //fragment lengths, Lali, Lali/2, Lali/4 ... 4 int L_ini_min = 4; if (Laliscore_max) { score_max = score; //save the rotation matrix for (k = 0; k<3; k++) { t0[k] = t[k]; u0[k][0] = u[k][0]; u0[k][1] = u[k][1]; u0[k][2] = u[k][2]; } } if (maxsub_tmp>maxsub) maxsub=maxsub_tmp; for (k=0;k<5;k++) if (GDT_list_tmp[k]>GDT_list[k]) GDT_list[k]=GDT_list_tmp[k]; //try to extend the alignment iteratively d = local_d0_search + 1; for (int it = 0; itscore_max) { score_max = score; //save the rotation matrix for (k = 0; k<3; k++) { t0[k] = t[k]; u0[k][0] = u[k][0]; u0[k][1] = u[k][1]; u0[k][2] = u[k][2]; } } if (maxsub_tmp>maxsub) maxsub=maxsub_tmp; for (k=0;k<5;k++) if (GDT_list_tmp[k]>GDT_list[k]) GDT_list[k]=GDT_list_tmp[k]; //check if it converges if (n_cut == ka) { for (k = 0; kiL_max) i = iL_max; //do this to use the last missed fragment } else if (i >= iL_max) break; }//while(1) //end of one fragment }//for(i_init return score_max; } double detailed_search_standard( double **r1, double **r2, double **xtm, double **ytm, double **xt, double **x, double **y, int xlen, int ylen, int invmap0[], double t[3], double u[3][3], int simplify_step, int score_sum_method, double local_d0_search, const bool& bNormalize, double Lnorm, double score_d8, double d0, double GDT_list[5], double &maxsub) { //x is model, y is template, try to superpose onto y int i, j, k; double tmscore; double rmsd; k=0; for(i=0; i=0) //aligned { xtm[k][0]=x[j][0]; xtm[k][1]=x[j][1]; xtm[k][2]=x[j][2]; ytm[k][0]=y[i][0]; ytm[k][1]=y[i][1]; ytm[k][2]=y[i][2]; k++; } } //detailed search 40-->1 tmscore = TMscore8_search_standard( r1, r2, xtm, ytm, xt, k, t, u, simplify_step, score_sum_method, &rmsd, local_d0_search, score_d8, d0, GDT_list, maxsub); if (bNormalize)// "-i", to use standard_TMscore, then bNormalize=true, else bNormalize=false; tmscore = tmscore * k / Lnorm; return tmscore; } /* Entry function for TM-score. Return TM-score calculation status: * 0 - full TM-score calculation * 1 - terminated due to exception * 2-7 - pre-terminated due to low TM-score */ int TMscore_main(double **xa, double **ya, const char *seqx, const char *seqy, double t0[3], double u0[3][3], double &TM1, double &TM2, double &TM3, double &TM4, double &TM5, double &d0_0, double &TM_0, double &d0A, double &d0B, double &d0u, double &d0a, double &d0_out, string &seqM, string &seqxA, string &seqyA, double &rmsd0, int &L_ali, double &Liden, double &TM_ali, double &rmsd_ali, int &n_ali, int &n_ali8, const int xlen, const int ylen, const vector sequence, const double Lnorm_ass, const double d0_scale, const int a_opt, const bool u_opt, const bool d_opt, const bool fast_opt, const int mol_type, double GDT_list[5], double &maxsub, const double TMcut=-1) { double D0_MIN; //for d0 double Lnorm; //normalization length double score_d8,d0,d0_search,dcu0;//for TMscore search double t[3], u[3][3]; //Kabsch translation vector and rotation matrix double **score; // Input score table for dynamic programming bool **path; // for dynamic programming double **val; // for dynamic programming double **xtm, **ytm; // for TMscore search engine double **xt; //for saving the superposed version of r_1 or xtm double **r1, **r2; // for Kabsch rotation /***********************/ /* allocate memory */ /***********************/ int minlen = min(xlen, ylen); NewArray(&score, xlen+1, ylen+1); NewArray(&path, xlen+1, ylen+1); NewArray(&val, xlen+1, ylen+1); NewArray(&xtm, minlen, 3); NewArray(&ytm, minlen, 3); NewArray(&xt, xlen, 3); NewArray(&r1, minlen, 3); NewArray(&r2, minlen, 3); /***********************/ /* parameter set */ /***********************/ parameter_set4search(xlen, ylen, D0_MIN, Lnorm, score_d8, d0, d0_search, dcu0); int simplify_step = 40; //for simplified search engine int score_sum_method = 8; //for scoring method, whether only sum over pairs with dis= ylen || i1 >= xlen) kk1 = L; else if (sequence[0][kk1] != '-') invmap[i2] = i1; } } //--------------- 2. Align proteins from original alignment double prevD0_MIN = D0_MIN;// stored for later use int prevLnorm = Lnorm; double prevd0 = d0; TM_ali = standard_TMscore(r1, r2, xtm, ytm, xt, xa, ya, xlen, ylen, invmap, L_ali, rmsd_ali, D0_MIN, Lnorm, d0, d0_search, score_d8, t, u, mol_type); D0_MIN = prevD0_MIN; Lnorm = prevLnorm; d0 = prevd0; TM = detailed_search_standard(r1, r2, xtm, ytm, xt, xa, ya, xlen, ylen, invmap, t, u, 40, 8, local_d0_search, true, Lnorm, score_d8, d0); if (TM > TMmax) { TMmax = TM; for (i = 0; i=0) { flag=true; break; } } if(!flag) { cout << "There is no alignment between the two proteins! " << "Program stop with no result!" << endl; return 1; } /* last TM-score pre-termination */ if (TMcut>0) { double TMtmp=approx_TM(xlen, ylen, a_opt, xa, ya, t0, u0, invmap0, mol_type); if (TMtmp<0.6*TMcut) { TM1=TM2=TM3=TM4=TM5=TMtmp; clean_up_after_approx_TM(invmap0, invmap, score, path, val, xtm, ytm, xt, r1, r2, xlen, minlen); return 7; } } //********************************************************************// // Detailed TMscore search engine --> prepare for final TMscore // //********************************************************************// //run detailed TMscore search engine for the best alignment, and //extract the best rotation matrix (t, u) for the best alignment simplify_step=1; if (fast_opt) simplify_step=40; score_sum_method=8; TM = detailed_search_standard(r1, r2, xtm, ytm, xt, xa, ya, xlen, ylen, invmap0, t, u, simplify_step, score_sum_method, local_d0_search, false, Lnorm, score_d8, d0, GDT_list, maxsub); //select pairs with dis=0)//aligned { n_ali++; d=sqrt(dist(&xt[i][0], &ya[j][0])); m1[k]=i; m2[k]=j; xtm[k][0]=xa[i][0]; xtm[k][1]=xa[i][1]; xtm[k][2]=xa[i][2]; ytm[k][0]=ya[j][0]; ytm[k][1]=ya[j][1]; ytm[k][2]=ya[j][2]; r1[k][0] = xt[i][0]; r1[k][1] = xt[i][1]; r1[k][2] = xt[i][2]; r2[k][0] = ya[j][0]; r2[k][1] = ya[j][1]; r2[k][2] = ya[j][2]; k++; } } n_ali8=k; Kabsch(r1, r2, n_ali8, 0, &rmsd0, t, u);// rmsd0 is used for final output, only recalculate rmsd0, not t & u rmsd0 = sqrt(rmsd0 / n_ali8); //****************************************// // Final TMscore // // Please set parameters for output // //****************************************// double rmsd; simplify_step=1; score_sum_method=0; double Lnorm_0=ylen; //normalized by length of structure A parameter_set4final(Lnorm_0, D0_MIN, Lnorm, d0, d0_search, mol_type); d0A=d0; d0_0=d0A; local_d0_search = d0_search; TM1 = TMscore8_search(r1, r2, xtm, ytm, xt, n_ali8, t0, u0, simplify_step, score_sum_method, &rmsd, local_d0_search, Lnorm, score_d8, d0, GDT_list, maxsub); TM_0 = TM1; double Lnorm_d0; if (a_opt>0) { //normalized by average length of structures A, B Lnorm_0=(xlen+ylen)*0.5; parameter_set4final(Lnorm_0, D0_MIN, Lnorm, d0, d0_search, mol_type); d0a=d0; d0_0=d0a; local_d0_search = d0_search; TM3 = TMscore8_search(r1, r2, xtm, ytm, xt, n_ali8, t0, u0, simplify_step, score_sum_method, &rmsd, local_d0_search, Lnorm, score_d8, d0); TM_0=TM3; } if (u_opt) { //normalized by user assigned length parameter_set4final(Lnorm_ass, D0_MIN, Lnorm, d0, d0_search, mol_type); d0u=d0; d0_0=d0u; Lnorm_0=Lnorm_ass; local_d0_search = d0_search; TM4 = TMscore8_search(r1, r2, xtm, ytm, xt, n_ali8, t0, u0, simplify_step, score_sum_method, &rmsd, local_d0_search, Lnorm, score_d8, d0); TM_0=TM4; } if (d_opt) { //scaled by user assigned d0 parameter_set4scale(ylen, d0_scale, Lnorm, d0, d0_search); d0_out=d0_scale; d0_0=d0_scale; //Lnorm_0=ylen; Lnorm_d0=Lnorm_0; local_d0_search = d0_search; TM5 = TMscore8_search(r1, r2, xtm, ytm, xt, n_ali8, t0, u0, simplify_step, score_sum_method, &rmsd, local_d0_search, Lnorm, score_d8, d0); TM_0=TM5; } /* derive alignment from superposition */ int ali_len=xlen+ylen; //maximum length of alignment seqxA.assign(ali_len,'-'); seqM.assign( ali_len,' '); seqyA.assign(ali_len,'-'); //do_rotation(xa, xt, xlen, t, u); do_rotation(xa, xt, xlen, t0, u0); int kk=0, i_old=0, j_old=0; d=0; for(int k=0; k&resi_vec1, const vector&resi_vec2) { if (outfmt_opt<=0) { printf("\nStructure1: %s%s Length=%5d\n", xname.c_str(), chainID1.c_str(), xlen); printf("Structure2: %s%s Length=%5d (by which all scores are normalized)\n", yname.c_str(), chainID2.c_str(), ylen); printf("Number of residues in common=%5d\n", n_ali8); printf("RMSD of the common residues=%9.3f\n\n", rmsd); printf("TM-score = %6.4f (d0= %.2f)\n", TM1, d0A); printf("MaxSub-score= %6.4f (d0= 3.50)\n", maxsub/ylen); double gdt_ts_score=0; double gdt_ha_score=0; int i; for (i=0;i<4;i++) { gdt_ts_score+=GDT_list[i+1]; gdt_ha_score+=GDT_list[i]; } gdt_ts_score/=(4*ylen); gdt_ha_score/=(4*ylen); printf("GDT-TS-score= %6.4f %%(d<1)=%6.4f %%(d<2)=%6.4f %%(d<4)=%6.4f %%(d<8)=%6.4f\n", gdt_ts_score, GDT_list[1]/ylen, GDT_list[2]/ylen, GDT_list[3]/ylen, GDT_list[4]/ylen); printf("GDT-HA-score= %6.4f %%(d<0.5)=%6.4f %%(d<1)=%6.4f %%(d<2)=%6.4f %%(d<4)=%6.4f\n", gdt_ha_score, GDT_list[0]/ylen, GDT_list[1]/ylen, GDT_list[2]/ylen, GDT_list[3]/ylen); if (a_opt==1) printf("TM-score = %5.4f (if normalized by average length of two structures, i.e., LN= %.1f, d0= %.2f)\n", TM3, (xlen+ylen)*0.5, d0a); if (u_opt) printf("TM-score = %5.4f (if normalized by user-specified LN=%.2f and d0=%.2f)\n", TM4, Lnorm_ass, d0u); if (d_opt) printf("TM-score = %5.5f (if scaled by user-specified d0= %.2f, and LN= %d)\n", TM5, d0_scale, ylen); printf("\n -------- rotation matrix to rotate Chain-1 to Chain-2 ------\n"); printf(" i t(i) u(i,1) u(i,2) u(i,3)\n"); printf(" 1 %17.10f %14.10f %14.10f %14.10f\n",t[0],u[0][0],u[0][1],u[0][2]); printf(" 2 %17.10f %14.10f %14.10f %14.10f\n",t[1],u[1][0],u[1][1],u[1][2]); printf(" 3 %17.10f %14.10f %14.10f %14.10f\n",t[2],u[2][0],u[2][1],u[2][2]); //output alignment string seq_scale=seqM; for (i=0;i%s%s\tL=%d\td0=%.2f\tseqID=%.3f\tTM-score=%.5f\n", xname.c_str(), chainID1.c_str(), xlen, d0B, Liden/xlen, TM2); printf("%s\n", seqxA); printf(">%s%s\tL=%d\td0=%.2f\tseqID=%.3f\tTM-score=%.5f\n", yname.c_str(), chainID2.c_str(), ylen, d0A, Liden/ylen, TM1); printf("%s\n", seqyA); printf("# Lali=%d\tRMSD=%.2f\tseqID_ali=%.3f\n", n_ali8, rmsd, (n_ali8>0)?Liden/n_ali8:0); if(a_opt) printf("# TM-score=%.5f (normalized by average length of two structures: L=%.1f\td0=%.2f)\n", TM3, (xlen+ylen)*0.5, d0a); if(u_opt) printf("# TM-score=%.5f (normalized by user-specified L=%.2f\td0=%.2f)\n", TM4, Lnorm_ass, d0u); if(d_opt) printf("# TM-score=%.5f (scaled by user-specified d0=%.2f\tL=%d)\n", TM5, d0_scale, ylen); printf("$$$$\n"); } else if (outfmt_opt==2) { printf("%s%s\t%s%s\t%.4f\t%.4f\t%.2f\t%4.3f\t%4.3f\t%4.3f\t%d\t%d\t%d", xname.c_str(), chainID1.c_str(), yname.c_str(), chainID2.c_str(), TM2, TM1, rmsd, Liden/xlen, Liden/ylen, (n_ali8>0)?Liden/n_ali8:0, xlen, ylen, n_ali8); } cout << endl; if (strlen(fname_matrix)) output_rotation_matrix(fname_matrix, t, u); if (strlen(fname_super)) { output_pymol(xname, yname, fname_super, t, u, ter_opt, 0, split_opt, mirror_opt, seqM, seqxA, seqyA, resi_vec1, resi_vec2, chainID1, chainID2); output_rasmol(xname, yname, fname_super, t, u, ter_opt, 0, split_opt, mirror_opt, seqM, seqxA, seqyA, resi_vec1, resi_vec2, chainID1, chainID2, xlen, ylen, d0A, n_ali8, rmsd, TM1, Liden); } } int main(int argc, char *argv[]) { if (argc < 2) print_help(); /**********************/ /* get argument */ /**********************/ string xname = ""; string yname = ""; string fname_super = ""; // file name for superposed structure string fname_lign = ""; // file name for user alignment string fname_matrix= ""; // file name for output matrix vector sequence; // get value from alignment file double Lnorm_ass, d0_scale; bool h_opt = false; // print full help message bool v_opt = false; // print version bool m_opt = false; // flag for -m, output rotation matrix bool o_opt = false; // flag for -o, output superposed structure int a_opt = 0; // flag for -a, do not normalized by average length bool u_opt = false; // flag for -u, normalized by user specified length bool d_opt = false; // flag for -d, user specified d0 double TMcut =-1; int infmt1_opt=-1; // PDB or PDBx/mmCIF format for chain_1 int infmt2_opt=-1; // PDB or PDBx/mmCIF format for chain_2 int ter_opt =3; // TER, END, or different chainID int split_opt =0; // do not split chain int outfmt_opt=0; // set -outfmt to full output bool fast_opt =false; // flags for -fast, fTM-align algorithm int mirror_opt=0; // do not align mirror int het_opt=0; // do not read HETATM residues string atom_opt ="auto";// use C alpha atom for protein and C3' for RNA string mol_opt ="auto";// auto-detect the molecule type as protein/RNA string suffix_opt=""; // set -suffix to empty string dir_opt =""; // set -dir to empty string dir1_opt =""; // set -dir1 to empty string dir2_opt =""; // set -dir2 to empty int byresi_opt=1; // TM-score without -c vector chain1_list; // only when -dir1 is set vector chain2_list; // only when -dir2 is set for(int i = 1; i < argc; i++) { if ( !strcmp(argv[i],"-o") && i < (argc-1) ) { fname_super = argv[i + 1]; o_opt = true; i++; } else if ( (!strcmp(argv[i],"-u") || !strcmp(argv[i],"-l") || !strcmp(argv[i],"-L")) && i < (argc-1) ) { Lnorm_ass = atof(argv[i + 1]); u_opt = true; i++; } else if ( !strcmp(argv[i],"-a") && i < (argc-1) ) { if (!strcmp(argv[i + 1], "T")) a_opt=true; else if (!strcmp(argv[i + 1], "F")) a_opt=false; else { a_opt=atoi(argv[i + 1]); if (a_opt!=-2 && a_opt!=-1 && a_opt!=1) PrintErrorAndQuit("-a must be -2, -1, 1, T or F"); } i++; } else if ( !strcmp(argv[i],"-d") && i < (argc-1) ) { d0_scale = atof(argv[i + 1]); d_opt = true; i++; } else if ( !strcmp(argv[i],"-v") ) { v_opt = true; } else if ( !strcmp(argv[i],"-h") ) { h_opt = true; } else if (!strcmp(argv[i], "-m") && i < (argc-1) ) { fname_matrix = argv[i + 1]; m_opt = true; i++; }// get filename for rotation matrix else if (!strcmp(argv[i], "-fast")) { fast_opt = true; } else if ( !strcmp(argv[i],"-infmt1") && i < (argc-1) ) { infmt1_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-infmt2") && i < (argc-1) ) { infmt2_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-ter") && i < (argc-1) ) { ter_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-split") && i < (argc-1) ) { split_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-atom") && i < (argc-1) ) { atom_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-mol") && i < (argc-1) ) { mol_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-dir") && i < (argc-1) ) { dir_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-dir1") && i < (argc-1) ) { dir1_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-dir2") && i < (argc-1) ) { dir2_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-suffix") && i < (argc-1) ) { suffix_opt=argv[i + 1]; i++; } else if ( !strcmp(argv[i],"-outfmt") && i < (argc-1) ) { outfmt_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-c") ) { byresi_opt=2; } else if ( !strcmp(argv[i],"-seq") ) { byresi_opt=5; } else if ( !strcmp(argv[i],"-mirror") && i < (argc-1) ) { mirror_opt=atoi(argv[i + 1]); i++; } else if ( !strcmp(argv[i],"-het") && i < (argc-1) ) { het_opt=atoi(argv[i + 1]); i++; } else if (xname.size() == 0) xname=argv[i]; else if (yname.size() == 0) yname=argv[i]; else PrintErrorAndQuit(string("ERROR! Undefined option ")+argv[i]); } if(xname.size()==0 || (yname.size()==0 && dir_opt.size()==0) || (yname.size() && dir_opt.size())) { if (h_opt) print_help(h_opt); if (v_opt) { print_version(); exit(EXIT_FAILURE); } if (xname.size()==0) PrintErrorAndQuit("Please provide input structures"); else if (yname.size()==0 && dir_opt.size()==0) PrintErrorAndQuit("Please provide structure B"); else if (yname.size() && dir_opt.size()) PrintErrorAndQuit("Please provide only one file name if -dir is set"); } if (suffix_opt.size() && dir_opt.size()+dir1_opt.size()+dir2_opt.size()==0) PrintErrorAndQuit("-suffix is only valid if -dir, -dir1 or -dir2 is set"); if ((dir_opt.size() || dir1_opt.size() || dir2_opt.size())) { if (m_opt || o_opt) PrintErrorAndQuit("-m or -o cannot be set with -dir, -dir1 or -dir2"); else if (dir_opt.size() && (dir1_opt.size() || dir2_opt.size())) PrintErrorAndQuit("-dir cannot be set with -dir1 or -dir2"); } if (atom_opt.size()!=4) PrintErrorAndQuit("ERROR! Atom name must have 4 characters, including space."); if (mol_opt!="auto" && mol_opt!="protein" && mol_opt!="RNA") PrintErrorAndQuit("ERROR! Molecule type must be either RNA or protein."); else if (mol_opt=="protein" && atom_opt=="auto") atom_opt=" CA "; else if (mol_opt=="RNA" && atom_opt=="auto") atom_opt=" C3'"; if (u_opt && Lnorm_ass<=0) PrintErrorAndQuit("Wrong value for option -u! It should be >0"); if (d_opt && d0_scale<=0) PrintErrorAndQuit("Wrong value for option -d! It should be >0"); if (outfmt_opt>=2 && (a_opt || u_opt || d_opt)) PrintErrorAndQuit("-outfmt 2 cannot be used with -a, -u, -L, -d"); if (byresi_opt>=2 && byresi_opt<=3 && ter_opt>=2) PrintErrorAndQuit("-c should be used with -ter <=1"); if (split_opt==1 && ter_opt!=0) PrintErrorAndQuit("-split 1 should be used with -ter 0"); else if (split_opt==2 && ter_opt!=0 && ter_opt!=1) PrintErrorAndQuit("-split 2 should be used with -ter 0 or 1"); if (split_opt<0 || split_opt>2) PrintErrorAndQuit("-split can only be 0, 1 or 2"); if (m_opt && fname_matrix == "") // Output rotation matrix: matrix.txt PrintErrorAndQuit("ERROR! Please provide a file name for option -m!"); /* parse file list */ if (dir1_opt.size()+dir_opt.size()==0) chain1_list.push_back(xname); else file2chainlist(chain1_list, xname, dir_opt+dir1_opt, suffix_opt); if (dir_opt.size()) for (int i=0;i=4) cerr<<"WARNING! The residue correspondence between the two structures" <<" are automatically established by sequence alignment. Results" <<" may be unreliable."< >PDB_lines1; // text of chain1 vector >PDB_lines2; // text of chain2 vector mol_vec1; // molecule type of chain1, RNA if >0 vector mol_vec2; // molecule type of chain2, RNA if >0 vector chainID_list1; // list of chainID1 vector chainID_list2; // list of chainID2 int i,j; // file index int chain_i,chain_j; // chain index int r; // residue index int xlen, ylen; // chain length int xchainnum,ychainnum;// number of chains in a PDB file char *seqx, *seqy; // for the protein sequence double **xa, **ya; // for input vectors xa[0...xlen-1][0..2] and // ya[0...ylen-1][0..2], in general, // ya is regarded as native structure // --> superpose xa onto ya vector resi_vec1; // residue index for chain1 vector resi_vec2; // residue index for chain2 /* loop over file names */ for (i=0;i0)*(i+1);j1) { yname.clear(); for (chain_j=0;chain_j