<commit_before>(function(obj){
var ADL = obj;
function getQueryVariable(variable)
{
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++)
    {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable)
        {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
}

function cb_wrap(cb)
{
    return function()
    {
        var args = arguments;
        window.setTimeout(function()
        {
            var callerArgs = [];
            for (var i = 0; i < args.length; i++)
            {
                callerArgs.push(args[i]);
            }
            cb.apply(window, callerArgs);
        }, 0)
    }
}
//The library will append the necessary launch info to each new A that is linked to the page.
//NOTE: This cannot work if you programmatically change the window location. If you do, you must
//execute the logic in setupCourseLinks to send the initialization data to the new location (if
//you wish that new location to track as part of this session)
function observeForNewLinks()
{
    // select the target node
    var target = document.body;
    // create an observer instance
    var observer = new MutationObserver(function(mutations)
    {
        mutations.forEach(function(mutation)
        {
            for (var i in mutation.addedNodes)
            {
                if (mutation.addedNodes[i].constructor == HTMLAnchorElement)
                {
                    var node = mutation.addedNodes[i];
                    setupCourseLinks([node]);
                }
            }
        });
    });
    // configuration of the observer:
    var config = {
        attributes: true,
        childList: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // later, you can stop observing
    ///  observer.disconnect();
}
//This library will init all links in the DOM that include the attribute "courseLink = true"
//with the information necessary for the document at that link to track as part of this session.
function setupCourseLinks(_nodes)
{
    var launchToken = getQueryVariable("xAPILaunchKey");
    var launchEndpoint = getQueryVariable("xAPILaunchService");
    var encrypted = getQueryVariable("encrypted");
    var query = "xAPILaunchKey=" + launchToken + "&xAPILaunchService=" + launchEndpoint;
    if (encrypted)
    {
        query += "&encrypted=true";
    }
    for(var i = 0; i < _nodes.length; i++)
    {
        var link = _nodes[i];
        var href = link.href;
        var courseLink = link.attributes.getNamedItem('courselink')
        if (courseLink && courseLink.value == "true")
        {
            if (href.indexOf("?") > -1)
            {
                href = href + "&" + query;
            }
            else
                href = href + "?" + query;
            link.href = href;
        }
    };
}

function xAPILaunch(cb, terminate_on_unload)
{
    cb = cb_wrap(cb);
    try
    {
        var launchToken = getQueryVariable("xAPILaunchKey");
        var launchEndpoint = getQueryVariable("xAPILaunchService");
        var encrypted = getQueryVariable("encrypted");
        if (!encrypted)
        {
            //here, we'd have to implement decryption for the data. This makes little sense in a client side only course
        }
        if (!launchToken || !launchEndpoint)
            return cb("invalid launch parameters");
        var launch = new URL(launchEndpoint);
        launch.pathname += "launch/" + launchToken;
        var xhr = new XMLHttpRequest();
        xhr.withCredentials = true;
        xhr.crossDomain = true;
        xhr.onerror = function(err)
        {
            //exit the try catch so inner execptions in the callback don't trigger this catch
            window.setTimeout(function()
            {
                return cb(err);
            })
        }
        xhr.onload = function(e)
        {
            if (xhr.status !== 200)
            {
                return xhr.onerror(xhr.responseText);
            }
            var body = JSON.parse(xhr.responseText);
            var launchData = body;
            var conf = {};
            conf['endpoint'] = launchData.endpoint;
            conf["actor"] = launchData.actor;
            conf.withCredentials = true;
            window.onunload = function()
            {
                if (!terminate_on_unload)
                    return;
                var launch = new URL(launchEndpoint);
                launch.pathname += "launch/" + launchToken + "/terminate";
                var xhr2 = new XMLHttpRequest();
                xhr2.withCredentials = true;
                xhr2.crossDomain = true;

                xhr2.open('POST', launch.toString(), false);
                xhr2.setRequestHeader("Content-type" , "application/json");
                xhr2.send('{"code":0,"description":"User closed content"}');
            }
            var wrapper = new ADL.XAPIWrapper.constructor();
            wrapper.changeConfig(conf);
            console.log("in xapi launch", wrapper.lrs);
            //Links that include "courseLink='true'"
            setupCourseLinks(document.body.querySelectorAll('a'));
            //Also, if links are added dynamically, we will do the same logic for those links.
            observeForNewLinks();
            return cb(null, body, wrapper);
        }
        xhr.open('POST', launch.toString(), true);
        xhr.send();
    }
    catch (e)
    {
        cb(e);
    }
};
ADL.launch = xAPILaunch;
})(window.ADL = window.ADL || {});
<commit_msg>update to terminate so clients can call it<commit_after>(function(obj){
var ADL = obj;
function getQueryVariable(variable)
{
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++)
    {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable)
        {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
}

function cb_wrap(cb)
{
    return function()
    {
        var args = arguments;
        window.setTimeout(function()
        {
            var callerArgs = [];
            for (var i = 0; i < args.length; i++)
            {
                callerArgs.push(args[i]);
            }
            cb.apply(window, callerArgs);
        }, 0)
    }
}
//The library will append the necessary launch info to each new A that is linked to the page.
//NOTE: This cannot work if you programmatically change the window location. If you do, you must
//execute the logic in setupCourseLinks to send the initialization data to the new location (if
//you wish that new location to track as part of this session)
function observeForNewLinks()
{
    // select the target node
    var target = document.body;
    // create an observer instance
    var observer = new MutationObserver(function(mutations)
    {
        mutations.forEach(function(mutation)
        {
            for (var i in mutation.addedNodes)
            {
                if (mutation.addedNodes[i].constructor == HTMLAnchorElement)
                {
                    var node = mutation.addedNodes[i];
                    setupCourseLinks([node]);
                }
            }
        });
    });
    // configuration of the observer:
    var config = {
        attributes: true,
        childList: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // later, you can stop observing
    ///  observer.disconnect();
}
//This library will init all links in the DOM that include the attribute "courseLink = true"
//with the information necessary for the document at that link to track as part of this session.
function setupCourseLinks(_nodes)
{
    var launchToken = getQueryVariable("xAPILaunchKey");
    var launchEndpoint = getQueryVariable("xAPILaunchService");
    var encrypted = getQueryVariable("encrypted");
    var query = "xAPILaunchKey=" + launchToken + "&xAPILaunchService=" + launchEndpoint;
    if (encrypted)
    {
        query += "&encrypted=true";
    }
    for(var i = 0; i < _nodes.length; i++)
    {
        var link = _nodes[i];
        var href = link.href;
        var courseLink = link.attributes.getNamedItem('courselink')
        if (courseLink && courseLink.value == "true")
        {
            if (href.indexOf("?") > -1)
            {
                href = href + "&" + query;
            }
            else
                href = href + "?" + query;
            link.href = href;
        }
    };
}

function xAPILaunch(cb, terminate_on_unload)
{
    cb = cb_wrap(cb);
    try
    {
        var launchToken = getQueryVariable("xAPILaunchKey");
        var launchEndpoint = getQueryVariable("xAPILaunchService");
        var encrypted = getQueryVariable("encrypted");
        if (encrypted)
        {
            //here, we'd have to implement decryption for the data. This makes little sense in a client side only course
        }

        xAPILaunch.terminate = function(message)
        {
            var launch = new URL(launchEndpoint);
            launch.pathname += "launch/" + launchToken + "/terminate";
            var xhr2 = new XMLHttpRequest();
            xhr2.withCredentials = true;
            xhr2.crossDomain = true;

            xhr2.open('POST', launch.toString(), false);
            xhr2.setRequestHeader("Content-type" , "application/json");
            xhr2.send(JSON.stringify({"code":0,"description": message ||"User closed content"});

        }

        if (!launchToken || !launchEndpoint)
            return cb("invalid launch parameters");
        var launch = new URL(launchEndpoint);
        launch.pathname += "launch/" + launchToken;
        var xhr = new XMLHttpRequest();
        xhr.withCredentials = true;
        xhr.crossDomain = true;
        xhr.onerror = function(err)
        {
            //exit the try catch so inner execptions in the callback don't trigger this catch
            window.setTimeout(function()
            {
                return cb(err);
            })
        }
        xhr.onload = function(e)
        {
            if (xhr.status !== 200)
            {
                return xhr.onerror(xhr.responseText);
            }
            var body = JSON.parse(xhr.responseText);
            var launchData = body;
            var conf = {};
            conf['endpoint'] = launchData.endpoint;
            conf["actor"] = launchData.actor;
            conf.withCredentials = true;
            window.onunload = function()
            {
                if (!terminate_on_unload)
                    return;
                xAPILaunch.terminate("User closed content")
            }
            var wrapper = new ADL.XAPIWrapper.constructor();
            wrapper.changeConfig(conf);
            console.log("in xapi launch", wrapper.lrs);
            //Links that include "courseLink='true'"
            setupCourseLinks(document.body.querySelectorAll('a'));
            //Also, if links are added dynamically, we will do the same logic for those links.
            observeForNewLinks();
            return cb(null, body, wrapper);
        }
        xhr.open('POST', launch.toString(), true);
        xhr.send();
    }
    catch (e)
    {
        cb(e);
    }
};
ADL.launch = xAPILaunch;
})(window.ADL = window.ADL || {});
<|endoftext|>


<commit_before>'use strict';

const should = require('should');

const LeaseManager = require('../lib/lease-manager');

/**
 * A mock SecretProvider that fails to initialize N times before succeeding
 */
class CountingInitializeProvider {

  constructor(count) {
    this.count = count;
  }

  initialize(callback) {
    if (this.count > 1) {
      this.count -= 1;
      callback(new Error(`Need ${this.count} more calls to initialize`), null);
    }
    else {
      callback(null, {data: 'SECRET'});
    }
  }
}

describe('LeaseManager#constructor', function () {
  it('has a default status of PENDING', function () {
    should(new LeaseManager().status).eql('PENDING');
  });

  it('has default data that is null', function () {
    should(new LeaseManager().data).be.null();
  });

  it('changes status to READY when the provider immediately succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(0));

    manager.initialize();
    return Promise.resolve(manager.status).should.eventually.eql('READY');
  });

  it('changes data to a secret when the provider immediately succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(0));

    manager.initialize();
    return Promise.resolve(manager.data).should.eventually.eql('SECRET');
  });

  it('change status to ready when the provider eventually succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.initialize();
    return Promise.resolve(manager.status).should.eventually.eql('READY');
  });

  it('change data to a secret when the provider eventually succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.initialize();
    return Promise.resolve(manager.data).should.eventually.eql('SECRET');
  });

  it('emits ready event when the provider succeeds', function (done) {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.on('ready', function () {
      should(manager.data).eql('SECRET');
      done();
    });

    manager.initialize();
  });
});
<commit_msg>Fails tests to ensure lease duration is tracked for secrets.<commit_after>'use strict';

const should = require('should');

const LeaseManager = require('../lib/lease-manager');

/**
 * A mock SecretProvider that fails to initialize N times before succeeding
 */
class CountingInitializeProvider {

  constructor(count) {
    this.count = count;
  }

  initialize(callback) {
    if (this.count > 1) {
      this.count -= 1;
      callback(new Error(`Need ${this.count} more calls to initialize`), null);
    }
    else {
      callback(null, {
        data: 'SECRET',
        lease_duration: 1
      });
    }
  }
}

describe('LeaseManager#constructor', function () {
  it('has a default status of PENDING', function () {
    should(new LeaseManager().status).eql('PENDING');
  });

  it('has default data that is null', function () {
    should(new LeaseManager().data).be.null();
  });

  it('has a default lease duration that is zero', function () {
    should(new LeaseManager().lease_duration).eql(0);
  });

  it('changes status to READY when the provider immediately succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(0));

    manager.initialize();
    return Promise.resolve(manager.status).should.eventually.eql('READY');
  });

  it('changes data to a secret when the provider immediately succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(0));

    manager.initialize();
    return Promise.resolve(manager.data).should.eventually.eql('SECRET');
  });

  it('changes lease duration to non-zero when the provider immediately succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(0));

    manager.initialize();
    return Promise.resolve(manager.lease_duration).should.eventually.eql(1);
  });

  it('change status to ready when the provider eventually succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.initialize();
    return Promise.resolve(manager.status).should.eventually.eql('READY');
  });

  it('change data to a secret when the provider eventually succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.initialize();
    return Promise.resolve(manager.data).should.eventually.eql('SECRET');
  });

  it('change lease duration to non-zero when the provider eventually succeeds', function () {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.initialize();
    return Promise.resolve(manager.lease_duration).should.eventually.eql(1);
  });

  it('emits ready event when the provider succeeds', function (done) {
    const manager = new LeaseManager(new CountingInitializeProvider(2));

    manager.on('ready', function () {
      should(manager.data).eql('SECRET');
      done();
    });

    manager.initialize();
  });
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import directory from 'stellarterm-directory';
import * as StellarSdk from 'stellar-sdk';
import MagicSpoon from '../MagicSpoon';
import Stellarify from '../Stellarify';
import Validate from '../Validate';
import Event from '../Event';
import * as EnvConsts from '../../env-consts';
import ErrorHandler from '../ErrorHandler';
import * as request from '../api/request';
import { getUrlWithParams } from '../api/endpoints';

export default class Send {
    constructor(driver) {
        this.event = new Event();
        this.d = driver;

        this.state = 'setup'; // 'setup' | 'review' | 'pending' | 'error' | 'success'

        this.accountId = '';
        this.targetAccount = null;
        this.destInput = '';
        this.destinationName = '';
        this.federationResolving = false;
        this.federationAddress = '';

        this.amountToSend = '';
        this.choosenSlug = 'XLM-native';
        this.assetToSend = {};
        this.availableAssets = {};

        this.sep29MemoRequired = false;
        this.memoRequired = false;
        this.memoType = 'none'; // 'none' | 'MEMO_ID' |'MEMO_TEXT' | 'MEMO_HASH' | 'MEMO_RETURN'
        this.memoContent = '';

        this.allFieldsValid = false;

        this.getAsset = this.getAsset.bind(this);
        this.resetSendForm = this.resetSendForm.bind(this);
        this.updateMemoType = this.updateMemoType.bind(this);
        this.clickBackToSend = this.clickBackToSend.bind(this);
        this.getMaxAssetSpend = this.getMaxAssetSpend.bind(this);
        this.pickAssetToSend = this.pickAssetToSend.bind(this);
        this.updateMemoContent = this.updateMemoContent.bind(this);
        this.updateDestination = this.updateDestination.bind(this);
        this.updateAmountValue = this.updateAmountValue.bind(this);
        this.clickReviewPayment = this.clickReviewPayment.bind(this);
        this.submitSendTransaction = this.submitSendTransaction.bind(this);
        this.calculateAvailableAssets();
    }

    getAsset() {
        const { asset } = this.assetToSend;
        return new StellarSdk.Asset(asset.code, asset.issuer);
    }

    getMaxAssetSpend(assetBalance) {
        const { account } = this.d.session;
        const openOrdersSum = account.getReservedBalance(this.getAsset());
        return parseFloat(assetBalance) > parseFloat(openOrdersSum) ? (assetBalance - openOrdersSum).toFixed(7) : 0;
    }

    loadTargetAccountDetails() {
        if (!Validate.publicKey(this.accountId).ready) {
            return;
        }

        this.d.Server.loadAccount(this.accountId).then((account) => {
            if (account.id === this.accountId) {
                // Prevent race conditions using this check
                this.targetAccount = account;
                this.calculateAvailableAssets();
                this.event.trigger();
            }

            account.data({ key: 'config.memo_required' }).then(({ value }) => {
                const decodedMemoRequirement = new Buffer(value, 'base64').toString();
                this.sep29MemoRequired = decodedMemoRequirement === '1';
                this.event.trigger();
            }).catch(() => {
                this.sep29MemoRequired = false;
                this.event.trigger();
            });

            if (account.home_domain) {
                StellarSdk.StellarTomlResolver.resolve(account.home_domain).then((toml) => {
                    if (!toml.FEDERATION_SERVER) {
                        return;
                    }

                    request.get(`${getUrlWithParams(toml.FEDERATION_SERVER, { q: account.id, type: 'id' })}`, {})
                        .then((res) => {
                            this.federationAddress = res.stellar_address;
                            this.event.trigger();
                        });
                });
            }
        }).then(() => {
            this.allFieldsValid = this.validateAllFields();
            this.event.trigger();
        }).catch(() => { });
    }

    fetchSelfAssets() {
        const isEnteredValidAddress = Validate.publicKey(this.destInput).ready ||
            Validate.address(this.destInput).ready;

        if (isEnteredValidAddress) {
            this.loadTargetAccountDetails();
            return;
        }

        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) { return; }

            this.availableAssets[slug] = {
                asset,
                sendable: true,
            };
        });
    }

    calculateAvailableAssets() {
        if (!Validate.publicKey(this.accountId).ready) {
            this.availableAssets[Stellarify.assetToSlug(new StellarSdk.Asset.native())] = {
                asset: new StellarSdk.Asset.native(),
                sendable: true,
            };
            this.assetToSend = this.availableAssets['XLM-native'];
            return;
        }

        const senderTrusts = {};
        const receiverTrusts = {};
        const sendableAssets = {};
        const unSendableAssets = {};

        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            if (asset.issuer === this.targetAccount.accountId()) {
                // Edgecase: Receiver is the issuer of the asset
                // Note: Accounts cant extend trust to themselves, so no further edgecases on this situation
                this.availableAssets[slug] = {
                    asset,
                    sendable: true,
                };
                receiverTrusts[slug] = true;
            } else {
                senderTrusts[slug] = true;
            }
        });

        _.each(this.targetAccount.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            // We don't really care about the usecase of sending to issuer.
            receiverTrusts[slug] = true;
        });

        _.each(this.targetAccount.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (Object.prototype.hasOwnProperty.call(senderTrusts, slug)) {
                sendableAssets[slug] = {
                    asset,
                    sendable: true,
                };
            } else if (asset.getIssuer() === this.d.session.account.accountId()) {
                // Edgecase: Sender is the issuer of the asset
                sendableAssets[slug] = {
                    asset,
                    sendable: true,
                };
            } else {
                // Asset can't be sent.
            }
        });

        // Show stuff the recipient doesn't trust
        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            if (!Object.prototype.hasOwnProperty.call(sendableAssets, slug) &&
                !Object.prototype.hasOwnProperty.call(receiverTrusts, slug)) {
                unSendableAssets[slug] = {
                    asset,
                    sendable: false,
                    reason: 'receiverNoTrust',
                };
            }
        });
        _.each(sendableAssets, (availability, slug) => {
            this.availableAssets[slug] = availability;
        });
        _.each(unSendableAssets, (availability, slug) => {
            this.availableAssets[slug] = availability;
        });
    }

    updateDestination(value) {
        this.destInput = value;
        // Reset the defaults
        this.accountId = '';
        this.destinationName = '';
        this.federationAddress = '';

        if ((this.memoContent === '' && this.destInput === '') || (this.memoContentLocked && this.memoRequired)) {
            this.memoType = 'none';
            this.memoContent = '';
        }
        this.memoRequired = false;
        this.sep29MemoRequired = false;
        this.memoContentLocked = false;
        this.federationNotFound = false;
        this.federationResolving = false;

        if (Validate.publicKey(this.destInput).ready) {
            this.accountId = this.destInput;
            // Check for memo requirements in the destination
            if (Object.prototype.hasOwnProperty.call(directory.destinations, this.accountId)) {
                const destination = directory.destinations[this.accountId];
                this.destinationName = `[${destination.name}]`;

                if (destination.requiredMemoType) {
                    this.memoContent = '';
                    this.memoRequired = true;
                    this.memoType = destination.requiredMemoType;
                }
            }
            this.loadTargetAccountDetails();
        } else if (Validate.address(this.destInput).ready) {
            // Prevent race conditions
            const destInput = this.destInput;
            const targetDomain = destInput.split('*')[1];
            const federationDomain = targetDomain === 'stellarterm.com' ? EnvConsts.HOME_DOMAIN : targetDomain;
            this.federationResolving = true;

            StellarSdk.FederationServer.createForDomain(federationDomain)
                .then(federationServer => federationServer.resolveAddress(this.destInput))
                .then((federationRecord) => {
                    if (destInput !== this.destInput) {
                        return;
                    }
                    this.federationAddress = this.destInput;
                    if (!Validate.publicKey(federationRecord.account_id).ready) {
                        throw new Error('Invalid account_id from federation response');
                    }
                    this.accountId = federationRecord.account_id;
                    if (federationRecord.memo_type) {
                        switch (federationRecord.memo_type) {
                        case 'id':
                            this.memoType = 'MEMO_ID';
                            break;
                        case 'text':
                            this.memoType = 'MEMO_TEXT';
                            break;
                        case 'hash':
                            this.memoType = 'MEMO_HASH';
                            break;
                        case 'return':
                            this.memoType = 'MEMO_RETURN';
                            break;
                        default:
                            throw new Error('Invalid memo_type from federation response');
                        }
                        console.log(federationRecord);
                        this.memoRequired = true;
                    }
                    if (federationRecord.memo) {
                        this.memoContent = federationRecord.memo;
                        this.memoContentLocked = true;
                    }

                    this.federationResolving = false;
                    this.allFieldsValid = this.validateAllFields();
                    this.loadTargetAccountDetails();
                    this.event.trigger();
                })
                .catch((error) => {
                    // stellar.toml does not exist or it does not contain information about federation server.
                    if (destInput !== this.destInput) {
                        return;
                    }
                    console.error(error);
                    this.federationNotFound = true;
                    this.allFieldsValid = this.validateAllFields();
                    this.event.trigger();
                });
        }
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    updateAmountValue(value) {
        const regexp = new RegExp(/^(\d{0,15})([.]\d{1,7})?$/);

        const valueToSet = value;
        const isTheOnlyDot = valueToSet.split('.').length === 2;
        const isAmountValid = valueToSet.slice(-1) === '.' && valueToSet.slice(-2) !== '..' && isTheOnlyDot;

        if (isAmountValid || regexp.test(valueToSet)) {
            this.amountToSend = value;
            this.allFieldsValid = this.validateAllFields();
            this.event.trigger();
        }
    }

    updateMemoType(value) {
        this.memoType = value;
        if (this.memoType === 'none') {
            this.memoContent = '';
        }
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    updateMemoContent(e) {
        this.memoContent = e.target.value;
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    pickAssetToSend(slug) {
        if (!Validate.publicKey(this.accountId).ready) {
            this.availableAssets[slug] = {
                asset: Stellarify.parseAssetSlug(slug),
                sendable: true,
            };
        }

        this.assetToSend = this.availableAssets[slug];
        this.choosenSlug = slug;
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    clickReviewPayment() {
        this.state = 'review';
        this.event.trigger();
    }

    clickBackToSend() {
        this.state = 'setup';
        this.event.trigger();
    }

    async submitSendTransaction() {
        try {
            const sendMemo = this.memoType === 'none'
                ? undefined
                : {
                    type: this.memoType,
                    content: this.memoContent,
                };

            const tx = await MagicSpoon.buildTxSendPayment(this.d.Server, this.d.session.account, {
                destination: this.accountId,
                asset: this.assetToSend.asset,
                amount: this.amountToSend,
                memo: sendMemo,
            });
            const bssResult = await this.d.session.handlers.buildSignSubmit(tx);

            if (bssResult.status === 'finish') {
                this.state = 'pending';
                this.event.trigger();
                const result = await bssResult.serverResult;
                this.txId = result.hash;
                this.state = 'success';
            } else if (bssResult.status === 'await_signers') {
                this.state = 'success_signers';
                this.event.trigger();
            }
        } catch (err) {
            this.state = 'error';
            this.errorDetails = ErrorHandler(err, 'payment');
            this.event.trigger();
        }
    }

    validateAllFields() {
        const destinationIsEmpty = this.destInput === '';
        const notValidDestination =
            !Validate.publicKey(this.destInput).ready &&
            !Validate.address(this.destInput).ready;

        const notValidAmount = !Validate.amount(this.amountToSend);
        const notValidMemo = (this.memoRequired && this.memoType !== 'none' && !Validate.memo(this.memoContent, this.memoType).ready)
            || ((this.sep29MemoRequired && this.memoType === 'none') || !Validate.memo(this.memoContent, this.memoType).ready);
        const destNoTrustline = !this.availableAssets[this.choosenSlug].sendable;

        const isXlmNative = this.getAsset(this.assetToSend).isNative();
        const targetBalance = this.d.session.account.getBalance(this.getAsset());
        const maxAssetSpend = isXlmNative
            ? this.d.session.account.maxLumenSpend()
            : this.getMaxAssetSpend(targetBalance);
        const notEnoughAsset = Number(this.amountToSend) > Number(maxAssetSpend);

        if (
            destinationIsEmpty ||
            notValidDestination ||
            this.federationResolving ||
            this.federationNotFound ||
            notValidAmount ||
            notEnoughAsset ||
            notValidMemo ||
            destNoTrustline) {
            return false;
        }

        return true;
    }

    resetSendForm() {
        this.federationAddress = '';
        this.destInput = '';
        this.accountId = '';
        this.amountToSend = '';

        this.memoRequired = false;
        this.memoType = 'none';
        this.memoContent = '';

        this.state = 'setup';
        this.event.trigger();
    }
}
<commit_msg>Fix federation resolve, standart send flow fixes<commit_after>import _ from 'lodash';
import directory from 'stellarterm-directory';
import * as StellarSdk from 'stellar-sdk';
import MagicSpoon from '../MagicSpoon';
import Stellarify from '../Stellarify';
import Validate from '../Validate';
import Event from '../Event';
import * as EnvConsts from '../../env-consts';
import ErrorHandler from '../ErrorHandler';
import * as request from '../api/request';
import { getUrlWithParams } from '../api/endpoints';

export default class Send {
    constructor(driver) {
        this.event = new Event();
        this.d = driver;

        this.state = 'setup'; // 'setup' | 'review' | 'pending' | 'error' | 'success'

        this.accountId = '';
        this.targetAccount = null;
        this.destInput = '';
        this.destinationName = '';
        this.requestIsPending = false;
        this.federationAddress = '';

        this.amountToSend = '';
        this.choosenSlug = 'XLM-native';
        this.assetToSend = {};
        this.availableAssets = {};

        this.sep29MemoRequired = false;
        this.memoRequired = false;
        this.memoType = 'none'; // 'none' | 'MEMO_ID' |'MEMO_TEXT' | 'MEMO_HASH' | 'MEMO_RETURN'
        this.memoContent = '';

        this.allFieldsValid = false;

        this.getAsset = this.getAsset.bind(this);
        this.resetSendForm = this.resetSendForm.bind(this);
        this.updateMemoType = this.updateMemoType.bind(this);
        this.clickBackToSend = this.clickBackToSend.bind(this);
        this.getMaxAssetSpend = this.getMaxAssetSpend.bind(this);
        this.pickAssetToSend = this.pickAssetToSend.bind(this);
        this.updateMemoContent = this.updateMemoContent.bind(this);
        this.updateDestination = this.updateDestination.bind(this);
        this.updateAmountValue = this.updateAmountValue.bind(this);
        this.clickReviewPayment = this.clickReviewPayment.bind(this);
        this.submitSendTransaction = this.submitSendTransaction.bind(this);
        this.calculateAvailableAssets();
    }

    getAsset() {
        const { asset } = this.assetToSend;
        return new StellarSdk.Asset(asset.code, asset.issuer);
    }

    getMaxAssetSpend(assetBalance) {
        const { account } = this.d.session;
        const openOrdersSum = account.getReservedBalance(this.getAsset());
        return parseFloat(assetBalance) > parseFloat(openOrdersSum) ? (assetBalance - openOrdersSum).toFixed(7) : 0;
    }

    loadTargetAccountDetails() {
        if (!Validate.publicKey(this.accountId).ready) {
            return;
        }

        // This is made for case, when config sep29 request is pending, its block sending without memo
        this.requestIsPending = true;
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();

        this.d.Server.loadAccount(this.accountId).then((account) => {
            if (account.id === this.accountId) {
                // Prevent race conditions using this check
                this.targetAccount = account;
                this.calculateAvailableAssets();
                this.event.trigger();
            }

            if (account.home_domain && this.federationAddress === '') {
                StellarSdk.StellarTomlResolver.resolve(account.home_domain).then((toml) => {
                    if (!toml.FEDERATION_SERVER) {
                        return;
                    }

                    request.get(`${getUrlWithParams(toml.FEDERATION_SERVER, { q: account.id, type: 'id' })}`, {})
                        .then((res) => {
                            this.federationAddress = res.stellar_address;
                            this.event.trigger();
                        });
                });
            }
            return account;
        }).then(account => account.data({ key: 'config.memo_required' },
        )).then(({ value }) => {
            const decodedMemoRequirement = new Buffer(value, 'base64').toString();
            this.sep29MemoRequired = decodedMemoRequirement === '1';
            this.requestIsPending = false;
            this.allFieldsValid = this.validateAllFields();
            this.event.trigger();
        }).catch(() => {
            this.requestIsPending = false;
            this.sep29MemoRequired = false;
            this.allFieldsValid = this.validateAllFields();
            this.event.trigger();
        });
    }

    fetchSelfAssets() {
        const isEnteredValidAddress = Validate.publicKey(this.destInput).ready ||
            Validate.address(this.destInput).ready;

        if (isEnteredValidAddress) {
            this.loadTargetAccountDetails();
            return;
        }

        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) { return; }

            this.availableAssets[slug] = {
                asset,
                sendable: true,
            };
        });
    }

    calculateAvailableAssets() {
        if (!Validate.publicKey(this.accountId).ready) {
            this.availableAssets[Stellarify.assetToSlug(new StellarSdk.Asset.native())] = {
                asset: new StellarSdk.Asset.native(),
                sendable: true,
            };
            this.assetToSend = this.availableAssets['XLM-native'];
            return;
        }

        const senderTrusts = {};
        const receiverTrusts = {};
        const sendableAssets = {};
        const unSendableAssets = {};

        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            if (asset.issuer === this.targetAccount.accountId()) {
                // Edgecase: Receiver is the issuer of the asset
                // Note: Accounts cant extend trust to themselves, so no further edgecases on this situation
                this.availableAssets[slug] = {
                    asset,
                    sendable: true,
                };
                receiverTrusts[slug] = true;
            } else {
                senderTrusts[slug] = true;
            }
        });

        _.each(this.targetAccount.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            // We don't really care about the usecase of sending to issuer.
            receiverTrusts[slug] = true;
        });

        _.each(this.targetAccount.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (Object.prototype.hasOwnProperty.call(senderTrusts, slug)) {
                sendableAssets[slug] = {
                    asset,
                    sendable: true,
                };
            } else if (asset.getIssuer() === this.d.session.account.accountId()) {
                // Edgecase: Sender is the issuer of the asset
                sendableAssets[slug] = {
                    asset,
                    sendable: true,
                };
            } else {
                // Asset can't be sent.
            }
        });

        // Show stuff the recipient doesn't trust
        _.each(this.d.session.account.balances, (balance) => {
            const asset = Stellarify.asset(balance);
            const slug = Stellarify.assetToSlug(asset);
            if (asset.isNative()) {
                return;
            }
            if (!Object.prototype.hasOwnProperty.call(sendableAssets, slug) &&
                !Object.prototype.hasOwnProperty.call(receiverTrusts, slug)) {
                unSendableAssets[slug] = {
                    asset,
                    sendable: false,
                    reason: 'receiverNoTrust',
                };
            }
        });
        _.each(sendableAssets, (availability, slug) => {
            this.availableAssets[slug] = availability;
        });
        _.each(unSendableAssets, (availability, slug) => {
            this.availableAssets[slug] = availability;
        });
    }

    updateDestination(value) {
        this.destInput = value;
        // Reset the defaults
        this.accountId = '';
        this.destinationName = '';
        this.federationAddress = '';

        if ((this.memoContent === '' && this.destInput === '') || (this.memoContentLocked && this.memoRequired)) {
            this.memoType = 'none';
            this.memoContent = '';
        }
        this.memoRequired = false;
        this.sep29MemoRequired = false;
        this.memoContentLocked = false;
        this.federationNotFound = false;
        this.requestIsPending = false;

        if (Validate.publicKey(this.destInput).ready) {
            this.accountId = this.destInput;
            // Check for memo requirements in the destination
            if (Object.prototype.hasOwnProperty.call(directory.destinations, this.accountId)) {
                const destination = directory.destinations[this.accountId];
                this.destinationName = `[${destination.name}]`;

                if (destination.requiredMemoType) {
                    this.memoContent = '';
                    this.memoRequired = true;
                    this.memoType = destination.requiredMemoType;
                }
            }
            this.loadTargetAccountDetails();
        } else if (Validate.address(this.destInput).ready) {
            // Prevent race conditions
            const destInput = this.destInput;
            const targetDomain = destInput.split('*')[1];
            const federationDomain = targetDomain === 'stellarterm.com' ? EnvConsts.HOME_DOMAIN : targetDomain;
            this.requestIsPending = true;

            StellarSdk.FederationServer.createForDomain(federationDomain)
                .then(federationServer => federationServer.resolveAddress(this.destInput))
                .then((federationRecord) => {
                    if (destInput !== this.destInput) {
                        return;
                    }
                    this.federationAddress = federationRecord.stellar_address;
                    if (!Validate.publicKey(federationRecord.account_id).ready) {
                        throw new Error('Invalid account_id from federation response');
                    }
                    this.accountId = federationRecord.account_id;
                    if (federationRecord.memo_type) {
                        switch (federationRecord.memo_type) {
                        case 'id':
                            this.memoType = 'MEMO_ID';
                            break;
                        case 'text':
                            this.memoType = 'MEMO_TEXT';
                            break;
                        case 'hash':
                            this.memoType = 'MEMO_HASH';
                            break;
                        case 'return':
                            this.memoType = 'MEMO_RETURN';
                            break;
                        default:
                            throw new Error('Invalid memo_type from federation response');
                        }
                        this.memoRequired = true;
                    }
                    if (federationRecord.memo) {
                        this.memoContent = federationRecord.memo;
                        this.memoContentLocked = true;
                    }

                    this.requestIsPending = false;
                    this.allFieldsValid = this.validateAllFields();
                    this.loadTargetAccountDetails();
                    this.event.trigger();
                })
                .catch((error) => {
                    // stellar.toml does not exist or it does not contain information about federation server.
                    if (destInput !== this.destInput) {
                        return;
                    }
                    console.error(error);
                    this.federationNotFound = true;
                    this.allFieldsValid = this.validateAllFields();
                    this.event.trigger();
                });
        }
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    updateAmountValue(value) {
        const regexp = new RegExp(/^(\d{0,15})([.]\d{1,7})?$/);

        const valueToSet = value;
        const isTheOnlyDot = valueToSet.split('.').length === 2;
        const isAmountValid = valueToSet.slice(-1) === '.' && valueToSet.slice(-2) !== '..' && isTheOnlyDot;

        if (isAmountValid || regexp.test(valueToSet)) {
            this.amountToSend = value;
            this.allFieldsValid = this.validateAllFields();
            this.event.trigger();
        }
    }

    updateMemoType(value) {
        this.memoType = value;
        if (this.memoType === 'none') {
            this.memoContent = '';
        }
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    updateMemoContent(e) {
        this.memoContent = e.target.value;
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    pickAssetToSend(slug) {
        if (!Validate.publicKey(this.accountId).ready) {
            this.availableAssets[slug] = {
                asset: Stellarify.parseAssetSlug(slug),
                sendable: true,
            };
        }

        this.assetToSend = this.availableAssets[slug];
        this.choosenSlug = slug;
        this.allFieldsValid = this.validateAllFields();
        this.event.trigger();
    }

    clickReviewPayment() {
        this.state = 'review';
        this.event.trigger();
    }

    clickBackToSend() {
        this.state = 'setup';
        this.event.trigger();
    }

    async submitSendTransaction() {
        try {
            const sendMemo = this.memoType === 'none'
                ? undefined
                : {
                    type: this.memoType,
                    content: this.memoContent,
                };

            const tx = await MagicSpoon.buildTxSendPayment(this.d.Server, this.d.session.account, {
                destination: this.accountId,
                asset: this.assetToSend.asset,
                amount: this.amountToSend,
                memo: sendMemo,
            });
            const bssResult = await this.d.session.handlers.buildSignSubmit(tx);

            if (bssResult.status === 'finish') {
                this.state = 'pending';
                this.event.trigger();
                const result = await bssResult.serverResult;
                this.txId = result.hash;
                this.state = 'success';
            } else if (bssResult.status === 'await_signers') {
                this.state = 'success_signers';
                this.event.trigger();
            }
        } catch (err) {
            this.state = 'error';
            this.errorDetails = ErrorHandler(err, 'payment');
            this.event.trigger();
        }
    }

    validateAllFields() {
        const destinationIsEmpty = this.destInput === '';
        const notValidDestination =
            !Validate.publicKey(this.destInput).ready &&
            !Validate.address(this.destInput).ready;

        const notValidAmount = !Validate.amount(this.amountToSend);
        const notValidMemoType = this.memoType === 'none' && (this.memoRequired || this.sep29MemoRequired);
        const notValidMemoContent = this.memoType !== 'none' && !Validate.memo(this.memoContent, this.memoType).ready;
        const destNoTrustline = !this.availableAssets[this.choosenSlug].sendable;

        const isXlmNative = this.getAsset(this.assetToSend).isNative();
        const targetBalance = this.d.session.account.getBalance(this.getAsset());
        const maxAssetSpend = isXlmNative
            ? this.d.session.account.maxLumenSpend()
            : this.getMaxAssetSpend(targetBalance);
        const notEnoughAsset = Number(this.amountToSend) > Number(maxAssetSpend);

        if (
            destinationIsEmpty ||
            notValidDestination ||
            this.requestIsPending ||
            this.federationNotFound ||
            notValidAmount ||
            notEnoughAsset ||
            notValidMemoType ||
            notValidMemoContent ||
            destNoTrustline) {
            return false;
        }

        return true;
    }

    resetSendForm() {
        this.federationAddress = '';
        this.destInput = '';
        this.accountId = '';
        this.amountToSend = '';
        this.destinationName = '';

        this.memoRequired = false;
        this.sep29MemoRequired = false;
        this.memoType = 'none';
        this.memoContent = '';

        this.state = 'setup';
        this.event.trigger();
    }
}
<|endoftext|>


<commit_before>var DEFAULT_POKEMON_SETS = {
   'ATTACKER' : [
      {
         name : 'Physical Sweeper',
         nature : 'Hardy',
         item : 'Life Orb',
         ev : [ 0, 252, 0, 4, 0, 252 ],
      },
      {
         name : 'Special Sweeper',
         nature : 'Hardy',
         item : 'Life Orb',
         ev : [ 0, 4, 0, 252, 0, 252 ],
      },
      {
         name : 'Choice Band',
         nature : 'Adamant',
         item : 'Choice Band',
         ev : [ 4, 252, 0, 0, 0, 252 ],
      },
      {
         name : 'Choice Specs',
         nature : 'Modest',
         item : 'Choice Specs',
         ev : [ 4, 0, 0, 252, 0, 252 ],
      },
   ],
   'TARGET' : [
      {
         name : 'Physically Defensive',
         nature : 'Bold',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
      {
         name : 'Specially Defensive',
         nature : 'Calm',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
      {
         name : 'Bulky',
         nature : 'Hardy',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
   ],
};

<commit_msg>Added none set<commit_after>var DEFAULT_POKEMON_SETS = {
   'ATTACKER' : [
      {
         name : 'None',
         nature : 'Hardy',
         ev : [ 0, 0, 0, 0, 0, 0 ],
      },
      {
         name : 'Physical Sweeper',
         nature : 'Hasty',
         item : 'Life Orb',
         ev : [ 0, 252, 0, 4, 0, 252 ],
      },
      {
         name : 'Special Sweeper',
         nature : 'Hasty',
         item : 'Life Orb',
         ev : [ 0, 4, 0, 252, 0, 252 ],
      },
      {
         name : 'Choice Band',
         nature : 'Adamant',
         item : 'Choice Band',
         ev : [ 4, 252, 0, 0, 0, 252 ],
      },
      {
         name : 'Choice Specs',
         nature : 'Modest',
         item : 'Choice Specs',
         ev : [ 4, 0, 0, 252, 0, 252 ],
      },
   ],
   'TARGET' : [
      {
         name : 'None',
         nature : 'Hardy',
         ev : [ 0, 0, 0, 0, 0, 0 ],
      },
      {
         name : 'Physically Defensive',
         nature : 'Bold',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
      {
         name : 'Specially Defensive',
         nature : 'Calm',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
      {
         name : 'Bulky',
         nature : 'Hardy',
         ev : [ 252, 0, 252, 0, 4, 252 ],
      },
   ],
};

<|endoftext|>


<commit_before>function Bubble(b){ // data
    var that = this;
    this.budget = b;
    this.asMoney = d3.format('$,');
    this.column = null;
    this.data = null;
    this.sizes = {width: 950, height: 500, padding: 100};
    this.force = null;
    this.circles = null;
    this.force_gravity = -0.05; // -0.018
    this.damper = 0.6; // 0.4 tightness of the bubbles
    this.center = {x: this.sizes.width / 2, y: this.sizes.height / 2};
    this.radius_scale = d3.scale.pow().exponent(0.4).domain([0, 115000000]).range([3, 25]); // 15
    this.nodes = [];
}

Bubble.prototype.setColumn = function(column){
    // if (this.column !== null) {
    //     this.column = column;
    // }
    this.column = column;
};

Bubble.prototype.setData = function(newData){
    this.data = newData;
};

Bubble.prototype.setBudget = function(budget){
    this.budget = budget;
}

Bubble.prototype.make_svg = function(){
    if(document.querySelector('svg')){
        d3.select('svg').remove();
    }
    this.svg = d3.select('#chart').append('svg')
        .attr('width', this.sizes.width)
        .attr('height', this.sizes.height);
};

Bubble.prototype.create_nodes = function(set){
    if(this.nodes.length){
        this.nodes = [];
    }
    for(var i = 0, j = set.length; i < j; i++){
        var that = this,
            current = set[i];
        current.myx = this.center.x;
        current.myy = this.center.y;
        current.radius = (function(){
            if(current[that.budget] && current[that.budget] !== 'NA' && current[that.budget] !== ''){
               // return (that.radius_scale(parseInt(current[that.budget])));
               return Math.pow(parseInt(current[that.budget]), 0.157);
            } else {
                if (current[that.budget] === 'NA'){
                    console.log('NA', current);
                    return 5;
                } else {
                    console.log('not ready', current);
                    return 3;
                }
            }
        }());
        this.nodes.push(current);
    }
    //this.nodes.sort(function(a,b){ return b[budget] - a[budget]});
};

Bubble.prototype.add_bubbles = function(set){
     this.circles = this.svg.append('g').attr('id', 'groupCircles')
        .selectAll('circle')
        .data(set)
        .enter()
        .append('circle')
        .attr('class', 'circle')
        .style('fill', function(d,i){
            return set[i].color;
        })
        .attr('cx', function(d,i){
            return set[i].myx;
        })
        .attr('cy', function(d,i){
            return set[i].myy;
        })
        .attr('r', function(d,i){
            //console.log(set[i].radius);
            //console.log(set[i]);

            return set[i].radius;})
        ;
};

Bubble.prototype.add_tootltips = function(d){
    var that = this;
    this.circles.on('mouseenter', function(d){

        // GET THE X/Y COOD OF OBJECT
        var tooltipPadding = 160,
            xPosition = d3.select(this)[0][0]['cx'].animVal.value + tooltipPadding,
            yPosition = d3.select(this)[0][0]['cy'].animVal.value;

        // TOOLTIP INFO
        d3.select('#school').text('School: ' + camel(d.School));
        d3.select('#agency').text('Agency: ' + d.Agency);
        d3.select('#ward').text('Ward: ' + d.Ward);
        if(d.ProjectType && d.ProjectType !== 'NA'){
            d3.select('#project').text('Project: ' + d.ProjectType);
        } else {
            d3.select('#project').text('');
        }
        if(d.YrComplete && d.YrComplete !== 'NA'){
            d3.select('#yearComplete').text('Year Completed: ' + d.YrComplete);
        } else {
            d3.select('#yearComplete').text('');
        }
        d3.select('#majorexp').text('Total Spent: ' + that.asMoney(d[this.budget]));
        d3.select('#spent_sqft').text('Spent per Sq.Ft.: ' + that.asMoney(d.SpentPerSqFt) + '/sq. ft.');
        d3.select('#expPast').text('Spent per Maximum Occupancy: ' + that.asMoney(d.SpentPerMaxOccupancy));
        if(d.FeederHS && d.FeederHS !== "NA"){
            d3.select('#hs').text('High School: ' + camel(d.FeederHS));
        } else {
            d3.select('#hs').text('');
        }

        // Make the tooltip visisble
        d3.select('#tooltip')
            .style('left', xPosition + 'px')
            .style('top', yPosition + 'px');
        d3.select('#tooltip').classed('hidden', false);
    })
    .on('mouseleave', function(){
        d3.select('#tooltip').classed('hidden', true);
    });
}

Bubble.prototype.set_force = function() {
    var that = this;
    this.force = d3.layout.force()
        .nodes(this.data)
        .links([])
        .size([this.sizes.width, this.sizes.height])
        .gravity(this.force_gravity) // -0.01
        .charge(function(d){ return that.charge(d) || -15; })
        .friction(0.9); // 0.9

};

Bubble.prototype.charge = function(d) {
    var charge = (-Math.pow(d.radius, 1.8) / 2.2); // 1.3
    if(charge == NaN){
        charge = -25;
    }
    return charge;
};

Bubble.prototype.group_bubbles = function(d){
    var that = this;
    this.force.on('tick', function(e){
        that.circles.each(that.move_towards_centers(e.alpha/2, that.column))
            .attr('cx', function(d){ return d.x;})
            .attr('cy', function(d){ return d.y;});
        })
        ;
    this.force.start();

};

Bubble.prototype.move_towards_center = function(alpha){
    var that = this;
    return function(d){
        d.x = d.x + (that.center.x - d.x) * (that.damper + 0.02) * alpha;
        d.y = d.y + (that.center.y - d.y) * (that.damper + 0.02) * alpha;
    };
}

Bubble.prototype.move_towards_centers = function(alpha, column) {
    // Make an array of unique items
    var that = this,
        items = _.uniq(_.pluck(this.nodes, column)).sort(),
        unique = [];
    for (var i = 0; i < items.length; i++) {
        unique.push({name: items[i]});
    }

    // Assign unique_item a point to occupy
    var width = this.sizes.width,
        height = this.sizes.height,
        padding = this.sizes.padding;
    for (var i in unique){
        // Make the grid here
        unique[i].x = (i * width / unique.length) * 0.6 + 250; //+ 500; // * alpha
        unique[i].y = this.center.y; // * alpha
    }

    // Attach the target coordinates to each node
    _.each(this.nodes, function(node){
        for (var i = 0; i < unique.length; i++) {
            if (node[column] === unique[i].name){
                node.target = {
                    x: unique[i].x,
                    y: unique[i].y
                };
            }
        }
    });

    // Send the nodes the their corresponding point
    return function(d){
        // d3.select('#groupCircles').attr('transform', 'translate(' + that.center.x + ', ' + that.center.y + ')');
        d.x = d.x + (d.target.x - d.x) * (that.damper + 0.02) * alpha;
        d.y = d.y + (d.target.y - d.y) * (that.damper + 0.02) * alpha;
    }
};

Bubble.prototype.graph = function(set){
    this.make_svg();
    this.set_force();
    this.create_nodes(set);
    this.add_bubbles(this.nodes);
    this.add_tootltips();
    this.group_bubbles();

};

// Utility functions
function get(sel){return document.querySelector(sel);}
function getAll(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel));}
function camel(str){ return str.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase();});}<commit_msg>Added text labels; positions need adjusting<commit_after>function Bubble(b){ // data
    var that = this;
    this.budget = b;
    this.asMoney = d3.format('$,');
    this.column = null;
    this.data = null;
    this.sizes = {width: 950, height: 500, padding: 100};
    this.force = null;
    this.circles = null;
    this.force_gravity = -0.05; // -0.018
    this.damper = 0.6; // 0.4 tightness of the bubbles
    this.center = {x: this.sizes.width / 2, y: this.sizes.height / 2};
    this.radius_scale = d3.scale.pow().exponent(0.4).domain([0, 115000000]).range([3, 25]); // 15
    this.nodes = [];
    this.unique = null;
}

Bubble.prototype.setColumn = function(column){
    // if (this.column !== null) {
    //     this.column = column;
    // }
    this.column = column;
};

Bubble.prototype.setData = function(newData){
    this.data = newData;
};

Bubble.prototype.setBudget = function(budget){
    this.budget = budget;
}

Bubble.prototype.make_svg = function(){
    if(document.querySelector('svg')){
        d3.select('svg').remove();
    }
    this.svg = d3.select('#chart').append('svg')
        .attr('width', this.sizes.width)
        .attr('height', this.sizes.height);
};

Bubble.prototype.create_nodes = function(set){
    if(this.nodes.length){
        this.nodes = [];
    }
    for(var i = 0, j = set.length; i < j; i++){
        var that = this,
            current = set[i];
        current.myx = this.center.x;
        current.myy = this.center.y;
        current.radius = (function(){
            if(current[that.budget] && current[that.budget] !== 'NA' && current[that.budget] !== ''){
               // return (that.radius_scale(parseInt(current[that.budget])));
               return Math.pow(parseInt(current[that.budget]), 0.157);
            } else {
                if (current[that.budget] === 'NA'){
                    console.log('NA', current);
                    return 5;
                } else {
                    console.log('not ready', current);
                    return 3;
                }
            }
        }());
        this.nodes.push(current);
    }
    //this.nodes.sort(function(a,b){ return b[budget] - a[budget]});
};

Bubble.prototype.add_bubbles = function(set){
     this.circles = this.svg.append('g').attr('id', 'groupCircles')
        .selectAll('circle')
        .data(set)
        .enter()
        .append('circle')
        .attr('class', 'circle')
        .style('fill', function(d,i){
            return set[i].color;
        })
        .attr('cx', function(d,i){
            return set[i].myx;
        })
        .attr('cy', function(d,i){
            return set[i].myy;
        })
        .attr('r', function(d,i){
            //console.log(set[i].radius);
            //console.log(set[i]);

            return set[i].radius;})
        ;
};

Bubble.prototype.add_tootltips = function(d){
    var that = this;
    this.circles.on('mouseenter', function(d){

        // GET THE X/Y COOD OF OBJECT
        var tooltipPadding = 160,
            xPosition = d3.select(this)[0][0]['cx'].animVal.value + tooltipPadding,
            yPosition = d3.select(this)[0][0]['cy'].animVal.value;

        // TOOLTIP INFO
        d3.select('#school').text('School: ' + camel(d.School));
        d3.select('#agency').text('Agency: ' + d.Agency);
        d3.select('#ward').text('Ward: ' + d.Ward);
        if(d.ProjectType && d.ProjectType !== 'NA'){
            d3.select('#project').text('Project: ' + d.ProjectType);
        } else {
            d3.select('#project').text('');
        }
        if(d.YrComplete && d.YrComplete !== 'NA'){
            d3.select('#yearComplete').text('Year Completed: ' + d.YrComplete);
        } else {
            d3.select('#yearComplete').text('');
        }
        d3.select('#majorexp').text('Total Spent: ' + that.asMoney(d[this.budget]));
        d3.select('#spent_sqft').text('Spent per Sq.Ft.: ' + that.asMoney(d.SpentPerSqFt) + '/sq. ft.');
        d3.select('#expPast').text('Spent per Maximum Occupancy: ' + that.asMoney(d.SpentPerMaxOccupancy));
        if(d.FeederHS && d.FeederHS !== "NA"){
            d3.select('#hs').text('High School: ' + camel(d.FeederHS));
        } else {
            d3.select('#hs').text('');
        }

        // Make the tooltip visisble
        d3.select('#tooltip')
            .style('left', xPosition + 'px')
            .style('top', yPosition + 'px');
        d3.select('#tooltip').classed('hidden', false);
    })
    .on('mouseleave', function(){
        d3.select('#tooltip').classed('hidden', true);
    });
}

Bubble.prototype.set_force = function() {
    var that = this;
    this.force = d3.layout.force()
        .nodes(this.data)
        .links([])
        .size([this.sizes.width, this.sizes.height])
        .gravity(this.force_gravity) // -0.01
        .charge(function(d){ return that.charge(d) || -15; })
        .friction(0.9); // 0.9

};

Bubble.prototype.charge = function(d) {
    var charge = (-Math.pow(d.radius, 1.8) / 2.2); // 1.3
    if(charge == NaN){
        charge = -25;
    }
    return charge;
};

Bubble.prototype.group_bubbles = function(d){
    var that = this;
    this.force.on('tick', function(e){
        that.circles.each(that.move_towards_centers(e.alpha/2, that.column))
            .attr('cx', function(d){ return d.x;})
            .attr('cy', function(d){ return d.y;});
        })
        ;
    this.force.start();

};

Bubble.prototype.move_towards_center = function(alpha){
    var that = this;
    return function(d){
        d.x = d.x + (that.center.x - d.x) * (that.damper + 0.02) * alpha;
        d.y = d.y + (that.center.y - d.y) * (that.damper + 0.02) * alpha;
    };
}

Bubble.prototype.move_towards_centers = function(alpha, column) {
    // Make an array of unique items
    var that = this,
        items = _.uniq(_.pluck(this.nodes, column)).sort();
        unique = [];
    for (var i = 0; i < items.length; i++) {
        unique.push({name: items[i]});
    }

    // Assign unique_item a point to occupy
    var width = this.sizes.width,
        height = this.sizes.height,
        padding = this.sizes.padding;
    for (var i in unique){
        // Make the grid here
        unique[i].x = (i * width / unique.length) * 0.6 + 250; //+ 500; // * alpha
        unique[i].y = this.center.y; // * alpha
    }

    // Attach the target coordinates to each node
    _.each(this.nodes, function(node){
        for (var i = 0; i < unique.length; i++) {
            if (node[column] === unique[i].name){
                node.target = {
                    x: unique[i].x,
                    y: unique[i].y
                };
            }
        }
    });

    // Add Text
    this.svg.selectAll('text')
        .data(unique)
        .enter()
        .append('text')
        .attr('class', 'sub_titles')
        .attr('x', function(d){return d.x *1.8 - 450;})
        .attr('y', function(d){return d.y - 150;})
        .text(function(d){
            return d.name;
        })
        ;
    // Send the nodes the their corresponding point
    return function(d){
        // d3.select('#groupCircles').attr('transform', 'translate(' + that.center.x + ', ' + that.center.y + ')');
        d.x = d.x + (d.target.x - d.x) * (that.damper + 0.02) * alpha;
        d.y = d.y + (d.target.y - d.y) * (that.damper + 0.02) * alpha;
    }
};

Bubble.prototype.graph = function(set){
    this.make_svg();
    this.set_force();
    this.create_nodes(set);
    this.add_bubbles(this.nodes);
    this.add_tootltips();
    this.group_bubbles();

};

// Utility functions
function get(sel){return document.querySelector(sel);}
function getAll(sel){ return Array.prototype.slice.call(document.querySelectorAll(sel));}
function camel(str){ return str.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase();});}<|endoftext|>


<commit_before>describe("Interpreter", function () {
    var int;

    //
    // Interpreter creation tests
    //
    it('tests it\'s creation', function () {
        expect(function () {int = new Evo.Interpreter();}).not.toThrow();
    });
    it('runs itself without parameters', function () {
        int = new Evo.Interpreter();
        expect(function () {int.run();}).not.toThrow();
    });
    it('runs simple script', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
    });
    //
    // Tests configurations
    //
    it('tests codeLen config', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0]), codeLen: 4});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0])});
        expect(int.getVars()[0]).toBe(2);
    });
    it('tests i config', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0]), i: 4});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0])});
        expect(int.getVars()[0]).toBe(2);
    });
    it('tests inCb config', function (done) {
        int = new Evo.Interpreter();
        // in v1,v1
        int.run({code: new Uint16Array([24,1,1,0]), inCb: function(cb, v) {
            setTimeout(function () {
                cb(v+2);
                expect(int.getVars()[1]).toBe(2);
                done();
            }, 0);
        }});
    });
    it('tests outCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  set 2,v2;  out v1,v2;
        int.run({code: new Uint16Array([0,1,1,0, 0,2,2,0, 25,1,2,0]), outCb: function(v1, v2) {
            expect(v1).toBe(1);
            expect(v2).toBe(2);
        }});
    });
    it('tests stepCb config', function (done) {
        int = new Evo.Interpreter();
        // set 1,v1;  step v1
        int.run({code: new Uint16Array([0,1,1,0, 26,1,0,0]), stepCb: function(cb, v) {
            expect(v).toBe(1);
            setTimeout(function () {
                // we just need to be here without checks
                cb();
                done();
            }, 0);
        }});
    });
    it('tests eatCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  set 2,v2;  eat v1,v2;
        int.run({code: new Uint16Array([0,1,1,0, 0,2,2,0, 27,1,2,0]), eatCb: function(v1, v2) {
            expect(v1).toBe(1);
            expect(v2).toBe(2);
        }});
    });
    it('tests cloneCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  clone v1;
        int.run({code: new Uint16Array([0,1,1,0, 28,1,0,0]), cloneCb: function(v1) {
            expect(v1).toBe(1);
        }});
    });
    it('tests echoCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  echo v1;
        int.run({code: new Uint16Array([0,1,1,0, 14,1,0,0]), echoCb: function(v1) {
            expect(v1).toBe(1);
        }});
    });
    //
    // Tests commands
    //
    it('tests set command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([0,1,1,0])});
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([0,65535,2,0])});
        expect(int.getVars()[2]).toBe(65535);
        int.run({code: new Uint16Array([0,65536,3,0])});
        expect(int.getVars()[3]).toBe(0);
        int.run({code: new Uint16Array([0,65537,4,0])});
        expect(int.getVars()[4]).toBe(1);
        int.run({code: new Uint16Array([0,-1,5,0])});
        expect(int.getVars()[5]).toBe(65535);
        int.run({code: new Uint16Array([0,1,6,1])});
        expect(int.getVars()[6]).toBe(1);
    });
    it('tests move command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([1,0,1,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 1,0,1,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([0,1,2,0, 1,2,2,0])});
        expect(int.getVars()[2]).toBe(1);
        int.run({code: new Uint16Array([0,1,1,0, 1,1,2,3])});
        expect(int.getVars()[1]).toBe(1);
        expect(int.getVars()[2]).toBe(1);
    });
    it('tests inc command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([2,0,0,0])});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([2,0,0,0, 2,0,0,0])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([2,0,0,0, 2,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([2,0,0,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([2,0,1,2])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
    });
    it('tests dec command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([3,0,0,0])});
        expect(int.getVars()[0]).toBe(65535);
        int.run({code: new Uint16Array([3,0,0,0, 3,0,0,0])});
        expect(int.getVars()[0]).toBe(65534);
        int.run({code: new Uint16Array([0,1,0,0, 3,0,0,0, 3,1,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(65535);
        int.run({code: new Uint16Array([0,1,0,0, 3,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([3,0,1,2])});
        expect(int.getVars()[0]).toBe(65535);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
    });
    it('tests add command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([4,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0, 4,0,0,0])});
        expect(int.getVars()[0]).toBe(4);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0, 4,1,0,0])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0])});
        expect(int.getVars()[0]).toBe(2);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([0,65535,0,0, 0,1,1,0, 4,1,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(1);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,1])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,2,0,0, 0,65535,1,0, 4,0,1,1])});
        expect(int.getVars()[0]).toBe(2);
        expect(int.getVars()[1]).toBe(1);
    });
});<commit_msg>+ Added unit test for dec command<commit_after>describe("Interpreter", function () {
    var int;

    //
    // Interpreter creation tests
    //
    it('tests it\'s creation', function () {
        expect(function () {int = new Evo.Interpreter();}).not.toThrow();
    });
    it('runs itself without parameters', function () {
        int = new Evo.Interpreter();
        expect(function () {int.run();}).not.toThrow();
    });
    it('runs simple script', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
    });
    //
    // Tests configurations
    //
    it('tests codeLen config', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0]), codeLen: 4});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0])});
        expect(int.getVars()[0]).toBe(2);
    });
    it('tests i config', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0]), i: 4});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,1,0,0, 0,2,0,0])});
        expect(int.getVars()[0]).toBe(2);
    });
    it('tests inCb config', function (done) {
        int = new Evo.Interpreter();
        // in v1,v1
        int.run({code: new Uint16Array([24,1,1,0]), inCb: function(cb, v) {
            setTimeout(function () {
                cb(v+2);
                expect(int.getVars()[1]).toBe(2);
                done();
            }, 0);
        }});
    });
    it('tests outCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  set 2,v2;  out v1,v2;
        int.run({code: new Uint16Array([0,1,1,0, 0,2,2,0, 25,1,2,0]), outCb: function(v1, v2) {
            expect(v1).toBe(1);
            expect(v2).toBe(2);
        }});
    });
    it('tests stepCb config', function (done) {
        int = new Evo.Interpreter();
        // set 1,v1;  step v1
        int.run({code: new Uint16Array([0,1,1,0, 26,1,0,0]), stepCb: function(cb, v) {
            expect(v).toBe(1);
            setTimeout(function () {
                // we just need to be here without checks
                cb();
                done();
            }, 0);
        }});
    });
    it('tests eatCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  set 2,v2;  eat v1,v2;
        int.run({code: new Uint16Array([0,1,1,0, 0,2,2,0, 27,1,2,0]), eatCb: function(v1, v2) {
            expect(v1).toBe(1);
            expect(v2).toBe(2);
        }});
    });
    it('tests cloneCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  clone v1;
        int.run({code: new Uint16Array([0,1,1,0, 28,1,0,0]), cloneCb: function(v1) {
            expect(v1).toBe(1);
        }});
    });
    it('tests echoCb config', function () {
        int = new Evo.Interpreter();
        // set 1,v1;  echo v1;
        int.run({code: new Uint16Array([0,1,1,0, 14,1,0,0]), echoCb: function(v1) {
            expect(v1).toBe(1);
        }});
    });
    //
    // Tests commands
    //
    it('tests set command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([0,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([0,1,1,0])});
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([0,65535,2,0])});
        expect(int.getVars()[2]).toBe(65535);
        int.run({code: new Uint16Array([0,65536,3,0])});
        expect(int.getVars()[3]).toBe(0);
        int.run({code: new Uint16Array([0,65537,4,0])});
        expect(int.getVars()[4]).toBe(1);
        int.run({code: new Uint16Array([0,-1,5,0])});
        expect(int.getVars()[5]).toBe(65535);
        int.run({code: new Uint16Array([0,1,6,1])});
        expect(int.getVars()[6]).toBe(1);
    });
    it('tests move command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([1,0,1,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 1,0,1,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([0,1,2,0, 1,2,2,0])});
        expect(int.getVars()[2]).toBe(1);
        int.run({code: new Uint16Array([0,1,1,0, 1,1,2,3])});
        expect(int.getVars()[1]).toBe(1);
        expect(int.getVars()[2]).toBe(1);
    });
    it('tests inc command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([2,0,0,0])});
        expect(int.getVars()[0]).toBe(1);
        int.run({code: new Uint16Array([2,0,0,0, 2,0,0,0])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([2,0,0,0, 2,1,0,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([2,0,0,0])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([2,0,1,2])});
        expect(int.getVars()[0]).toBe(1);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
    });
    it('tests dec command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([3,0,0,0])});
        expect(int.getVars()[0]).toBe(65535);
        int.run({code: new Uint16Array([3,0,0,0, 3,0,0,0])});
        expect(int.getVars()[0]).toBe(65534);
        int.run({code: new Uint16Array([0,1,0,0, 3,0,0,0, 3,1,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(65535);
        int.run({code: new Uint16Array([0,1,0,0, 3,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([3,0,1,2])});
        expect(int.getVars()[0]).toBe(65535);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
    });
    it('tests add command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([4,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0, 4,0,0,0])});
        expect(int.getVars()[0]).toBe(4);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0, 4,1,0,0])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,0])});
        expect(int.getVars()[0]).toBe(2);
        expect(int.getVars()[1]).toBe(0);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([0,65535,0,0, 0,1,1,0, 4,1,0,0])});
        expect(int.getVars()[0]).toBe(0);
        expect(int.getVars()[1]).toBe(1);
        expect(int.getVars()[2]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 4,0,0,1])});
        expect(int.getVars()[0]).toBe(2);
        int.run({code: new Uint16Array([0,2,0,0, 0,65535,1,0, 4,0,1,1])});
        expect(int.getVars()[0]).toBe(2);
        expect(int.getVars()[1]).toBe(1);
        int.run({code: new Uint16Array([4,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
    });
    it('tests dec command', function () {
        int = new Evo.Interpreter();
        int.run({code: new Uint16Array([5,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 5,0,0,0])});
        expect(int.getVars()[0]).toBe(0);
        int.run({code: new Uint16Array([0,1,0,0, 5,0,1,0])});
        expect(int.getVars()[1]).toBe(65535);
    });
});<|endoftext|>