text: /**********************************************************************
  *These solidity codes have been obtained from Etherscan for extracting
  *the smartcontract related info.
  *The data will be used by MATRIX AI team as the reference basis for
  *MATRIX model analysis,extraction of contract semantics,
  *as well as AI based data analysis, etc.
  **********************************************************************/
  pragma solidity ^0.4.24;
  
  
  interface PlayerBookReceiverInterface {
      function receivePlayerInfo(uint256 _pID, address _addr, bytes32 _name, uint256 _laff) external;
      function receivePlayerNameList(uint256 _pID, bytes32 _name) external;
  }
  
  
  contract PlayerBook {
      using NameFilter for string;
      using SafeMath for uint256;
      
      address private communityAddr = 0xfd76dB2AF819978d43e07737771c8D9E8bd8cbbF;
      address private activate_addr = 0x6C7DFE3c255a098Ea031f334436DD50345cFC737;
  //==============================================================================
  //     _| _ _|_ _    _ _ _|_    _   .
  //    (_|(_| | (_|  _\(/_ | |_||_)  .
  //=============================|================================================    
      uint256 public registrationFee_ = 10 finney;            // price to register a name
      mapping(uint256 => PlayerBookReceiverInterface) public games_;  // mapping of our game interfaces for sending your account info to games
      mapping(address => bytes32) public gameNames_;          // lookup a games name
      mapping(address => uint256) public gameIDs_;            // lokup a games ID
      uint256 public gID_;        // total number of games
      uint256 public pID_;        // total number of players
      mapping (address => uint256) public pIDxAddr_;          // (addr => pID) returns player id by address
      mapping (bytes32 => uint256) public pIDxName_;          // (name => pID) returns player id by name
      mapping (uint256 => Player) public plyr_;               // (pID => data) player data
      mapping (uint256 => mapping (bytes32 => bool)) public plyrNames_; // (pID => name => bool) list of names a player owns.  (used so you can change your display name amoungst any name you own)
      mapping (uint256 => mapping (uint256 => bytes32)) public plyrNameList_; // (pID => nameNum => name) list of names a player owns
      struct Player {
          address addr;
          bytes32 name;
          uint256 laff;
          uint256 names;
      }
  //==============================================================================
  //     _ _  _  __|_ _    __|_ _  _  .
  //    (_(_)| |_\ | | |_|(_ | (_)|   .  (initial data setup upon contract deploy)
  //==============================================================================    
      constructor()
          public
      {
          // premine the dev names (sorry not sorry)
              // No keys are purchased with this method, it's simply locking our addresses,
              // PID's and names for referral codes.
          plyr_[1].addr = 0x33E161A482C560DCA9180D84706eCDd2D906668B;
          plyr_[1].name = "west1";
          plyr_[1].names = 1;
          pIDxAddr_[0x33E161A482C560DCA9180D84706eCDd2D906668B] = 1;
          pIDxName_["west1"] = 1;
          plyrNames_[1]["west1"] = true;
          plyrNameList_[1][1] = "west1";
          
          plyr_[2].addr = 0x9eb79e917b9e051A1BEf27f8A6cCDA316F228a7c;
          plyr_[2].name = "west2";
          plyr_[2].names = 1;
          pIDxAddr_[0x9eb79e917b9e051A1BEf27f8A6cCDA316F228a7c] = 2;
          pIDxName_["west2"] = 2;
          plyrNames_[2]["west2"] = true;
          plyrNameList_[2][1] = "west2";
          
          plyr_[3].addr = 0x261901840C99C914Aa8Cc2f7AEd0d2e09A749c8B;
          plyr_[3].name = "west3";
          plyr_[3].names = 1;
          pIDxAddr_[0x261901840C99C914Aa8Cc2f7AEd0d2e09A749c8B] = 3;
          pIDxName_["west3"] = 3;
          plyrNames_[3]["west3"] = true;
          plyrNameList_[3][1] = "west3";
          
          plyr_[4].addr = 0x7649938FAdf6C597F27349D338e3bDC8488c14e6;
          plyr_[4].name = "west4";
          plyr_[4].names = 1;
          pIDxAddr_[0x7649938FAdf6C597F27349D338e3bDC8488c14e6] = 4;
          pIDxName_["west4"] = 4;
          plyrNames_[4]["west4"] = true;
          plyrNameList_[4][1] = "west4";
          
          pID_ = 4;
      }
  //==============================================================================
  //     _ _  _  _|. |`. _  _ _  .
  //    | | |(_)(_||~|~|(/_| _\  .  (these are safety checks)
  //==============================================================================    
      /**
       * @dev prevents contracts from interacting with fomo3d 
       */
      modifier isHuman() {
          address _addr = msg.sender;
          uint256 _codeLength;
          
          assembly {_codeLength := extcodesize(_addr)}
          require(_codeLength == 0, "sorry humans only");
          _;
      }
      
      modifier onlyCommunity() 
      {
          require(msg.sender == activate_addr, "msg sender is not the community");
          _;
      }
      
      modifier isRegisteredGame()
      {
          require(gameIDs_[msg.sender] != 0);
          _;
      }
  //==============================================================================
  //     _    _  _ _|_ _  .
  //    (/_\/(/_| | | _\  .
  //==============================================================================    
      // fired whenever a player registers a name
      event onNewName
      (
          uint256 indexed playerID,
          address indexed playerAddress,
          bytes32 indexed playerName,
          bool isNewPlayer,
          uint256 affiliateID,
          address affiliateAddress,
          bytes32 affiliateName,
          uint256 amountPaid,
          uint256 timeStamp
      );
  //==============================================================================
  //     _  _ _|__|_ _  _ _  .
  //    (_|(/_ |  | (/_| _\  . (for UI & viewing things on etherscan)
  //=====_|=======================================================================
      function checkIfNameValid(string _nameStr)
          public
          view
          returns(bool)
      {
          bytes32 _name = _nameStr.nameFilter();
          if (pIDxName_[_name] == 0)
              return (true);
          else 
              return (false);
      }
  //==============================================================================
  //     _    |_ |. _   |`    _  __|_. _  _  _  .
  //    |_)|_||_)||(_  ~|~|_|| |(_ | |(_)| |_\  .  (use these to interact with contract)
  //====|=========================================================================    
      /**
       * @dev registers a name.  UI will always display the last name you registered.
       * but you will still own all previously registered names to use as affiliate 
       * links.
       * - must pay a registration fee.
       * - name must be unique
       * - names will be converted to lowercase
       * - name cannot start or end with a space 
       * - cannot have more than 1 space in a row
       * - cannot be only numbers
       * - cannot start with 0x 
       * - name must be at least 1 char
       * - max length of 32 characters long
       * - allowed characters: a-z, 0-9, and space
       * -functionhash- 0x921dec21 (using ID for affiliate)
       * -functionhash- 0x3ddd4698 (using address for affiliate)
       * -functionhash- 0x685ffd83 (using name for affiliate)
       * @param _nameString players desired name
       * @param _affCode affiliate ID, address, or name of who refered you
       * @param _all set to true if you want this to push your info to all games 
       * (this might cost a lot of gas)
       */
      function registerNameXID(string _nameString, uint256 _affCode, bool _all)
          isHuman()
          public
          payable 
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // filter name + condition checks
          bytes32 _name = NameFilter.nameFilter(_nameString);
          
          // set up address 
          address _addr = msg.sender;
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given, no new affiliate code was given, or the 
          // player tried to use their own pID as an affiliate code, lolz
          if (_affCode != 0 && _affCode != plyr_[_pID].laff && _affCode != _pID) 
          {
              // update last affiliate 
              plyr_[_pID].laff = _affCode;
          } else if (_affCode == _pID) {
              _affCode = 0;
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affCode, _name, _isNewPlayer, _all);
      }
      
      function registerNameXaddr(string _nameString, address _affCode, bool _all)
          isHuman()
          public
          payable 
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // filter name + condition checks
          bytes32 _name = NameFilter.nameFilter(_nameString);
          
          // set up address 
          address _addr = msg.sender;
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given or player tried to use their own, lolz
          uint256 _affID;
          if (_affCode != address(0) && _affCode != _addr)
          {
              // get affiliate ID from aff Code 
              _affID = pIDxAddr_[_affCode];
              
              // if affID is not the same as previously stored 
              if (_affID != plyr_[_pID].laff)
              {
                  // update last affiliate
                  plyr_[_pID].laff = _affID;
              }
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affID, _name, _isNewPlayer, _all);
      }
      
      function registerNameXname(string _nameString, bytes32 _affCode, bool _all)
          isHuman()
          public
          payable 
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // filter name + condition checks
          bytes32 _name = NameFilter.nameFilter(_nameString);
          
          // set up address 
          address _addr = msg.sender;
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given or player tried to use their own, lolz
          uint256 _affID;
          if (_affCode != "" && _affCode != _name)
          {
              // get affiliate ID from aff Code 
              _affID = pIDxName_[_affCode];
              
              // if affID is not the same as previously stored 
              if (_affID != plyr_[_pID].laff)
              {
                  // update last affiliate
                  plyr_[_pID].laff = _affID;
              }
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affID, _name, _isNewPlayer, _all);
      }
      
      /**
       * @dev players, if you registered a profile, before a game was released, or
       * set the all bool to false when you registered, use this function to push
       * your profile to a single game.  also, if you've  updated your name, you
       * can use this to push your name to games of your choosing.
       * -functionhash- 0x81c5b206
       * @param _gameID game id 
       */
      function addMeToGame(uint256 _gameID)
          isHuman()
          public
      {
          require(_gameID <= gID_, "silly player, that game doesn't exist yet");
          address _addr = msg.sender;
          uint256 _pID = pIDxAddr_[_addr];
          require(_pID != 0, "hey there buddy, you dont even have an account");
          uint256 _totalNames = plyr_[_pID].names;
          
          // add players profile and most recent name
          games_[_gameID].receivePlayerInfo(_pID, _addr, plyr_[_pID].name, plyr_[_pID].laff);
          
          // add list of all names
          if (_totalNames > 1)
              for (uint256 ii = 1; ii <= _totalNames; ii++)
                  games_[_gameID].receivePlayerNameList(_pID, plyrNameList_[_pID][ii]);
      }
      
      /**
       * @dev players, use this to push your player profile to all registered games.
       * -functionhash- 0x0c6940ea
       */
      function addMeToAllGames()
          isHuman()
          public
      {
          address _addr = msg.sender;
          uint256 _pID = pIDxAddr_[_addr];
          require(_pID != 0, "hey there buddy, you dont even have an account");
          uint256 _laff = plyr_[_pID].laff;
          uint256 _totalNames = plyr_[_pID].names;
          bytes32 _name = plyr_[_pID].name;
          
          for (uint256 i = 1; i <= gID_; i++)
          {
              games_[i].receivePlayerInfo(_pID, _addr, _name, _laff);
              if (_totalNames > 1)
                  for (uint256 ii = 1; ii <= _totalNames; ii++)
                      games_[i].receivePlayerNameList(_pID, plyrNameList_[_pID][ii]);
          }
                  
      }
      
      /**
       * @dev players use this to change back to one of your old names.  tip, you'll
       * still need to push that info to existing games.
       * -functionhash- 0xb9291296
       * @param _nameString the name you want to use 
       */
      function useMyOldName(string _nameString)
          isHuman()
          public 
      {
          // filter name, and get pID
          bytes32 _name = _nameString.nameFilter();
          uint256 _pID = pIDxAddr_[msg.sender];
          
          // make sure they own the name 
          require(plyrNames_[_pID][_name] == true, "umm... thats not a name you own");
          
          // update their current name 
          plyr_[_pID].name = _name;
      }
      
  //==============================================================================
  //     _ _  _ _   | _  _ . _  .
  //    (_(_)| (/_  |(_)(_||(_  . 
  //=====================_|=======================================================    
      function registerNameCore(uint256 _pID, address _addr, uint256 _affID, bytes32 _name, bool _isNewPlayer, bool _all)
          private
      {
          // if names already has been used, require that current msg sender owns the name
          if (pIDxName_[_name] != 0)
              require(plyrNames_[_pID][_name] == true, "sorry that names already taken");
          
          // add name to player profile, registry, and name book
          plyr_[_pID].name = _name;
          pIDxName_[_name] = _pID;
          if (plyrNames_[_pID][_name] == false)
          {
              plyrNames_[_pID][_name] = true;
              plyr_[_pID].names++;
              plyrNameList_[_pID][plyr_[_pID].names] = _name;
          }
          
          // registration fee goes directly to community rewards
          communityAddr.transfer(address(this).balance);
          
          // push player info to games
          if (_all == true)
              for (uint256 i = 1; i <= gID_; i++)
                  games_[i].receivePlayerInfo(_pID, _addr, _name, _affID);
          
          // fire event
          emit onNewName(_pID, _addr, _name, _isNewPlayer, _affID, plyr_[_affID].addr, plyr_[_affID].name, msg.value, now);
      }
  //==============================================================================
  //    _|_ _  _ | _  .
  //     | (_)(_)|_\  .
  //==============================================================================    
      function determinePID(address _addr)
          private
          returns (bool)
      {
          if (pIDxAddr_[_addr] == 0)
          {
              pID_++;
              pIDxAddr_[_addr] = pID_;
              plyr_[pID_].addr = _addr;
              
              // set the new player bool to true
              return (true);
          } else {
              return (false);
          }
      }
  //==============================================================================
  //   _   _|_ _  _ _  _ |   _ _ || _  .
  //  (/_>< | (/_| | |(_||  (_(_|||_\  .
  //==============================================================================
      function getPlayerID(address _addr)
          isRegisteredGame()
          external
          returns (uint256)
      {
          determinePID(_addr);
          return (pIDxAddr_[_addr]);
      }
      function getPlayerName(uint256 _pID)
          external
          view
          returns (bytes32)
      {
          return (plyr_[_pID].name);
      }
      function getPlayerLAff(uint256 _pID)
          external
          view
          returns (uint256)
      {
          return (plyr_[_pID].laff);
      }
      function getPlayerAddr(uint256 _pID)
          external
          view
          returns (address)
      {
          return (plyr_[_pID].addr);
      }
      function getNameFee()
          external
          view
          returns (uint256)
      {
          return(registrationFee_);
      }
      function registerNameXIDFromDapp(address _addr, bytes32 _name, uint256 _affCode, bool _all)
          isRegisteredGame()
          external
          payable
          returns(bool, uint256)
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given, no new affiliate code was given, or the 
          // player tried to use their own pID as an affiliate code, lolz
          uint256 _affID = _affCode;
          if (_affID != 0 && _affID != plyr_[_pID].laff && _affID != _pID) 
          {
              // update last affiliate 
              plyr_[_pID].laff = _affID;
          } else if (_affID == _pID) {
              _affID = 0;
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affID, _name, _isNewPlayer, _all);
          
          return(_isNewPlayer, _affID);
      }
      function registerNameXaddrFromDapp(address _addr, bytes32 _name, address _affCode, bool _all)
          isRegisteredGame()
          external
          payable
          returns(bool, uint256)
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given or player tried to use their own, lolz
          uint256 _affID;
          if (_affCode != address(0) && _affCode != _addr)
          {
              // get affiliate ID from aff Code 
              _affID = pIDxAddr_[_affCode];
              
              // if affID is not the same as previously stored 
              if (_affID != plyr_[_pID].laff)
              {
                  // update last affiliate
                  plyr_[_pID].laff = _affID;
              }
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affID, _name, _isNewPlayer, _all);
          
          return(_isNewPlayer, _affID);
      }
      function registerNameXnameFromDapp(address _addr, bytes32 _name, bytes32 _affCode, bool _all)
          isRegisteredGame()
          external
          payable
          returns(bool, uint256)
      {
          // make sure name fees paid
          require (msg.value >= registrationFee_, "umm.....  you have to pay the name fee");
          
          // set up our tx event data and determine if player is new or not
          bool _isNewPlayer = determinePID(_addr);
          
          // fetch player id
          uint256 _pID = pIDxAddr_[_addr];
          
          // manage affiliate residuals
          // if no affiliate code was given or player tried to use their own, lolz
          uint256 _affID;
          if (_affCode != "" && _affCode != _name)
          {
              // get affiliate ID from aff Code 
              _affID = pIDxName_[_affCode];
              
              // if affID is not the same as previously stored 
              if (_affID != plyr_[_pID].laff)
              {
                  // update last affiliate
                  plyr_[_pID].laff = _affID;
              }
          }
          
          // register name 
          registerNameCore(_pID, _addr, _affID, _name, _isNewPlayer, _all);
          
          return(_isNewPlayer, _affID);
      }
      
  //==============================================================================
  //   _ _ _|_    _   .
  //  _\(/_ | |_||_)  .
  //=============|================================================================
      function addGame(address _gameAddress, string _gameNameStr)
       onlyCommunity()
          public
      {
          require(gameIDs_[_gameAddress] == 0, "derp, that games already been registered");
  
              gID_++;
              bytes32 _name = _gameNameStr.nameFilter();
              gameIDs_[_gameAddress] = gID_;
              gameNames_[_gameAddress] = _name;
              games_[gID_] = PlayerBookReceiverInterface(_gameAddress);
          
              games_[gID_].receivePlayerInfo(1, plyr_[1].addr, plyr_[1].name, 0);
              games_[gID_].receivePlayerInfo(2, plyr_[2].addr, plyr_[2].name, 0);
              games_[gID_].receivePlayerInfo(3, plyr_[3].addr, plyr_[3].name, 0);
              games_[gID_].receivePlayerInfo(4, plyr_[4].addr, plyr_[4].name, 0);
      }
      
      function setRegistrationFee(uint256 _fee)
       onlyCommunity()
          public
      {
              registrationFee_ = _fee;
      }
          
  } 
  
  /**
  * @title -Name Filter- v0.1.9
  * ┌┬┐┌─┐┌─┐┌┬┐   ╦╦ ╦╔═╗╔╦╗  ┌─┐┬─┐┌─┐┌─┐┌─┐┌┐┌┌┬┐┌─┐
  *  │ ├┤ ├─┤│││   ║║ ║╚═╗ ║   ├─┘├┬┘├┤ └─┐├┤ │││ │ └─┐
  *  ┴ └─┘┴ ┴┴ ┴  ╚╝╚═╝╚═╝ ╩   ┴  ┴└─└─┘└─┘└─┘┘└┘ ┴ └─┘
  *                                  _____                      _____
  *                                 (, /     /)       /) /)    (, /      /)          /)
  *          ┌─┐                      /   _ (/_      // //       /  _   // _   __  _(/
  *          ├─┤                  ___/___(/_/(__(_/_(/_(/_   ___/__/_)_(/_(_(_/ (_(_(_
  *          ┴ ┴                /   /          .-/ _____   (__ /                               
  *                            (__ /          (_/ (, /                                      /)™ 
  *                                                 /  __  __ __ __  _   __ __  _  _/_ _  _(/
  * ┌─┐┬─┐┌─┐┌┬┐┬ ┬┌─┐┌┬┐                          /__/ (_(__(_)/ (_/_)_(_)/ (_(_(_(__(/_(_(_
  * ├─┘├┬┘│ │ │││ ││   │                      (__ /              .-/  © Jekyll Island Inc. 2018
  * ┴  ┴└─└─┘─┴┘└─┘└─┘ ┴                                        (_/
  *              _       __    _      ____      ____  _   _    _____  ____  ___  
  *=============| |\ |  / /\  | |\/| | |_ =====| |_  | | | |    | |  | |_  | |_)==============*
  *=============|_| \| /_/--\ |_|  | |_|__=====|_|   |_| |_|__  |_|  |_|__ |_| \==============*
  *
  * ╔═╗┌─┐┌┐┌┌┬┐┬─┐┌─┐┌─┐┌┬┐  ╔═╗┌─┐┌┬┐┌─┐ ┌──────────┐
  * ║  │ ││││ │ ├┬┘├─┤│   │   ║  │ │ ││├┤  │ dddos │
  * ╚═╝└─┘┘└┘ ┴ ┴└─┴ ┴└─┘ ┴   ╚═╝└─┘─┴┘└─┘ └──────────┘
  */
  library NameFilter {
      
      /**
       * @dev filters name strings
       * -converts uppercase to lower case.  
       * -makes sure it does not start/end with a space
       * -makes sure it does not contain multiple spaces in a row
       * -cannot be only numbers
       * -cannot start with 0x 
       * -restricts characters to A-Z, a-z, 0-9, and space.
       * @return reprocessed string in bytes32 format
       */
      function nameFilter(string _input)
          internal
          pure
          returns(bytes32)
      {
          bytes memory _temp = bytes(_input);
          uint256 _length = _temp.length;
          
          //sorry limited to 32 characters
          require (_length <= 32 && _length > 0, "string must be between 1 and 32 characters");
          // make sure it doesnt start with or end with space
          require(_temp[0] != 0x20 && _temp[_length-1] != 0x20, "string cannot start or end with space");
          // make sure first two characters are not 0x
          if (_temp[0] == 0x30)
          {
              require(_temp[1] != 0x78, "string cannot start with 0x");
              require(_temp[1] != 0x58, "string cannot start with 0X");
          }
          
          // create a bool to track if we have a non number character
          bool _hasNonNumber;
          
          // convert & check
          for (uint256 i = 0; i < _length; i++)
          {
              // if its uppercase A-Z
              if (_temp[i] > 0x40 && _temp[i] < 0x5b)
              {
                  // convert to lower case a-z
                  _temp[i] = byte(uint(_temp[i]) + 32);
                  
                  // we have a non number
                  if (_hasNonNumber == false)
                      _hasNonNumber = true;
              } else {
                  require
                  (
                      // require character is a space
                      _temp[i] == 0x20 || 
                      // OR lowercase a-z
                      (_temp[i] > 0x60 && _temp[i] < 0x7b) ||
                      // or 0-9
                      (_temp[i] > 0x2f && _temp[i] < 0x3a),
                      "string contains invalid characters"
                  );
                  // make sure theres not 2x spaces in a row
                  if (_temp[i] == 0x20)
                      require( _temp[i+1] != 0x20, "string cannot contain consecutive spaces");
                  
                  // see if we have a character other than a number
                  if (_hasNonNumber == false && (_temp[i] < 0x30 || _temp[i] > 0x39))
                      _hasNonNumber = true;    
              }
          }
          
          require(_hasNonNumber == true, "string cannot be only numbers");
          
          bytes32 _ret;
          assembly {
              _ret := mload(add(_temp, 32))
          }
          return (_ret);
      }
  }
  
  /**
   * @title SafeMath v0.1.9
   * @dev Math operations with safety checks that throw on error
   * change notes:  original SafeMath library from OpenZeppelin modified by dddos
   * - added sqrt
   * - added sq
   * - added pwr 
   * - changed asserts to requires with error log outputs
   * - removed div, its useless
   */
  library SafeMath {
      
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 a, uint256 b) 
          internal 
          pure 
          returns (uint256 c) 
      {
          if (a == 0) {
              return 0;
          }
          c = a * b;
          require(c / a == b, "SafeMath mul failed");
          return c;
      }
  
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b)
          internal
          pure
          returns (uint256) 
      {
          require(b <= a, "SafeMath sub failed");
          return a - b;
      }
  
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 a, uint256 b)
          internal
          pure
          returns (uint256 c) 
      {
          c = a + b;
          require(c >= a, "SafeMath add failed");
          return c;
      }
      
      /**
       * @dev gives square root of given x.
       */
      function sqrt(uint256 x)
          internal
          pure
          returns (uint256 y) 
      {
          uint256 z = ((add(x,1)) / 2);
          y = x;
          while (z < y) 
          {
              y = z;
              z = ((add((x / z),z)) / 2);
          }
      }
      
      /**
       * @dev gives square. multiplies x by x
       */
      function sq(uint256 x)
          internal
          pure
          returns (uint256)
      {
          return (mul(x,x));
      }
      
      /**
       * @dev x to the power of y 
       */
      function pwr(uint256 x, uint256 y)
          internal 
          pure 
          returns (uint256)
      {
          if (x==0)
              return (0);
          else if (y==0)
              return (1);
          else 
          {
              uint256 z = x;
              for (uint256 i=1; i < y; i++)
                  z = mul(z,x);
              return (z);
          }
      }
  }