<commit_before>/*jslint todo: true */
"use strict";

var assert = require("chai").assert;

var GBot = require("../../lib/bot/GBot.js"),
    KBase = require("../bot/KBase"),
    Utils = require("../../lib/utils/Utils"),
    TextLib = require("../../lib/utils/TextLib"),
    AppConfig = require("../../config/AppConfig"),
    Bonfires = require("../app/Bonfires"),
    InputWrap = require("../bot/InputWrap");

// var httpSync = require('http-sync');

var newline = '\n';

    // Rooms = require('../app/Rooms'),
    // RoomData = require('../../data/RoomData');

function clog(msg, obj) {
    Utils.clog("BotCommands>", msg, obj);
}

function tlog(msg, obj) {
    Utils.warn("BotCommands>", msg, obj);
}

// function tlog(p1, p2, p3, p4) {
//     Utils.tlog("BotCommands>", p1, p2, p3, p4);
// }

// var contactBox = "\n if you'd like to help please [get in touch!](https://github.com/freecodecamp/freecodecamp) :thumbsup: ",
//     topLine = "----\n",
//     wipHeader = "\n work in progress!";

var BotCommands = {

    isCommand: function (input) {
        var cmds, one, res;
        cmds = BotCommands.cmdList.filter(function (c) {
            return (c === input.keyword);
        });
        one = cmds[0];
        if (one) {
            res = true;
        } else {
            res = false;
            Utils.warn('isCommand', 'not command', input);
            Utils.warn('isCommand',
                `[ isCommand: ${input.keyword} ] one: ${one} | res ${res} ` );
        }
        return res;
    },

    version: function(){
        return "botVersion: " + AppConfig.botVersion;
    },

    test: function (input, bot) {
        var msg = "All bot systems are go!";
        return msg;
    },

    wiki: function(input, bot) {
        var output = "", topicData;
        debugger;

        topicData = KBase.getTopicData(input.params);
        clog('topicData', topicData);
        if (topicData) {
            output = `**${input.params}** wikiEntry\n`;
            output += TextLib.trimLines(topicData.data);
            output += topicData.data + "\n";
            output += "\n![bothelp](https://avatars1.githubusercontent.com/bothelp?v=3&s=16)";
            output += " [PM CamperBot](" + AppConfig.topicDmUri(topicData.topic) + ")";
            output += " | [wikilink **" + topicData.topic + "**](" + AppConfig.wikiHost + topicData.topic + ")";
        } else {
            Utils.warn(`cant find topic for [ ${input.params} ]`);
            output = `no wiki entry for ${input.params}`;
        }
        return output;
    },

    // bonfire features
    hint: function(input, bot) {
        var str;
        str = Bonfires.getHint(input);
        return (str);
    },

    links: function(input, bot) {
        var str;
        str = Bonfires.getLinksFromInput(input);
        return str;
    },

    seed: function(input, bot) {
        var str;
        str = Bonfires.getChallengeSeedFromInput(input);
        return str;
    },

    archive: function(input, bot) {
        var str, roomName, shortName, roomUri, timeStamp;
        roomName = input.message.room.name;
        shortName = InputWrap.roomShortName(input);

        roomUri = AppConfig.gitterHost + roomName + "/archives/" ;
        str = "Archives for **" + shortName + "**" + newline;
        str += "\n- [All Time](" + roomUri + "all)";

        timeStamp = Utils.timeStamp("yesterday");
        str += "\n- [Yesterday](" + roomUri + timeStamp + ")";

        // tlog(str);

        return str;
        // https://gitter.im/dcsan/botzy/archives/all
        // date ; //# => Thu Mar 31 2011 11:14:50 GMT+0200 (CEST)
        // https://gitter.im/bothelp/GeneralChat/archives/2015/07/25
    },

    init: function (bot) {
        // FIXME - this is sketchy storing references like a global
        // called from the bot where we don't always have an instance
        BotCommands.bot = bot;
    },

    help: function (input, bot) {
        // input;
        // var msg = Utils.makeMessageFromString("help help");
        // return "try this: `wiki $topic` or topics for a list";
        // return bot.findAnyReply(msg);
        if (input.params) {
            return this.wiki(input, bot);
        } else {
            var topicData = KBase.getTopicData("bothelp");
            return topicData.data;
        }
    },

    menu: function (input, bot) {
        var msg = "type help for a list of things the bot can do";
        return msg;
    },

    // TODO - sort alphabetically
    rooms: function (input, bot) {
        var uri, link, str, roomNames;
        roomNames = bot.roomList.map(function (rm) {
            uri = "https://gitter.im/" + rm.name;
            link = "\n- [" + rm.name + "](" + uri + ")  ";
            return link;
        });
        str = "## rooms" + roomNames;
        return str;
    },

    welcome: function (input, bot) {
        var str = "## welcome " + input.message.model.fromUser.username;
        str += "\n type `help` for some things the bot can do.";
        return str;
    },

    // gitter limits to first 10 lines or so
    // TODO - pagination
    topics: function (input, bot) {
        var str, shortList, list;
        str = "## topics\n";
        shortList = KBase.topicList.slice(0, 10);
        list = shortList.map(function (t) {
            return (Utils.linkify(t, "wiki"));
        });
        str += list.join("\n");
        // clog("shortList", shortList);
        // clog("topics", str);
        // return "list"
        return str;
    },

    find: function (input, bot) {
        var str = `find **${input.params}**\n`;
        var shortList = KBase.findTopics(input.params);
        bot.context = {
            state: "finding",
            commands: shortList.commands
        };
        str += shortList;
        clog("find", str);
        return (str);
    },

    commands: function (input, bot) {
        var str = "## commands:\n";
        str += BotCommands.cmdList.join("\n- ");
        return str;
    },

    // FIXME - this isn't working it seems
    rejoin: function (input, bot) {
        clog("GBot", GBot);
        BotCommands.bot.scanRooms();
        return "rejoined";
    },
    music: function (input, bot) {
        var str = "## Music!";
        str += "\n http://plug.dj/freecodecamp";
        return str;
    },

    rickroll: function (input, bot) {
        var fromUser = "@" + input.message.model.fromUser.username;
        var str = fromUser + " has a nice video";
        str += "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
        return str;
    },

    wikiUpdate: function (input, bot) {
        return "WIP wiki-update";
    },

    camperCount: function (input, bot) {
        return "WIP camperCount";
    },

    // search: function (input, bot) {
    //     var str = topLine + wipHeader;
    //     str += "## search for" + input.text;
    //     str += "\n results will be here!";
    //     str += contactBox;
    //     return str;
    // },

};

BotCommands.about = require("./cmds/about");
BotCommands.thanks = require("./cmds/thanks");

// setup aliases
// BotCommands.help = BotCommands.menu;
BotCommands.hi = BotCommands.welcome;
// BotCommands.bothelp = BotCommands.menu;
BotCommands.hello = BotCommands.welcome;
BotCommands.index = BotCommands.topics;

BotCommands.log = BotCommands.archive;
BotCommands.archives = BotCommands.archive;

// BotCommands['@bothelp hi'] = BotCommands.menu;

// TODO - some of these should be filtered/as private
BotCommands.cmdList = Object.keys(BotCommands);

module.exports = BotCommands;
<commit_msg>splitting commands into separate files<commit_after>/*jslint todo: true */
"use strict";

var assert = require("chai").assert;
var _ = require("lodash");

var GBot = require("../../lib/bot/GBot.js"),
    KBase = require("../bot/KBase"),
    Utils = require("../../lib/utils/Utils"),
    TextLib = require("../../lib/utils/TextLib"),
    AppConfig = require("../../config/AppConfig"),
    Bonfires = require("../app/Bonfires"),
    InputWrap = require("../bot/InputWrap");

// var httpSync = require('http-sync');

var newline = '\n';

    // Rooms = require('../app/Rooms'),
    // RoomData = require('../../data/RoomData');

function clog(msg, obj) {
    Utils.clog("BotCommands>", msg, obj);
}

function tlog(msg, obj) {
    Utils.warn("BotCommands>", msg, obj);
}

// function tlog(p1, p2, p3, p4) {
//     Utils.tlog("BotCommands>", p1, p2, p3, p4);
// }

// var contactBox = "\n if you'd like to help please [get in touch!](https://github.com/freecodecamp/freecodecamp) :thumbsup: ",
//     topLine = "----\n",
//     wipHeader = "\n work in progress!";

var BotCommands = {

    isCommand: function (input) {
        var cmds, one, res;
        cmds = BotCommands.cmdList.filter(function (c) {
            return (c === input.keyword);
        });
        one = cmds[0];
        if (one) {
            res = true;
        } else {
            res = false;
            Utils.warn('isCommand', 'not command', input);
            Utils.warn('isCommand',
                `[ isCommand: ${input.keyword} ] one: ${one} | res ${res} ` );
        }
        return res;
    },

    version: function(){
        return "botVersion: " + AppConfig.botVersion;
    },

    test: function (input, bot) {
        var msg = "All bot systems are go!";
        return msg;
    },

    // bonfire features
    hint: function(input, bot) {
        var str;
        str = Bonfires.getHint(input);
        return (str);
    },

    links: function(input, bot) {
        var str;
        str = Bonfires.getLinksFromInput(input);
        return str;
    },

    seed: function(input, bot) {
        var str;
        str = Bonfires.getChallengeSeedFromInput(input);
        return str;
    },

    archive: function(input, bot) {
        var str, roomName, shortName, roomUri, timeStamp;
        roomName = input.message.room.name;
        shortName = InputWrap.roomShortName(input);

        roomUri = AppConfig.gitterHost + roomName + "/archives/" ;
        str = "Archives for **" + shortName + "**" + newline;
        str += "\n- [All Time](" + roomUri + "all)";

        timeStamp = Utils.timeStamp("yesterday");
        str += "\n- [Yesterday](" + roomUri + timeStamp + ")";

        // tlog(str);

        return str;
        // https://gitter.im/dcsan/botzy/archives/all
        // date ; //# => Thu Mar 31 2011 11:14:50 GMT+0200 (CEST)
        // https://gitter.im/bothelp/GeneralChat/archives/2015/07/25
    },

    init: function (bot) {
        // FIXME - this is sketchy storing references like a global
        // called from the bot where we don't always have an instance
        BotCommands.bot = bot;
    },

    // help on its own we return `help bothelp`
    help: function (input, bot) {
        // input;
        // var msg = Utils.makeMessageFromString("help help");
        // return "try this: `wiki $topic` or topics for a list";
        // return bot.findAnyReply(msg);
        if (input.params) {
            return this.wiki(input, bot);
        } else {
            var topicData = KBase.getTopicData("bothelp");
            return topicData.data;
        }
    },

    menu: function (input, bot) {
        var msg = "type help for a list of things the bot can do";
        return msg;
    },

    // TODO - sort alphabetically
    rooms: function (input, bot) {
        var uri, link, str, roomNames;
        roomNames = bot.roomList.map(function (rm) {
            uri = "https://gitter.im/" + rm.name;
            link = "\n- [" + rm.name + "](" + uri + ")  ";
            return link;
        });
        str = "## rooms" + roomNames;
        return str;
    },

    welcome: function (input, bot) {
        var str = "## welcome " + input.message.model.fromUser.username;
        str += "\n type `help` for some things the bot can do.";
        return str;
    },

    // gitter limits to first 10 lines or so
    // TODO - pagination
    topics: function (input, bot) {
        var str, shortList, list;
        str = "## topics\n";
        shortList = KBase.topicList.slice(0, 10);
        list = shortList.map(function (t) {
            return (Utils.linkify(t, "wiki"));
        });
        str += list.join("\n");
        // clog("shortList", shortList);
        // clog("topics", str);
        // return "list"
        return str;
    },

    find: function (input, bot) {
        var str = `find **${input.params}**\n`;
        var shortList = KBase.findTopics(input.params);
        bot.context = {
            state: "finding",
            commands: shortList.commands
        };
        str += shortList;
        clog("find", str);
        return (str);
    },

    commands: function (input, bot) {
        var str = "## commands:\n";
        str += BotCommands.cmdList.join("\n- ");
        return str;
    },

    // FIXME - this isn't working it seems
    rejoin: function (input, bot) {
        clog("GBot", GBot);
        BotCommands.bot.scanRooms();
        return "rejoined";
    },
    music: function (input, bot) {
        var str = "## Music!";
        str += "\n http://plug.dj/freecodecamp";
        return str;
    },

    rickroll: function (input, bot) {
        var fromUser = "@" + input.message.model.fromUser.username;
        var str = fromUser + " has a nice video";
        str += "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
        return str;
    },

    wikiUpdate: function (input, bot) {
        return "WIP wiki-update";
    },

    camperCount: function (input, bot) {
        return "WIP camperCount";
    },

    // search: function (input, bot) {
    //     var str = topLine + wipHeader;
    //     str += "## search for" + input.text;
    //     str += "\n results will be here!";
    //     str += contactBox;
    //     return str;
    // },

};

BotCommands.about = require("./cmds/about");
BotCommands.thanks = require("./cmds/thanks");

var wiki = require("./cmds/wiki");

_.merge(BotCommands, wiki);

// Object.assign(BotCommands, wiki);

// setup aliases
// BotCommands.help = BotCommands.menu;
BotCommands.hi = BotCommands.welcome;
// BotCommands.bothelp = BotCommands.menu;
BotCommands.hello = BotCommands.welcome;
BotCommands.index = BotCommands.topics;

BotCommands.log = BotCommands.archive;
BotCommands.archives = BotCommands.archive;

// BotCommands['@bothelp hi'] = BotCommands.menu;

// TODO - some of these should be filtered/as private
BotCommands.cmdList = Object.keys(BotCommands);

module.exports = BotCommands;
<|endoftext|>


<commit_before>
function SimpleSendController($scope, userService) {
  var wallet = userService.getWallet();

  MySimpleSendHelpers(wallet);

}
function HomeCtrl($scope, $templateCache, $injector, $location, $http, $q) {
  if ($injector.get('userService').getUUID()) {
    $location.url('/wallet/overview');
  } else {
    //DEV ONLY
    console.log('cleared cache');
    $templateCache.removeAll();

    $scope.balanceAddress = "";
    $scope.hasBalances = false;
    $scope.total = 0;
    $scope.checkBalance = function() {
      var balances = {};
      var appraiser = $injector.get('appraiser');
      $injector.get('balanceService').balance($scope.balanceAddress).then(function(result) {
        result.data.balance.forEach(function(currencyItem) {
          if(currencyItem.divisible)
            var value=new Big(currencyItem.value).times(WHOLE_UNIT).valueOf();
          balances[currencyItem.symbol] = {
            "symbol": currencyItem.symbol,
            "balance": +value || currencyItem.value,
            "value": appraiser.getValue(currencyItem.value, currencyItem.symbol),
          };
          if (currencyItem.symbol == 'BTC') {
            balances[currencyItem.symbol].name = "Bitcoin";
          }
        });
        $http.get('/v1/transaction/values.json').then(function(result) {
          currencyInfo = result.data;

          currencyInfo.forEach(function(item) {
            if (balances.hasOwnProperty(item.currency))
              balances[item.currency].name = item.name;
          });

          // Now, any applicable smart properties.
          var spReqs = [];

          for (var b in balances) {
            var spMatch = balances[b].symbol.match(/^SP([0-9]+)$/);

            if (spMatch != null) {
              var updateFunction = function(result) {
                if (result.status == 200) {
                  this.property_type = result.data[0].formatted_property_type;
                  this.name = result.data[0].propertyName + ' (' + this.symbol.match(/^SP([0-9]+)$/)[1] + ')';
                }
              };
              spReqs.push($http.get('/v1/property/' + spMatch[1] + '.json').then(updateFunction.bind(balances[b])));
            }
          }

          if (spReqs.length > 0) {
            $q.all(spReqs).then(function() {
              $scope.balances = balances;
              $scope.hasBalances = true;
            });
          } else {
            $scope.balances = balances;
            $scope.hasBalances = true;
          }

        }
        );

      });
    };

  }
}
function StatsCtrl($scope, $route, $routeParams, $http) {

  $http.get('/v1/system/stats.json', {}).success(function(data) {
    $scope.stats = data;
  });
}

function Ctrl($scope, $route, $routeParams, $modal, $location, browser) {

  $scope.$route = $route;
  $scope.$location = $location;
  $scope.browser = browser;

  /*$scope.$on('$locationChangeStart', function(event, next) {
    if (browser === 'chrome') {
      return;
    }

    event.preventDefault();

    $modal.open({
      backdrop: 'static',
      templateUrl: '/partials/browser_message_modal.html'
    });
  });*/

  $scope.templates = {
    'header': '/header.html',
    'footer': '/footer.html',
    'sidecar': '/partials/sidecar.html',
    'add_address': '/partials/add_address.html',
    'disclaimer': '/partials/disclaimer.html'
  };

}

function HiddenLoginController($scope, $modal, $location) {
  $scope.open = function() {
    $scope.uuid = $location.path().replace("/login/", "");

    $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginControllerUUID,
      resolve: {
        uuid: function() {
          return $scope.uuid;
        }
      }
    });
  }
}

function RevisionController($scope, $http, $modal, userService) {

  $scope.getData = function() {
    console.log('init 0');
    $http.get('/v1/system/revision.json', {}).success(function(data) {
      $scope.rev = data;
    });
  };
}

function NavigationController($scope, $http, $modal, userService) {

  $scope.getNavData = function() {
    console.log('init 0');
  };

  $scope.openCreateModal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_create_modal.html',
      controller: CreateWalletController
    });
  };

  $scope.openImportModal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_import_modal.html',
      controller: WalletController
    });
  };

  $scope.openLoginModal = function() {
    $scope.login ={
      title:'Login',
      button:'Open Wallet'
    };
    $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginController,
      scope: $scope
    });
  };

  $scope.openUUIDmodal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_uuid_modal.html',
      controller: WalletController
    });
  };

  $scope.openNewUUIDmodal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_new_modal.html',
      controller: WalletController
    });
  };

  $scope.logout = function() {
    window.location.reload(false);
  };

  $scope.user = userService.data;
}

function ExplorerController($scope, $http, hashExplorer) {
  $scope.setHashExplorer = hashExplorer.setHash.bind(hashExplorer);
  // Scope members
  $scope.searchQueryText = '';
  $scope.transactions = [];
  $scope.currencies = ['MSC', 'TMSC'];
  $scope.currency = 'MSC';

  $scope.getData = function getData() {
    var currency = $scope.currency;
    console.log('did', currency);
    $http.get('/v1/transaction/values.json', {}). success(function(data) {
      for (var i = 0; i < data.length; i++) {
        if (currency == data[i].currency) {
          var file = '/v1/transaction/general/' + currency + '_0001.json';
          $http.get(file, {}).success(function(data, status, headers, config) {
            $scope.transactions = data;
          });
        }
      }
    });
  }

  $scope.searchQuery = function(trans) {
    return ($scope.searchQueryText === '' || trans.tx_hash.indexOf($scope.searchQueryText) >= 0 || trans.from_address.indexOf($scope.searchQueryText) >= 0 || trans.to_address.indexOf($scope.searchQueryText) >= 0);
  };
}
function ExplorerInspectorController($scope, $location, $http, hashExplorer) {
  function setData() {
    $scope.transactionData = JSON.parse(hashExplorer.tx);
    $scope.tx_keys = Object.keys($scope.transactionData);
    $scope.fieldlist = $scope.tx_keys;
    $scope.pastLoc = hashExplorer.loc;
  }

  if (hashExplorer.tx) {
    setData();
  } else {
    $http.get('/v1/transaction/tx/' + $location.search()['view'] + '.json'). success(function(data) {
      hashExplorer.setHash(data[0]);
      setData();
    });
  }
}
function SidecarController($scope, $http, $modal, $location, userService, balanceService) {
  $scope.values = {};
  $scope.setView = function(viewName) {
    $scope.view = $scope.sidecarTemplates[viewName];
  };
  $scope.getView = function() {
    return $scope.view;
  };
  $scope.sidecarTemplates = {
    'explorer': '/partials/explorer_sc.html',
    'about': '/partials/about_sc.html',
    'wallet': '/partials/wallet_sc.html'
  };

  $scope.hasAddresses = userService.data.loggedIn && userService.getAllAddresses().length != 0 ? true : false;
  $scope.hasAddressesWithPrivkey = userService.data.loggedIn && getAddressesWithPrivkey().length != 0 ? true : false;
  $scope.hasTradableCoins = false;
  $scope.hasBTC = false;
  checkBalance(getAddressesWithPrivkey());

  $scope.checkSendingEnabled = function($event) {
    var error = "Send page is unavailable because ";
    if(!$scope.hasAddressesWithPrivkey){
      $event.preventDefault();
      $event.stopPropagation();
      error += "the wallet has no addresses with private keys (no address to send from)";
    } else {
      if(!$scope.hasTradableCoins){
        $event.preventDefault();
        $event.stopPropagation();
        error += "the wallet has no coins in the addresses that have private keys (nothing to send)";
      } else {
        if(!$scope.hasBTC){
          $event.preventDefault();
          $event.stopPropagation();
          error += "wallet has no BTC in addresses that have private keys (no way to pay tx fees)";
        }
      }
    }

    if(error.length > 33){
      $modal.open({
        templateUrl: "/partials/popup_error.html",
        controller: function($scope, error){
          $scope.error = error;
        },
        resolve:{
          error:function(){
            return error;
          }
        }
      });
    } else {
      $location.path("/wallet/send");
    }
  };

  $scope.$watch(function() {
    return userService.getAllAddresses()
  }, function(result) {
    $scope.hasAddresses = userService.data.loggedIn && result.length != 0 ? true : false;
    $scope.hasAddressesWithPrivkey = userService.data.loggedIn && getAddressesWithPrivkey().length != 0 ? true : false;
    checkBalance(getAddressesWithPrivkey())
  }, true);

  function getAddressesWithPrivkey() {
    var addresses = []
    userService.getAllAddresses().map(function(e, i, a) {
      if (e.privkey && e.privkey.length == 58) {
        addresses.push(e.address);
      }
    }
    );
    return addresses;
  }

  function checkBalance(addresses){
    $scope.hasTradableCoins = false;
    $scope.hasBTC = false;
    if(addresses instanceof Array){
      addresses.forEach(function(address){
        balanceService.balance(address).then(function(result){
          var balances = result.data.balance;
          balances.forEach(function(balance){
            if(balance.value > 0)
              $scope.hasTradableCoins = true;
            if(balance.symbol == "BTC" && balance.value > 0)
              $scope.hasBTC = true;
          });
        });
      });
    }
  }
}

<commit_msg>Ensure checkBalance is only called when logged in<commit_after>
function SimpleSendController($scope, userService) {
  var wallet = userService.getWallet();

  MySimpleSendHelpers(wallet);

}
function HomeCtrl($scope, $templateCache, $injector, $location, $http, $q) {
  if ($injector.get('userService').getUUID()) {
    $location.url('/wallet/overview');
  } else {
    //DEV ONLY
    console.log('cleared cache');
    $templateCache.removeAll();

    $scope.balanceAddress = "";
    $scope.hasBalances = false;
    $scope.total = 0;
    $scope.checkBalance = function() {
      var balances = {};
      var appraiser = $injector.get('appraiser');
      $injector.get('balanceService').balance($scope.balanceAddress).then(function(result) {
        result.data.balance.forEach(function(currencyItem) {
          if(currencyItem.divisible)
            var value=new Big(currencyItem.value).times(WHOLE_UNIT).valueOf();
          balances[currencyItem.symbol] = {
            "symbol": currencyItem.symbol,
            "balance": +value || currencyItem.value,
            "value": appraiser.getValue(currencyItem.value, currencyItem.symbol),
          };
          if (currencyItem.symbol == 'BTC') {
            balances[currencyItem.symbol].name = "Bitcoin";
          }
        });
        $http.get('/v1/transaction/values.json').then(function(result) {
          currencyInfo = result.data;

          currencyInfo.forEach(function(item) {
            if (balances.hasOwnProperty(item.currency))
              balances[item.currency].name = item.name;
          });

          // Now, any applicable smart properties.
          var spReqs = [];

          for (var b in balances) {
            var spMatch = balances[b].symbol.match(/^SP([0-9]+)$/);

            if (spMatch != null) {
              var updateFunction = function(result) {
                if (result.status == 200) {
                  this.property_type = result.data[0].formatted_property_type;
                  this.name = result.data[0].propertyName + ' (' + this.symbol.match(/^SP([0-9]+)$/)[1] + ')';
                }
              };
              spReqs.push($http.get('/v1/property/' + spMatch[1] + '.json').then(updateFunction.bind(balances[b])));
            }
          }

          if (spReqs.length > 0) {
            $q.all(spReqs).then(function() {
              $scope.balances = balances;
              $scope.hasBalances = true;
            });
          } else {
            $scope.balances = balances;
            $scope.hasBalances = true;
          }

        }
        );

      });
    };

  }
}
function StatsCtrl($scope, $route, $routeParams, $http) {

  $http.get('/v1/system/stats.json', {}).success(function(data) {
    $scope.stats = data;
  });
}

function Ctrl($scope, $route, $routeParams, $modal, $location, browser) {

  $scope.$route = $route;
  $scope.$location = $location;
  $scope.browser = browser;

  /*$scope.$on('$locationChangeStart', function(event, next) {
    if (browser === 'chrome') {
      return;
    }

    event.preventDefault();

    $modal.open({
      backdrop: 'static',
      templateUrl: '/partials/browser_message_modal.html'
    });
  });*/

  $scope.templates = {
    'header': '/header.html',
    'footer': '/footer.html',
    'sidecar': '/partials/sidecar.html',
    'add_address': '/partials/add_address.html',
    'disclaimer': '/partials/disclaimer.html'
  };

}

function HiddenLoginController($scope, $modal, $location) {
  $scope.open = function() {
    $scope.uuid = $location.path().replace("/login/", "");

    $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginControllerUUID,
      resolve: {
        uuid: function() {
          return $scope.uuid;
        }
      }
    });
  }
}

function RevisionController($scope, $http, $modal, userService) {

  $scope.getData = function() {
    console.log('init 0');
    $http.get('/v1/system/revision.json', {}).success(function(data) {
      $scope.rev = data;
    });
  };
}

function NavigationController($scope, $http, $modal, userService) {

  $scope.getNavData = function() {
    console.log('init 0');
  };

  $scope.openCreateModal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_create_modal.html',
      controller: CreateWalletController
    });
  };

  $scope.openImportModal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_import_modal.html',
      controller: WalletController
    });
  };

  $scope.openLoginModal = function() {
    $scope.login ={
      title:'Login',
      button:'Open Wallet'
    };
    $modal.open({
      templateUrl: '/partials/login_modal.html',
      controller: LoginController,
      scope: $scope
    });
  };

  $scope.openUUIDmodal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_uuid_modal.html',
      controller: WalletController
    });
  };

  $scope.openNewUUIDmodal = function() {
    $modal.open({
      templateUrl: '/partials/wallet_new_modal.html',
      controller: WalletController
    });
  };

  $scope.logout = function() {
    window.location.reload(false);
  };

  $scope.user = userService.data;
}

function ExplorerController($scope, $http, hashExplorer) {
  $scope.setHashExplorer = hashExplorer.setHash.bind(hashExplorer);
  // Scope members
  $scope.searchQueryText = '';
  $scope.transactions = [];
  $scope.currencies = ['MSC', 'TMSC'];
  $scope.currency = 'MSC';

  $scope.getData = function getData() {
    var currency = $scope.currency;
    console.log('did', currency);
    $http.get('/v1/transaction/values.json', {}). success(function(data) {
      for (var i = 0; i < data.length; i++) {
        if (currency == data[i].currency) {
          var file = '/v1/transaction/general/' + currency + '_0001.json';
          $http.get(file, {}).success(function(data, status, headers, config) {
            $scope.transactions = data;
          });
        }
      }
    });
  }

  $scope.searchQuery = function(trans) {
    return ($scope.searchQueryText === '' || trans.tx_hash.indexOf($scope.searchQueryText) >= 0 || trans.from_address.indexOf($scope.searchQueryText) >= 0 || trans.to_address.indexOf($scope.searchQueryText) >= 0);
  };
}
function ExplorerInspectorController($scope, $location, $http, hashExplorer) {
  function setData() {
    $scope.transactionData = JSON.parse(hashExplorer.tx);
    $scope.tx_keys = Object.keys($scope.transactionData);
    $scope.fieldlist = $scope.tx_keys;
    $scope.pastLoc = hashExplorer.loc;
  }

  if (hashExplorer.tx) {
    setData();
  } else {
    $http.get('/v1/transaction/tx/' + $location.search()['view'] + '.json'). success(function(data) {
      hashExplorer.setHash(data[0]);
      setData();
    });
  }
}
function SidecarController($scope, $http, $modal, $location, userService, balanceService) {
  $scope.values = {};
  $scope.setView = function(viewName) {
    $scope.view = $scope.sidecarTemplates[viewName];
  };
  $scope.getView = function() {
    return $scope.view;
  };
  $scope.sidecarTemplates = {
    'explorer': '/partials/explorer_sc.html',
    'about': '/partials/about_sc.html',
    'wallet': '/partials/wallet_sc.html'
  };

  $scope.hasAddresses = userService.data.loggedIn && userService.getAllAddresses().length != 0 ? true : false;
  $scope.hasAddressesWithPrivkey = userService.data.loggedIn && getAddressesWithPrivkey().length != 0 ? true : false;
  $scope.hasTradableCoins = false;
  $scope.hasBTC = false;
  if (userService.data.loggedIn) checkBalance(getAddressesWithPrivkey());

  $scope.checkSendingEnabled = function($event) {
    var error = "Send page is unavailable because ";
    if(!$scope.hasAddressesWithPrivkey){
      $event.preventDefault();
      $event.stopPropagation();
      error += "the wallet has no addresses with private keys (no address to send from)";
    } else {
      if(!$scope.hasTradableCoins){
        $event.preventDefault();
        $event.stopPropagation();
        error += "the wallet has no coins in the addresses that have private keys (nothing to send)";
      } else {
        if(!$scope.hasBTC){
          $event.preventDefault();
          $event.stopPropagation();
          error += "wallet has no BTC in addresses that have private keys (no way to pay tx fees)";
        }
      }
    }

    if(error.length > 33){
      $modal.open({
        templateUrl: "/partials/popup_error.html",
        controller: function($scope, error){
          $scope.error = error;
        },
        resolve:{
          error:function(){
            return error;
          }
        }
      });
    } else {
      $location.path("/wallet/send");
    }
  };

  $scope.$watch(function() {
    return userService.getAllAddresses()
  }, function(result) {
    $scope.hasAddresses = userService.data.loggedIn && result.length != 0 ? true : false;
    $scope.hasAddressesWithPrivkey = userService.data.loggedIn && getAddressesWithPrivkey().length != 0 ? true : false;
    if (userService.data.loggedIn) checkBalance(getAddressesWithPrivkey());
  }, true);

  function getAddressesWithPrivkey() {
    var addresses = []
    userService.getAllAddresses().map(function(e, i, a) {
      if (e.privkey && e.privkey.length == 58) {
        addresses.push(e.address);
      }
    }
    );
    return addresses;
  }

  function checkBalance(addresses){
    $scope.hasTradableCoins = false;
    $scope.hasBTC = false;
    if(addresses instanceof Array){
      addresses.forEach(function(address){
        balanceService.balance(address).then(function(result){
          var balances = result.data.balance;
          balances.forEach(function(balance){
            if(balance.value > 0)
              $scope.hasTradableCoins = true;
            if(balance.symbol == "BTC" && balance.value > 0)
              $scope.hasBTC = true;
          });
        });
      });
    }
  }
}

<|endoftext|>


<commit_before>// JavaScript Document

/*
 * FileSender www.filesender.org
 *
 * Copyright (c) 2009-2012, AARNet, Belnet, HEAnet, SURFnet, UNINETT
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * *	Redistributions of source code must retain the above copyright
 * 	notice, this list of conditions and the following disclaimer.
 * *	Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * *	Neither the name of AARNet, Belnet, HEAnet, SURFnet and UNINETT nor the
 * 	names of its contributors may be used to endorse or promote products
 * 	derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * Client side language handling
 */

if(!('filesender' in window)) window.filesender = {};

/**
 * AJAX webservice client
 */
window.filesender.client = {
    // REST service base path
    base_path: null,

    // Send a request to the webservice
    call: function(method, resource, data, callback, options) {
        if(!this.base_path) {
            var path = window.location.href;
            path = path.split('/');
            path.pop();
            path = path.join('/');
            this.base_path = path + '/rest.php';
        }

        var args = {};
        if(options && options.args) for(var k in options.args) args[k] = options.args[k];
        args._ = (new Date()).getTime(); // Defeat cache
        var urlargs = [];
        for(var k in args) urlargs.push(k + '=' + args[k]);

        if(data) {
            var raw = options && ('rawdata' in options) && options.rawdata;

            if(!raw) data = JSON.stringify(data);
        }else data = undefined;

        var settings = {
            cache: false,
            contentType: 'application/json;charset=utf-8',
            context: window,
            data: data,
            processData: false,
            dataType: 'json',
            error: this.error,
            success: callback,
            type: method.toUpperCase(),
            url: this.base_path + resource + '?' + urlargs.join('&')
        };

        for(var k in options) settings[k] = options[k];

        jQuery.ajax(settings);
    },

    // Error handler
    error: function(xhr, status, error) {
        var msg = xhr.responseText.replace(/^\s+/, '').replace(/\s+$/, '');

        try {
            var error = JSON.parse(msg);
            filesender.ui.error(error);
        } catch(e) {
            filesender.ui.rawError(msg);
        }
    },

    get: function(resource, callback, options) {
        this.call('get', resource, undefined, callback, options);
    },

    post: function(resource, data, callback, options) {
        this.call('post', resource, data, function(data, status, xhr) {
            callback.call(this, xhr.getResponseHeader('Location'), data);
        }, options);
    },

    put: function(resource, data, callback, options) {
        this.call('put', resource, data, callback, options);
    },

    delete: function(resource, callback, options) {
        this.call('delete', resource, undefined, callback, options);
    },

    /**
     * Get public info about the Filesender instance
     */
    getInfo: function(callback) {
        this.get('/info', callback);
    },

    /**
     * Start a transfer
     *
     * @param string from sender email
     * @param array files array of file objects with name, size and sha1 properties
     * @param array recipients array of recipients addresses
     * @param string subject optionnal subject
     * @param string message optionnal message
     * @param string expires expiry date (yyyy-mm-dd or unix timestamp)
     * @param array options array of selected option identifiers
     * @param callable callback function to call with transfer path and transfer info once done
     */
    postTransfer: function(from, files, recipients, subject, message, expires, options, callback, onerror) {
        var opts = {};
        if(onerror) opts.error = onerror;

        this.post('/transfer', {
            from: from,
            files: files,
            recipients: recipients,
            subject: subject,
            message: message,
            expires: expires,
            options: options
        }, callback, opts);
    },

    /**
     * Post a file chunk
     *
     * @param object file
     * @param blob chunk
     * @param callable callback
     */
    postChunk: function(file, blob, callback, onerror) {
        var opts = {
            contentType: 'application/octet-stream',
            rawdata: true
        };
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.post('/file/' + file.id + '/chunk', blob, callback, opts);
    },

    /**
     * Put a file chunk
     *
     * @param object file
     * @param blob chunk
     * @param int offset
     * @param callable callback
     */
    putChunk: function(file, blob, offset, callback, onerror) {
        var opts = {
            contentType: 'application/octet-stream',
            rawdata: true
        };
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.put('/file/' + file.id + '/chunk/' + offset, blob, callback, opts);
    },

    /**
     * Signal file completion (along with checking data)
     *
     * @param object file
     * @param object data check data
     * @param callable callback
     */
    fileComplete: function(file, data, callback, onerror) {
        var opts = {};
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.put('/file/' + file.id + '/complete', data, callback, opts);
    },

    /**
     * Signal transfer completion (along with checking data)
     *
     * @param object transfer
     * @param object data check data
     * @param callable callback
     */
    transferComplete: function(transfer, data, callback, onerror) {
        var opts = {};
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: transfer.files[0].uid};

        if(onerror) opts.error = onerror;

        this.put('/transfer/' + transfer.id + '/complete', data, callback, opts);
    },

    /**
     * Delete a transfer
     *
     * @param object transfer
     * @param callable callback
     */
    deleteTransfer: function(transfer, callback, onerror) {
        var id = transfer;
        var opts = {};

        if(typeof transfer == 'object') {
            id = transfer.id;
            if(filesender.config.chunk_upload_security == 'key') opts.args = {key: transfer.files[0].uid};
        }

        if(onerror) opts.error = onerror;

        this.delete('/transfer/' + id, callback, opts);
    },

    /**
     * Get a guest voucher
     *
     * @param mixed guest voucher object or id
     * @param callable callback
     */
    getGuest: function(voucher, callback) {
        var id = voucher;

        if(typeof voucher == 'object')
            id = voucher.id;

        this.get('/guest/' + id, callback);
    },

    /**
     * Create a guest voucher
     *
     * @param string from sender email
     * @param string subject optionnal subject
     * @param string message optionnal message
     * @param string expires expiry date (yyyy-mm-dd or unix timestamp)
     * @param array options array of selected option identifiers
     * @param callable callback function to call with guest voucher path and guest voucher info once done
     */
    postGuest: function(from, recipient, subject, message, expires, options, callback) {
        this.post('/guest', {
            from: from,
            recipient: recipient,
            subject: subject,
            message: message,
            expires: expires,
            options: options
        }, callback);
    },

    /**
     * Delete a guest voucher
     *
     * @param mixed guest voucher object or id
     * @param callable callback
     */
    deleteGuest: function(voucher, callback) {
        var id = voucher;

        if(typeof voucher == 'object')
            id = voucher.id;

        this.delete('/guest/' + id, callback);
    },

    /**
     * Override part of the config (if allowed)
     *
     * @param object overrides
     * @param callable callback
     */
    overrideConfig: function(overrides, callback) {
        this.put('/config', overrides, callback);
    },

    getFrequentRecipients: function(needle, callback){
        this.get('/user/@me/frequent_recipients',callback,needle?{args: {"filterOp[contains]":needle}}:undefined);
    }
};
<commit_msg>Fix error reporting.<commit_after>// JavaScript Document

/*
 * FileSender www.filesender.org
 *
 * Copyright (c) 2009-2012, AARNet, Belnet, HEAnet, SURFnet, UNINETT
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * *	Redistributions of source code must retain the above copyright
 * 	notice, this list of conditions and the following disclaimer.
 * *	Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * *	Neither the name of AARNet, Belnet, HEAnet, SURFnet and UNINETT nor the
 * 	names of its contributors may be used to endorse or promote products
 * 	derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * Client side language handling
 */

if(!('filesender' in window)) window.filesender = {};

/**
 * AJAX webservice client
 */
window.filesender.client = {
    // REST service base path
    base_path: null,

    // Send a request to the webservice
    call: function(method, resource, data, callback, options) {
        if(!this.base_path) {
            var path = window.location.href;
            path = path.split('/');
            path.pop();
            path = path.join('/');
            this.base_path = path + '/rest.php';
        }

        var args = {};
        if(options && options.args) for(var k in options.args) args[k] = options.args[k];
        args._ = (new Date()).getTime(); // Defeat cache
        var urlargs = [];
        for(var k in args) urlargs.push(k + '=' + args[k]);

        if(data) {
            var raw = options && ('rawdata' in options) && options.rawdata;

            if(!raw) data = JSON.stringify(data);
        }else data = undefined;

        var errorhandler = filesender.ui.error;
        if(options.error) {
            errorhandler = options.error;
            delete options.error;
        }

        var settings = {
            cache: false,
            contentType: 'application/json;charset=utf-8',
            context: window,
            data: data,
            processData: false,
            dataType: 'json',
            error: function(xhr, status, error) {
                var msg = xhr.responseText.replace(/^\s+/, '').replace(/\s+$/, '');

                try {
                    var error = JSON.parse(msg);
                    errorhandler(error);
                } catch(e) {
                    filesender.ui.rawError(msg);
                }
            },
            success: callback,
            type: method.toUpperCase(),
            url: this.base_path + resource + '?' + urlargs.join('&')
        };

        for(var k in options) settings[k] = options[k];

        jQuery.ajax(settings);
    },

    get: function(resource, callback, options) {
        this.call('get', resource, undefined, callback, options);
    },

    post: function(resource, data, callback, options) {
        this.call('post', resource, data, function(data, status, xhr) {
            callback.call(this, xhr.getResponseHeader('Location'), data);
        }, options);
    },

    put: function(resource, data, callback, options) {
        this.call('put', resource, data, callback, options);
    },

    delete: function(resource, callback, options) {
        this.call('delete', resource, undefined, callback, options);
    },

    /**
     * Get public info about the Filesender instance
     */
    getInfo: function(callback) {
        this.get('/info', callback);
    },

    /**
     * Start a transfer
     *
     * @param string from sender email
     * @param array files array of file objects with name, size and sha1 properties
     * @param array recipients array of recipients addresses
     * @param string subject optionnal subject
     * @param string message optionnal message
     * @param string expires expiry date (yyyy-mm-dd or unix timestamp)
     * @param array options array of selected option identifiers
     * @param callable callback function to call with transfer path and transfer info once done
     */
    postTransfer: function(from, files, recipients, subject, message, expires, options, callback, onerror) {
        var opts = {};
        if(onerror) opts.error = onerror;

        this.post('/transfer', {
            from: from,
            files: files,
            recipients: recipients,
            subject: subject,
            message: message,
            expires: expires,
            options: options
        }, callback, opts);
    },

    /**
     * Post a file chunk
     *
     * @param object file
     * @param blob chunk
     * @param callable callback
     */
    postChunk: function(file, blob, callback, onerror) {
        var opts = {
            contentType: 'application/octet-stream',
            rawdata: true
        };
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.post('/file/' + file.id + '/chunk', blob, callback, opts);
    },

    /**
     * Put a file chunk
     *
     * @param object file
     * @param blob chunk
     * @param int offset
     * @param callable callback
     */
    putChunk: function(file, blob, offset, callback, onerror) {
        var opts = {
            contentType: 'application/octet-stream',
            rawdata: true
        };
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.put('/file/' + file.id + '/chunk/' + offset, blob, callback, opts);
    },

    /**
     * Signal file completion (along with checking data)
     *
     * @param object file
     * @param object data check data
     * @param callable callback
     */
    fileComplete: function(file, data, callback, onerror) {
        var opts = {};
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: file.uid};

        if(onerror) opts.error = onerror;

        this.put('/file/' + file.id + '/complete', data, callback, opts);
    },

    /**
     * Signal transfer completion (along with checking data)
     *
     * @param object transfer
     * @param object data check data
     * @param callable callback
     */
    transferComplete: function(transfer, data, callback, onerror) {
        var opts = {};
        if(filesender.config.chunk_upload_security == 'key') opts.args = {key: transfer.files[0].uid};

        if(onerror) opts.error = onerror;

        this.put('/transfer/' + transfer.id + '/complete', data, callback, opts);
    },

    /**
     * Delete a transfer
     *
     * @param object transfer
     * @param callable callback
     */
    deleteTransfer: function(transfer, callback, onerror) {
        var id = transfer;
        var opts = {};

        if(typeof transfer == 'object') {
            id = transfer.id;
            if(filesender.config.chunk_upload_security == 'key') opts.args = {key: transfer.files[0].uid};
        }

        if(onerror) opts.error = onerror;

        this.delete('/transfer/' + id, callback, opts);
    },

    /**
     * Get a guest voucher
     *
     * @param mixed guest voucher object or id
     * @param callable callback
     */
    getGuest: function(voucher, callback) {
        var id = voucher;

        if(typeof voucher == 'object')
            id = voucher.id;

        this.get('/guest/' + id, callback);
    },

    /**
     * Create a guest voucher
     *
     * @param string from sender email
     * @param string subject optionnal subject
     * @param string message optionnal message
     * @param string expires expiry date (yyyy-mm-dd or unix timestamp)
     * @param array options array of selected option identifiers
     * @param callable callback function to call with guest voucher path and guest voucher info once done
     */
    postGuest: function(from, recipient, subject, message, expires, options, callback) {
        this.post('/guest', {
            from: from,
            recipient: recipient,
            subject: subject,
            message: message,
            expires: expires,
            options: options
        }, callback);
    },

    /**
     * Delete a guest voucher
     *
     * @param mixed guest voucher object or id
     * @param callable callback
     */
    deleteGuest: function(voucher, callback) {
        var id = voucher;

        if(typeof voucher == 'object')
            id = voucher.id;

        this.delete('/guest/' + id, callback);
    },

    /**
     * Override part of the config (if allowed)
     *
     * @param object overrides
     * @param callable callback
     */
    overrideConfig: function(overrides, callback) {
        this.put('/config', overrides, callback);
    },

    getFrequentRecipients: function(needle, callback){
        this.get('/user/@me/frequent_recipients',callback,needle?{args: {"filterOp[contains]":needle}}:undefined);
    }
};
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.03'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var IdleStatus = 0;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 0;

//RK Variables
var start = -1;
var content = "empty";
var findLocation = '123';
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			Molpy.Notify(Molpy.options.showhide[lootBoxes[i]], 1);
			if (Molpy.options.showhide[lootBoxes[i]] != 1) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide[lootBoxes[i]]) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location, does nothing for locations 1, 2 or 3
	//Molpy.Notify('FindRK Run', 1);
	findLocation = '123';
	if (Molpy.redactedVisible == 4) {
		findLocation = Molpy.redactedGr;
	}
	else if (Molpy.redactedVisible == 5) {
		findLocation = 'badges';
	}
	else if (Molpy.redactedVisible == 6) {
		findLocation = 'badgesav';
	}

	//Opens RK location
	if (findLocation != '123') {
		ToggleMenus(findLocation);
	}

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
	return findLocation;
}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;
	RKLocation = '123';

	//If a RedundaKitty is active
	if (Molpy.redactedVisible > 0) {

		//If RK is new, find it.
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKLocation = FindRK();
			RKNewAudio = 1;
			RKNew = 0;
		}

		//Determines if it is an RK or LC
		//If RK is visible
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red"); //Highlights RK
			content = $('#redacteditem').html();
			//If RK contains word statement, it is a LC.
			if (content.indexOf("statement") !== -1) {
				Logicat = 1;
			}
			//Otherwise it is an RK
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 1) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		//If RK not visible, LC to 99.
		else {
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 1 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			ToggleMenus('none');
			RKLocation = '123';
		}
		//Solves LC if AutoClick Enabled
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			RKNew = 1;
			ToggleMenus('none');
			RKLocation = '123';
		}

		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			if (Math.floor(RKTimer % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	//If no RK active, update title Timer. Reset some variables.
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		if (RKNew != 1) {
			RKNew = 1;
		}
	}
}

function Logicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Spawn RK

');
//$('#optionsItems').append('

Blank

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<commit_msg>Release candidate bug fix<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.03'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var IdleStatus = 0;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 0;

//RK Variables
var start = -1;
var content = "empty";
var findLocation = '123';
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			Molpy.Notify(Molpy.options.showhide[lootBoxes[i]], 1);
			if (Molpy.options.showhide[lootBoxes[i]] != 1) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide[lootBoxes[i]]) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location, does nothing for locations 1, 2 or 3
	//Molpy.Notify('FindRK Run', 1);
	findLocation = '123';
	if (Molpy.redactedVisible == 4) {
		findLocation = Molpy.redactedGr;
	}
	else if (Molpy.redactedVisible == 5) {
		findLocation = 'badges';
	}
	else if (Molpy.redactedVisible == 6) {
		findLocation = 'badgesav';
	}

	//Opens RK location
	if (findLocation != '123') {
		ToggleMenus(findLocation);
	}

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
	return findLocation;
}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;
	RKLocation = '123';

	//If a RedundaKitty is active
	if (Molpy.redactedVisible > 0) {

		//If RK is new, find it.
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKLocation = FindRK();
			RKNewAudio = 1;
			RKNew = 0;
		}

		//Determines if it is an RK or LC
		//If RK is visible
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red"); //Highlights RK
			content = $('#redacteditem').html();
			//If RK contains word statement, it is a LC.
			if (content.indexOf("statement") !== -1) {
				Logicat = 1;
			}
			//Otherwise it is an RK
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 0) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		//If RK not visible, LC to 99.
		else {
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 1 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			ToggleMenus('none');
			RKLocation = '123';
		}
		//Solves LC if AutoClick Enabled
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			RKNew = 1;
			ToggleMenus('none');
			RKLocation = '123';
		}

		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			if (Math.floor(RKTimer % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	//If no RK active, update title Timer. Reset some variables.
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		if (RKNew != 1) {
			RKNew = 1;
		}
	}
}

function Logicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Spawn RK

');
//$('#optionsItems').append('

Blank

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var AudioAlertsStatus = 0;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid white");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0};
			status = NinjaAutoClickStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 4) {AudioAlertsStatus = 0};
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	if (option == 'RKAutoClick' || option == 'NinjaAutoClick') {
		switch (status) {
			case '1':
				description = 'On';
				break;
			case '0':
				description = 'Off';
				break;
			default:
				Molpy.Notify('Display Description Error',1);
		}
	}
	if (option == 'AudioAlerts') {
		switch (status) {
			case '0':
				description = 'Off';
				break;
			case '1':
				description = 'RK Only';
				break;
			case '3':
				description = 'ONG Only';
				break;
			case '4':
				description = 'RK and ONG';
				break;
			default:
				Molpy.Notify('Display Description Error',1);
		}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}

//Beach Ball Startup
//Set Settings
IdleStatus = prompt("Set to idle? (1 = Yes, 0 = No)");
RKAutoClickStatus = IdleStatus;
NinjaAutoClickStatus = IdleStatus;
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

RK Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick',RKAutoClickStatus);
DisplayDescription('NinjaAutoClick',NinjaAutoClickStatus);
DisplayDescription('AudioAlerts',AudioAlertsStatus);

//Main Loop
setInterval(function() {
	Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
    RedundaKitty();
    Ninja();
}, 1800);
<commit_msg>Audio Alerts Bug Fixing<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var AudioAlertsStatus = 0;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid white");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0};
			status = NinjaAutoClickStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 4) {AudioAlertsStatus = 0};
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	if (option == 'RKAutoClick' || option == 'NinjaAutoClick') {
		switch (status) {
			case '1':
				description = 'On';
				break;
			case '0':
				description = 'Off';
				break;
			default:
				Molpy.Notify('Display Description Error',1);
		}
	}
	if (option == 'AudioAlerts') {
		switch (status) {
			case '0':
				description = 'Off';
				break;
			case '1':
				description = 'RK Only';
				break;
			case '3':
				description = 'ONG Only';
				break;
			case '4':
				description = 'RK and ONG';
				break;
			default:
				Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);
		}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}

//Beach Ball Startup
//Set Settings
IdleStatus = prompt("Set to idle? (1 = Yes, 0 = No)");
RKAutoClickStatus = IdleStatus;
NinjaAutoClickStatus = IdleStatus;
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

RK Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick',RKAutoClickStatus);
DisplayDescription('NinjaAutoClick',NinjaAutoClickStatus);
DisplayDescription('AudioAlerts',AudioAlertsStatus);

//Main Loop
setInterval(function() {
	Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
    RedundaKitty();
    Ninja();
}, 1800);
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.021'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var Logicat = 0;
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var NinjaAutoClickStatus = 1;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

var start = -1;
var content = "empty";
var length = 0;
var RKLevel = '-1';
var RKLocation = 'null';

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	//Refresh Timer Variable
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	//If RedundaKitty is available
	if (Molpy.redactedVisible > 0) {
		//Molpy.Notify('Redacted Visible: ' + Molpy.redactedVisible, 1);
		/*
		RV of 1 is Sand Tools
		RV of 2 is Castle Tools
		RV of 3 is Boosts Main Page
		RV of 4 is Boosts Menus, Hill People Tech, etc.
		RV of 5 is Badges Earned
		RV of 6 is Badges Available
		*/

		//Determines RK location
		if (Molpy.redactedVisible == 1 || Molpy.redactedVisible == 2 || Molpy.redactedVisible == 3) {
			//Do Nothing
		}
		else if (Molpy.redactedVisible == 4) {
			RKLocation = 'null';
			Molpy.Notify('Unknown Location', 0);
		}
		else if (Molpy.redactedVisible == 5) {
			RKLocation = 'badges';
		}
		else if (Molpy.redactedVisible == 6) {
			RKLocation = 'badgesav';
		}

		if (RKLocation != 'null' && !Molpy.options.showhide[RKLocation]) {
			showhideToggle(RKLocation);
		}

		//Determines if it is a Logicat or RK
		if (RKLocation  != 'null') {
			var content = $('#redacteditem').html();
		}

		if (content.indexOf("statement") !== -1) {
			Logicat = 1;
			//Molpy.Notify("Logicat Found",0);
		}
		else {
			Logicat = 0;
			//Molpy.Notify("Redundakitty Found",0);
			start = content.indexOf("ClickRedacted");
			content = content.substring(start,start+17);
			content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
			var length = content.length;
			RKLevel = content.substring(13,length);
			Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
		}

		//Highlight Redundakitty Border to make it easier to find
		$('#redacteditem').css("border","2px solid red");

		//Clicks if RedundaKitty AutoClicker Enabled and Not a Logicat
		if (RKAutoClickStatus == 1 && Logicat == 0) {
			Molpy.ClickRedacted(RKLevel);
			if (RKLocation != 'null') {
				showhideToggle(RKLocation);
				RKLocation = 'null';
			}
		}
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			if (RKLocation != 'null') {
				showhideToggle(RKLocation);
				RKLocation = 'null';
			}
		}
		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function Logicat() {
	i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1)
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 3 second startup delay
setTimeout(MainLoop, 3000);

<commit_msg>Bug Fix Open RK Location<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.021'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var Logicat = 0;
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var NinjaAutoClickStatus = 1;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

var start = -1;
var content = "empty";
var length = 0;
var RKLevel = '-1';
var RKLocation = 'null';

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	//Refresh Timer Variable
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	//If RedundaKitty is available
	if (Molpy.redactedVisible > 0) {
		//Molpy.Notify('Redacted Visible: ' + Molpy.redactedVisible, 1);
		/*
		RV of 1 is Sand Tools
		RV of 2 is Castle Tools
		RV of 3 is Boosts Main Page
		RV of 4 is Boosts Menus, Hill People Tech, etc.
		RV of 5 is Badges Earned
		RV of 6 is Badges Available
		*/

		//Determines RK location
		if (Molpy.redactedVisible == 1 || Molpy.redactedVisible == 2 || Molpy.redactedVisible == 3) {
			//Do Nothing
		}
		else if (Molpy.redactedVisible == 4) {
			RKLocation = '4';
			Molpy.Notify('Unknown Location', 0);
		}
		else if (Molpy.redactedVisible == 5) {
			RKLocation = 'badges';
		}
		else if (Molpy.redactedVisible == 6) {
			RKLocation = 'badgesav';
		}

		if (RKLocation != 'null' && !Molpy.options.showhide[RKLocation]) {
			showhideToggle(RKLocation);
		}

		//Determines if it is a Logicat or RK
		if (RKLocation  != '4') {
			var content = $('#redacteditem').html();
		}

		if (content.indexOf("statement") !== -1) {
			Logicat = 1;
			//Molpy.Notify("Logicat Found",0);
		}
		else {
			Logicat = 0;
			//Molpy.Notify("Redundakitty Found",0);
			start = content.indexOf("ClickRedacted");
			content = content.substring(start,start+17);
			content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
			var length = content.length;
			RKLevel = content.substring(13,length);
			Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
		}

		//Highlight Redundakitty Border to make it easier to find
		$('#redacteditem').css("border","2px solid red");

		//Clicks if RedundaKitty AutoClicker Enabled and Not a Logicat
		if (RKAutoClickStatus == 1 && Logicat == 0) {
			Molpy.ClickRedacted(RKLevel);
			if (RKLocation != 'null') {
				showhideToggle(RKLocation);
				RKLocation = 'null';
			}
		}
		else if (LCAutoClickStatus == 1 && Logicat == 1) {
			Logicat();
			if (RKLocation != 'null') {
				showhideToggle(RKLocation);
				RKLocation = 'null';
			}
		}
		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0 && (AudioAlertsStatus == 1 || AudioAlertsStatus == 3)) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function Logicat() {
	i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);

	/*while (Molpy.redactedPuzzleTarget != undefined) {
		LCSolution = String.fromCharCode(i);
		if (Molpy.redactedPuzzleTarget == Molpy.redactedSGen.StatementValue(LCSolution)) {
			Molpy.ClickRedactedPuzzle(LCSolution);
			Molpy.redactedPuzzleTarget = undefined;
		}
		else {i++;}
	}*/
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 1) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'RKAutoClick' || option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error',1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only';}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG';}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status,1);}
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1)
	setInterval(function() {
		//Molpy.Notify('1 mNP', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, 1800);
}

//Run Main Loop after 3 second startup delay
setTimeout(MainLoop, 3000);

<|endoftext|>