Started on the calculation function

Started on the calculation function

contract Master
{
  //Initialize master data store
  mapping (address => uint) tokenBalance;
  mapping (address => string) tagName;
  mapping (string => address) tagAddressFromName;
  mapping (address => address[]) achievements;
  mapping (address => bool) availability;
  mapping (address => address) users;

  event TagCreation
  ( string _tagName,
    address _tagAddress,
    address[] _parents);

  function Master()
  {
    tokenBalance[address(this)] = 1;
    address[] memory a;
    uint useless = addTag("account", a, "Initial Account Tag");
  }

  function mapTokenBalance(address user, uint balance)
  {
    if(tagAddressFromName[tagName[msg.sender]] == 0)
    {
      tokenBalance[user] = balance;
    }
  }
  function mapTagName(address tagAddress, string name)
  {
    tagName[tagAddress] = name;
  }
  function mapTagAddressFromName(string name, address tagAddress)
  {
    tagAddressFromName[name] = tagAddress;
  }
  function mapAchievement(address user, address achievment)
  {
    achievements[user].push(achievment);
  }
  function mapAvailability(address user, bool available)
  {
    availability[user] = available;
  }

  function getTokenBalance(address user) returns(uint)
  {
    return tokenBalance[user];
  }
  function getTagName(address tagAddress) returns(string)
  {
    return tagName[tagAddress];
  }
  function getTagAddressFromName(string name) returns(address)
  {
    return tagAddressFromName[name];
  }
  function getAchievement(address user) returns(address[])
  {
    return achievements[user];
  }
  function getNumberOfachievments(address user) returns(uint)
  {
    return achievements[user].length;
  }
  function getAvailability(address user) returns(bool)
  {
    return availability[user];
  }
 function getTagDescription(address tagAddress) returns(string)
  {
    return Tag(tagAddress).getDescription();
  }

  function addUser()
  {
    User newUser = new User(msg.sender, address(this));
    Tag(tagAddressFromName["account"]).startAssessment(address(newUser),5, 600);
  }

  function addTag(string name, address[] parentList, string description) returns(uint) //Creates a new tag contract
  {
    uint response = 0;
    address[] parents;
    if(tokenBalance[msg.sender] < 1)
    {
      response += 1;
    }
    if(tagAddressFromName[name] == 0)
    {
      response += 10;
    }
    if(response==0)
    {
      for(uint i=0; i<= parentList.length; i++) //adds all the given parents
      {
        if(parentList[i]==0)
        {
          response += 100*(10**i);
        }
        else
        {
          parents.push(parentList[i]);
        }
      }
      Tag newTag = new Tag(name, parents, address(this), description);
      address newTagAddress = address(newTag);
      tagName[newTagAddress] = name;
      tagAddressFromName[name] = newTagAddress;
      tokenBalance[msg.sender] -= 1;
      TagCreation(name, newTagAddress, parents);
    }
    return response;
  }
}

//Defines the meta-contract for a Tag
contract Tag
{
  address[] parentTags;
  address master;
  string name;
  string description;
  address[] owners; //Those who have earned the tag
  mapping(address => address[]) assessmentHistory; //All assessments completed
  mapping(address => uint) scores; //All positive assessements scores
  event CompletedAssessment
  ( address _assessee,
    bool _pass,
    uint _score,
    address _assessment);

  function Tag(string tagName, address[] parents, address masterAddress, string tagDescription)
  {
    name = tagName;
    parentTags = parents;
    master = masterAddress;
    description = tagDescription;
  }

  function getDescription() returns(string)
  {
    return description;
  }

  function getOwners() returns(address[])
  {
    return owners;
  }

  function getOwnerLength() returns(uint)
  {
    return owners.length;
  }

  function getOwner(uint index) returns(address)
  {
    return owners[index];
  }

  function getParents() returns(address[])
  {
    return parentTags;
  }

  function getParentsLength() returns(uint)
  {
    return parentTags.length;
  }

  function getParent(uint index) returns(address)
  {
      return parentTags[index];
  }

  function setAssessorPool(address tagAddress, address assessment)
  {
    for(uint i = 0; i < Tag(tagAddress).getOwnerLength() && Assessment(assessment).getAssessmentPoolSize() != 0; i++)
    {
      if(Assessment(assessment).getAssessorPoolLength() < Tag(tagAddress).getOwnerLength()/10)
      {
        address random = Tag(tagAddress).getOwner(getRandom(Tag(tagAddress).getOwnerLength()-1));
        if(Master(master).getAvailability(random) == true)
        {
          Assessment(assessment).addToAssessorPool(random);
          Assessment(assessment).setAssessmentPoolSize(Assessment(assessment).getAssessmentPoolSize() -1);
        }
      }
      else
      {
        for(uint j = 0; j < Tag(tagAddress).getParentsLength(); j++)
        {
          setAssessorPool(Tag(tagAddress).getParent(j), assessment);
        }
      }
      if(Assessment(assessment).getAssessmentPoolSize() <= 0)
      {
        Assessment(assessment).setPotentialAssessor();
      }
    }
  }

  function startAssessment(address assessee, uint size, uint timeForSettingTask)
  {
    Assessment newAssessment = new Assessment(assessee, address(this), master, timeForSettingTask);
    newAssessment.setNumberOfAssessors(size);
    newAssessment.setAssessmentPoolSize(size*20);
    setAssessorPool(address(this), address(newAssessment));
  }

  function finishAssessment(bool pass, uint score, address assessee, address assessment)
  {
    if(pass == true)
    {
      owners.push(assessee);
      scores[assessee] = score;
      Master(master).mapAchievement(assessee,address(this));
    }
    if(pass == false && address(this) == Master(master).getTagAddressFromName("account"))
    {
      User(assessee).remove();
    }
    assessmentHistory[assessee].push(assessment);
    CompletedAssessment(assessee, pass, score, assessment);
  }
  function getRandom(uint i) returns(uint)
  {
    return 12;
  }
}

//Defines the meta-contract for an assessment
contract Assessment
{
  address assessee; //We need a better word for this
  address[] assessorPool;
  mapping (address => uint) assessors;
  address[] finalAssessors;
  address tag;
  address master;
  uint poolSizeRemaining;
  uint numberOfAssessors;
  mapping(address => string) assessmentTasks; //Given by the assessors as IPFS hashes
  mapping(address => string) assessmentResponses; //Given by the assessee as IPFS hashes
  mapping(address => int) assessmentResults; //Pass/Fail and Score given by assessors
  mapping(int => address) addressFromScore;
  address currentAssessor;
  uint finalScore;
  bool finalResult;
  uint taskCreationTime;
  uint taskCompletionTime;
  uint taskGradingTime;
  uint referenceTime;
  uint numberCancelled;

  function Assessment(address assesseeAddress, address tagAddress, address masterAddress, uint timeForTaskCreation)
  {
    assessee = assesseeAddress;
    tag = tagAddress;
    master = masterAddress;
    referenceTime = block.timestamp;
    taskCreationTime = timeForTaskCreation;
  }

  function getTaskCreationTime() returns(uint)
  {
      return taskCreationTime;
  }

  function getTaskCompletionTime() returns(uint)
  {
      return taskCompletionTime;
  }

  function setNumberOfAssessors(uint number)
  {
    numberOfAssessors = number;
  }

  function getNumberOfAssessors() returns(uint)
  {
    return numberOfAssessors;
  }

  function setAssessmentPoolSize(uint sizeRemaining)
  {
    poolSizeRemaining = sizeRemaining;
  }

  function getAssessmentPoolSize() returns(uint)
  {
    return poolSizeRemaining;
  }

  function addToAssessorPool(address potentialAddress)
  {
    assessorPool.push(potentialAddress);
  }

  function setPotentialAssessor()
  {
    bool potentialAssessorSet = false;
    while(potentialAssessorSet == false)
    {
      address randomAssessor = assessorPool[getRandom(assessorPool.length)];
      if(assessors[randomAssessor] == 0)
      {
        assessors[randomAssessor] = 3;
        currentAssessor = randomAssessor;
        potentialAssessorSet = true;
        User(randomAssessor).notification("Called As A Potential Assessor",tag, 1);
      }
    }
    referenceTime = now;
  }

  function getAssessorPoolLength() returns(uint)
  {
      return assessorPool.length;
  }

  function getRandom(uint i) returns(uint)
  {
    return 12;
  }

  function setTask(string data, uint timeLimit)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 5 && now - referenceTime <= taskCreationTime)
    {
      assessmentTasks[currentAssessor] = data;
      taskCompletionTime = timeLimit;
      assessors[currentAssessor] = 6;
      User(currentAssessor).notification("Task Data Inputted", tag, 5);
      User(assessee).notification("New Task Available", tag, 7);
      referenceTime = now;
    }
    if(now - referenceTime > taskCreationTime && assessors[currentAssessor]!=5)
    {
      User(currentAssessor).notification("Did Not Submit Task On Time", tag, 6);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
  }

  function cancelAssessment()
  {
    User(assessee).notification("Assessment Cancled", tag, 8);
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      User(finalAssessors[i]).notification("Assessment Cancled", tag, 8);
    }
    suicide(master);
  }

  function getTask(address assessorAddress) returns(string)
  {
    return assessmentTasks[assessorAddress];
  }

  function setResponse(string data)
  {
    if(assessors[currentAssessor] == 6 && now - referenceTime <= taskCompletionTime)
    {
      assessmentResponses[currentAssessor] = data;
      assessors[currentAssessor] = 7;
      User(currentAssessor).notification("Task Response Inputted", tag, 10);
      taskGradingTime = (3*(now - referenceTime))/2;
      referenceTime = now;
    }
    if(now - referenceTime > taskCompletionTime && assessors[currentAssessor]!=6)
    {
      User(assessee).notification("Did Not Submit Task Response On Time", tag, 11);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      cancelAssessment();
    }
  }

  function getResponse(address assesseeAddress) returns(string)
  {
    return assessmentResponses[assesseeAddress];
  }

  function setResult(int score)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 7 && now - referenceTime <= taskGradingTime)
    {
      assessmentResults[currentAssessor] = score;
      User(assessee).notification("Task Result Inputted", tag, 12);
      finalAssessors.push(currentAssessor);
    }
    if(now - referenceTime <= taskGradingTime && assessors[currentAssessor] != 7)
    {
      User(currentAssessor).notification("Did Not Submit Task Results On Time", tag, 13);
      User(assessee).notification("Assessor Has Not Graded In Time", tag, 14);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
    if(finalAssessors.length == numberOfAssessors)
    {
      calculateResult();
    }
    if(finalAssessors.length < numberOfAssessors)
    {
      setPotentialAssessor;
    }
  }

  function calculateResult()
  {
    int[][] clusters;
    int[] scores;
    int n = 0;
    int meanScore;
    int totalRelativeDistance;
    int meanAbsoluteDeviation;
    for(uint i = 0; i < numberOfAssessors; i++)
    {
      scores.push(assessmentResults[finalAssessors[i]]);
      n++;
    }
    for(uint j = 0; j < scores.length; j++)
    {
      meanScore += scores[j];
      if(j == scores.length - 1)
      {
        meanScore /= n;
      }
    }
    for(uint k = 0; k < scores.length; k++)
    {
      int distanceFromMean = scores[k] - meanScore;
      if(distanceFromMean < 0)
      {
        distanceFromMean *= -1;
      }
      totalRelativeDistance += distanceFromMean;
    }
    meanAbsoluteDeviation = totalRelativeDistance/n;
    for(uint l = 0; l < scores.length; l++)
    {
      for(uint m = 0; m < scores.length; m++)
      {
        if(scores[l] - scores[m] <= meanAbsoluteDeviation)
        {
          clusters[l].push(scores[m]);
        }
      }
    }
  }

  function confirmAssessor(uint confirm, bool timeKnow)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] != 0 && now - referenceTime <= 180)
    {
      assessors[currentAssessor] = confirm;
      if(confirm == 1)
      {
        User(currentAssessor).notification("Confirmed As Potential Assessor", tag, 2);
        referenceTime = now;
      }
      if(confirm == 2 || confirm == 4)
      {
        User(currentAssessor).notification("Confirmed As Not Assessing", tag, 3);
        numberCancelled ++;
        setPotentialAssessor();
      }
      if(confirm == 5)
      {
        User(currentAssessor).notification("Confirmed As Assessing", tag, 9);
        referenceTime = now;
      }
    }
    if(now - referenceTime > 180)
    {
      if(timeKnow == false && assessors[currentAssessor]==3)
      {
      User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      setPotentialAssessor();
      }
      if(timeKnow == true && assessors[currentAssessor]==1)
      {
        User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
        setPotentialAssessor();
      }
    }
  }

  function returnResults()
  {
    Tag(tag).finishAssessment(finalResult, finalScore, assessee, address(this));
  }

  function cashout()
  {

  }
}

contract User
{
  address user;
  address master;
  address[] acheivements;
  string userData;
  uint reputation;

  event Notification
  ( string _description,
    address _sender,
    address _user,
    address _tag,
    uint _code);

  function User(address userAddress, address masterAddress)
  {
    user = userAddress;
    master = masterAddress;
    reputation = 1;
  }

  function getReputation() returns(uint)
  {
    return reputation;
  }

  function setReputation(uint newReputation)
  {
    reputation = newReputation;
  }

  function notification(string description, address tag, uint code)
  {
    Notification(description, msg.sender, address(this), tag, code);
  }

  function setUserData(string hash)
  {
    userData = hash;
  }

  function getUserData() returns(string)
  {
    return userData;
  }

  function remove()
  {
    suicide(master);
  }
}

contract Master
{
  //Initialize master data store
  mapping (address => uint) tokenBalance;
  mapping (address => string) tagName;
  mapping (string => address) tagAddressFromName;
  mapping (address => address[]) achievements;
  mapping (address => bool) availability;
  mapping (address => address) users;

  event TagCreation
  ( string _tagName,
    address _tagAddress,
    address[] _parents);

  function Master()
  {
    tokenBalance[address(this)] = 1;
    address[] memory a;
    uint useless = addTag("account", a, "Initial Account Tag");
  }

  function mapTokenBalance(address user, uint balance)
  {
    if(tagAddressFromName[tagName[msg.sender]] == 0)
    {
      tokenBalance[user] = balance;
    }
  }
  function mapTagName(address tagAddress, string name)
  {
    tagName[tagAddress] = name;
  }
  function mapTagAddressFromName(string name, address tagAddress)
  {
    tagAddressFromName[name] = tagAddress;
  }
  function mapAchievement(address user, address achievment)
  {
    achievements[user].push(achievment);
  }
  function mapAvailability(address user, bool available)
  {
    availability[user] = available;
  }

  function getTokenBalance(address user) returns(uint)
  {
    return tokenBalance[user];
  }
  function getTagName(address tagAddress) returns(string)
  {
    return tagName[tagAddress];
  }
  function getTagAddressFromName(string name) returns(address)
  {
    return tagAddressFromName[name];
  }
  function getAchievement(address user) returns(address[])
  {
    return achievements[user];
  }
  function getNumberOfachievments(address user) returns(uint)
  {
    return achievements[user].length;
  }
  function getAvailability(address user) returns(bool)
  {
    return availability[user];
  }
 function getTagDescription(address tagAddress) returns(string)
  {
    return Tag(tagAddress).getDescription();
  }

  function addUser()
  {
    User newUser = new User(msg.sender, address(this));
    Tag(tagAddressFromName["account"]).startAssessment(address(newUser),5, 600);
  }

  function addTag(string name, address[] parentList, string description) returns(uint) //Creates a new tag contract
  {
    uint response = 0;
    address[] parents;
    if(tokenBalance[msg.sender] < 1)
    {
      response += 1;
    }
    if(tagAddressFromName[name] == 0)
    {
      response += 10;
    }
    if(response==0)
    {
      for(uint i=0; i<= parentList.length; i++) //adds all the given parents
      {
        if(parentList[i]==0)
        {
          response += 100*(10**i);
        }
        else
        {
          parents.push(parentList[i]);
        }
      }
      Tag newTag = new Tag(name, parents, address(this), description);
      address newTagAddress = address(newTag);
      tagName[newTagAddress] = name;
      tagAddressFromName[name] = newTagAddress;
      tokenBalance[msg.sender] -= 1;
      TagCreation(name, newTagAddress, parents);
    }
    return response;
  }
}

//Defines the meta-contract for a Tag
contract Tag
{
  address[] parentTags;
  address master;
  string name;
  string description;
  address[] owners; //Those who have earned the tag
  mapping(address => address[]) assessmentHistory; //All assessments completed
  mapping(address => uint) scores; //All positive assessements scores
  event CompletedAssessment
  ( address _assessee,
    bool _pass,
    uint _score,
    address _assessment);

  function Tag(string tagName, address[] parents, address masterAddress, string tagDescription)
  {
    name = tagName;
    parentTags = parents;
    master = masterAddress;
    description = tagDescription;
  }

  function getDescription() returns(string)
  {
    return description;
  }

  function getOwners() returns(address[])
  {
    return owners;
  }

  function getOwnerLength() returns(uint)
  {
    return owners.length;
  }

  function getOwner(uint index) returns(address)
  {
    return owners[index];
  }

  function getParents() returns(address[])
  {
    return parentTags;
  }

  function getParentsLength() returns(uint)
  {
    return parentTags.length;
  }

  function getParent(uint index) returns(address)
  {
      return parentTags[index];
  }

  function setAssessorPool(address tagAddress, address assessment)
  {
    for(uint i = 0; i < Tag(tagAddress).getOwnerLength() && Assessment(assessment).getAssessmentPoolSize() != 0; i++)
    {
      if(Assessment(assessment).getAssessorPoolLength() < Tag(tagAddress).getOwnerLength()/10)
      {
        address random = Tag(tagAddress).getOwner(getRandom(Tag(tagAddress).getOwnerLength()-1));
        if(Master(master).getAvailability(random) == true)
        {
          Assessment(assessment).addToAssessorPool(random);
          Assessment(assessment).setAssessmentPoolSize(Assessment(assessment).getAssessmentPoolSize() -1);
        }
      }
      else
      {
        for(uint j = 0; j < Tag(tagAddress).getParentsLength(); j++)
        {
          setAssessorPool(Tag(tagAddress).getParent(j), assessment);
        }
      }
      if(Assessment(assessment).getAssessmentPoolSize() <= 0)
      {
        Assessment(assessment).setPotentialAssessor();
      }
    }
  }

  function startAssessment(address assessee, uint size, uint timeForSettingTask)
  {
    Assessment newAssessment = new Assessment(assessee, address(this), master, timeForSettingTask);
    newAssessment.setNumberOfAssessors(size);
    newAssessment.setAssessmentPoolSize(size*20);
    setAssessorPool(address(this), address(newAssessment));
  }

  function finishAssessment(bool pass, uint score, address assessee, address assessment)
  {
    if(pass == true)
    {
      owners.push(assessee);
      scores[assessee] = score;
      Master(master).mapAchievement(assessee,address(this));
    }
    if(pass == false && address(this) == Master(master).getTagAddressFromName("account"))
    {
      User(assessee).remove();
    }
    assessmentHistory[assessee].push(assessment);
    CompletedAssessment(assessee, pass, score, assessment);
  }
  function getRandom(uint i) returns(uint)
  {
    return 12;
  }
}

//Defines the meta-contract for an assessment
contract Assessment
{
  address assessee; //We need a better word for this
  address[] assessorPool;
  mapping (address => uint) assessors;
  address[] finalAssessors;
  address tag;
  address master;
  uint poolSizeRemaining;
  uint numberOfAssessors;
  struct Results
  {
    bool pass;
    uint score;
  }
  mapping(address => string) assessmentTasks; //Given by the assessors as IPFS hashes
  mapping(address => string) assessmentResponses; //Given by the assessee as IPFS hashes
  mapping(address => Results) assessmentResults; //Pass/Fail and Score given by assessors
  address currentAssessor;
  uint finalScore;
  bool finalResult;
  uint taskCreationTime;
  uint taskCompletionTime;
  uint taskGradingTime;
  uint referenceTime;
  uint numberCancelled;

  function Assessment(address assesseeAddress, address tagAddress, address masterAddress, uint timeForTaskCreation)
  {
    assessee = assesseeAddress;
    tag = tagAddress;
    master = masterAddress;
    referenceTime = block.timestamp;
    taskCreationTime = timeForTaskCreation;
  }

  function getTaskCreationTime() returns(uint)
  {
      return taskCreationTime;
  }

  function getTaskCompletionTime() returns(uint)
  {
      return taskCompletionTime;
  }

  function setNumberOfAssessors(uint number)
  {
    numberOfAssessors = number;
  }

  function getNumberOfAssessors() returns(uint)
  {
    return numberOfAssessors;
  }

  function setAssessmentPoolSize(uint sizeRemaining)
  {
    poolSizeRemaining = sizeRemaining;
  }

  function getAssessmentPoolSize() returns(uint)
  {
    return poolSizeRemaining;
  }

  function addToAssessorPool(address potentialAddress)
  {
    assessorPool.push(potentialAddress);
  }

  function setPotentialAssessor()
  {
    bool potentialAssessorSet = false;
    while(potentialAssessorSet == false)
    {
      address randomAssessor = assessorPool[getRandom(assessorPool.length)];
      if(assessors[randomAssessor] == 0)
      {
        assessors[randomAssessor] = 3;
        currentAssessor = randomAssessor;
        potentialAssessorSet = true;
        User(randomAssessor).notification("Called As A Potential Assessor",tag, 1);
      }
    }
    referenceTime = now;
  }

  function getAssessorPoolLength() returns(uint)
  {
      return assessorPool.length;
  }

  function getRandom(uint i) returns(uint)
  {
    return 12;
  }

  function setTask(string data, uint timeLimit)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 5 && now - referenceTime <= taskCreationTime)
    {
      assessmentTasks[currentAssessor] = data;
      taskCompletionTime = timeLimit;
      assessors[currentAssessor] = 6;
      User(currentAssessor).notification("Task Data Inputted", tag, 5);
      User(assessee).notification("New Task Available", tag, 7);
      referenceTime = now;
    }
    if(now - referenceTime > taskCreationTime && assessors[currentAssessor]!=5)
    {
      User(currentAssessor).notification("Did Not Submit Task On Time", tag, 6);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      setPotentialAssessor();
    }
  }

  function cancelAssessment()
  {
    User(assessee).notification("Assessment Cancled", tag, 8);
    for(uint i = 0; i < finalAssessors.length; i++)
    {
      User(finalAssessors[i]).notification("Assessment Cancled", tag, 8);
    }
    suicide(master);
  }

  function getTask(address assessorAddress) returns(string)
  {
    return assessmentTasks[assessorAddress];
  }

  function setResponse(string data)
  {
    if(assessors[currentAssessor] == 6 && now - referenceTime <= taskCompletionTime)
    {
      assessmentResponses[currentAssessor] = data;
      assessors[currentAssessor] = 7;
      User(currentAssessor).notification("Task Response Inputted", tag, 10);
      taskGradingTime = 1.5*(now - referenceTime);
      referenceTime = now;
    }
    if(now - referenceTime > taskCompletionTime && assessors[currentAssessor]!=6)
    {
      User(assessee).notification("Did Not Submit Task Response On Time", tag, 11);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      cancelAssessment();
    }
  }

  function getResponse(address assesseeAddress) returns(string)
  {
    return assessmentResponses[assesseeAddress];
  }

  function setResult(bool pass, uint score)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] == 7 && now - referenceTime <= taskGradingTime)
    {
      Results memory results;
      results.pass = pass;
      results.score = score;
      assessmentResults[currentAssessor] = results;
      User(assessee).notification("Task Result Inputted", tag, 12);
      finalAssessors.push(currentAssessor);
    }
    if(now - referenceTime <= taskGradingTime && assessors[currentAssessor] != 7)
    {
      User(currentAssessor).notification("Did Not Submit Task Results On Time", tag, 13);
      User(assessee).notification("Assessor Has Not Graded In Time", tag, 14)
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(assessee) - 1);
      User(currentAssessor).setReputation(User(currentAssessor).getReputation() + 1);
      numberCancelled++;
      getPotentialAssessor();
    }
    if(finalAssessors.length == numberOfAssessors)
    {
      calculateResult();
    }
    if(finalAssessors.length < numberOfAssessors)
    {
      getPotentialAssessor;
    }
  }

  function calculateResult()
  {

  }

  function confirmAssessor(uint confirm, bool timeKnow)
  {
    if(numberCancelled >= numberOfAssessors)
    {
      cancelAssessment();
    }
    if(assessors[currentAssessor] != 0 && now - referenceTime <= 180)
    {
      assessors[currentAssessor] = confirm;
      if(confirm == 1)
      {
        User(currentAssessor).notification("Confirmed As Potential Assessor", tag, 2);
        referenceTime = now;
      }
      if(confirm == 2 || confirm == 4)
      {
        User(currentAssessor).notification("Confirmed As Not Assessing", tag, 3);
        numberCancelled ++;
        setPotentialAssessor();
      }
      if(confirm == 5)
      {
        User(currentAssessor).notification("Confirmed As Assessing", tag, 9);
        referenceTime = now;
      }
    }
    if(now - referenceTime > 180)
    {
      if(timeKnow == false && assessors[currentAssessor]==3)
      {
      User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
      Master(master).mapTokenBalance(currentAssessor, Master(master).getTokenBalance(currentAssessor) - 1);
      setPotentialAssessor();
      }
      if(timeKnow == true && assessors[currentAssessor]==1)
      {
        User(currentAssessor).notification("Did Not Respond In Time To Be Assessor", tag, 4);
        setPotentialAssessor();
      }
    }
  }

  function returnResults()
  {
    Tag(tag).finishAssessment(finalResult, finalScore, assessee, address(this));
  }

  function cashout()
  {

  }
}

contract User
{
  address user;
  address master;
  address[] acheivements;
  string userData;
  uint reputation;

  event Notification
  ( string _description,
    address _sender,
    address _user,
    address _tag,
    uint _code);

  function User(address userAddress, address masterAddress)
  {
    user = userAddress;
    master = masterAddress;
    reputation = 1;
  }

  function getReputation() returns(uint)
  {
    return reputation;
  }

  function setReputation(uint newReputation)
  {
    reputation = newReputation;
  }

  function notification(string description, address tag, uint code)
  {
    Notification(description, msg.sender, address(this), tag, code);
  }

  function setUserData(string hash)
  {
    userData = hash;
  }

  function getUserData() returns(string)
  {
    return userData;
  }

  function remove()
  {
    suicide(master);
  }
}


Contracts: inherit Owned by Processables.

pragma solidity ^0.4.17;

// ----------------------------------------------------------------------------
// Processables
//
// Copyright (c) 2017 OpenST Ltd.
// https://simpletoken.org/
//
// The MIT Licence.
// ----------------------------------------------------------------------------

import "./Owned.sol";

/// @title Processables
/// @dev Abstract contract to be inherited by operations contracts that aid certain transfers related to the token sale
contract Processables is Owned {
	address[] public addresses;

	// Count of successful process iterations
	uint256 public totalProcessed;

	// status of this contract
	Status public status;

	// enum processables status
	//   Unlocked
	//   Locked
	//   Approved
	//   Completed
	//	 Disapproved
	enum Status { Unlocked, Locked, Approved, Completed, Disapproved }

	event Locked();
	event Approved();
	event Completed();
	event Disapproved();

	// limits execution to when this contract is unlocked
	modifier onlyIfUnlocked() {
		require(status == Status.Unlocked);
		_;
	}

	// limits execution to when this contract is locked
	modifier onlyIfLocked() {
		require(status == Status.Locked);
		_;
	}

	// limits execution to when this contract is approved
	modifier onlyIfApproved() {
		require(status == Status.Approved);
		_;
	}

	// limits execution to when this contract is locked or approved
	modifier onlyIfLockedOrApproved() {
		require(status == Status.Locked ||
				status == Status.Approved);
		_;
	}

	/// @dev Constructor
	function Processables()
			Owned()
			public { }

	/// @dev Adds address to addresses
	/// @param _address address to add
	/// @return true
	function addInternal(address _address)
			internal
			onlyIfUnlocked
			returns(bool result)
	{
		require(_address != address(0));
		addresses.push(_address);

		return true;
	}

	/// @dev Returns addresses
	/// @return addresses array
	function getAddresses() public view returns(address[]) { return addresses; }

	/// @dev Returns size of addresses
	/// @return size of addresses
	function getAddressesSize() public view returns(uint256 size) { return addresses.length; }

	/// @dev Sets status to Locked
	/// @return true
	function lock()
			public
			onlyOwner
			onlyIfUnlocked
			returns(bool result)
	{
		require(addresses.length > 0);

		status = Status.Locked;

		Locked();

		return true;
	}

	/// @dev Sets status to Approved, to be called by inheriting contracts with access control
	/// @return true
	function approveInternal()
			internal
			onlyIfLocked
			returns(bool result)
	{
		status = Status.Approved;

		Approved();

		return true;
	}

	/// @dev Sets status to Completed, to be called by inheriting contracts with access control
	/// @return true
	function completeInternal()
			internal
			onlyIfApproved
			returns(bool result)
	{
		status = Status.Completed;

		Completed();

		return true;
	}

	/// @dev Sets status to Disapproved, to be called by inheriting contracts with access control
	/// @return true
	function disapproveInternal()
			internal
			onlyIfLockedOrApproved
			returns(bool result)
	{
		status = Status.Disapproved;

		Disapproved();

		return true;
	}

	/// @dev Interface for processing processables to be implemented by inheriting contracts
	/// @param _from index of address at which to begin processing
	/// @return index of final address processed
	function process(uint256 _from) public returns(uint256 to);
}

pragma solidity ^0.4.17;

// ----------------------------------------------------------------------------
// Processables
//
// Copyright (c) 2017 OpenST Ltd.
// https://simpletoken.org/
//
// The MIT Licence.
// ----------------------------------------------------------------------------

/// @title Processables
/// @dev Abstract contract to be inherited by operations contracts that aid certain transfers related to the token sale
contract Processables {
	address[] public addresses;

	// Address that creates and administers this contract
	address public owner;

	// Count of successful process iterations
	uint256 public totalProcessed;

	// status of this contract
	Status public status;

	// enum processables status
	//   Unlocked
	//   Locked
	//   Approved
	//   Completed
	//	 Disapproved
	enum Status { Unlocked, Locked, Approved, Completed, Disapproved }

	event Locked();
	event Approved();
	event Completed();
	event Disapproved();

	// limits execution to owner
	modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

	// limits execution to when this contract is unlocked
	modifier onlyIfUnlocked() {
		require(status == Status.Unlocked);
		_;
	}

	// limits execution to when this contract is locked
	modifier onlyIfLocked() {
		require(status == Status.Locked);
		_;
	}

	// limits execution to when this contract is approved
	modifier onlyIfApproved() {
		require(status == Status.Approved);
		_;
	}

	// limits execution to when this contract is locked or approved
	modifier onlyIfLockedOrApproved() {
		require(status == Status.Locked ||
				status == Status.Approved);
		_;
	}

	/// @dev Constructor
	function Processables()
			public
	{
		owner = msg.sender;
	}

	/// @dev Adds address to addresses
	/// @param _address address to add
	/// @return true
	function addInternal(address _address)
			internal
			onlyIfUnlocked
			returns(bool result)
	{
		require(_address != address(0));
		addresses.push(_address);

		return true;
	}

	/// @dev Returns addresses
	/// @return addresses array
	function getAddresses() public view returns(address[]) { return addresses; }

	/// @dev Returns size of addresses
	/// @return size of addresses
	function getAddressesSize() public view returns(uint256 size) { return addresses.length; }

	/// @dev Sets status to Locked
	/// @return true
	function lock()
			public
			onlyOwner
			onlyIfUnlocked
			returns(bool result)
	{
		require(addresses.length > 0);

		status = Status.Locked;

		Locked();

		return true;
	}

	/// @dev Sets status to Approved, to be called by inheriting contracts with access control
	/// @return true
	function approveInternal()
			internal
			onlyIfLocked
			returns(bool result)
	{
		status = Status.Approved;

		Approved();

		return true;
	}

	/// @dev Sets status to Completed, to be called by inheriting contracts with access control
	/// @return true
	function completeInternal()
			internal
			onlyIfApproved
			returns(bool result)
	{
		status = Status.Completed;

		Completed();

		return true;
	}

	/// @dev Sets status to Disapproved, to be called by inheriting contracts with access control
	/// @return true
	function disapproveInternal()
			internal
			onlyIfLockedOrApproved
			returns(bool result)
	{
		status = Status.Disapproved;

		Disapproved();

		return true;
	}

	/// @dev Interface for processing processables to be implemented by inheriting contracts
	/// @param _from index of address at which to begin processing
	/// @return index of final address processed
	function process(uint256 _from) public returns(uint256 to);
}


Hotfix for #30

Hotfix for #30

pragma solidity ^0.4.11;

import "./historical/StandardToken.sol";
import "./PLCRVoting.sol";
import "./Parameterizer.sol";

contract Registry {

    // ------
    // EVENTS
    // ------

    event _Application(string domain, uint deposit);
    event _Challenge(string domain, uint deposit, uint pollID);
    event _Deposit(string domain, uint added, uint newTotal);
    event _Withdrawal(string domain, uint withdrew, uint newTotal);
    event _NewDomainWhitelisted(string domain);
    event _ApplicationRemoved(string domain);
    event _ListingRemoved(string domain);
    event _ChallengeFailed(uint challengeID);
    event _ChallengeSucceeded(uint challengeID);
    event _RewardClaimed(address voter, uint challengeID, uint reward);

    struct Listing {
        uint applicationExpiry; // Expiration date of apply stage
        bool whitelisted;       // Indicates registry status
        address owner;          // Owner of Listing
        uint unstakedDeposit;   // Number of unlocked tokens with potential risk if challenged
        uint challengeID;       // Identifier of canonical challenge
    }

    struct Challenge {
        uint rewardPool;        // (remaining) Pool of tokens distributed amongst winning voters
        address challenger;     // Owner of Challenge
        bool resolved;          // Indication of if challenge is resolved
        uint stake;             // Number of tokens at risk for either party during challenge
        uint totalTokens;       // (remaining) Amount of tokens used for voting by the winning side
    }

    // Maps challengeIDs to associated challenge data
    mapping(uint => Challenge) public challengeMap;

    // Maps domainHashes to associated listing data
    mapping(bytes32 => Listing) public listingMap;

    // Maps challengeIDs and address to token claim data
    mapping(uint => mapping(address => bool)) public tokenClaims;

    // Global Variables
    StandardToken public token;
    PLCRVoting public voting;
    Parameterizer public parameterizer;

    // ------------
    // CONSTRUCTOR:
    // ------------

    /**
    @dev Contructor
    @notice                 Sets the addresses for token, voting, and parameterizer
    @param _tokenAddr       Address of the native ERC20 token (ADT)
    @param _plcrAddr        Address of a PLCR voting contract for the provided token
    @param _paramsAddr      Address of a Parameterizer contract for the provided PLCR voting contract
    */
    function Registry(
        address _tokenAddr,
        address _plcrAddr,
        address _paramsAddr
    ) {
        token = StandardToken(_tokenAddr);
        voting = PLCRVoting(_plcrAddr);
        parameterizer = Parameterizer(_paramsAddr);
    }

    // --------------------
    // PUBLISHER INTERFACE:
    // --------------------

    /**
    @notice             Allows a user to start an application.
    @notice             Takes tokens from user and sets apply stage end time.
    @param _domain      The domain of a potential listing a user is applying to add to the registry
    @param _amount      The number of ERC20 tokens a user is willing to potentially stake
    */
    function apply(string _domain, uint _amount) external {
        require(!isWhitelisted(_domain));
        require(!appWasMade(_domain));
        require(_amount >= parameterizer.get("minDeposit"));

        // Sets owner
        Listing storage listing = listingMap[keccak256(_domain)];
        listing.owner = msg.sender;

        // Transfers tokens from user to Registry contract
        require(token.transferFrom(listing.owner, this, _amount));

        // Sets apply stage end time
        listing.applicationExpiry = block.timestamp + parameterizer.get("applyStageLen");
        listing.unstakedDeposit = _amount;

        _Application(_domain, _amount);
    }

    /**
    @notice             Allows the owner of a domain to increase their unstaked deposit.
    @param _domain      The domain of a user's application/listing
    @param _amount      The number of ERC20 tokens to increase a user's unstaked deposit
    */
    function deposit(string _domain, uint _amount) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(listing.owner == msg.sender);
        require(token.transferFrom(msg.sender, this, _amount));

        listing.unstakedDeposit += _amount;

        _Deposit(_domain, _amount, listing.unstakedDeposit);
    }

    /**
    @notice             Allows the owner of a domain to decrease their unstaked deposit.
    @notice             The listing keeps its previous status.
    @param _domain      The domain of a user's application/listing
    @param _amount      The number of ERC20 tokens to decrease a user's unstaked deposit
    */
    function withdraw(string _domain, uint _amount) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(listing.owner == msg.sender);
        require(_amount <= listing.unstakedDeposit);
        require(listing.unstakedDeposit - _amount >= parameterizer.get("minDeposit"));

        require(token.transfer(msg.sender, _amount));

        listing.unstakedDeposit -= _amount;

        _Withdrawal(_domain, _amount, listing.unstakedDeposit);
    }

    /**
    @notice             Allows the owner of a listing to remove the listing from the whitelist
    @notice             Returns all tokens to the owner of the listing
    @param _domain      The domain of a user's listing
    */
    function exit(string _domain) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(msg.sender == listing.owner);
        require(isWhitelisted(_domain));

        // Cannot exit during ongoing challenge
        require(listing.challengeID == 0 || challengeMap[listing.challengeID].resolved);

        // Remove domain & return tokens
        resetListing(_domain);
    }

    // -----------------------
    // TOKEN HOLDER INTERFACE:
    // -----------------------

    /**
    @notice             Starts a poll for a domain which is either
    @notice             in the apply stage or already in the whitelist.
    @dev                Tokens are taken from the challenger and the applicant's deposit is locked.
    @param _domain      The domain of an applicant's potential listing
    */
    function challenge(string _domain) external returns (uint challengeID) {
        bytes32 domainHash = keccak256(_domain);
        Listing storage listing = listingMap[domainHash];
        uint deposit = parameterizer.get("minDeposit");

        // Domain must be in apply stage or already on the whitelist
        require(appWasMade(_domain) || listing.whitelisted);
        // Prevent multiple challenges
        require(listing.challengeID == 0 || challengeMap[listing.challengeID].resolved);

        if (listing.unstakedDeposit < deposit) {
            // Not enough tokens, domain auto-delisted
            resetListing(_domain);
            return 0;
        }

        // Takes tokens from challenger
        require(token.transferFrom(msg.sender, this, deposit));

        // Starts poll
        uint pollID = voting.startPoll(
            parameterizer.get("voteQuorum"),
            parameterizer.get("commitStageLen"),
            parameterizer.get("revealStageLen")
        );

        challengeMap[pollID] = Challenge({
            challenger: msg.sender,
            rewardPool: ((100 - parameterizer.get("dispensationPct")) * deposit) / 100,
            stake: deposit,
            resolved: false,
            totalTokens: 0
        });

        // Updates listing to store most recent challenge
        listingMap[domainHash].challengeID = pollID;

        // Locks tokens for listing during challenge
        listingMap[domainHash].unstakedDeposit -= deposit;

        _Challenge(_domain, deposit, pollID);
        return pollID;
    }

    /**
    @notice             Updates a domain's status from 'application' to 'listing'
    @notice             or resolves a challenge if one exists.
    @param _domain      The domain whose status is being updated
    */
    function updateStatus(string _domain) public {
        if (canBeWhitelisted(_domain)) {
          whitelistApplication(_domain);
          _NewDomainWhitelisted(_domain);
        } else if (challengeCanBeResolved(_domain)) {
          resolveChallenge(_domain);
        } else {
          revert();
        }
    }

    // ----------------
    // TOKEN FUNCTIONS:
    // ----------------

    /**
    @notice             Called by a voter to claim his/her reward for each completed vote.
    @dev                Someone must call updateStatus() before this can be called.
    @param _challengeID The pollID of the challenge a reward is being claimed for
    @param _salt        The salt of a voter's commit hash in the given poll
    */
    function claimReward(uint _challengeID, uint _salt) public {
        // Ensures the voter has not already claimed tokens and challenge results have been processed
        require(tokenClaims[_challengeID][msg.sender] == false);
        require(challengeMap[_challengeID].resolved == true);

        uint voterTokens = voting.getNumPassingTokens(msg.sender, _challengeID, _salt);
        uint reward = calculateVoterReward(msg.sender, _challengeID, _salt);

        // Subtracts the voter's information to preserve the participation ratios
        // of other voters compared to the remaining pool of rewards
        challengeMap[_challengeID].totalTokens -= voterTokens;
        challengeMap[_challengeID].rewardPool -= reward;

        require(token.transfer(msg.sender, reward));

        // Ensures a voter cannot claim tokens again
        tokenClaims[_challengeID][msg.sender] = true;

        _RewardClaimed(msg.sender, _challengeID, reward);
    }

    /**
    @dev                Calculates the provided voter's token reward for the given poll.
    @param _voter       The address of the voter whose reward balance is to be returned
    @param _challengeID The pollID of the challenge a reward balance is being queried for
    @param _salt        The salt of the voter's commit hash in the given poll
    @return             The uint indicating the voter's reward (in nano-ADT)
    */
    function calculateVoterReward(address _voter, uint _challengeID, uint _salt)
    public constant returns (uint) {
        uint totalTokens = challengeMap[_challengeID].totalTokens;
        uint rewardPool = challengeMap[_challengeID].rewardPool;
        uint voterTokens = voting.getNumPassingTokens(_voter, _challengeID, _salt);
        return (voterTokens * rewardPool) / totalTokens;
    }

    // --------
    // GETTERS:
    // --------

    /**
    @dev                Determines whether the domain of an application can be whitelisted.
    @param _domain      The domain whose status should be examined
    */
    function canBeWhitelisted(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        // Ensures that the application was made,
        // the application period has ended,
        // the domain can be whitelisted,
        // and either: the challengeID == 0, or the challenge has been resolved.
        if (
            appWasMade(_domain) &&
            isExpired(listingMap[domainHash].applicationExpiry) &&
            !isWhitelisted(_domain) &&
            (challengeID == 0 || challengeMap[challengeID].resolved == true)
        ) { return true; }

        return false;
    }

    // Returns true if domain is whitelisted
    function isWhitelisted(string _domain) constant public returns (bool whitelisted) {
        return listingMap[keccak256(_domain)].whitelisted;
    }

    // Returns true if apply(domain) was called for this domain
    function appWasMade(string _domain) constant public returns (bool exists) {
        return listingMap[keccak256(_domain)].applicationExpiry > 0;
    }

    // Returns true if the application/listing has an unresolved challenge
    function challengeExists(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        return (listingMap[domainHash].challengeID > 0 && !challengeMap[challengeID].resolved);
    }

    /**
    @notice             Determines whether voting has concluded in a challenge for a given domain.
    @dev                Throws if no challenge exists.
    @param _domain      A domain with an unresolved challenge
    */
    function challengeCanBeResolved(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        require(challengeExists(_domain));

        return voting.pollEnded(challengeID);
    }

    /**
    @notice             Determines the number of tokens awarded to the winning party in a challenge.
    @param _challengeID The challengeID to determine a reward for
    */
    function determineReward(uint _challengeID) public constant returns (uint) {
        require(!challengeMap[_challengeID].resolved && voting.pollEnded(_challengeID));

        // Edge case, nobody voted, give all tokens to the challenger.
        if (voting.getTotalNumberOfTokensForWinningOption(_challengeID) == 0) {
            return 2 * challengeMap[_challengeID].stake;
        }

        return (2 * challengeMap[_challengeID].stake) - challengeMap[_challengeID].rewardPool;
    }

    // Returns true if the provided termDate has passed
    function isExpired(uint _termDate) constant public returns (bool expired) {
        return _termDate < block.timestamp;
    }

    // Deletes a listing from the whitelist and transfers tokens back to owner
    function resetListing(string _domain) internal {
        bytes32 domainHash = keccak256(_domain);
        Listing storage listing = listingMap[domainHash];

        // Transfers any remaining balance back to the owner
        if (listing.unstakedDeposit > 0)
            require(token.transfer(listing.owner, listing.unstakedDeposit));

        delete listingMap[domainHash];
    }

    // ----------------
    // PRIVATE FUNCTIONS:
    // ----------------

    /**
    @notice             Determines the winner in a challenge.
    @notice             Rewards the winner tokens and either whitelists or de-whitelists the domain.
    @param _domain      A domain with a challenge that is to be resolved
    */
    function resolveChallenge(string _domain) private {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        // Calculates the winner's reward,
        // which is: (winner's full stake) + (dispensationPct * loser's stake)
        uint reward = determineReward(challengeID);

        // Records whether the domain is a listing or an application
        bool wasWhitelisted = isWhitelisted(_domain);

        // Case: challenge failed
        if (voting.isPassed(challengeID)) {
            whitelistApplication(_domain);
            // Unlock stake so that it can be retrieved by the applicant
            listingMap[domainHash].unstakedDeposit += reward;

            _ChallengeFailed(challengeID);
            if (!wasWhitelisted) { _NewDomainWhitelisted(_domain); }
        }
        // Case: challenge succeeded
        else {
            resetListing(_domain);
            // Transfer the reward to the challenger
            require(token.transfer(challengeMap[challengeID].challenger, reward));

            _ChallengeSucceeded(challengeID);
            if (wasWhitelisted) { _ListingRemoved(_domain); }
            else { _ApplicationRemoved(_domain); }
        }

        // Sets flag on challenge being processed
        challengeMap[challengeID].resolved = true;

        // Stores the total tokens used for voting by the winning side for reward purposes
        challengeMap[challengeID].totalTokens =
            voting.getTotalNumberOfTokensForWinningOption(challengeID);
    }

    /**
    @dev                Called by updateStatus() if the applicationExpiry date passed without a challenge being made.
    @dev                Called by resolveChallenge() if an application/listing beat a challenge.
    @param _domain      The domain of an application/listing to be whitelisted
    */
    function whitelistApplication(string _domain) private {
        bytes32 domainHash = keccak256(_domain);

        listingMap[domainHash].whitelisted = true;
    }
}

pragma solidity ^0.4.11;

import "./historical/StandardToken.sol";
import "./PLCRVoting.sol";
import "./Parameterizer.sol";

contract Registry {

    // ------
    // EVENTS
    // ------

    event _Application(string domain, uint deposit);
    event _Challenge(string domain, uint deposit, uint pollID);
    event _Deposit(string domain, uint added, uint newTotal);
    event _Withdrawal(string domain, uint withdrew, uint newTotal);
    event _NewDomainWhitelisted(string domain);
    event _ApplicationRemoved(string domain);
    event _ListingRemoved(string domain);
    event _ChallengeFailed(uint challengeID);
    event _ChallengeSucceeded(uint challengeID);
    event _RewardClaimed(address voter, uint challengeID, uint reward);

    struct Listing {
        uint applicationExpiry; // Expiration date of apply stage
        bool whitelisted;       // Indicates registry status
        address owner;          // Owner of Listing
        uint unstakedDeposit;   // Number of unlocked tokens with potential risk if challenged
        uint challengeID;       // Identifier of canonical challenge
    }

    struct Challenge {
        uint rewardPool;        // (remaining) Pool of tokens distributed amongst winning voters
        address challenger;     // Owner of Challenge
        bool resolved;          // Indication of if challenge is resolved
        uint stake;             // Number of tokens at risk for either party during challenge
        uint totalTokens;       // (remaining) Amount of tokens used for voting by the winning side
    }

    // Maps challengeIDs to associated challenge data
    mapping(uint => Challenge) public challengeMap;

    // Maps domainHashes to associated listing data
    mapping(bytes32 => Listing) public listingMap;

    // Maps challengeIDs and address to token claim data
    mapping(uint => mapping(address => bool)) public tokenClaims;

    // Global Variables
    StandardToken public token;
    PLCRVoting public voting;
    Parameterizer public parameterizer;

    // ------------
    // CONSTRUCTOR:
    // ------------

    /**
    @dev Contructor
    @notice                 Sets the addresses for token, voting, and parameterizer
    @param _tokenAddr       Address of the native ERC20 token (ADT)
    @param _plcrAddr        Address of a PLCR voting contract for the provided token
    @param _paramsAddr      Address of a Parameterizer contract for the provided PLCR voting contract
    */
    function Registry(
        address _tokenAddr,
        address _plcrAddr,
        address _paramsAddr
    ) {
        token = StandardToken(_tokenAddr);
        voting = PLCRVoting(_plcrAddr);
        parameterizer = Parameterizer(_paramsAddr);
    }

    // --------------------
    // PUBLISHER INTERFACE:
    // --------------------

    /**
    @notice             Allows a user to start an application.
    @notice             Takes tokens from user and sets apply stage end time.
    @param _domain      The domain of a potential listing a user is applying to add to the registry
    @param _amount      The number of ERC20 tokens a user is willing to potentially stake
    */
    function apply(string _domain, uint _amount) external {
        require(!isWhitelisted(_domain));
        require(!appWasMade(_domain));
        require(_amount >= parameterizer.get("minDeposit"));

        // Sets owner
        Listing storage listing = listingMap[keccak256(_domain)];
        listing.owner = msg.sender;

        // Transfers tokens from user to Registry contract
        require(token.transferFrom(listing.owner, this, _amount));

        // Sets apply stage end time
        listing.applicationExpiry = block.timestamp + parameterizer.get("applyStageLen");
        listing.unstakedDeposit = _amount;

        _Application(_domain, _amount);
    }

    /**
    @notice             Allows the owner of a domain to increase their unstaked deposit.
    @param _domain      The domain of a user's application/listing
    @param _amount      The number of ERC20 tokens to increase a user's unstaked deposit
    */
    function deposit(string _domain, uint _amount) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(listing.owner == msg.sender);
        require(token.transferFrom(msg.sender, this, _amount));

        listing.unstakedDeposit += _amount;

        _Deposit(_domain, _amount, listing.unstakedDeposit);
    }

    /**
    @notice             Allows the owner of a domain to decrease their unstaked deposit.
    @notice             The listing keeps its previous status.
    @param _domain      The domain of a user's application/listing
    @param _amount      The number of ERC20 tokens to decrease a user's unstaked deposit
    */
    function withdraw(string _domain, uint _amount) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(listing.owner == msg.sender);
        require(_amount <= listing.unstakedDeposit);
        require(listing.unstakedDeposit - _amount >= parameterizer.get("minDeposit"));

        require(token.transfer(msg.sender, _amount));

        listing.unstakedDeposit -= _amount;

        _Withdrawal(_domain, _amount, listing.unstakedDeposit);
    }

    /**
    @notice             Allows the owner of a listing to remove the listing from the whitelist
    @notice             Returns all tokens to the owner of the listing
    @param _domain      The domain of a user's listing
    */
    function exit(string _domain) external {
        Listing storage listing = listingMap[keccak256(_domain)];

        require(msg.sender == listing.owner);
        require(isWhitelisted(_domain));

        // Cannot exit during ongoing challenge
        require(listing.challengeID == 0 || challengeMap[listing.challengeID].resolved);

        // Remove domain & return tokens
        resetListing(_domain);
    }

    // -----------------------
    // TOKEN HOLDER INTERFACE:
    // -----------------------

    /**
    @notice             Starts a poll for a domain which is either
    @notice             in the apply stage or already in the whitelist.
    @dev                Tokens are taken from the challenger and the applicant's deposit is locked.
    @param _domain      The domain of an applicant's potential listing
    */
    function challenge(string _domain) external returns (uint challengeID) {
        bytes32 domainHash = keccak256(_domain);
        Listing storage listing = listingMap[domainHash];
        uint deposit = parameterizer.get("minDeposit");

        // Domain must be in apply stage or already on the whitelist
        require(appWasMade(_domain) || listing.whitelisted);
        // Prevent multiple challenges
        require(listing.challengeID == 0 || challengeMap[listing.challengeID].resolved);

        if (listing.unstakedDeposit < deposit) {
            // Not enough tokens, domain auto-delisted
            resetListing(_domain);
            return 0;
        }

        // Takes tokens from challenger
        require(token.transferFrom(msg.sender, this, deposit));

        // Starts poll
        uint pollID = voting.startPoll(
            parameterizer.get("voteQuorum"),
            parameterizer.get("commitStageLen"),
            parameterizer.get("revealStageLen")
        );

        challengeMap[pollID] = Challenge({
            challenger: msg.sender,
            rewardPool: ((100 - parameterizer.get("dispensationPct")) * deposit) / 100,
            stake: deposit,
            resolved: false,
            totalTokens: 0
        });

        // Updates listing to store most recent challenge
        listingMap[domainHash].challengeID = pollID;

        // Locks tokens for listing during challenge
        listingMap[domainHash].unstakedDeposit -= deposit;

        _Challenge(_domain, deposit, pollID);
        return pollID;
    }

    /**
    @notice             Updates a domain's status from 'application' to 'listing'
    @notice             or resolves a challenge if one exists.
    @param _domain      The domain whose status is being updated
    */
    function updateStatus(string _domain) public {
        if (canBeWhitelisted(_domain)) {
          whitelistApplication(_domain);
          _NewDomainWhitelisted(_domain);
        } else if (challengeCanBeResolved(_domain)) {
          resolveChallenge(_domain);
        } else {
          revert();
        }
    }

    // ----------------
    // TOKEN FUNCTIONS:
    // ----------------

    /**
    @notice             Called by a voter to claim his/her reward for each completed vote.
    @dev                Someone must call updateStatus() before this can be called.
    @param _challengeID The pollID of the challenge a reward is being claimed for
    @param _salt        The salt of a voter's commit hash in the given poll
    */
    function claimReward(uint _challengeID, uint _salt) public {
        // Ensures the voter has not already claimed tokens and challenge results have been processed
        require(tokenClaims[_challengeID][msg.sender] == false);
        require(challengeMap[_challengeID].resolved = true);

        uint voterTokens = voting.getNumPassingTokens(msg.sender, _challengeID, _salt);
        uint reward = calculateVoterReward(msg.sender, _challengeID, _salt);

        // Subtracts the voter's information to preserve the participation ratios
        // of other voters compared to the remaining pool of rewards
        challengeMap[_challengeID].totalTokens -= voterTokens;
        challengeMap[_challengeID].rewardPool -= reward;

        require(token.transfer(msg.sender, reward));

        // Ensures a voter cannot claim tokens again
        tokenClaims[_challengeID][msg.sender] = true;

        _RewardClaimed(msg.sender, _challengeID, reward);
    }

    /**
    @dev                Calculates the provided voter's token reward for the given poll.
    @param _voter       The address of the voter whose reward balance is to be returned
    @param _challengeID The pollID of the challenge a reward balance is being queried for
    @param _salt        The salt of the voter's commit hash in the given poll
    @return             The uint indicating the voter's reward (in nano-ADT)
    */
    function calculateVoterReward(address _voter, uint _challengeID, uint _salt)
    public constant returns (uint) {
        uint totalTokens = challengeMap[_challengeID].totalTokens;
        uint rewardPool = challengeMap[_challengeID].rewardPool;
        uint voterTokens = voting.getNumPassingTokens(_voter, _challengeID, _salt);
        return (voterTokens * rewardPool) / totalTokens;
    }

    // --------
    // GETTERS:
    // --------

    /**
    @dev                Determines whether the domain of an application can be whitelisted.
    @param _domain      The domain whose status should be examined
    */
    function canBeWhitelisted(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        // Ensures that the application was made,
        // the application period has ended,
        // the domain can be whitelisted,
        // and either: the challengeID == 0, or the challenge has been resolved.
        if (
            appWasMade(_domain) &&
            isExpired(listingMap[domainHash].applicationExpiry) &&
            !isWhitelisted(_domain) &&
            (challengeID == 0 || challengeMap[challengeID].resolved == true)
        ) { return true; }

        return false;
    }

    // Returns true if domain is whitelisted
    function isWhitelisted(string _domain) constant public returns (bool whitelisted) {
        return listingMap[keccak256(_domain)].whitelisted;
    }

    // Returns true if apply(domain) was called for this domain
    function appWasMade(string _domain) constant public returns (bool exists) {
        return listingMap[keccak256(_domain)].applicationExpiry > 0;
    }

    // Returns true if the application/listing has an unresolved challenge
    function challengeExists(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        return (listingMap[domainHash].challengeID > 0 && !challengeMap[challengeID].resolved);
    }

    /**
    @notice             Determines whether voting has concluded in a challenge for a given domain.
    @dev                Throws if no challenge exists.
    @param _domain      A domain with an unresolved challenge
    */
    function challengeCanBeResolved(string _domain) constant public returns (bool) {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        require(challengeExists(_domain));

        return voting.pollEnded(challengeID);
    }

    /**
    @notice             Determines the number of tokens awarded to the winning party in a challenge.
    @param _challengeID The challengeID to determine a reward for
    */
    function determineReward(uint _challengeID) public constant returns (uint) {
        require(!challengeMap[_challengeID].resolved && voting.pollEnded(_challengeID));

        // Edge case, nobody voted, give all tokens to the challenger.
        if (voting.getTotalNumberOfTokensForWinningOption(_challengeID) == 0) {
            return 2 * challengeMap[_challengeID].stake;
        }

        return (2 * challengeMap[_challengeID].stake) - challengeMap[_challengeID].rewardPool;
    }

    // Returns true if the provided termDate has passed
    function isExpired(uint _termDate) constant public returns (bool expired) {
        return _termDate < block.timestamp;
    }

    // Deletes a listing from the whitelist and transfers tokens back to owner
    function resetListing(string _domain) internal {
        bytes32 domainHash = keccak256(_domain);
        Listing storage listing = listingMap[domainHash];

        // Transfers any remaining balance back to the owner
        if (listing.unstakedDeposit > 0)
            require(token.transfer(listing.owner, listing.unstakedDeposit));

        delete listingMap[domainHash];
    }

    // ----------------
    // PRIVATE FUNCTIONS:
    // ----------------

    /**
    @notice             Determines the winner in a challenge.
    @notice             Rewards the winner tokens and either whitelists or de-whitelists the domain.
    @param _domain      A domain with a challenge that is to be resolved
    */
    function resolveChallenge(string _domain) private {
        bytes32 domainHash = keccak256(_domain);
        uint challengeID = listingMap[domainHash].challengeID;

        // Calculates the winner's reward,
        // which is: (winner's full stake) + (dispensationPct * loser's stake)
        uint reward = determineReward(challengeID);

        // Records whether the domain is a listing or an application
        bool wasWhitelisted = isWhitelisted(_domain);

        // Case: challenge failed
        if (voting.isPassed(challengeID)) {
            whitelistApplication(_domain);
            // Unlock stake so that it can be retrieved by the applicant
            listingMap[domainHash].unstakedDeposit += reward;

            _ChallengeFailed(challengeID);
            if (!wasWhitelisted) { _NewDomainWhitelisted(_domain); }
        }
        // Case: challenge succeeded
        else {
            resetListing(_domain);
            // Transfer the reward to the challenger
            require(token.transfer(challengeMap[challengeID].challenger, reward));

            _ChallengeSucceeded(challengeID);
            if (wasWhitelisted) { _ListingRemoved(_domain); }
            else { _ApplicationRemoved(_domain); }
        }

        // Sets flag on challenge being processed
        challengeMap[challengeID].resolved = true;

        // Stores the total tokens used for voting by the winning side for reward purposes
        challengeMap[challengeID].totalTokens =
            voting.getTotalNumberOfTokensForWinningOption(challengeID);
    }

    /**
    @dev                Called by updateStatus() if the applicationExpiry date passed without a challenge being made.
    @dev                Called by resolveChallenge() if an application/listing beat a challenge.
    @param _domain      The domain of an application/listing to be whitelisted
    */
    function whitelistApplication(string _domain) private {
        bytes32 domainHash = keccak256(_domain);

        listingMap[domainHash].whitelisted = true;
    }
}


Invalid constant declaration

Invalid constant declaration

pragma solidity ^0.4.11;

import './ERC20Basic.sol';
import "../token/SafeERC20.sol";

/**
 * @title TokenTimelock
 * @dev TokenTimelock is a token holder contract that will allow a
 * beneficiary to extract the tokens after a given release time
 */
contract TokenTimelock {
  using SafeERC20 for ERC20Basic;

  // ERC20 basic token contract being held
  ERC20Basic public token;

  // beneficiary of tokens after they are released
  address public beneficiary;

  // timestamp when token release is enabled
  uint64 public releaseTime;

  function TokenTimelock(ERC20Basic _token, address _beneficiary, uint64 _releaseTime) {
    require(_releaseTime > now);
    token = _token;
    beneficiary = _beneficiary;
    releaseTime = _releaseTime;
  }

  /**
   * @notice Transfers tokens held by timelock to beneficiary.
   * Deprecated: please use TokenTimelock#release instead.
   */
  function claim() public {
    require(msg.sender == beneficiary);
    release();
  }

  /**
   * @notice Transfers tokens held by timelock to beneficiary.
   */
  function release() public {
    require(now >= releaseTime);

    uint256 amount = token.balanceOf(this);
    require(amount > 0);

    token.safeTransfer(beneficiary, amount);
  }
}

pragma solidity ^0.4.11;

import './ERC20Basic.sol';
import "../token/SafeERC20.sol";

/**
 * @title TokenTimelock
 * @dev TokenTimelock is a token holder contract that will allow a
 * beneficiary to extract the tokens after a given release time
 */
contract TokenTimelock {
  using SafeERC20 for ERC20Basic;

  // ERC20 basic token contract being held
  ERC20Basic public token;

  // beneficiary of tokens after they are released
  address public beneficiary;

  // timestamp when token release is enabled
  uint64 public releaseTime;

  function TokenTimelock(ERC20Basic _token, address _beneficiary, uint64 _releaseTime) {
    require(_releaseTime > now);
    token = _token;
    beneficiary = _beneficiary;
    releaseTime = _releaseTime;
  }

  /**
   * @notice Transfers tokens held by timelock to beneficiary.
   * Deprecated: please use TokenTimelock#release instead.
   */
  function claim() public constant {
    require(msg.sender == beneficiary);
    release();
  }

  /**
   * @notice Transfers tokens held by timelock to beneficiary.
   */
  function release() public constant {
    require(now >= releaseTime);

    uint256 amount = token.balanceOf(this);
    require(amount > 0);

    token.safeTransfer(beneficiary, amount);
  }
}


removed redundant file

removed redundant file

//В этом контракте даны коментарии на русском языке, о его функциональности
//MarsTokenV1 - представляет из себя централизованный ерс20 совместимый смартконтракт,
//Из основных минусов - записи балансов хранятся в отдельном смартконтракте BalanceSheet,
//Этот смартконтракт можно заменить в любое время на новый смартконтракт функцией setBalanceSheet(address _sheet).
//Все переводы MarsTokenV1 могут быть заморожены, MarsTokenV1 расширяет Pausable.
//Адреса держателей могут быть добавлены в черный список, а затем их баланс может быть стерт, MarsTokenV1 расширяет Blacklistable
//
//
//
pragma solidity ^0.4.25;

// File: contracts/openzeppelin/ERC20/ERC20Basic.sol

/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * See https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address _who) public view returns (uint256);
  function transfer(address _to, uint256 _value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

// File: contracts/openzeppelin/ERC20/ERC20.sol

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address _owner, address _spender)
    public view returns (uint256);

  function transferFrom(address _from, address _to, uint256 _value)
    public returns (bool);

  function approve(address _spender, uint256 _value) public returns (bool);
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );
}

// File: contracts/openzeppelin/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (_a == 0) {
      return 0;
    }

    c = _a * _b;
    require(c / _a == _b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    // Solidity only automatically asserts when dividing by 0
    require(_b > 0);
    // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
    return _a / _b;
  }

  /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    require(_b <= _a);
    return _a - _b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    c = _a + _b;
    require(c >= _a);
    return c;
  }
}

// File: contracts/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract from https://github.com/zeppelinos/labs/blob/master/upgradeability_ownership/contracts/ownership/Ownable.sol
 * branch: master commit: 3887ab77b8adafba4a26ace002f3a684c1a3388b modified to:
 * 1) Add emit prefix to OwnershipTransferred event (7/13/18)
 * 2) Replace constructor with constructor syntax (7/13/18)
 * 3) consolidate OwnableStorage into this contract
 */
contract Ownable {

  // Owner of the contract
  address private _owner;

  /**
  * @dev Event to show ownership has been transferred
  * @param previousOwner representing the address of the previous owner
  * @param newOwner representing the address of the new owner
  */
  event OwnershipTransferred(address previousOwner, address newOwner);

  /**
  * @dev The constructor sets the original owner of the contract to the sender account.
  */
  constructor() public {
    setOwner(msg.sender);
  }

  /**
 * @dev Tells the address of the owner
 * @return the address of the owner
 */
  function owner() public view returns (address) {
    return _owner;
  }

  /**
   * @dev Sets a new owner address
   */
  function setOwner(address newOwner) internal {
    _owner = newOwner;
  }

  /**
  * @dev Throws if called by any account other than the owner.
  */
  modifier onlyOwner() {
    require(msg.sender == owner());
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    emit OwnershipTransferred(owner(), newOwner);
    setOwner(newOwner);
  }
}

// File: contracts/Blacklistable.sol

/**
 * @title Blacklistable Token
 * @dev Allows accounts to be blacklisted by a "blacklister" role
*/
contract Blacklistable is Ownable {

  address public blacklister;
  mapping(address => bool) internal blacklisted;

  event Blacklisted(address indexed _account);
  event UnBlacklisted(address indexed _account);
  event BlacklisterChanged(address indexed newBlacklister);

  /**
   * @dev Throws if called by any account other than the blacklister
  */
  modifier onlyBlacklister() {
    require(msg.sender == blacklister);
    _;
  }

  /**
   * @dev Throws if argument account is blacklisted
   * @param _account The address to check
  */
  modifier notBlacklisted(address _account) {
    require(blacklisted[_account] == false);
    _;
  }

  /**
   * @dev Checks if account is blacklisted
   * @param _account The address to check
  */
  function isBlacklisted(address _account) public view returns (bool) {
    return blacklisted[_account];
  }

  /**
   * @dev Adds account to blacklist
   * @param _account The address to blacklist
  */
  function blacklist(address _account) public onlyBlacklister {
    blacklisted[_account] = true;
    emit Blacklisted(_account);
  }

  /**
   * @dev Removes account from blacklist
   * @param _account The address to remove from the blacklist
  */
  function unBlacklist(address _account) public onlyBlacklister {
    blacklisted[_account] = false;
    emit UnBlacklisted(_account);
  }

  function updateBlacklister(address _newBlacklister) public onlyOwner {
    require(_newBlacklister != address(0));
    blacklister = _newBlacklister;
    emit BlacklisterChanged(blacklister);
  }
}

// File: contracts/Pausable.sol

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 * Based on openzeppelin tag v1.10.0 commit: feb665136c0dae9912e08397c1a21c4af3651ef3
 * Modifications:
 * 1) Added pauser role, switched pause/unpause to be onlyPauser (6/14/2018)
 * 2) Removed whenNotPause/whenPaused from pause/unpause (6/14/2018)
 * 3) Removed whenPaused (6/14/2018)
 * 4) Switches ownable library to use zeppelinos (7/12/18)
 * 5) Remove constructor (7/13/18)
 */
contract Pausable is Ownable {
  event Pause();
  event Unpause();
  event PauserChanged(address indexed newAddress);

  address public pauser;
  bool public paused = false;

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * @dev throws if called by any account other than the pauser
   */
  modifier onlyPauser() {
    require(msg.sender == pauser);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() public onlyPauser {
    paused = true;
    emit Pause();
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() public onlyPauser {
    paused = false;
    emit Unpause();
  }

  /**
   * @dev update the pauser role
   */
  function updatePauser(address _newPauser) public onlyOwner {
    require(_newPauser != address(0));
    pauser = _newPauser;
    emit PauserChanged(pauser);
  }

}

// File: contracts/sheets/DelegateContract.sol

contract DelegateContract is Ownable {
  address delegate_;

  event LogicContractChanged(address indexed newAddress);

  /**
  * @dev Throws if called by any account other than the owner.
  */
  modifier onlyFromAccept() {
    require(msg.sender == delegate_);
    _;
  }

  function setLogicContractAddress(address _addr) public onlyOwner {
    delegate_ = _addr;
    emit LogicContractChanged(_addr);
  }

  function isDelegate(address _addr) public view returns(bool) {
    return _addr == delegate_;
  }
}

// File: contracts/sheets/AllowanceSheet.sol

// A wrapper around the allowanceOf mapping.
contract AllowanceSheet is DelegateContract {
  using SafeMath for uint256;

  mapping (address => mapping (address => uint256)) public allowanceOf;

  function subAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyFromAccept {
    allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].sub(_value);
  }

  function setAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyFromAccept {
    allowanceOf[_tokenHolder][_spender] = _value;
  }
}

// File: contracts/sheets/BalanceSheet.sol

// A wrapper around the balanceOf mapping.
contract BalanceSheet is DelegateContract, AllowanceSheet {
  using SafeMath for uint256;

  uint256 internal totalSupply_ = 0;

  mapping (address => uint256) public balanceOf;

  function addBalance(address _addr, uint256 _value) public onlyFromAccept {
    balanceOf[_addr] = balanceOf[_addr].add(_value);
  }

  function subBalance(address _addr, uint256 _value) public onlyFromAccept {
    balanceOf[_addr] = balanceOf[_addr].sub(_value);
  }

  function increaseSupply(uint256 _amount) public onlyFromAccept {
    totalSupply_ = totalSupply_.add(_amount);
  }

  function decreaseSupply(uint256 _amount) public onlyFromAccept {
    totalSupply_ = totalSupply_.sub(_amount);
  }

  function totalSupply() public view returns (uint256) {
    return totalSupply_;
  }
}

// File: contracts\MarsTokenV1.sol

/**
 * @title MarsToken
 * @dev ERC20 Token backed by fiat reserves
 */
contract MarsTokenV1 is Ownable, ERC20, Pausable, Blacklistable {
  using SafeMath for uint256;

  string public name;
  string public symbol;
  uint8 public decimals;
  string public currency;
  address public masterMinter;

  //mapping(address => uint256) internal balances;
  //mapping(address => mapping(address => uint256)) internal allowed;
  //uint256 internal totalSupply_ = 0;
  mapping(address => bool) internal minters;
  mapping(address => uint256) internal minterAllowed;

  event Mint(address indexed minter, address indexed to, uint256 amount);
  event Burn(address indexed burner, uint256 amount);
  event MinterConfigured(address indexed minter, uint256 minterAllowedAmount);
  event MinterRemoved(address indexed oldMinter);
  event MasterMinterChanged(address indexed newMasterMinter);
  event DestroyedBlackFunds(address indexed _account, uint256 _balance);

  BalanceSheet public balances;
  event BalanceSheetSet(address indexed sheet);

  /**
  * @dev ownership of the balancesheet contract
  * @param _sheet The address to of the balancesheet.
  */
  function setBalanceSheet(address _sheet) public onlyOwner returns (bool) {
    balances = BalanceSheet(_sheet);
    emit BalanceSheetSet(_sheet);
    return true;
  }

  constructor(
    string _name,
    string _symbol,
    string _currency,
    uint8 _decimals,
    address _masterMinter,
    address _pauser,
    address _blacklister
  ) public {
    require(_masterMinter != address(0));
    require(_pauser != address(0));
    require(_blacklister != address(0));

    name = _name;
    symbol = _symbol;
    currency = _currency;
    decimals = _decimals;
    masterMinter = _masterMinter;
    pauser = _pauser;
    blacklister = _blacklister;
    setOwner(msg.sender);
  }

  /**
  * @dev Throws if called by any account other than a minter
  */
  modifier onlyMinters() {
    require(minters[msg.sender] == true);
    _;
  }

  /**
  * @dev Function to mint tokens
  * @param _to The address that will receive the minted tokens.
  * @param _amount The amount of tokens to mint. Must be less than or equal to the minterAllowance of the caller.
  * @return A boolean that indicates if the operation was successful.
  */
  function mint(address _to, uint256 _amount) public whenNotPaused onlyMinters notBlacklisted(msg.sender) notBlacklisted(_to) returns (bool) {
    require(_to != address(0));
    require(_amount > 0);

    uint256 mintingAllowedAmount = minterAllowed[msg.sender];
    require(_amount <= mintingAllowedAmount);

    //totalSupply_ = totalSupply_.add(_amount);
    balances.increaseSupply(_amount);
    //balances[_to] = balances[_to].add(_amount);
    balances.addBalance(_to, _amount);
    minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount);
    emit Mint(msg.sender, _to, _amount);
    emit Transfer(0x0, _to, _amount);
    return true;
  }

  /**
  * @dev Throws if called by any account other than the masterMinter
  */
  modifier onlyMasterMinter() {
    require(msg.sender == masterMinter);
    _;
  }

  /**
  * @dev Get minter allowance for an account
  * @param minter The address of the minter
  */
  function minterAllowance(address minter) public view returns (uint256) {
    return minterAllowed[minter];
  }

  /**
  * @dev Checks if account is a minter
  * @param account The address to check
  */
  function isMinter(address account) public view returns (bool) {
    return minters[account];
  }

  /**
  * @dev Get allowed amount for an account
  * @param owner address The account owner
  * @param spender address The account spender
  */
  function allowance(address owner, address spender) public view returns (uint256) {
    //return allowed[owner][spender];
    return balances.allowanceOf(owner,spender);
  }

  /**
  * @dev Get totalSupply of token
  */
  function totalSupply() public view returns (uint256) {
    return balances.totalSupply();
  }

  /**
  * @dev Get token balance of an account
  * @param account address The account
  */
  function balanceOf(address account) public view returns (uint256) {
    //return balances[account];
    return balances.balanceOf(account);
  }

  /**
  * @dev Adds blacklisted check to approve
  * @return True if the operation was successful.
  */
  function approve(address _spender, uint256 _value) public whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_spender) returns (bool) {
    require(_spender != address(0));
    //allowed[msg.sender][_spender] = _value;
    balances.setAllowance(msg.sender, _spender, _value);
    emit Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
  * @dev Transfer tokens from one address to another.
  * @param _from address The address which you want to send tokens from
  * @param _to address The address which you want to transfer to
  * @param _value uint256 the amount of tokens to be transferred
  * @return bool success
  */
  function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused notBlacklisted(_to) notBlacklisted(msg.sender) notBlacklisted(_from) returns (bool) {
    require(_to != address(0));
    require(_value <= balances.balanceOf(_from));
    require(_value <= balances.allowanceOf(_from, msg.sender));

    //allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    balances.subAllowance(_from, msg.sender, _value);
    //balances[_from] = balances[_from].sub(_value);
    balances.subBalance(_from, _value);
    //balances[_to] = balances[_to].add(_value);
    balances.addBalance(_to, _value);
    emit Transfer(_from, _to, _value);
    return true;
  }

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  * @return bool success
  */
  function transfer(address _to, uint256 _value) public whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_to) returns (bool) {
    require(_to != address(0));
    require(_value <= balances.balanceOf(msg.sender));

    //balances[msg.sender] = balances[msg.sender].sub(_value);
    balances.subBalance(msg.sender, _value);
    //balances[_to] = balances[_to].add(_value);
    balances.addBalance(_to, _value);
    emit Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Function to add/update a new minter
  * @param minter The address of the minter
  * @param minterAllowedAmount The minting amount allowed for the minter
  * @return True if the operation was successful.
  */
  function configureMinter(address minter, uint256 minterAllowedAmount) public whenNotPaused onlyMasterMinter notBlacklisted(minter) returns (bool) {
    minters[minter] = true;
    minterAllowed[minter] = minterAllowedAmount;
    emit MinterConfigured(minter, minterAllowedAmount);
    return true;
  }

  /**
  * @dev Function to remove a minter
  * @param minter The address of the minter to remove
  * @return True if the operation was successful.
  */
  function removeMinter(address minter) public onlyMasterMinter returns (bool) {
    minters[minter] = false;
    minterAllowed[minter] = 0;
    emit MinterRemoved(minter);
    return true;
  }

  /**
  * @dev allows a minter to burn some of its own tokens
  * Validates that caller is a minter and that sender is not blacklisted
  * amount is less than or equal to the minter's account balance
  * @param _amount uint256 the amount of tokens to be burned
  */
  function burn(uint256 _amount) public whenNotPaused onlyMinters notBlacklisted(msg.sender) {
    uint256 balance = balances.balanceOf(msg.sender);
    require(_amount > 0);
    require(balance >= _amount);

    //totalSupply_ = totalSupply_.sub(_amount);
    balances.decreaseSupply(_amount);
    //balances[msg.sender] = balance.sub(_amount);
    balances.subBalance(msg.sender, _amount);
    emit Burn(msg.sender, _amount);
    emit Transfer(msg.sender, address(0), _amount);
  }

  function updateMasterMinter(address _newMasterMinter) public onlyOwner {
    require(_newMasterMinter != address(0));
    masterMinter = _newMasterMinter;
    emit MasterMinterChanged(masterMinter);
  }

  /**
   * @dev Destroy funds of account from blacklist
   * @param _account The address to destory funds
  */
  function destroyBlackFunds(address _account) public onlyOwner {
    require(blacklisted[_account]);
    uint256 _balance = balances.balanceOf(_account);
    balances.subBalance(_account, _balance);
    balances.decreaseSupply(_balance);
    emit DestroyedBlackFunds(_account, _balance);
    emit Transfer(_account, address(0), _balance);
  }

}