Return move fields in getBasicInfo()

Return move fields in getBasicInfo()

/**
 * @title Glofile
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract Glofile {

  enum GlofileType { Anon, Person, Project, Organization, Proxy, Parody, Bot }
  enum SafetyLevel { Safe, NSFW, NSFL }

  struct Glofile {
    bool dontIndex;
    GlofileType glofileType;
    SafetyLevel safetyLevel;
    uint16 publicKeyCount;
    bytes uris;
    string fullName;
    string location;
    bytes3[] foregroundColors;
    bytes3[] backgroundColors;
    bytes3[] bioLangs;
    bytes[] avatars;
    bytes[] coverImages;
    bytes[] backgroundImages;
    string[] topics;
    string[] parents;
    string[] children;
    mapping (bytes3 => bytes) bioTranslations;
  }

  mapping (address => Glofile) glofiles;

  event Update(address indexed account);
  event Delete(address indexed account);
  event PublicKeyAdd(address indexed account, uint indexed i, bytes publicKey);
  event PublicKeyDelete(address indexed account, uint indexed i);

  /**
   * @notice Set your Glofile don't index flag to `dontIndex`
   * @dev Sets the "don't index" flag. Glofiles with this flag set should only be accessible directly and not be discoverable via search.
   * @param dontIndex flag to indicate that this Glofile should not be indexed
   */
  function setDontIndex(bool dontIndex) {
    glofiles[msg.sender].dontIndex = dontIndex;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile type to `glofileType`
   * @dev Sets the Glofile type.
   * @param glofileType Glofile type
   */
  function setGlofileType(GlofileType glofileType) {
    glofiles[msg.sender].glofileType = glofileType;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile safety level to `safetyLevel`
   * @dev Sets the safety level. The account may publish content that is less safe than this, so long as it is flagged as such.
   * @param safetyLevel safety level
   */
  function setSafetyLevel(SafetyLevel safetyLevel) {
    glofiles[msg.sender].safetyLevel = safetyLevel;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile full name to `fullName`
   * @dev Sets the full name.
   * @param fullName UTF-8 string of full name - max length 128 chars
   * @return fullName UTF-8 string of full name
   */
  function setFullName(string fullName) {
    glofiles[msg.sender].fullName = fullName;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile location
   * @dev Sets the location. A dedicated contract could be used for more sophisticated location functionality.
   * @param location UTF-8 string of location - max string length 128 chars
   */
  function setLocation(string location) {
    glofiles[msg.sender].location = location;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile basic info
   * @dev Gets all the info that can be retreived in a single call.
   * @param account Glofile to access
   * @return dontIndex flag to indicate that this Glofile should not be indexed
   * @return glofileType Glofile type
   * @return safetyLevel safety level
   */
  function getBasicInfo(address account) constant returns (bool dontIndex, GlofileType glofileType, SafetyLevel safetyLevel, string fullName, string location) {
    Glofile glofile = glofiles[account];
    dontIndex = glofile.dontIndex;
    glofileType = glofile.glofileType;
    safetyLevel = glofile.safetyLevel;
    fullName = glofile.fullName;
    location = glofile.location;
  }

  /**
   * @notice Set your Glofile foreground colors
   * @dev Sets all the foreground colors.
   * @param colors array of RGB triplets
   */
  function setForegroundColors(bytes3[] colors) {
    glofiles[msg.sender].foregroundColors = colors;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile background colors
   * @dev Sets all the background colors.
   * @param colors array of RGB triplets
   */
  function setBackgroundColors(bytes3[] colors) {
    glofiles[msg.sender].backgroundColors = colors;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile colors
   * @dev Gets the foreground and background colors
   * @param account Glofile to access
   * @return foregroundColors array of RGB triplets of foreground colors
   * @return backgroundColors array of RGB triplets of background colors
   */
  function getColors(address account) constant returns (bytes3[] foregroundColors, bytes3[] backgroundColors) {
    Glofile glofile = glofiles[account];
    foregroundColors = glofile.foregroundColors;
    backgroundColors = glofile.backgroundColors;
  }

  /**
   * @notice Set your Glofile bio with langauge code `lang`
   * @dev Sets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param translation UTF-8 Markdown of bio compressed with DEFLATE - max Markdown length 256 chars
   */
  function setBio(bytes3 lang, bytes translation) {
    Glofile glofile = glofiles[msg.sender];
    // Check if we already have the language code.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        break;
      }
    }
    if (i == glofile.bioLangs.length) {
      // We didn't find it. Try to find a free slot.
      for (i = 0; i < glofile.bioLangs.length; i++) {
        if (glofile.bioLangs[i] == 0) {
          break;
        }
      }
      if (i == glofile.bioLangs.length) {
        // We didn't find a free slot. Make the array bigger.
        glofile.bioLangs.length++;
      }
      glofile.bioLangs[i] = lang;
    }
    // Set translation.
    glofile.bioTranslations[lang] = translation;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile bio with language code `lang`
   * @dev Deletes a bio translation.
   * @param lang 3 letter ISO 639-3 language code
   */
  function deleteBio(bytes3 lang) {
    Glofile glofile = glofiles[msg.sender];
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        delete glofile.bioLangs[i];
        break;
      }
    }
    // Delete the actual mapping in case a client accesses without checking
    // language key.
    delete glofile.bioTranslations[lang];
    Update(msg.sender);
  }

  /**
   * @notice Delete all of your Glofile bio translations
   * @dev Deletes all of the bio translations.
   */
  function deleteAllBioTranslations() {
    Glofile glofile = glofiles[msg.sender];
    // Delete the actual mappings in case a client accesses without checking
    // language key.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      delete glofile.bioTranslations[glofile.bioLangs[i]];
    }
    delete glofile.bioLangs;
    Update(msg.sender);
  }

  /**
   * @notice Get the list of language code a Glofile bio is available in
   * @dev Gets the list of language codes the bio is available in.
   * @param account Glofile to access
   * @return array of 3 letter ISO 639-3 language codes
   */
  function getBioLangCodes(address account) constant returns (bytes3[]) {
    return glofiles[account].bioLangs;
  }

  /**
   * @notice Get the Glofile bio with language code `lang`
   * @dev Gets the bio in a specific language.
   * @param account Glofile to access
   * @param lang 3 letter ISO 639-3 language code
   * @return UTF-8 Markdown of bio compressed with DEFLATE
   */
  function getBioTranslation(address account, bytes3 lang) constant returns (bytes) {
    return glofiles[account].bioTranslations[lang];
  }

  /**
   * @notice Set your Glofile avatar with index `i` to `ipfsHash`
   * @dev Sets the avatar with a specific index to an IPFS hash.
   * @param i index of avatar to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setAvatar(uint i, bytes ipfsHash) {
    bytes[] avatars = glofiles[msg.sender].avatars;
    // Make sure the array is long enough.
    if (avatars.length <= i) {
      avatars.length = i + 1;
    }
    avatars[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile avatar with index `i`
   * @dev Deletes an avatar with a specific index.
   * @param i index of avatar to delete
   */
  function deleteAvatar(uint i) {
    delete glofiles[msg.sender].avatars[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile avatars
   * @dev Deletes all avatars from the Glofile.
   */
  function deleteAllAvatars() {
    delete glofiles[msg.sender].avatars;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile avatars
   * @dev Gets the number of avatars.
   * @param account Glofile to access
   * @return number of avatars
   */
  function getAvatarCount(address account) constant returns (uint) {
    return glofiles[account].avatars.length;
  }

  /**
   * @notice Get the Glofile avatar with index `i`
   * @dev Gets the avatar with a specific index.
   * @param account Glofile to access
   * @param i index of avatar to get
   * @return binary IPFS hash of image
   */
  function getAvatar(address account, uint i) constant returns (bytes) {
    return glofiles[account].avatars[i];
  }

  /**
   * @notice Set your Glofile cover image with index `i` to `ipfsHash`
   * @dev Sets the cover image with a specific index to an IPFS hash.
   * @param i index of cover image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setCoverImage(uint i, bytes ipfsHash) {
    bytes[] coverImages = glofiles[msg.sender].coverImages;
    // Make sure the array is long enough.
    if (coverImages.length <= i) {
      coverImages.length = i + 1;
    }
    coverImages[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile cover image with index `i`
   * @dev Deletes the cover image with a specific index.
   * @param i index of cover image to delete
   */
  function deleteCoverImage(uint i) {
    delete glofiles[msg.sender].coverImages[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile cover images
   * @dev Deletes all cover images from the Glofile.
   */
  function deleteAllCoverImages() {
    delete glofiles[msg.sender].coverImages;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile cover images
   * @dev Gets the number of cover images.
   * @param account Glofile to access
   * @return number of cover images
   */
  function getCoverImageCount(address account) constant returns (uint) {
    return glofiles[account].coverImages.length;
  }

  /**
   * @notice Get the Glofile cover image with index `i`
   * @dev Gets the cover image with a specific index.
   * @param account Glofile to access
   * @param i index of cover image to get
   * @return binary IPFS hash of image
   */
  function getCoverImage(address account, uint i) constant returns (bytes) {
    return glofiles[account].coverImages[i];
  }

  /**
   * @notice Set your Glofile background image with index `i` to `ipfsHash`
   * @dev Sets the background image with a specific index to an IPFS hash.
   * @param i index of background image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setBackgroundImage(uint i, bytes ipfsHash) {
    bytes[] backgroundImages = glofiles[msg.sender].backgroundImages;
    // Make sure the array is long enough.
    if (backgroundImages.length <= i) {
      backgroundImages.length = i + 1;
    }
    backgroundImages[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile background image with index `i`
   * @dev Deletes the background image with a specific index.
   * @param i index of background image to delete
   */
  function deleteBackgroundImage(uint i) {
    delete glofiles[msg.sender].backgroundImages[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile background images
   * @dev Deletes all the background images.
   */
  function deleteAllBackgroundImages() {
    delete glofiles[msg.sender].backgroundImages;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile background images
   * @dev Gets the number of background images.
   * @param account Glofile to access
   * @return number of background images
   */
  function getBackgroundImageCount(address account) constant returns (uint) {
    return glofiles[account].backgroundImages.length;
  }

  /**
   * @notice Get the Glofile background image with index `i`
   * @dev Gets the background image with a specific index.
   * @param i index of cover image to get
   * @param account Glofile to access
   * @return binary IPFS hash of image
   */
  function getBackgroundImage(address account, uint i) constant returns (bytes) {
    return glofiles[account].backgroundImages[i];
  }

  /**
   * @notice Set your Glofile topic with index `i` to `topic`
   * @dev Sets the topic with a specific index.
   * @param i index of topic to set
   * @param topic UTF-8 string of topic (no whitespace)
   */
  function setTopic(uint i, string topic) {
    string[] topics = glofiles[msg.sender].topics;
    // Make sure the array is long enough.
    if (topics.length <= i) {
      topics.length = i + 1;
    }
    topics[i] = topic;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile topic with index `i`
   * @dev Deletes an topic with a specific index.
   * @param i index of topic to delete
   */
  function deleteTopic(uint i) {
    delete glofiles[msg.sender].topics[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile topics
   * @dev Deletes all topics from the Glofile.
   */
  function deleteAllTopics() {
    delete glofiles[msg.sender].topics;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile topics
   * @dev Gets the number of topics.
   * @param account Glofile to access
   * @return number of topics
   */
  function getTopicCount(address account) constant returns (uint) {
    return glofiles[account].topics.length;
  }

  /**
   * @notice Get the Glofile topic with index `i`
   * @dev Gets the topic with a specific index.
   * @param account Glofile to access
   * @param i index of topic to get
   * @return UTF-8 string of topic
   */
  function getTopic(address account, uint i) constant returns (string) {
    return glofiles[account].topics[i];
  }

  /**
   * @notice Set your Glofile parent with index `i` to `parent`
   * @dev Sets the parent with a specific index.
   * @param i index of parent to set
   * @param parent UTF-8 string of parent
   */
  function setParent(uint i, string parent) {
    string[] parents = glofiles[msg.sender].parents;
    // Make sure the array is long enough.
    if (parents.length <= i) {
      parents.length = i + 1;
    }
    parents[i] = parent;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile parent with index `i`
   * @dev Deletes an parent with a specific index.
   * @param i index of parent to delete
   */
  function deleteParent(uint i) {
    delete glofiles[msg.sender].parents[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile parents
   * @dev Deletes all parents from the Glofile.
   */
  function deleteAllParents() {
    delete glofiles[msg.sender].parents;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile parents
   * @dev Gets the number of parents.
   * @param account Glofile to access
   * @return number of parents
   */
  function getParentCount(address account) constant returns (uint) {
    return glofiles[account].parents.length;
  }

  /**
   * @notice Get the Glofile parent with index `i`
   * @dev Gets the parent with a specific index.
   * @param account Glofile to access
   * @param i index of parent to get
   * @return UTF-8 string of parent
   */
  function getParent(address account, uint i) constant returns (string) {
    return glofiles[account].parents[i];
  }

  /**
   * @notice Set your Glofile child with index `i` to `child`
   * @dev Sets the child with a specific index.
   * @param i index of child to set
   * @param child UTF-8 string of child
   */
  function setChild(uint i, string child) {
    string[] children = glofiles[msg.sender].children;
    // Make sure the array is long enough.
    if (children.length <= i) {
      children.length = i + 1;
    }
    children[i] = child;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile child with index `i`
   * @dev Deletes an child with a specific index.
   * @param i index of child to delete
   */
  function deleteChild(uint i) {
    delete glofiles[msg.sender].children[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile children
   * @dev Deletes all children from the Glofile.
   */
  function deleteAllChildren() {
    delete glofiles[msg.sender].children;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile children
   * @dev Gets the number of children.
   * @param account Glofile to access
   * @return number of children
   */
  function getChildCount(address account) constant returns (uint) {
    return glofiles[account].children.length;
  }

  /**
   * @notice Get the Glofile child with index `i`
   * @dev Gets the child with a specific index.
   * @param account Glofile to access
   * @param i index of child to get
   * @return UTF-8 string of child
   */
  function getChild(address account, uint i) constant returns (string) {
    return glofiles[account].children[i];
  }

  /**
   * @notice Add a public key to your Glofile
   * @dev Adds a public key.
   * @param publicKey UTF-8 public key compressed with DEFLATE
   */
  function addPublicKey(bytes publicKey) {
    uint i = glofiles[msg.sender].publicKeyCount++;
    PublicKeyAdd(msg.sender, i, publicKey);
  }

  /**
   * @notice Delete the public key with index `i` from your Glofile
   * @dev Deletes the public key with a specific index.
   * @param i index of public key to delete
   */
  function deletePublicKey(uint i) {
    PublicKeyDelete(msg.sender, i);
  }

  /**
   * @notice Copy entire Glofile from `source`
   * @dev Copies the Glofile from another account to this one.
   * @param source account of Glofile to copy from
   * TODO: check this works
   */
  function copyEntireGlofile(address source) {
    glofiles[msg.sender] = glofiles[source];
    Update(msg.sender);
  }

  /**
   * @notice Delete your entire Glofile
   * @dev Deletes the Glofile completely.
   * TODO: make sure this deletes everything
   */
  function deleteEntireGlofile() {
    delete glofiles[msg.sender];
    Delete(msg.sender);
  }

}

/**
 * @title Glofile
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract Glofile {

  enum GlofileType { Anon, Person, Project, Organization, Proxy, Parody, Bot }
  enum SafetyLevel { Safe, NSFW, NSFL }

  struct Glofile {
    bool dontIndex;
    GlofileType glofileType;
    SafetyLevel safetyLevel;
    uint16 publicKeyCount;
    bytes uris;
    string fullName;
    string location;
    bytes3[] foregroundColors;
    bytes3[] backgroundColors;
    bytes3[] bioLangs;
    bytes[] avatars;
    bytes[] coverImages;
    bytes[] backgroundImages;
    string[] topics;
    string[] parents;
    string[] children;
    mapping (bytes3 => bytes) bioTranslations;
  }

  mapping (address => Glofile) glofiles;

  event Update(address indexed account);
  event Delete(address indexed account);
  event PublicKeyAdd(address indexed account, uint indexed i, bytes publicKey);
  event PublicKeyDelete(address indexed account, uint indexed i);

  /**
   * @notice Set your Glofile don't index flag to `dontIndex`
   * @dev Sets the "don't index" flag. Glofiles with this flag set should only be accessible directly and not be discoverable via search.
   * @param dontIndex flag to indicate that this Glofile should not be indexed
   */
  function setDontIndex(bool dontIndex) {
    glofiles[msg.sender].dontIndex = dontIndex;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile type to `glofileType`
   * @dev Sets the Glofile type.
   * @param glofileType Glofile type
   */
  function setGlofileType(GlofileType glofileType) {
    glofiles[msg.sender].glofileType = glofileType;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile safety level to `safetyLevel`
   * @dev Sets the safety level. The account may publish content that is less safe than this, so long as it is flagged as such.
   * @param safetyLevel safety level
   */
  function setSafetyLevel(SafetyLevel safetyLevel) {
    glofiles[msg.sender].safetyLevel = safetyLevel;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile basic info
   * @dev Gets all the info that can be retreived in a single call.
   * @param account Glofile to access
   * @return dontIndex flag to indicate that this Glofile should not be indexed
   * @return glofileType Glofile type
   * @return safetyLevel safety level
   */
  function getBasicInfo(address account) constant returns (bool dontIndex, GlofileType glofileType, SafetyLevel safetyLevel) {
    Glofile glofile = glofiles[account];
    dontIndex = glofile.dontIndex;
    glofileType = glofile.glofileType;
    safetyLevel = glofile.safetyLevel;
  }

  /**
   * @notice Set your Glofile full name to `fullName`
   * @dev Sets the full name.
   * @param fullName UTF-8 string of full name - max length 128 chars
   * @return fullName UTF-8 string of full name
   */
  function setFullName(string fullName) {
    glofiles[msg.sender].fullName = fullName;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile full name for `account`
   * @dev Gets the full name.
   * @param account Glofile to access
   * @return UTF-8 string of full name
   */
  function getFullName(address account) constant returns (string) {
    return glofiles[account].fullName;
  }

  /**
   * @notice Set your Glofile location
   * @dev Sets the location. A dedicated contract could be used for more sophisticated location functionality.
   * @param location UTF-8 string of location - max string length 128 chars
   */
  function setLocation(string location) {
    glofiles[msg.sender].location = location;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile location for `account`
   * @dev Gets the location.
   * @param account Glofile to access
   * @return UTF-8 string of location
   */
  function getLocation(address account) constant returns (string) {
    return glofiles[account].location;
  }

  /**
   * @notice Set your Glofile foreground colors
   * @dev Sets all the foreground colors.
   * @param colors array of RGB triplets
   */
  function setForegroundColors(bytes3[] colors) {
    glofiles[msg.sender].foregroundColors = colors;
    Update(msg.sender);
  }

  /**
   * @notice Set your Glofile background colors
   * @dev Sets all the background colors.
   * @param colors array of RGB triplets
   */
  function setBackgroundColors(bytes3[] colors) {
    glofiles[msg.sender].backgroundColors = colors;
    Update(msg.sender);
  }

  /**
   * @notice Get Glofile colors
   * @dev Gets the foreground and background colors
   * @param account Glofile to access
   * @return foregroundColors array of RGB triplets of foreground colors
   * @return backgroundColors array of RGB triplets of background colors
   */
  function getColors(address account) constant returns (bytes3[] foregroundColors, bytes3[] backgroundColors) {
    Glofile glofile = glofiles[account];
    foregroundColors = glofile.foregroundColors;
    backgroundColors = glofile.backgroundColors;
  }

  /**
   * @notice Set your Glofile bio with langauge code `lang`
   * @dev Sets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param translation UTF-8 Markdown of bio compressed with DEFLATE - max Markdown length 256 chars
   */
  function setBio(bytes3 lang, bytes translation) {
    Glofile glofile = glofiles[msg.sender];
    // Check if we already have the language code.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        break;
      }
    }
    if (i == glofile.bioLangs.length) {
      // We didn't find it. Try to find a free slot.
      for (i = 0; i < glofile.bioLangs.length; i++) {
        if (glofile.bioLangs[i] == 0) {
          break;
        }
      }
      if (i == glofile.bioLangs.length) {
        // We didn't find a free slot. Make the array bigger.
        glofile.bioLangs.length++;
      }
      glofile.bioLangs[i] = lang;
    }
    // Set translation.
    glofile.bioTranslations[lang] = translation;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile bio with language code `lang`
   * @dev Deletes a bio translation.
   * @param lang 3 letter ISO 639-3 language code
   */
  function deleteBio(bytes3 lang) {
    Glofile glofile = glofiles[msg.sender];
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        delete glofile.bioLangs[i];
        break;
      }
    }
    // Delete the actual mapping in case a client accesses without checking
    // language key.
    delete glofile.bioTranslations[lang];
    Update(msg.sender);
  }

  /**
   * @notice Delete all of your Glofile bio translations
   * @dev Deletes all of the bio translations.
   */
  function deleteAllBioTranslations() {
    Glofile glofile = glofiles[msg.sender];
    // Delete the actual mappings in case a client accesses without checking
    // language key.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      delete glofile.bioTranslations[glofile.bioLangs[i]];
    }
    delete glofile.bioLangs;
    Update(msg.sender);
  }

  /**
   * @notice Get the list of language code a Glofile bio is available in
   * @dev Gets the list of language codes the bio is available in.
   * @param account Glofile to access
   * @return array of 3 letter ISO 639-3 language codes
   */
  function getBioLangCodes(address account) constant returns (bytes3[]) {
    return glofiles[account].bioLangs;
  }

  /**
   * @notice Get the Glofile bio with language code `lang`
   * @dev Gets the bio in a specific language.
   * @param account Glofile to access
   * @param lang 3 letter ISO 639-3 language code
   * @return UTF-8 Markdown of bio compressed with DEFLATE
   */
  function getBioTranslation(address account, bytes3 lang) constant returns (bytes) {
    return glofiles[account].bioTranslations[lang];
  }

  /**
   * @notice Set your Glofile avatar with index `i` to `ipfsHash`
   * @dev Sets the avatar with a specific index to an IPFS hash.
   * @param i index of avatar to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setAvatar(uint i, bytes ipfsHash) {
    bytes[] avatars = glofiles[msg.sender].avatars;
    // Make sure the array is long enough.
    if (avatars.length <= i) {
      avatars.length = i + 1;
    }
    avatars[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile avatar with index `i`
   * @dev Deletes an avatar with a specific index.
   * @param i index of avatar to delete
   */
  function deleteAvatar(uint i) {
    delete glofiles[msg.sender].avatars[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile avatars
   * @dev Deletes all avatars from the Glofile.
   */
  function deleteAllAvatars() {
    delete glofiles[msg.sender].avatars;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile avatars
   * @dev Gets the number of avatars.
   * @param account Glofile to access
   * @return number of avatars
   */
  function getAvatarCount(address account) constant returns (uint) {
    return glofiles[account].avatars.length;
  }

  /**
   * @notice Get the Glofile avatar with index `i`
   * @dev Gets the avatar with a specific index.
   * @param account Glofile to access
   * @param i index of avatar to get
   * @return binary IPFS hash of image
   */
  function getAvatar(address account, uint i) constant returns (bytes) {
    return glofiles[account].avatars[i];
  }

  /**
   * @notice Set your Glofile cover image with index `i` to `ipfsHash`
   * @dev Sets the cover image with a specific index to an IPFS hash.
   * @param i index of cover image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setCoverImage(uint i, bytes ipfsHash) {
    bytes[] coverImages = glofiles[msg.sender].coverImages;
    // Make sure the array is long enough.
    if (coverImages.length <= i) {
      coverImages.length = i + 1;
    }
    coverImages[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile cover image with index `i`
   * @dev Deletes the cover image with a specific index.
   * @param i index of cover image to delete
   */
  function deleteCoverImage(uint i) {
    delete glofiles[msg.sender].coverImages[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile cover images
   * @dev Deletes all cover images from the Glofile.
   */
  function deleteAllCoverImages() {
    delete glofiles[msg.sender].coverImages;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile cover images
   * @dev Gets the number of cover images.
   * @param account Glofile to access
   * @return number of cover images
   */
  function getCoverImageCount(address account) constant returns (uint) {
    return glofiles[account].coverImages.length;
  }

  /**
   * @notice Get the Glofile cover image with index `i`
   * @dev Gets the cover image with a specific index.
   * @param account Glofile to access
   * @param i index of cover image to get
   * @return binary IPFS hash of image
   */
  function getCoverImage(address account, uint i) constant returns (bytes) {
    return glofiles[account].coverImages[i];
  }

  /**
   * @notice Set your Glofile background image with index `i` to `ipfsHash`
   * @dev Sets the background image with a specific index to an IPFS hash.
   * @param i index of background image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setBackgroundImage(uint i, bytes ipfsHash) {
    bytes[] backgroundImages = glofiles[msg.sender].backgroundImages;
    // Make sure the array is long enough.
    if (backgroundImages.length <= i) {
      backgroundImages.length = i + 1;
    }
    backgroundImages[i] = ipfsHash;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile background image with index `i`
   * @dev Deletes the background image with a specific index.
   * @param i index of background image to delete
   */
  function deleteBackgroundImage(uint i) {
    delete glofiles[msg.sender].backgroundImages[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile background images
   * @dev Deletes all the background images.
   */
  function deleteAllBackgroundImages() {
    delete glofiles[msg.sender].backgroundImages;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile background images
   * @dev Gets the number of background images.
   * @param account Glofile to access
   * @return number of background images
   */
  function getBackgroundImageCount(address account) constant returns (uint) {
    return glofiles[account].backgroundImages.length;
  }

  /**
   * @notice Get the Glofile background image with index `i`
   * @dev Gets the background image with a specific index.
   * @param i index of cover image to get
   * @param account Glofile to access
   * @return binary IPFS hash of image
   */
  function getBackgroundImage(address account, uint i) constant returns (bytes) {
    return glofiles[account].backgroundImages[i];
  }

  /**
   * @notice Set your Glofile topic with index `i` to `topic`
   * @dev Sets the topic with a specific index.
   * @param i index of topic to set
   * @param topic UTF-8 string of topic (no whitespace)
   */
  function setTopic(uint i, string topic) {
    string[] topics = glofiles[msg.sender].topics;
    // Make sure the array is long enough.
    if (topics.length <= i) {
      topics.length = i + 1;
    }
    topics[i] = topic;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile topic with index `i`
   * @dev Deletes an topic with a specific index.
   * @param i index of topic to delete
   */
  function deleteTopic(uint i) {
    delete glofiles[msg.sender].topics[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile topics
   * @dev Deletes all topics from the Glofile.
   */
  function deleteAllTopics() {
    delete glofiles[msg.sender].topics;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile topics
   * @dev Gets the number of topics.
   * @param account Glofile to access
   * @return number of topics
   */
  function getTopicCount(address account) constant returns (uint) {
    return glofiles[account].topics.length;
  }

  /**
   * @notice Get the Glofile topic with index `i`
   * @dev Gets the topic with a specific index.
   * @param account Glofile to access
   * @param i index of topic to get
   * @return UTF-8 string of topic
   */
  function getTopic(address account, uint i) constant returns (string) {
    return glofiles[account].topics[i];
  }

  /**
   * @notice Set your Glofile parent with index `i` to `parent`
   * @dev Sets the parent with a specific index.
   * @param i index of parent to set
   * @param parent UTF-8 string of parent
   */
  function setParent(uint i, string parent) {
    string[] parents = glofiles[msg.sender].parents;
    // Make sure the array is long enough.
    if (parents.length <= i) {
      parents.length = i + 1;
    }
    parents[i] = parent;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile parent with index `i`
   * @dev Deletes an parent with a specific index.
   * @param i index of parent to delete
   */
  function deleteParent(uint i) {
    delete glofiles[msg.sender].parents[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile parents
   * @dev Deletes all parents from the Glofile.
   */
  function deleteAllParents() {
    delete glofiles[msg.sender].parents;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile parents
   * @dev Gets the number of parents.
   * @param account Glofile to access
   * @return number of parents
   */
  function getParentCount(address account) constant returns (uint) {
    return glofiles[account].parents.length;
  }

  /**
   * @notice Get the Glofile parent with index `i`
   * @dev Gets the parent with a specific index.
   * @param account Glofile to access
   * @param i index of parent to get
   * @return UTF-8 string of parent
   */
  function getParent(address account, uint i) constant returns (string) {
    return glofiles[account].parents[i];
  }

  /**
   * @notice Set your Glofile child with index `i` to `child`
   * @dev Sets the child with a specific index.
   * @param i index of child to set
   * @param child UTF-8 string of child
   */
  function setChild(uint i, string child) {
    string[] children = glofiles[msg.sender].children;
    // Make sure the array is long enough.
    if (children.length <= i) {
      children.length = i + 1;
    }
    children[i] = child;
    Update(msg.sender);
  }

  /**
   * @notice Delete your Glofile child with index `i`
   * @dev Deletes an child with a specific index.
   * @param i index of child to delete
   */
  function deleteChild(uint i) {
    delete glofiles[msg.sender].children[i];
    Update(msg.sender);
  }

  /**
   * @notice Delete all your Glofile children
   * @dev Deletes all children from the Glofile.
   */
  function deleteAllChildren() {
    delete glofiles[msg.sender].children;
    Update(msg.sender);
  }

  /**
   * @notice Get the number of Glofile children
   * @dev Gets the number of children.
   * @param account Glofile to access
   * @return number of children
   */
  function getChildCount(address account) constant returns (uint) {
    return glofiles[account].children.length;
  }

  /**
   * @notice Get the Glofile child with index `i`
   * @dev Gets the child with a specific index.
   * @param account Glofile to access
   * @param i index of child to get
   * @return UTF-8 string of child
   */
  function getChild(address account, uint i) constant returns (string) {
    return glofiles[account].children[i];
  }

  /**
   * @notice Add a public key to your Glofile
   * @dev Adds a public key.
   * @param publicKey UTF-8 public key compressed with DEFLATE
   */
  function addPublicKey(bytes publicKey) {
    uint i = glofiles[msg.sender].publicKeyCount++;
    PublicKeyAdd(msg.sender, i, publicKey);
  }

  /**
   * @notice Delete the public key with index `i` from your Glofile
   * @dev Deletes the public key with a specific index.
   * @param i index of public key to delete
   */
  function deletePublicKey(uint i) {
    PublicKeyDelete(msg.sender, i);
  }

  /**
   * @notice Copy entire Glofile from `source`
   * @dev Copies the Glofile from another account to this one.
   * @param source account of Glofile to copy from
   * TODO: check this works
   */
  function copyEntireGlofile(address source) {
    glofiles[msg.sender] = glofiles[source];
    Update(msg.sender);
  }

  /**
   * @notice Delete your entire Glofile
   * @dev Deletes the Glofile completely.
   * TODO: make sure this deletes everything
   */
  function deleteEntireGlofile() {
    delete glofiles[msg.sender];
    Delete(msg.sender);
  }

}


Contrato IdentityManager

Contrato IdentityManager


Optimizations

Optimizations

contract DateTime {
        /*
         *  Date and Time utilities for ethereum contracts
         *
         *  address: 0x1a6184cd4c5bea62b0116de7962ee7315b7bcbce
         */
        struct DateTime {
                uint16 year;
                uint8 month;
                uint8 day;
                uint8 hour;
                uint8 minute;
                uint8 second;
                uint8 weekday;
        }

        uint constant DAY_IN_SECONDS = 86400;
        uint constant YEAR_IN_SECONDS = 31536000;
        uint constant LEAP_YEAR_IN_SECONDS = 31622400;

        uint constant HOUR_IN_SECONDS = 3600;
        uint constant MINUTE_IN_SECONDS = 60;

        uint16 constant ORIGIN_YEAR = 1970;

        function isLeapYear(uint16 year) constant returns (bool) {
                if (year % 4 != 0) {
                        return false;
                }
                if (year % 100 != 0) {
                        return true;
                }
                if (year % 400 != 0) {
                        return false;
                }
                return true;
        }

        function leapYearsBefore(uint year) constant returns (uint) {
                year -= 1;
                return year / 4 - year / 100 + year / 400;
        }

        function getDaysInMonth(uint8 month, uint16 year) constant returns (uint8) {
                if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
                        return 31;
                }
                else if (month == 4 || month == 6 || month == 9 || month == 11) {
                        return 30;
                }
                else if (isLeapYear(year)) {
                        return 29;
                }
                else {
                        return 28;
                }
        }

        function parseTimestamp(uint timestamp) internal returns (DateTime dt) {
                uint secondsAccountedFor = 0;
                uint buf;
                uint8 i;

                dt.year = ORIGIN_YEAR;

                // Year
                dt.year = getYear(timestamp);
                buf = leapYearsBefore(dt.year) - leapYearsBefore(ORIGIN_YEAR);

                secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf;
                secondsAccountedFor += YEAR_IN_SECONDS * (dt.year - ORIGIN_YEAR - buf);

                // Month
                uint secondsInMonth;
                for (i = 1; i <= 12; i++) {
                        secondsInMonth = DAY_IN_SECONDS * getDaysInMonth(i, dt.year);
                        if (secondsInMonth + secondsAccountedFor > timestamp) {
                                dt.month = i + 1;
                                break;
                        }
                        secondsAccountedFor += secondsInMonth;
                }

                // Day
                for (i = 1; i < getDaysInMonth(dt.month, dt.year); i++) {
                        if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.day = i + 1;
                                break;
                        }
                        secondsAccountedFor += DAY_IN_SECONDS;
                }

                // Hour
                dt.hour = getHour(timestamp);

                // Minute
                dt.minute = getMinute(timestamp);

                // Second
                dt.second = getSecond(timestamp);

                // Day of week.
                dt.weekday = getWeekday(timestamp);
        }

        function getYear(uint timestamp) constant returns (uint16) {
                uint secondsAccountedFor = 0;
                uint16 year;
                uint numLeapYears;

                // Year
                year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS);
                numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR);

                secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears;
                secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears);

                while (secondsAccountedFor > timestamp) {
                        if (isLeapYear(uint16(year - 1))) {
                                secondsAccountedFor -= LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                secondsAccountedFor -= YEAR_IN_SECONDS;
                        }
                        year -= 1;
                }
                return year;
        }

        function getMonth(uint timestamp) constant returns (uint8) {
                return parseTimestamp(timestamp).month;
        }

        function getDay(uint timestamp) constant returns (uint8) {
                return parseTimestamp(timestamp).day;
        }

        function getHour(uint timestamp) constant returns (uint8) {
                return uint8((timestamp / 60 / 60) % 24);
        }

        function getMinute(uint timestamp) constant returns (uint8) {
                return uint8((timestamp / 60) % 60);
        }

        function getSecond(uint timestamp) constant returns (uint8) {
                return uint8(timestamp % 60);
        }

        function getWeekday(uint timestamp) constant returns (uint8) {
                return uint8((timestamp / DAY_IN_SECONDS + 3) % 7);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, 0, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, minute, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) constant returns (uint timestamp) {
                uint16 i;

                // Year
                for (i = ORIGIN_YEAR; i < year; i++) {
                        if (isLeapYear(i)) {
                                timestamp += LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                timestamp += YEAR_IN_SECONDS;
                        }
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                for (i = 1; i < month; i++) {
                        timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1];
                }

                // Day
                timestamp += DAY_IN_SECONDS * (day - 1);

                // Hour
                timestamp += HOUR_IN_SECONDS * (hour);

                // Minute
                timestamp += MINUTE_IN_SECONDS * (minute);

                // Second
                timestamp += second;

                return timestamp;
        }

        function __throw() {
                uint[] arst;
                arst[1];
        }
}

contract DateTime {
        /*
         *  Date and Time utilities for ethereum contracts
         *
         *  address: 0x1a6184cd4c5bea62b0116de7962ee7315b7bcbce
         */
        struct DateTime {
                uint16 year;
                uint8 month;
                uint8 day;
                uint8 hour;
                uint8 minute;
                uint8 second;
                uint8 weekday;
        }

        uint constant DAY_IN_SECONDS = 86400;
        uint constant YEAR_IN_SECONDS = 31536000;
        uint constant LEAP_YEAR_IN_SECONDS = 31622400;

        uint constant HOUR_IN_SECONDS = 3600;
        uint constant MINUTE_IN_SECONDS = 60;

        uint16 constant ORIGIN_YEAR = 1970;

        function isLeapYear(uint16 year) constant returns (bool) {
                if (year % 4 != 0) {
                        return false;
                }
                if (year % 100 != 0) {
                        return true;
                }
                if (year % 400 != 0) {
                        return false;
                }
                return true;
        }

        function leapYearsBefore(uint year) constant returns (uint) {
                year -= 1;
                return year / 4 - year / 100 + year / 400;
        }

        function parseTimestamp(uint timestamp) internal returns (DateTime dt) {
                uint secondsAccountedFor = 0;
                uint buf;
                uint8 i;

                dt.year = ORIGIN_YEAR;

                // Year
                dt.year = getYear(timestamp);
                buf = leapYearsBefore(dt.year) - leapYearsBefore(ORIGIN_YEAR);

                secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf;
                secondsAccountedFor += YEAR_IN_SECONDS * (dt.year - ORIGIN_YEAR - buf);

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(dt.year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                uint secondsInMonth;
                for (i = 0; i < monthDayCounts.length; i++) {
                        secondsInMonth = DAY_IN_SECONDS * monthDayCounts[i];
                        if (secondsInMonth + secondsAccountedFor > timestamp) {
                                dt.month = i + 1;
                                break;
                        }
                        secondsAccountedFor += secondsInMonth;
                }

                // Day
                for (i = 0; i < monthDayCounts[dt.month - 1]; i++) {
                        if (DAY_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.day = i + 1;
                                break;
                        }
                        secondsAccountedFor += DAY_IN_SECONDS;
                }

                // Hour
                for (i = 0; i < 24; i++) {
                        if (HOUR_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.hour = i;
                                break;
                        }
                        secondsAccountedFor += HOUR_IN_SECONDS;
                }

                // Minute
                for (i = 0; i < 60; i++) {
                        if (MINUTE_IN_SECONDS + secondsAccountedFor > timestamp) {
                                dt.minute = i;
                                break;
                        }
                        secondsAccountedFor += MINUTE_IN_SECONDS;
                }

                if (timestamp - secondsAccountedFor > 60) {
                        __throw();
                }

                // Second
                dt.second = uint8(timestamp - secondsAccountedFor);

                // Day of week.
                buf = timestamp / DAY_IN_SECONDS;
                dt.weekday = uint8((buf + 3) % 7);
        }

        function getYear(uint timestamp) constant returns (uint16) {
                uint secondsAccountedFor = 0;
                uint16 year;
                uint numLeapYears;

                // Year
                year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS);
                numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR);

                secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears;
                secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears);

                while (secondsAccountedFor > timestamp) {
                        if (isLeapYear(uint16(year - 1))) {
                                secondsAccountedFor -= LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                secondsAccountedFor -= YEAR_IN_SECONDS;
                        }
                        year -= 1;
                }
                return year;
        }

        function getMonth(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).month;
        }

        function getDay(uint timestamp) constant returns (uint16) {
                return parseTimestamp(timestamp).day;
        }

        function getHour(uint timestamp) constant returns (uint16) {
                return uint16((timestamp / 60 / 60) % 24);
        }

        function getMinute(uint timestamp) constant returns (uint16) {
                return uint16((timestamp / 60) % 60);
        }

        function getSecond(uint timestamp) constant returns (uint16) {
                return uint16(timestamp % 60);
        }

        function getWeekday(uint timestamp) constant returns (uint8) {
                return uint8((timestamp / DAY_IN_SECONDS + 3) % 7);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, 0, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, 0, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) constant returns (uint timestamp) {
                return toTimestamp(year, month, day, hour, minute, 0);
        }

        function toTimestamp(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second) constant returns (uint timestamp) {
                uint16 i;

                // Year
                for (i = ORIGIN_YEAR; i < year; i++) {
                        if (isLeapYear(i)) {
                                timestamp += LEAP_YEAR_IN_SECONDS;
                        }
                        else {
                                timestamp += YEAR_IN_SECONDS;
                        }
                }

                // Month
                uint8[12] monthDayCounts;
                monthDayCounts[0] = 31;
                if (isLeapYear(year)) {
                        monthDayCounts[1] = 29;
                }
                else {
                        monthDayCounts[1] = 28;
                }
                monthDayCounts[2] = 31;
                monthDayCounts[3] = 30;
                monthDayCounts[4] = 31;
                monthDayCounts[5] = 30;
                monthDayCounts[6] = 31;
                monthDayCounts[7] = 31;
                monthDayCounts[8] = 30;
                monthDayCounts[9] = 31;
                monthDayCounts[10] = 30;
                monthDayCounts[11] = 31;

                for (i = 1; i < month; i++) {
                        timestamp += DAY_IN_SECONDS * monthDayCounts[i - 1];
                }

                // Day
                timestamp += DAY_IN_SECONDS * (day - 1);

                // Hour
                timestamp += HOUR_IN_SECONDS * (hour);

                // Minute
                timestamp += MINUTE_IN_SECONDS * (minute);

                // Second
                timestamp += second;

                return timestamp;
        }

        function __throw() {
                uint[] arst;
                arst[1];
        }
}


deliberate error to test travis

deliberate error to test travis

DELIBERATE_ERROR
/// Partnership
/// Requires all pre-defined partners agreement on transactions and operations.
contract Partnership
{
	event Funded();
	event Deposit(address _from, uint _value);
	event TransactionProposed(bytes32 _id, address _initiator, string _description);
	event TransactionPassed(bytes32 _id, address _finalSigner, string _description);
	event TransactionSent(bytes32 _transaction, address _executor, string _description);
	event Withdrawal(address _partner, uint _amount);

	/// Price in wei of each equal share of the partnership
	uint public sharePrice;

	/// Flag indicating whether or not all partners have paid for their share
	bool public funded;

	/// Array of partner addresses
	address [] public partners;

	/// Collection of partner records
	mapping(address => Partner) public partnerRecords;

	/// Count of partners
	uint public partnerCount;

	/// Count of partners who have paid for their share
	uint public paidPartnerCount;

	/// Collection of pending transactions (ie send X ETH to Y with Z data)
	mapping(bytes32 => Transaction) public transactions;

	struct Partner {
		/// Flag indicating that this record has been initialized
		bool isPartner;
		/// Flag indicating that the partner has paid for their share
		bool paid;
		/// Total amount loaned to the partnership by the partner
		uint loanBalance;
		/// Amount released for withdrawal by the partner
		uint withdrawableAmount;
	}

	struct Transaction {
		/// Flag indicating that this record has been initialized
		bool valid;
		/// Proposed recipient for the transaction (0 indicates a new contract will be created)
		address to;
		/// Proposed amount to send (0 indicates no wei)
		uint value;
		/// Optional array of data to send with the transaction
		bytes data;
		/// Optional description of proposed transaction
		string description;
		/// Account that created the transaction
		address creator;
		/// Total number of partners that have confirmed/voted
		uint voteCount;
		/// Collection of partners that have confirmed/voted
		mapping(address => uint) votes;
		/// Flag indicating that all partners have confirmed
		bool passed;
		/// Flag indicatint that the transaction has been sent
		bool sent;
	}

	modifier onlyFunded {
		if (!funded)
	       		throw;
		_
	}

	modifier onlyPartner {
		if (!isPartner(msg.sender))
			throw;
		_
	}

	modifier onlyDao {
		if (msg.sender != address(this))
			throw;
		_
	}

	function Partnership(address[] _partners, uint _sharePrice) {
		funded = false;
		partners = _partners;
		sharePrice = _sharePrice;
		for (uint i = 0; i < _partners.length; i++) {
			partnerRecords[_partners[i]].isPartner = true;
		}
		partnerCount = _partners.length;
		paidPartnerCount = 0;
	}

	/// This executes when funds are sent to the contract
	function() {
		if (msg.value > 0) {
			if (funded) {
				if (isPartner(msg.sender)) {
					partnerRecords[msg.sender].loanBalance += msg.value;
				}
			}
			else {
				if (isPartner(msg.sender)) {
					if (partnerRecords[msg.sender].paid) {
						throw;
					}
					else {
						if (msg.value == sharePrice) {
							partnerRecords[msg.sender].paid = true;
							paidPartnerCount = paidPartnerCount + 1;
							if (paidPartnerCount == partnerCount) {
								funded = true;
								Funded();
							}
						}
						else {
							throw;
						}
					}
				}
				else {
					throw;
				}
			}
			Deposit(msg.sender, msg.value);
		}
	}

	/// Adds a proposed transaction to be confirmed by other partners
	function proposeTransaction(address _to, uint _value, bytes _data, string _description) onlyFunded onlyPartner external returns (bytes32) {

		// generate hash for easy specification in confirm and execute
		bytes32 id = sha3(msg.data, block.number);

		// grab the presumably blank transaction
		var transaction = transactions[id];

		transaction.valid = true;
		transaction.to = _to;
		transaction.value = _value;
		transaction.data = _data;
		transaction.description = _description;
		transaction.creator = msg.sender;
		transaction.voteCount = 1;
		transaction.votes[msg.sender] = 1;
		transaction.passed = false;
		transaction.sent = false;

		TransactionProposed(id, msg.sender, _description);

		return id;
	}

	/// Confirms an existing proposed transaction
	function confirmTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ensure this is a transaction we've set up
		if (!transaction.valid)
			throw;

		// ignore second confirmation
		if (transaction.votes[msg.sender] == 1)
			throw;

		// register the vote
		transaction.voteCount += 1;
		transaction.votes[msg.sender] = 1;

		if (transaction.voteCount == partnerCount) {
			transaction.passed = true;
			TransactionPassed(_id, msg.sender, transaction.description);
		}
	}

	/// Executes a passed transaction
	function executeTransaction(bytes32 _id) onlyFunded onlyPartner external {

		var transaction = transactions[_id];

		// ignore transactions that have not passed yet
		if (!transaction.passed)
			throw;

		// ignore transactions that have already been sent
		if (transaction.sent)
			throw;

		// register the sent transaction
		transaction.sent = true;

		// send the transaction
		if (transactions[_id].to.call.value(transactions[_id].value)(transactions[_id].data)) {

			TransactionSent(_id, msg.sender, transaction.description);

			// clear the transaction structure to free memory
			delete transactions[_id];
		}
		else {
			// roll back if the call failed
			transaction.sent = false;
		}
	}

	/// Distribute ETH to a partner
	function distribute(address _partner, uint _amount) onlyDao external {

		// ignore invalid partners
		if (!isPartner(_partner))
			throw;

		partnerRecords[_partner].withdrawableAmount += _amount;
	}

	/// Distribute ETH evenly amongst all partners
	function distributeEvenly(uint _amount) onlyDao external {

		var payout = _amount / partnerCount;

		for (uint i = 0; i < partnerCount; i++) {
			partnerRecords[partners[i]].withdrawableAmount += payout;
		}
	}

	/// Mark down partner's loan and make it available for withdrawal
	function repayLoan(address _partner, uint _amount) onlyDao external {

		// ignore invalid partners
		if (!partnerRecords[_partner].isPartner)
			throw;

		// ignore invalid amounts
		if (_amount > partnerRecords[_partner].loanBalance)
			throw;

		partnerRecords[_partner].loanBalance -= _amount;
		partnerRecords[_partner].withdrawableAmount += _amount;
	}

	/// Allow partner to withdraw funds marked as withdrawable
	function withdraw(uint _amount) onlyFunded onlyPartner external {

		// ignore requests for more than the amount allowed
		if (_amount > partnerRecords[msg.sender].withdrawableAmount)
			throw;

		// ignore requests for more than the available balance
		if (_amount > this.balance)
			throw;

		// mark the withdrawal as successful
		partnerRecords[msg.sender].withdrawableAmount -= _amount;

		// send the wei
		if (msg.sender.send(_amount)) {
			Withdrawal(msg.sender, _amount);
		}
		else {
			// roll back if the send failed
			partnerRecords[msg.sender].withdrawableAmount += _amount;
		}
	}

	/// Dissolve DAO and send the remaining ETH to a beneficiary
	function dissolve(address _beneficiary) onlyDao external {

		// ignore unset beneficiary
		if (_beneficiary == 0)
			throw;

		// prevent lost balance
		if (_beneficiary == address(this))
		    throw;

		suicide(_beneficiary);
	}

	function isPartner(address _address) internal returns (bool) {
		return partnerRecords[_address].isPartner;
	}

}


Added missing done++ to reveal function

Added missing done++ to reveal function

pragma solidity ^0.4.0;

import "math.sol";
import "userRegistry.sol";
import "concept.sol";
import "user.sol";
import "conceptRegistry.sol";

contract Assessment
{
  address assessee; //The address of the user being assessed
  address[] assessors;
  address[] finalAssessors; //The assessors who actually give an assessment
  mapping (address => State) assessorState;
  enum State //The state of the assessors
  {
    Called, //Been called as a potential assessor
    Confirmed, //Confirmed as assessing
    Committed, //Committed a score
    Done, //Completed the assessment processs
    Burned //Entire stake has been burned
  }
  address[] assessorPool; //The addresses of the user's that the assessors are randomly selected from
  address concept;
  address userRegistry;
  address conceptRegistry;
  address math = 0x90B66E80448eb60938FAed4A738dE0D5b630B2Fd;
  uint public startTime;
  uint public size;
  uint cost;
  mapping(address => string[]) public data; //IFFS hashes of data that can be passed between the assessors and the assessee for the assessment to occur
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint done = 0;
  mapping(address => int8) scores; //could save gas by making this an int8
  mapping(int => bool) inRewardCluster;
  int finalScore;
  event DataSet(address _dataSetter, uint _index);

  /*
  @type: modifier
  @name: onlyThis
  @purpose: to only allow the this contract to call a function to which this modifier is applied
  */
  modifier onlyThis()
  {
    if(msg.sender != address(this)) //Checks if msg.sender is this contract
    {
      throw; //Throws out the function call if it isn't
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyAssessorAssessee
  @purpose: to only allow the assessors and assessee to call a function to which this modifier is applied
  */
  modifier onlyAssessorAssessee()
  {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) //Checks if msg.sender has the same address as either the assessee or an assessor
    {
      throw; //Throws the function call if not
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyConceptAssessment
  @purpose: to only allow the this contract or the Concept contract that spawned it to call a function to which this modifier is applied
  */
  modifier onlyConceptAssessment()
  {
    if(msg.sender != address(this) && msg.sender != concept) //Checks if msg.sender has the same address as this contract or the Concept that spawned it
    {
      throw; //Throws the function call if not
    }
    _;
  }

  modifier onlyConcept()
  {
    if(msg.sender != concept)
    {
      throw;
    }
    _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost)
  {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    startTime = block.timestamp;
    size = _size;
    cost = _cost;
    User(assessee).notification(concept, 0); //Assessment made
  }

  function cancelAssessment() onlyConceptAssessment()
  {
    Concept(concept).setBalance(assessee, UserRegistry(userRegistry).balances(assessee) + cost*size);
    User(assessee).notification(concept, 3); //Assessment Cancled and you have been refunded
    for(uint i = 0; i < assessors.length; i++)
    {
      Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + cost);
      User(assessors[i]).notification(concept, 3); //Assessment Cancled and you have been refunded
    }
    suicide(conceptRegistry);
  }

  function addAssessorToPool(address assessor) onlyConcept() returns(bool)
  {
    if(uint(assessorState[assessor]) == 0) //Checks if the called assessor hasn't already been called
    {
      User(assessor).notification(concept, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called; //Sets the state of the assessor as called
      return true;
    }
    else
    {
      return false; //Returns false if the assessor has already been called
    }
  }

  /*
  @type: function
  @purpose: To recursively set the pool to draw assessors from in the assessment
  @param: uint seed = the seed number for random number generation
  @returns: nothing
  */
  function setAssessorPool(uint seed) onlyConceptAssessment()
  {
    if(Concept(ConceptRegistry(conceptRegistry).mewAddress()).getOwnerLength() < size*20) //Checks if the requested pool size is greater than the number of users in the system
    {
      for(uint i = 0; i < Concept(ConceptRegistry(conceptRegistry).mewAddress()).getOwnerLength(); i++) //If so, all users in the system are added to the pool
      {
        address assessor = Concept(ConceptRegistry(conceptRegistry).mewAddress()).owners(i);
        assessorPool.push(assessor);
        User(assessor).notification(concept, 1); //Called As A Potential Assessor
        assessorState[assessor] = State.Called;
      }
    }
    else
    {
      Concept(concept).getAssessors(size*20, seed, address(this)); //If the requested pool size is smaller that the number of users in the system call function in concept to obtain assessors
    }
  }

  function confirmAssessor()
  {
    if(block.number - startTime <= 15 && assessorState[msg.sender] == State.Called && assessors.length < size && UserRegistry(userRegistry).balances(msg.sender) >= cost) //Check if the time to confirm has not passed, that the assessor was actually called, assessors are still needed, and that the assessor has enough of a balance to pay the stake
    {
      assessors.push(msg.sender); //Adds the user that called this function to the array of confirmed assessors
      assessorState[msg.sender] = State.Confirmed; //Sets the assessor's state to confirmed
      stake[msg.sender] = cost; //Sets the current stake value of the assessor to the cost of the assessment
      Concept(concept).setBalance(msg.sender,UserRegistry(userRegistry).balances(msg.sender) - cost); //Takes the stake from the assessor
      User(msg.sender).notification(concept, 2); //Confirmed for assessing, stake has been taken
    }
    if(assessors.length == size) //If enough assessors have been called
    {
      notifyStart(); //Assessors and the assessee are notified that the assessmentn has begun
    }
    else if(block.number - startTime > 15 && assessors.length < size)
    {
      cancelAssessment(); //Cancels the assessment if not enough assessors confirm within 15 blocks
    }
  }

  function notifyStart() onlyThis() //Sends a notification to the assessors and the assessee informing them that the assessment has begun
  {
    for(uint i = 0; i < assessors.length; i++)
    {
      User(assessors[i]).notification(concept, 4); //Assessment Has Started
    }
    User(assessee).notification(concept, 4); //Assessment Has Started
  }

  function setData(string _data) onlyAssessorAssessee() //Allows the assessors and the assessee to publically add data for the purposes of the assessment
  {
    data[msg.sender].push(_data); //Adds the data to an array corresponding to the user that uploaded it
    DataSet(msg.sender, data[msg.sender].length - 1); //Spawns an event that contains the address of the user who just uploaded data and the index number of this piece of data in their corresponding array
    //NOTE: The front end should aggregrate these events and use them to build a data browser of sorts in the assessment area
  }

  function commit(bytes32 hash) //Assessors should call this to commit a sha3 hash of their final score and a bytes16
  { //NOTE: The front end should automatically hash the assessors submitted score with a random bytes16 and submit it to this function
    if(done > size/2) //If more than half the assessors have committed their score hash
    {
      for(uint i = 0; i < assessors.length; i++) //Loops through all the assessors
      {
        if(assessorState[assessors[i]] == State.Confirmed) //Checks if the assessor has not committed  a score yet
        {
          uint r = 38; //Inverse burn rate
          stake[assessors[i]] = cost*2**(-(now-startTime)/r) - 1; //Sets their stake to a lower value based off of how long its been since the first half of the assessors committed
        }
        if(stake[assessors[i]] == 0) //If an assessor's stake is entirely burned
        {
          assessorState[assessors[i]] = State.Burned; //Sets the assessor's state to Burned
          done++; //Increases done by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) //If all the assessors have either committed or had their entire stake burned
    {
      for(uint j = 0; j < assessors.length; j++) //Loops through all assessors
      {
        if(assessorState[assessors[j]] == State.Committed) //Sends a notification to all the assessors that have committed to reveal their score
        {
          User(assessors[j]).notification(concept, 5); //Send in Score
          //NOTE: The front end should receive this notification and then automatically call the reveal function
        }
      }
      startTime = block.number; //Resets the startTime
      done = 0; //Resets the done counter
    }
    if(assessorState[msg.sender] == State.Confirmed) //If the user calling this function is confirmed as an assessor
    {
      commits[msg.sender] = hash; //Maps the score hash to the assessor
      assessorState[msg.sender] == State.Committed; //Sets the assessor's state to Committed
      done++; //Increases done by 1 to help progress to the next assessment stage.

      if(done <= size/2) //If less than or half the assessors have committed
      {
        startTime = block.number; //Sets the startTime to the current block
      }
    }
  }

  function reveal(int8 score, bytes16 salt, address assessor) //Assessors reveal the components of their hash (which are checked), assessors can reveal other assessors hash components to report them for cheating
  { //NOTE: This function should be automatically called from the front end
    if(block.number - startTime <= 10) //If less than 10 blocks have passed since the socre commiting stage ended
    {
      bytes32 hash = sha3(score,salt); //Hashes the provided components
      if(commits[assessor] == hash) //Checks if the newly created hash is the same ad the one that the assessor provided in the parameter previously provided
      {
        if(msg.sender == assessor) //If it was correct and submitted by the assessor in the parameter
        {
          scores[msg.sender] = score; //That score is mapped to the assessor
          assessorState[assessor] = State.Done; //The assessor's state is set to done
          done++; //done increases by 1 to help progress to the next assessment stage
        }
        else //If it was correct and submitted by a user other than the assessor in the parameter
        {
          Concept(concept).setBalance(msg.sender,UserRegistry(userRegistry).balances(msg.sender) + stake[assessor]); //The user that called this function gets the assessor's stake
          stake[assessor] = 0;
          assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
      else if(msg.sender == assessor) //If the stake was wrong and was provided by the assessor in the parameter
      {
        stake[assessor] = 0; //The assessor's stake is completely burned
        assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
        done++; //done increases by 1 to help progress to the next assessment stage
      }
    }
    else //If more than 10 blocks have passed
    {
      for(uint i = 0; i < assessors.length; i++) //Loops through all the assessors
      {
        if(assessorState[assessors[i]] == State.Committed) //If the assessor has not revealed their score
        {
          stake[assessors[i]] = 0; //The assessor's stake is completely burned
          assessorState[assessors[i]] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) //If all the assessors have revealed their scored or burned their stakes
    {
      calculateResult(); //The final result is calculated
    }
  }

  function calculateResult() onlyThis()
  {
    mapping(uint => int[]) clusters; //Initializes mapping to store clusters of scores
    for(uint j = 0; j < size; j++) //Loops through the assessors
    {
      if(assessorState[assessors[i]] == State.Done)
      {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //Initializes a uint to store the index of the largest cluster in the clusters mapping
    int averageScore; //Initializes an int to store the average score
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      score[i] = scores[finalAssessors[i]]; //Puts all the scores in the score array
    }
    int meanAbsoluteDeviation = Math(math).calculateMAD(score,int(finalAssessors.length)); //Caclulates the MAD of the scores
    for(uint l = 0; l < score.length; l++) //Find the largest cluster of scores
    {
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation)
        {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length)
      {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) //Records which assessors submitted a score that was in the largest cluster
    {
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length); //Calculates the average score from the largest cluster
    finalScore = averageScore; //Sets the final score to the average score
    payout(clusters[largestClusterIndex].length); //Initializes the payout sequence
  }

  function payout(uint largestSize) onlyThis()
  {
    for(uint i = 0; i < size; i++) //Loops through all the confirmed assessors
    {
      int score = scores[assessors[i]]; //Gets the score of an assessor
      int scoreDistance = ((score - finalScore)*100)/finalScore; //Calculates the percent difference between the final score the assessors score
      if(scoreDistance < 0) //Makes negative scoreDistances positive
      {
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) //If the assessor's score was in the largest cluster
      {
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = q*cost*((100 - uint(scoreDistance))/100); //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        User(assessors[i]).notification(concept, 15); //You Have Received Payment For Your Assessment
      }
      if(inRewardCluster[score] == false) //If the assessor's score wasn't in the largest cluster
      {
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        User(assessors[i]).notification(concept, 16); //You Have Received Some of Your Stake Back For Your Assessment
      }
    }
    Concept(concept).finishAssessment(finalScore, assessee, address(this));(); //Sends assessment info to the concept so that it can update its records
  }

}

pragma solidity ^0.4.0;

import "math.sol";
import "userRegistry.sol";
import "concept.sol";
import "user.sol";
import "conceptRegistry.sol";

contract Assessment
{
  address assessee; //The address of the user being assessed
  address[] assessors;
  address[] finalAssessors; //The assessors who actually give an assessment
  mapping (address => State) assessorState;
  enum State //The state of the assessors
  {
    Called, //Been called as a potential assessor
    Confirmed, //Confirmed as assessing
    Committed, //Committed a score
    Done, //Completed the assessment processs
    Burned //Entire stake has been burned
  }
  address[] assessorPool; //The addresses of the user's that the assessors are randomly selected from
  address concept;
  address userRegistry;
  address conceptRegistry;
  address math = 0x90B66E80448eb60938FAed4A738dE0D5b630B2Fd;
  uint public startTime;
  uint public size;
  uint cost;
  mapping(address => string[]) public data; //IFFS hashes of data that can be passed between the assessors and the assessee for the assessment to occur
  mapping(address => bytes32) commits;
  mapping(address => uint) stake;
  uint done = 0;
  mapping(address => int8) scores; //could save gas by making this an int8
  mapping(int => bool) inRewardCluster;
  int finalScore;
  event DataSet(address _dataSetter, uint _index);

  /*
  @type: modifier
  @name: onlyThis
  @purpose: to only allow the this contract to call a function to which this modifier is applied
  */
  modifier onlyThis()
  {
    if(msg.sender != address(this)) //Checks if msg.sender is this contract
    {
      throw; //Throws out the function call if it isn't
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyAssessorAssessee
  @purpose: to only allow the assessors and assessee to call a function to which this modifier is applied
  */
  modifier onlyAssessorAssessee()
  {
    if(msg.sender != assessee && uint(assessorState[msg.sender]) == 0) //Checks if msg.sender has the same address as either the assessee or an assessor
    {
      throw; //Throws the function call if not
    }
    _;
  }

  /*
  @type: modifier
  @name: onlyConceptAssessment
  @purpose: to only allow the this contract or the Concept contract that spawned it to call a function to which this modifier is applied
  */
  modifier onlyConceptAssessment()
  {
    if(msg.sender != address(this) && msg.sender != concept) //Checks if msg.sender has the same address as this contract or the Concept that spawned it
    {
      throw; //Throws the function call if not
    }
    _;
  }

  modifier onlyConcept()
  {
    if(msg.sender != concept)
    {
      throw;
    }
    _;
  }

  function Assessment(address _assessee, address _userRegistry, address _conceptRegistry, uint _size, uint _cost)
  {
    assessee = _assessee;
    concept = msg.sender;
    userRegistry = _userRegistry;
    conceptRegistry = _conceptRegistry;
    startTime = block.timestamp;
    size = _size;
    cost = _cost;
    User(assessee).notification(concept, 0); //Assessment made
  }

  function cancelAssessment() onlyConceptAssessment()
  {
    Concept(concept).setBalance(assessee, UserRegistry(userRegistry).balances(assessee) + cost*size);
    User(assessee).notification(concept, 3); //Assessment Cancled and you have been refunded
    for(uint i = 0; i < assessors.length; i++)
    {
      Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + cost);
      User(assessors[i]).notification(concept, 3); //Assessment Cancled and you have been refunded
    }
    suicide(conceptRegistry);
  }

  function addAssessorToPool(address assessor) onlyConcept() returns(bool)
  {
    if(uint(assessorState[assessor]) == 0) //Checks if the called assessor hasn't already been called
    {
      User(assessor).notification(concept, 1); //Called As A Potential Assessor
      assessorState[assessor] = State.Called; //Sets the state of the assessor as called
      return true;
    }
    else
    {
      return false; //Returns false if the assessor has already been called
    }
  }

  /*
  @type: function
  @purpose: To recursively set the pool to draw assessors from in the assessment
  @param: uint seed = the seed number for random number generation
  @returns: nothing
  */
  function setAssessorPool(uint seed) onlyConceptAssessment()
  {
    if(Concept(ConceptRegistry(conceptRegistry).mewAddress()).getOwnerLength() < size*20) //Checks if the requested pool size is greater than the number of users in the system
    {
      for(uint i = 0; i < Concept(ConceptRegistry(conceptRegistry).mewAddress()).getOwnerLength(); i++) //If so, all users in the system are added to the pool
      {
        address assessor = Concept(ConceptRegistry(conceptRegistry).mewAddress()).owners(i);
        assessorPool.push(assessor);
        User(assessor).notification(concept, 1); //Called As A Potential Assessor
        assessorState[assessor] = State.Called;
      }
    }
    else
    {
      Concept(concept).getAssessors(size*20, seed, address(this)); //If the requested pool size is smaller that the number of users in the system call function in concept to obtain assessors
    }
  }

  function confirmAssessor()
  {
    if(block.number - startTime <= 15 && assessorState[msg.sender] == State.Called && assessors.length < size && UserRegistry(userRegistry).balances(msg.sender) >= cost) //Check if the time to confirm has not passed, that the assessor was actually called, assessors are still needed, and that the assessor has enough of a balance to pay the stake
    {
      assessors.push(msg.sender); //Adds the user that called this function to the array of confirmed assessors
      assessorState[msg.sender] = State.Confirmed; //Sets the assessor's state to confirmed
      stake[msg.sender] = cost; //Sets the current stake value of the assessor to the cost of the assessment
      Concept(concept).setBalance(msg.sender,UserRegistry(userRegistry).balances(msg.sender) - cost); //Takes the stake from the assessor
      User(msg.sender).notification(concept, 2); //Confirmed for assessing, stake has been taken
    }
    if(assessors.length == size) //If enough assessors have been called
    {
      notifyStart(); //Assessors and the assessee are notified that the assessmentn has begun
    }
    else if(block.number - startTime > 15 && assessors.length < size)
    {
      cancelAssessment(); //Cancels the assessment if not enough assessors confirm within 15 blocks
    }
  }

  function notifyStart() onlyThis() //Sends a notification to the assessors and the assessee informing them that the assessment has begun
  {
    for(uint i = 0; i < assessors.length; i++)
    {
      User(assessors[i]).notification(concept, 4); //Assessment Has Started
    }
    User(assessee).notification(concept, 4); //Assessment Has Started
  }

  function setData(string _data) onlyAssessorAssessee() //Allows the assessors and the assessee to publically add data for the purposes of the assessment
  {
    data[msg.sender].push(_data); //Adds the data to an array corresponding to the user that uploaded it
    DataSet(msg.sender, data[msg.sender].length - 1); //Spawns an event that contains the address of the user who just uploaded data and the index number of this piece of data in their corresponding array
    //NOTE: The front end should aggregrate these events and use them to build a data browser of sorts in the assessment area
  }

  function commit(bytes32 hash) //Assessors should call this to commit a sha3 hash of their final score and a bytes16
  { //NOTE: The front end should automatically hash the assessors submitted score with a random bytes16 and submit it to this function
    if(done > size/2) //If more than half the assessors have committed their score hash
    {
      for(uint i = 0; i < assessors.length; i++) //Loops through all the assessors
      {
        if(assessorState[assessors[i]] == State.Confirmed) //Checks if the assessor has not committed  a score yet
        {
          uint r = 38; //Inverse burn rate
          stake[assessors[i]] = cost*2**(-(now-startTime)/r) - 1; //Sets their stake to a lower value based off of how long its been since the first half of the assessors committed
        }
        if(stake[assessors[i]] == 0) //If an assessor's stake is entirely burned
        {
          assessorState[assessors[i]] = State.Burned; //Sets the assessor's state to Burned
          done++; //Increases done by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) //If all the assessors have either committed or had their entire stake burned
    {
      for(uint j = 0; j < assessors.length; j++) //Loops through all assessors
      {
        if(assessorState[assessors[j]] == State.Committed) //Sends a notification to all the assessors that have committed to reveal their score
        {
          User(assessors[j]).notification(concept, 5); //Send in Score
          //NOTE: The front end should receive this notification and then automatically call the reveal function
        }
      }
      startTime = block.number; //Resets the startTime
      done = 0; //Resets the done counter
    }
    if(assessorState[msg.sender] == State.Confirmed) //If the user calling this function is confirmed as an assessor
    {
      commits[msg.sender] = hash; //Maps the score hash to the assessor
      assessorState[msg.sender] == State.Committed; //Sets the assessor's state to Committed
      done++; //Increases done by 1 to help progress to the next assessment stage.

      if(done <= size/2) //If less than or half the assessors have committed
      {
        startTime = block.number; //Sets the startTime to the current block
      }
    }
  }

  function reveal(int8 score, bytes16 salt, address assessor) //Assessors reveal the components of their hash (which are checked), assessors can reveal other assessors hash components to report them for cheating
  { //NOTE: This function should be automatically called from the front end
    if(block.number - startTime <= 10) //If less than 10 blocks have passed since the socre commiting stage ended
    {
      bytes32 hash = sha3(score,salt); //Hashes the provided components
      if(commits[assessor] == hash) //Checks if the newly created hash is the same ad the one that the assessor provided in the parameter previously provided
      {
        if(msg.sender == assessor) //If it was correct and submitted by the assessor in the parameter
        {
          scores[msg.sender] = score; //That score is mapped to the assessor
          assessorState[assessor] = State.Done; //The assessor's state is set to done
          done++; //done increases by 1 to help progress to the next assessment stage
        }
        else //If it was correct and submitted by a user other than the assessor in the parameter
        {
          Concept(concept).setBalance(msg.sender,UserRegistry(userRegistry).balances(msg.sender) + stake[assessor]); //The user that called this function gets the assessor's stake
          stake[assessor] = 0;
          assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
        }
      }
      else if(msg.sender == assessor) //If the stake was wrong and was provided by the assessor in the parameter
      {
        stake[assessor] = 0; //The assessor's stake is completely burned
        assessorState[assessor] = State.Burned; //The assessor's state is set to Burned
        done++; //done increases by 1 to help progress to the next assessment stage
      }
    }
    else //If more than 10 blocks have passed
    {
      for(uint i = 0; i < assessors.length; i++) //Loops through all the assessors
      {
        if(assessorState[assessors[i]] == State.Committed) //If the assessor has not revealed their score
        {
          stake[assessors[i]] = 0; //The assessor's stake is completely burned
          assessorState[assessors[i]] = State.Burned; //The assessor's state is set to Burned
          done++; //done increases by 1 to help progress to the next assessment stage
        }
      }
    }
    if(done == size) //If all the assessors have revealed their scored or burned their stakes
    {
      calculateResult(); //The final result is calculated
    }
  }

  function calculateResult() onlyThis()
  {
    mapping(uint => int[]) clusters; //Initializes mapping to store clusters of scores
    for(uint j = 0; j < size; j++) //Loops through the assessors
    {
      if(assessorState[assessors[i]] == State.Done)
      {
        finalAssessors.push(assessors[i]); //Adds all the assessors that completed the assessment process to an array
      }
    }
    int[] memory score = new int[] (finalAssessors.length); //Initializes an array to store scores that is the same length as the number of finalAssessors
    uint largestClusterIndex = 0; //Initializes a uint to store the index of the largest cluster in the clusters mapping
    int averageScore; //Initializes an int to store the average score
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      score[i] = scores[finalAssessors[i]]; //Puts all the scores in the score array
    }
    int meanAbsoluteDeviation = Math(math).calculateMAD(score,int(finalAssessors.length)); //Caclulates the MAD of the scores
    for(uint l = 0; l < score.length; l++) //Find the largest cluster of scores
    {
      for(uint m = 0; m < score.length; m++)
      {
        if(score[l] - score[m] <= meanAbsoluteDeviation)
        {
          clusters[l].push(score[m]);
        }
      }
      if(clusters[l].length > clusters[largestClusterIndex].length)
      {
        largestClusterIndex = l;
      }
    }
    for(uint o = 0; o < clusters[largestClusterIndex].length; o++) //Records which assessors submitted a score that was in the largest cluster
    {
      averageScore += clusters[largestClusterIndex][o];
      inRewardCluster[clusters[largestClusterIndex][o]] = true;
    }
    averageScore /= int(clusters[largestClusterIndex].length); //Calculates the average score from the largest cluster
    finalScore = averageScore; //Sets the final score to the average score
    payout(clusters[largestClusterIndex].length); //Initializes the payout sequence
  }

  function payout(uint largestSize) onlyThis()
  {
    for(uint i = 0; i < size; i++) //Loops through all the confirmed assessors
    {
      int score = scores[assessors[i]]; //Gets the score of an assessor
      int scoreDistance = ((score - finalScore)*100)/finalScore; //Calculates the percent difference between the final score the assessors score
      if(scoreDistance < 0) //Makes negative scoreDistances positive
      {
        scoreDistance *= -1;
      }
      uint payoutValue = 1; //Initializes the payoutValue for the assessor
      if(inRewardCluster[score] == true) //If the assessor's score was in the largest cluster
      {
        uint q = 1; //Inflation rate factor, WE NEED TO FIGURE THIS OUT AT SOME POINT
        payoutValue = q*cost*((100 - uint(scoreDistance))/100); //The assessor's payout will be some constant times a propotion of their original stake determined by how close to the final score they were
        Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        User(assessors[i]).notification(concept, 15); //You Have Received Payment For Your Assessment
      }
      if(inRewardCluster[score] == false) //If the assessor's score wasn't in the largest cluster
      {
        payoutValue = stake[assessors[i]]*((200 - uint(scoreDistance))/200); //The assessor's payout will be a propotion of their remaining stake determined by their distance from the final score
        Concept(concept).setBalance(assessors[i], UserRegistry(userRegistry).balances(assessors[i]) + payoutValue); //Pays the user
        User(assessors[i]).notification(concept, 16); //You Have Received Some of Your Stake Back For Your Assessment
      }
    }
    Concept(concept).finishAssessment(finalScore, assessee, address(this));(); //Sends assessment info to the concept so that it can update its records
  }

}