<commit_before>/*
Language: Java
Author: Vsevolod Solovyov <vsevolod.solovyov@gmail.com>
*/

function(hljs) {
  var GENERIC_IDENT_RE = hljs.UNDERSCORE_IDENT_RE + '(<' + hljs.UNDERSCORE_IDENT_RE + '>)?';
  var KEYWORDS =
    'false synchronized int abstract float private char boolean static null if const ' +
    'for true while long throw strictfp finally protected import native final return void ' +
    'enum else break transient new catch instanceof byte super volatile case assert short ' +
    'package default double public try this switch continue throws protected public private';
  return {
    aliases: ['jsp'],
    keywords: KEYWORDS,
    illegal: /<\//,
    contains: [
      {
        className: 'javadoc',
        begin: '/\\*\\*', end: '\\*/',
        relevance: 0,
        contains: [{
          className: 'javadoctag', begin: '(^|\\s)@[A-Za-z]+'
        }]
      },
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      hljs.APOS_STRING_MODE,
      hljs.QUOTE_STRING_MODE,
      {
        className: 'class',
        beginKeywords: 'class interface', end: /[{;=]/, excludeEnd: true,
        keywords: 'class interface',
        illegal: /[:"\[\]]/,
        contains: [
          {beginKeywords: 'extends implements'},
          hljs.UNDERSCORE_TITLE_MODE
        ]
      },
      {
        // this prevents 'new Name(...)' from being recognized as a function definition
        beginKeywords: 'new', end: /\s/,
        relevance: 0
      },
      {
        // this prevents 'throw ...' from being recognized as a function definition
        beginKeywords: 'throw', end: /\s/,
        relevance: 0
      },
      {
        className: 'function',
        begin: '(' + GENERIC_IDENT_RE + '\\s+)+' + hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true, end: /[{;=]/,
        excludeEnd: true,
        keywords: KEYWORDS,
        contains: [
          {
            begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true,
            contains: [hljs.UNDERSCORE_TITLE_MODE]
          },
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            keywords: KEYWORDS,
            contains: [
              hljs.APOS_STRING_MODE,
              hljs.QUOTE_STRING_MODE,
              hljs.C_NUMBER_MODE,
              hljs.C_BLOCK_COMMENT_MODE
            ]
          },
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE
        ]
      },
      hljs.C_NUMBER_MODE,
      {
        className: 'annotation', begin: '@[A-Za-z]+'
      }
    ]
  };
}
<commit_msg>Shorter fix for ignoring throw keyword as function in java<commit_after>/*
Language: Java
Author: Vsevolod Solovyov <vsevolod.solovyov@gmail.com>
*/

function(hljs) {
  var GENERIC_IDENT_RE = hljs.UNDERSCORE_IDENT_RE + '(<' + hljs.UNDERSCORE_IDENT_RE + '>)?';
  var KEYWORDS =
    'false synchronized int abstract float private char boolean static null if const ' +
    'for true while long throw strictfp finally protected import native final return void ' +
    'enum else break transient new catch instanceof byte super volatile case assert short ' +
    'package default double public try this switch continue throws protected public private';
  return {
    aliases: ['jsp'],
    keywords: KEYWORDS,
    illegal: /<\//,
    contains: [
      {
        className: 'javadoc',
        begin: '/\\*\\*', end: '\\*/',
        relevance: 0,
        contains: [{
          className: 'javadoctag', begin: '(^|\\s)@[A-Za-z]+'
        }]
      },
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      hljs.APOS_STRING_MODE,
      hljs.QUOTE_STRING_MODE,
      {
        className: 'class',
        beginKeywords: 'class interface', end: /[{;=]/, excludeEnd: true,
        keywords: 'class interface',
        illegal: /[:"\[\]]/,
        contains: [
          {beginKeywords: 'extends implements'},
          hljs.UNDERSCORE_TITLE_MODE
        ]
      },
      {
        // this prevents 'new Name(...), or throw ...' from being recognized as a function definition
        beginKeywords: 'new throw', end: /\s/,
        relevance: 0
      },
      {
        className: 'function',
        begin: '(' + GENERIC_IDENT_RE + '\\s+)+' + hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true, end: /[{;=]/,
        excludeEnd: true,
        keywords: KEYWORDS,
        contains: [
          {
            begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', returnBegin: true,
            contains: [hljs.UNDERSCORE_TITLE_MODE]
          },
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            keywords: KEYWORDS,
            contains: [
              hljs.APOS_STRING_MODE,
              hljs.QUOTE_STRING_MODE,
              hljs.C_NUMBER_MODE,
              hljs.C_BLOCK_COMMENT_MODE
            ]
          },
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE
        ]
      },
      hljs.C_NUMBER_MODE,
      {
        className: 'annotation', begin: '@[A-Za-z]+'
      }
    ]
  };
}
<|endoftext|>


<commit_before>window.Alive = {};

function queryToObject(query) {
	var rv = {};
  var vars = query.substring(1).split('&');
	var pair;
  for (var i = 0; i < vars.length; i++) {
    pair = vars[i].split('=');
		rv[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1])
  }
	return rv;
}

function _loadString(string) {
	return new Promise(function(success) {
		success(string);
	});
}

var _loadFileCache = {};
function _loadFile(file) {
	return new Promise(function(success) {
		if (_loadFileCache[file]) {
			success(_loadFileCache[file]);
			return;
		}
		var request = new XMLHttpRequest();
		request.open("GET", file);
		request.onload = function() {
			_loadFileCache[file] = request.responseText;
			success(request.responseText);
		}
		request.send();
	});
}

function loadProject(preloadedCode) {
	var params = queryToObject(window.location.search);
	var requests = [
		_loadFile('linear.sjs'),
		_loadFile('modules/ViewController.coffee'),
		_loadFile('modules/Alive.coffee'),
		preloadedCode ? _loadString(preloadedCode) : _loadFile('app.coffee?id=' + params.id)
	];
	Promise.all(requests)
		.then(function(files){
			return new Promise(function(success) {
				console.time('compile');
				var coffee = [
					files[1],
					files[2],
					files[3]
				].join('\n');
				if (window.Alive.farmer) {
					window.Alive.farmer.terminate();
				}
				window.Alive.farmer = new Worker("farmer.js");
				window.Alive.farmer.onmessage = function(e) {
					success(e.data);
					window.Alive.farmer.terminate();
				}
				window.Alive.farmer.postMessage(coffee);
			});
		})
		.then(function(js){
			try {
				console.timeEnd('compile');
				Framer.Extras.ErrorDisplay.disable();
				if (window.Alive.isInitialized) {
					Framer.CurrentContext.reset();
				}
				eval(js);
				// require('builtin:apollo-sys').eval(js.join(''));
			} catch (error) {
				console.error('Alive: Compile Error', error);
			}
      ready();
		});
}

function ready() {

}

function sendMessage(message) {
	window.parent.postMessage(JSON.stringify(message), '*');
}

function receiveMessage(event) {
  if (!event.data) {
    return;
  }
  var origin = event.origin || event.originalEvent.origin; // XXX check
  var message = JSON.parse(event.data);
	console.log('received', message.type);
	if (message.type === 'change:app.coffee') {
		window.Alive.initialView = message.view;
		loadProject(message.code);
	} else if (message.type === 'show') {
    window.Alive.Navigation.show(window.Alive.layers[message.view]);
    // views.history.shift()
  }
}

window.addEventListener('message', receiveMessage, false);
document.write("<script src=\"/layers.js?id="+ queryToObject(location.search).id+"\"></script>");
<commit_msg>clenup spaces<commit_after>window.Alive = {};

function queryToObject(query) {
  var rv = {};
  var vars = query.substring(1).split('&');
  var pair;
  for (var i = 0; i < vars.length; i++) {
    pair = vars[i].split('=');
    rv[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1])
  }
  return rv;
}

function _loadString(string) {
  return new Promise(function(success) {
    success(string);
  });
}

var _loadFileCache = {};
function _loadFile(file) {
  return new Promise(function(success) {
    if (_loadFileCache[file]) {
      success(_loadFileCache[file]);
      return;
    }
    var request = new XMLHttpRequest();
    request.open("GET", file);
    request.onload = function() {
      _loadFileCache[file] = request.responseText;
      success(request.responseText);
    }
    request.send();
  });
}

function loadProject(preloadedCode) {
  var params = queryToObject(window.location.search);
  var requests = [
    _loadFile('linear.sjs'),
    _loadFile('modules/ViewController.coffee'),
    _loadFile('modules/Alive.coffee'),
    preloadedCode ? _loadString(preloadedCode) : _loadFile('app.coffee?id=' + params.id)
  ];
  Promise.all(requests)
    .then(function(files){
      return new Promise(function(success) {
        console.time('compile');
        var coffee = [
          files[1],
          files[2],
          files[3]
        ].join('\n');
        if (window.Alive.farmer) {
          window.Alive.farmer.terminate();
        }
        window.Alive.farmer = new Worker("farmer.js");
        window.Alive.farmer.onmessage = function(e) {
          success(e.data);
          window.Alive.farmer.terminate();
        }
        window.Alive.farmer.postMessage(coffee);
      });
    })
    .then(function(js){
      try {
        console.timeEnd('compile');
        Framer.Extras.ErrorDisplay.disable();
        if (window.Alive.isInitialized) {
          Framer.CurrentContext.reset();
        }
        eval(js);
        // require('builtin:apollo-sys').eval(js.join(''));
      } catch (error) {
        console.error('Alive: Compile Error', error);
      }
      ready();
    });
}

function ready() {

}

function sendMessage(message) {
  window.parent.postMessage(JSON.stringify(message), '*');
}

function receiveMessage(event) {
  if (!event.data) {
    return;
  }
  var origin = event.origin || event.originalEvent.origin; // XXX check
  var message = JSON.parse(event.data);
  console.log('received', message.type);
  if (message.type === 'change:app.coffee') {
    window.Alive.initialView = message.view;
    loadProject(message.code);
  } else if (message.type === 'show') {
    window.Alive.Navigation.show(window.Alive.layers[message.view]);
    // views.history.shift()
  }
}

window.addEventListener('message', receiveMessage, false);
document.write("<script src=\"/layers.js?id="+ queryToObject(location.search).id+"\"></script>");
<|endoftext|>


<commit_before>import _ from 'lodash';
import Stellarify from '../lib/Stellarify';
import BigNumber from 'bignumber.js';
import directory from '../directory';

// Spoonfed Stellar-SDK: Super easy to use higher level Stellar-Sdk functions
// Simplifies the objects to what is necessary. Listens to updates automagically.
// It's in the same file as the driver because the driver is the only one that
// should ever use the spoon.
const MagicSpoon = {
  async Account(Server, keypair, onUpdate) {
    let sdkAccount = await Server.loadAccount(keypair.publicKey())
    sdkAccount.sign = transaction => {
      transaction.sign(keypair);
    };

    sdkAccount.getLumenBalance = () => {
      return sdkAccount.balances[sdkAccount.balances.length - 1].balance;
    }

    // Expects StellarSdk.Asset
    // Returns null if there is no trust
    // Returns string of balance if exists
    sdkAccount.getBalance = (targetAsset) => {
      let targetBalance = null;
      if (targetAsset.isNative()) {
        _.each(sdkAccount.balances, balance => {
          if (balance.asset_type === 'native') {
            targetBalance = balance.balance;
          }
        });
      } else {
        _.each(sdkAccount.balances, balance => {
          if (balance.asset_code === targetAsset.getCode() && balance.asset_issuer === targetAsset.getIssuer()) {
            targetBalance = balance.balance;
          }
        });
      }
      return targetBalance;
    };

    // Should always return at least one item (which is lumens)
    sdkAccount.getSortedBalances = (opts) => {
      if (!opts) {
        opts = {};
      }
      let nativeBalances = [];
      let knownBalances = [];
      let unknownBalances = [];
      sdkAccount.balances.forEach(sdkBalance => {
        if (sdkBalance.asset_type === 'native') {
          if (opts.hideNative) {
            return;
          }
          return nativeBalances.push({
            code: 'XLM',
            issuer: null,
            balance: sdkBalance.balance,
            sdkBalance,
          });
        }
        let newBalance = { // Yay shoes :P
          code: sdkBalance.asset_code,
          issuer: sdkBalance.asset_issuer,
          balance: sdkBalance.balance,
        };
        let asset = directory.resolveAssetByAccountId(newBalance.code, newBalance.issuer);
        if (asset.domain === 'unknown') {
          return unknownBalances.push(newBalance);
        }
        return knownBalances.push(newBalance);
      });

      return nativeBalances.concat(knownBalances, unknownBalances);
    };

    let accountEventsClose = Server.accounts().accountId(keypair.publicKey()).stream({
      onmessage: res => {
        let updated = false;
        if (!_.isEqual(sdkAccount.balances, res.balances)) {
          sdkAccount.balances = res.balances;
          updated = true;
        }
        if (!_.isEqual(sdkAccount.sequence, res.sequence)) {
          sdkAccount.sequence = res.sequence;
          updated = true;
        }

        if (updated) {
          onUpdate();
        }
      }
    });

    sdkAccount.refresh = async () => {
      let newAccount = await Server.loadAccount(keypair.publicKey());
      sdkAccount.applyNewBalances(newAccount.balances);
    };

    sdkAccount.applyNewBalances = (newBalances) => {
      let updated = false;
      if (!_.isEqual(sdkAccount.balances, newBalances)) {
        sdkAccount.balances = newBalances;
        updated = true;
      }

      if (updated) {
        onUpdate();
      }
    };

    sdkAccount.explainReserve = () => {
      let items = [];
      let sumentries = 0;

      let entriesTrustlines = sdkAccount.balances.length - 1;
      let entriesOffers = Object.keys(sdkAccount.offers).length;
      let entriesOthers = sdkAccount.subentry_count - entriesTrustlines - entriesOffers;

      items.push({
        entryType: 'Base reserve',
        amount: 2,
        XLM: 20,
      });

      items.push({
        entryType: 'Trustlines',
        amount: entriesTrustlines,
        XLM: entriesTrustlines * 10,
      });

      items.push({
        entryType: 'Offers',
        amount: entriesOffers,
        XLM: entriesOffers * 10,
      });
      items.push({
        entryType: 'Others',
        amount: entriesOthers,
        XLM: entriesOthers * 10,
      });
      items.push({
        entryType: 'Extra',
        amount: '',
        XLM: 1,
      });

      let totalLumens = _.sumBy(items, 'XLM');
      return {
        items,
        totalLumens,
      }
    };

    // Will always be less than or equal to the current balance
    sdkAccount.calculatePaddedReserve = () => {
      let networkReserve = (2 + sdkAccount.subentry_count) * 10;
      let extra = 1;
      return networkReserve + extra;
    }

    sdkAccount.maxLumenSpend = () => {
      let balance = sdkAccount.getLumenBalance();
      let reserve = sdkAccount.calculatePaddedReserve();
      if (reserve > balance) {
        return 0;
      }
      return new BigNumber(balance).minus(reserve).toFixed(7);
    };

    sdkAccount.offers = {};

    // Horizon offers for account doesn't return us updates. So we will have to manually update it.
    // We won't miss any offers assuming that the user only updates their offers through the client
    // with just one window open at a time
    sdkAccount.updateOffers = () => {
      return Server.offers('accounts', keypair.publicKey())
        .limit(100) // TODO: Keep iterating through next() to show more than 100 offers
        .call()
        .then(res => {
          let newOffers = {};
          _.each(res.records, offer => {
            newOffers[offer.id] = offer;
          });
          sdkAccount.offers = newOffers;
          onUpdate();
          return null;
        });
    }
    sdkAccount.updateOffers();

    sdkAccount.close = () => {
      accountEventsClose();
    };

    return sdkAccount;
  },
  Orderbook(Server, baseBuying, counterSelling, onUpdate) {
    // Orderbook is an object that keeps track of the orderbook for you.
    // All the driver needs to do is remember to call the close function

    this.ready = false;
    const initialOrderbook = Server.orderbook(baseBuying, counterSelling).call()
      .then((res) => {
        this.asks = res.asks;
        this.bids = res.bids;
        this.baseBuying = baseBuying;
        this.counterSelling = counterSelling;
        this.ready = true;
        onUpdate();

      });
    let streamingOrderbookClose = Server.orderbook(baseBuying, counterSelling)
      .stream({
        onmessage: res => {
          let updated = false;
          if (!_.isEqual(this.bids, res.bids)) {
            this.bids = res.bids;
            updated = true;
          }
          if (!_.isEqual(this.asks, res.asks)) {
            this.asks = res.asks;
            updated = true;
          }
          if (updated) {
            onUpdate();
          }
        }
      })

    let fetchManyTrades = async () => {
      let records = [];
      let satisfied = false;
      let first = true;
      let depth = 0;
      const MAX_DEPTH = 5;
      let prevCall;
      let startTime = Date.now();

      while (!satisfied && depth < MAX_DEPTH && Date.now() - startTime < 5000) {
        depth += 1;
        let tradeResults;
        if (first) {
          tradeResults = await Server.orderbook(baseBuying, counterSelling).trades().limit(200).order('desc').call()
          first = false;
        } else {
          tradeResults = await prevCall();
        }
        prevCall = tradeResults.next;

        if (tradeResults.records.length < 200) {
          satisfied = true;
        }
        Array.prototype.push.apply(records, tradeResults.records);
      }
      // Optimization: use this filter before saving it into the records array
      this.trades = _.filter(
        _.map(records, (trade, index) => {
          return [new Date(trade.created_at).getTime(), new BigNumber(trade.bought_amount).dividedBy(trade.sold_amount).toNumber()];
        }),
        (entry) => {
          // Remote NaN elements that cause gaps in the chart.
          // NaN values happens when the trade bought and sold 0.0000000 of each asset
          return !isNaN(entry[1]);
        }
      );

      // Potential optimization: If we load the horizon results into the array in the correct order
      // then sorting will run at near optimal runtime

      // First sort it in reverse so that we can filter
      this.trades.sort((a,b) => {
        return b[0]-a[0];
      });

      // Iterate on trades from new to old
      // Remove trades that are greater than OUTLIER_THRESHOLD times the previous value
      const OUTLIER_THRESHOLD = 2;
      let lastAmount = this.trades[0];
      this.trades = _.filter(this.trades, (entry) => {
        let currentAmount = entry[1];
        let ratio = (currentAmount > lastAmount) ? currentAmount/lastAmount :  lastAmount/currentAmount;
        if (ratio > OUTLIER_THRESHOLD) {
          return false;
        }
        lastAmount = currentAmount;
        return true;
      });

      _.reverse(this.trades);

      onUpdate();
    }

    fetchManyTrades();

    this.close = streamingOrderbookClose;
    // TODO: Close
  },

  // opts.baseBuying -- StellarSdk.Asset (example: XLM)
  // opts.counterSelling -- StellarSdk.Asset (example: USD)
  // opts.price -- Exchange ratio selling/buying
  // opts.amount -- Here, it's relative to the base (JS-sdk does: Total amount selling)
  // opts.type -- String of either 'buy' or 'sell' (relative to base currency)
  createOffer(Server, spoonAccount, side, opts) {
    let sdkBuying;
    let sdkSelling;
    let sdkPrice;
    let sdkAmount;

    const bigOptsPrice = new BigNumber(opts.price).toPrecision(15);
    const bigOptsAmount = new BigNumber(opts.amount).toPrecision(15);

    console.log(`Creating *${side}* offer at price ${opts.price}`);
    if (side === 'buy') {
      sdkBuying = opts.baseBuying; // ex: lumens
      sdkSelling = opts.counterSelling; // ex: USD
      sdkPrice = new BigNumber(1).dividedBy(bigOptsPrice);
      sdkAmount = new BigNumber(bigOptsAmount).times(bigOptsPrice).toFixed(7);
    } else if (side === 'sell') {
      sdkBuying = opts.counterSelling; // ex: USD
      sdkSelling = opts.baseBuying; // ex: lumens
      sdkPrice = new BigNumber(bigOptsPrice);
      sdkAmount = new BigNumber(bigOptsAmount).toFixed(7);
    } else {
      throw new Error(`Invalid side ${side}`);
    }

    const operationOpts = {
      buying: sdkBuying,
      selling: sdkSelling,
      amount: String(sdkAmount),
      price: String(sdkPrice),
      offerId: 0, // 0 for new offer
    };
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.manageOffer(operationOpts))
      .build();
    spoonAccount.sign(transaction);
    return Server.submitTransaction(transaction)
      .then(res => {
        console.log('Offer create success');
        console.log(res)
        spoonAccount.updateOffers(); // Just to be doubly sure
        return;
      })
  },
  async sendPayment(Server, spoonAccount,  opts) {
    // sendPayment will detect if the account is a new account. If so, then it will
    // be a createAccount operation
    let transaction = new StellarSdk.TransactionBuilder(spoonAccount)
    try {
      let destAccount = await Server.loadAccount(opts.destination);
      transaction = transaction.addOperation(StellarSdk.Operation.payment({
        destination: opts.destination,
        asset: opts.asset,
        amount: opts.amount,
      }));
    } catch(e) {
      if (!opts.asset.isNative()) {
        throw new Error('Destination account does not exist. To create it, you must send a minimum of 20 lumens to create it');
      }
      transaction = transaction.addOperation(StellarSdk.Operation.createAccount({
        destination: opts.destination,
        startingBalance: opts.amount,
      }));
    }

    if (opts.memo) {
      transaction = transaction.addMemo(Stellarify.memo(opts.memo.type, opts.memo.content));
    }

    transaction = transaction.build();
    spoonAccount.sign(transaction);

    const transactionResult = await Server.submitTransaction(transaction);
    return transactionResult;
  },
  changeTrust(Server, spoonAccount, opts) {
    let sdkLimit;
    if (typeof opts.limit === 'string' || opts.limit instanceof String) {
      sdkLimit = opts.limit;
    } else if (opts.limit !== undefined) {
      throw new Error('changeTrust opts.limit must be a string');
    }

    const operationOpts = {
      asset: opts.asset,
      limit: sdkLimit,
    };
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.changeTrust(operationOpts))
      .build();
    spoonAccount.sign(transaction);
    return Server.submitTransaction(transaction)
      .then(txResult => {
        spoonAccount.refresh();
        return txResult;
      });
  },
  async removeOffer(Server, spoonAccount, offerId) {
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.manageOffer({
        buying: StellarSdk.Asset.native(),
        selling: new StellarSdk.Asset('REMOVE', spoonAccount.accountId()),
        amount: '0',
        price: '1',
        offerId,
      }))
      .build();
    spoonAccount.sign(transaction);
    const transactionResult = await Server.submitTransaction(transaction);
    spoonAccount.updateOffers();
    return transactionResult;
  },
};

export default MagicSpoon;
<commit_msg>update magic spoon to new trades api<commit_after>import _ from 'lodash';
import Stellarify from '../lib/Stellarify';
import BigNumber from 'bignumber.js';
import directory from '../directory';

// Spoonfed Stellar-SDK: Super easy to use higher level Stellar-Sdk functions
// Simplifies the objects to what is necessary. Listens to updates automagically.
// It's in the same file as the driver because the driver is the only one that
// should ever use the spoon.
const MagicSpoon = {
  async Account(Server, keypair, onUpdate) {
    let sdkAccount = await Server.loadAccount(keypair.publicKey())
    sdkAccount.sign = transaction => {
      transaction.sign(keypair);
    };

    sdkAccount.getLumenBalance = () => {
      return sdkAccount.balances[sdkAccount.balances.length - 1].balance;
    }

    // Expects StellarSdk.Asset
    // Returns null if there is no trust
    // Returns string of balance if exists
    sdkAccount.getBalance = (targetAsset) => {
      let targetBalance = null;
      if (targetAsset.isNative()) {
        _.each(sdkAccount.balances, balance => {
          if (balance.asset_type === 'native') {
            targetBalance = balance.balance;
          }
        });
      } else {
        _.each(sdkAccount.balances, balance => {
          if (balance.asset_code === targetAsset.getCode() && balance.asset_issuer === targetAsset.getIssuer()) {
            targetBalance = balance.balance;
          }
        });
      }
      return targetBalance;
    };

    // Should always return at least one item (which is lumens)
    sdkAccount.getSortedBalances = (opts) => {
      if (!opts) {
        opts = {};
      }
      let nativeBalances = [];
      let knownBalances = [];
      let unknownBalances = [];
      sdkAccount.balances.forEach(sdkBalance => {
        if (sdkBalance.asset_type === 'native') {
          if (opts.hideNative) {
            return;
          }
          return nativeBalances.push({
            code: 'XLM',
            issuer: null,
            balance: sdkBalance.balance,
            sdkBalance,
          });
        }
        let newBalance = { // Yay shoes :P
          code: sdkBalance.asset_code,
          issuer: sdkBalance.asset_issuer,
          balance: sdkBalance.balance,
        };
        let asset = directory.resolveAssetByAccountId(newBalance.code, newBalance.issuer);
        if (asset.domain === 'unknown') {
          return unknownBalances.push(newBalance);
        }
        return knownBalances.push(newBalance);
      });

      return nativeBalances.concat(knownBalances, unknownBalances);
    };

    let accountEventsClose = Server.accounts().accountId(keypair.publicKey()).stream({
      onmessage: res => {
        let updated = false;
        if (!_.isEqual(sdkAccount.balances, res.balances)) {
          sdkAccount.balances = res.balances;
          updated = true;
        }
        if (!_.isEqual(sdkAccount.sequence, res.sequence)) {
          sdkAccount.sequence = res.sequence;
          updated = true;
        }

        if (updated) {
          onUpdate();
        }
      }
    });

    sdkAccount.refresh = async () => {
      let newAccount = await Server.loadAccount(keypair.publicKey());
      sdkAccount.applyNewBalances(newAccount.balances);
    };

    sdkAccount.applyNewBalances = (newBalances) => {
      let updated = false;
      if (!_.isEqual(sdkAccount.balances, newBalances)) {
        sdkAccount.balances = newBalances;
        updated = true;
      }

      if (updated) {
        onUpdate();
      }
    };

    sdkAccount.explainReserve = () => {
      let items = [];
      let sumentries = 0;

      let entriesTrustlines = sdkAccount.balances.length - 1;
      let entriesOffers = Object.keys(sdkAccount.offers).length;
      let entriesOthers = sdkAccount.subentry_count - entriesTrustlines - entriesOffers;

      items.push({
        entryType: 'Base reserve',
        amount: 2,
        XLM: 20,
      });

      items.push({
        entryType: 'Trustlines',
        amount: entriesTrustlines,
        XLM: entriesTrustlines * 10,
      });

      items.push({
        entryType: 'Offers',
        amount: entriesOffers,
        XLM: entriesOffers * 10,
      });
      items.push({
        entryType: 'Others',
        amount: entriesOthers,
        XLM: entriesOthers * 10,
      });
      items.push({
        entryType: 'Extra',
        amount: '',
        XLM: 1,
      });

      let totalLumens = _.sumBy(items, 'XLM');
      return {
        items,
        totalLumens,
      }
    };

    // Will always be less than or equal to the current balance
    sdkAccount.calculatePaddedReserve = () => {
      let networkReserve = (2 + sdkAccount.subentry_count) * 10;
      let extra = 1;
      return networkReserve + extra;
    }

    sdkAccount.maxLumenSpend = () => {
      let balance = sdkAccount.getLumenBalance();
      let reserve = sdkAccount.calculatePaddedReserve();
      if (reserve > balance) {
        return 0;
      }
      return new BigNumber(balance).minus(reserve).toFixed(7);
    };

    sdkAccount.offers = {};

    // Horizon offers for account doesn't return us updates. So we will have to manually update it.
    // We won't miss any offers assuming that the user only updates their offers through the client
    // with just one window open at a time
    sdkAccount.updateOffers = () => {
      return Server.offers('accounts', keypair.publicKey())
        .limit(100) // TODO: Keep iterating through next() to show more than 100 offers
        .call()
        .then(res => {
          let newOffers = {};
          _.each(res.records, offer => {
            newOffers[offer.id] = offer;
          });
          sdkAccount.offers = newOffers;
          onUpdate();
          return null;
        });
    }
    sdkAccount.updateOffers();

    sdkAccount.close = () => {
      accountEventsClose();
    };

    return sdkAccount;
  },
  Orderbook(Server, baseBuying, counterSelling, onUpdate) {
    // Orderbook is an object that keeps track of the orderbook for you.
    // All the driver needs to do is remember to call the close function

    this.ready = false;
    const initialOrderbook = Server.orderbook(baseBuying, counterSelling).call()
      .then((res) => {
        this.asks = res.asks;
        this.bids = res.bids;
        this.baseBuying = baseBuying;
        this.counterSelling = counterSelling;
        this.ready = true;
        onUpdate();

      });
    let streamingOrderbookClose = Server.orderbook(baseBuying, counterSelling)
      .stream({
        onmessage: res => {
          let updated = false;
          if (!_.isEqual(this.bids, res.bids)) {
            this.bids = res.bids;
            updated = true;
          }
          if (!_.isEqual(this.asks, res.asks)) {
            this.asks = res.asks;
            updated = true;
          }
          if (updated) {
            onUpdate();
          }
        }
      })

    let fetchManyTrades = async () => {
      let records = [];
      let satisfied = false;
      let first = true;
      let depth = 0;
      const MAX_DEPTH = 5;
      let prevCall;
      let startTime = Date.now();

      while (!satisfied && depth < MAX_DEPTH && Date.now() - startTime < 5000) {
        depth += 1;
        let tradeResults;
        if (first) {
          tradeResults = await Server.trades().forAssetPair(baseBuying, counterSelling).limit(200).order('desc').call()
          first = false;
        } else {
          tradeResults = await prevCall();
        }
        prevCall = tradeResults.next;

        if (tradeResults.records.length < 200) {
          satisfied = true;
        }
        Array.prototype.push.apply(records, tradeResults.records);
      }
      // Optimization: use this filter before saving it into the records array
      this.trades = _.filter(
        _.map(records, (trade) => {
          return [new Date(trade.ledger_close_time).getTime(), new BigNumber(trade.counter_amount).dividedBy(trade.base_amount).toNumber()];
        }),
        (entry) => {
          // Remote NaN elements that cause gaps in the chart.
          // NaN values happens when the trade bought and sold 0.0000000 of each asset
          return !isNaN(entry[1]);
        }
      );

      // Potential optimization: If we load the horizon results into the array in the correct order
      // then sorting will run at near optimal runtime

      // First sort it in reverse so that we can filter
      this.trades.sort((a,b) => {
        return b[0]-a[0];
      });

      // Iterate on trades from new to old
      // Remove trades that are greater than OUTLIER_THRESHOLD times the previous value
      const OUTLIER_THRESHOLD = 2;
      let lastAmount = this.trades[0];
      this.trades = _.filter(this.trades, (entry) => {
        let currentAmount = entry[1];
        let ratio = (currentAmount > lastAmount) ? currentAmount/lastAmount :  lastAmount/currentAmount;
        if (ratio > OUTLIER_THRESHOLD) {
          return false;
        }
        lastAmount = currentAmount;
        return true;
      });

      _.reverse(this.trades);

      onUpdate();
    }

    fetchManyTrades();

    this.close = streamingOrderbookClose;
    // TODO: Close
  },

  // opts.baseBuying -- StellarSdk.Asset (example: XLM)
  // opts.counterSelling -- StellarSdk.Asset (example: USD)
  // opts.price -- Exchange ratio selling/buying
  // opts.amount -- Here, it's relative to the base (JS-sdk does: Total amount selling)
  // opts.type -- String of either 'buy' or 'sell' (relative to base currency)
  createOffer(Server, spoonAccount, side, opts) {
    let sdkBuying;
    let sdkSelling;
    let sdkPrice;
    let sdkAmount;

    const bigOptsPrice = new BigNumber(opts.price).toPrecision(15);
    const bigOptsAmount = new BigNumber(opts.amount).toPrecision(15);

    console.log(`Creating *${side}* offer at price ${opts.price}`);
    if (side === 'buy') {
      sdkBuying = opts.baseBuying; // ex: lumens
      sdkSelling = opts.counterSelling; // ex: USD
      sdkPrice = new BigNumber(1).dividedBy(bigOptsPrice);
      sdkAmount = new BigNumber(bigOptsAmount).times(bigOptsPrice).toFixed(7);
    } else if (side === 'sell') {
      sdkBuying = opts.counterSelling; // ex: USD
      sdkSelling = opts.baseBuying; // ex: lumens
      sdkPrice = new BigNumber(bigOptsPrice);
      sdkAmount = new BigNumber(bigOptsAmount).toFixed(7);
    } else {
      throw new Error(`Invalid side ${side}`);
    }

    const operationOpts = {
      buying: sdkBuying,
      selling: sdkSelling,
      amount: String(sdkAmount),
      price: String(sdkPrice),
      offerId: 0, // 0 for new offer
    };
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.manageOffer(operationOpts))
      .build();
    spoonAccount.sign(transaction);
    return Server.submitTransaction(transaction)
      .then(res => {
        console.log('Offer create success');
        console.log(res)
        spoonAccount.updateOffers(); // Just to be doubly sure
        return;
      })
  },
  async sendPayment(Server, spoonAccount,  opts) {
    // sendPayment will detect if the account is a new account. If so, then it will
    // be a createAccount operation
    let transaction = new StellarSdk.TransactionBuilder(spoonAccount)
    try {
      let destAccount = await Server.loadAccount(opts.destination);
      transaction = transaction.addOperation(StellarSdk.Operation.payment({
        destination: opts.destination,
        asset: opts.asset,
        amount: opts.amount,
      }));
    } catch(e) {
      if (!opts.asset.isNative()) {
        throw new Error('Destination account does not exist. To create it, you must send a minimum of 20 lumens to create it');
      }
      transaction = transaction.addOperation(StellarSdk.Operation.createAccount({
        destination: opts.destination,
        startingBalance: opts.amount,
      }));
    }

    if (opts.memo) {
      transaction = transaction.addMemo(Stellarify.memo(opts.memo.type, opts.memo.content));
    }

    transaction = transaction.build();
    spoonAccount.sign(transaction);

    const transactionResult = await Server.submitTransaction(transaction);
    return transactionResult;
  },
  changeTrust(Server, spoonAccount, opts) {
    let sdkLimit;
    if (typeof opts.limit === 'string' || opts.limit instanceof String) {
      sdkLimit = opts.limit;
    } else if (opts.limit !== undefined) {
      throw new Error('changeTrust opts.limit must be a string');
    }

    const operationOpts = {
      asset: opts.asset,
      limit: sdkLimit,
    };
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.changeTrust(operationOpts))
      .build();
    spoonAccount.sign(transaction);
    return Server.submitTransaction(transaction)
      .then(txResult => {
        spoonAccount.refresh();
        return txResult;
      });
  },
  async removeOffer(Server, spoonAccount, offerId) {
    const transaction = new StellarSdk.TransactionBuilder(spoonAccount)
      .addOperation(StellarSdk.Operation.manageOffer({
        buying: StellarSdk.Asset.native(),
        selling: new StellarSdk.Asset('REMOVE', spoonAccount.accountId()),
        amount: '0',
        price: '1',
        offerId,
      }))
      .build();
    spoonAccount.sign(transaction);
    const transactionResult = await Server.submitTransaction(transaction);
    spoonAccount.updateOffers();
    return transactionResult;
  },
};

export default MagicSpoon;
<|endoftext|>


<commit_before>/*

	javascript for Jamoma
	determining what OS is used
	by Trond Lossius
	modified by Nils Peters, Jul. 2011
	License: BSD

*/

inlets = 1;
outlets = 1;

// the following two variables are updated via the build script
MODULAR_VERSION = "0.5.4";
MODULAR_REV = "04e3c";

function bang()
{
	outlet(0, "os", this.max.os);
	outlet(0, "os_version", this.max.osversion);
	outlet(0, "max_version", this.max.version);
	outlet(0, "jamoma_version", MODULAR_VERSION);
	outlet(0, "jamoma_revision", MODULAR_REV);
	outlet(0, "plugin", this.max.isplugin);
	outlet(0, "runtime", this.max.isruntime);
}<commit_msg>Naaarghhhh…., at least the Javascript is 0.5.6 now...<commit_after>/*

	javascript for Jamoma
	determining what OS is used
	by Trond Lossius
	modified by Nils Peters, Jul. 2011
	License: BSD

*/

inlets = 1;
outlets = 1;

// the following two variables are updated via the build script
MODULAR_VERSION = "0.5.6 b1";
MODULAR_REV = "f6573";

function bang()
{
	outlet(0, "os", this.max.os);
	outlet(0, "os_version", this.max.osversion);
	outlet(0, "max_version", this.max.version);
	outlet(0, "jamoma_version", MODULAR_VERSION);
	outlet(0, "jamoma_revision", MODULAR_REV);
	outlet(0, "plugin", this.max.isplugin);
	outlet(0, "runtime", this.max.isruntime);
}<|endoftext|>


<commit_before>// @flow

import _ from 'lodash';

// Declare the private dataset.
const privData = new WeakMap();
function priv(ctx) { return privData.get(ctx); }

export default class Definition {
    name: string;
    options: Object;
    enums: Enum[];
    contracts: Contract[];
    models: Model[];
    services: Service[];
    extensions: Object;

    enumNames: string[];
    modelNames: string[];

    constructor(name: string, props: Object, options: Object = {}) {
        privData.set(this, {
            name: name
        });

        this.enumNames = _.map(props.enums || [], e => e.name);
        this.modelNames = _.map(props.models || [], e => e.name);

        this.options = props.options ? _.cloneDeep(props.options) : {};
        this.enums = _.map(props.enums || [], props => new Enum(this, props));
        this.contracts = _.map(props.contracts || [], props => new Contract(this, props));
        this.models = _.map(props.models || [], props => new Model(this, props));
        this.services = _.map(props.services || [], props => new Service(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};

        _.assign(this.options, options);
    }

    get name(): string { return priv(this).name; }

    resolveContext(context: any): Object {
        return {
            name: this.name,
            options: this.options,
            enums: this.enums.map(e => e.resolveContext()),
            contracts: this.contracts.map(e => e.resolveContext()),
            models: this.models.map(e => e.resolveContext()),
            services: this.services.map(e => e.resolveContext()),

            extensions: _.assign({}, this.extensions),

            context: context
        };
    }
}

class Enum {
    manifest: Definition;
    name: string;
    values: string[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.values = props.values ? _.clone(props.values) : [];
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            values: _.clone(this.values),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Contract {
    manifest: Definition;
    name: string;
    properties: ContractProperty[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.properties = _.map(props.properties || [], props => new ContractProperty(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            properties: this.properties.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Model {
    manifest: Definition;
    name: string;
    abstract: boolean;
    baseModel: string;
    properties: ModelProperty[];
    contracts: string[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.abstract = props.abstract;
        this.baseModel = props.baseModel;
        this.properties = _.map(props.properties || [], props => new ModelProperty(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
        this.contracts = props.contracts ? _.clone(props.contracts) : [];

        let manifestContracts = this.getContracts();
        for (let contract of manifestContracts) {
            for (let prop of contract.properties) {
                let existingProp = _.find(this.properties, existingProp => existingProp.name === prop.name);
                if (!existingProp) {
                    this.properties.push(prop.createModelProperty(this));
                }
                else {
                    if (existingProp.type !== prop.type) {
                        throw new Error(`Conflicting data types for contract property "${prop.name}"`);
                    }
                }
            }
        }
    }

    getContracts(): Contract[] {
        return _.map(this.contracts || [], (contractName) => {
            let contract = _.find(this.manifest.contracts, contract => contract.name === contractName);
            if (!contract) { throw new Error(`Contract "${contractName}" not defined`); }

            return contract;
        });
    }
    getBaseModel(): Model {
        let model = _.find(this.manifest.models, model => model.name === this.baseModel);
        if (!model) { throw new Error(`Base model "${this.baseModel}" not defined`); }

        return model;
    }

    resolveContext(): Object {
        return {
            name: this.name,
            abstract: this.abstract,
            baseModel: this.baseModel ? this.getBaseModel().resolveContext() : undefined,
            contracts: this.getContracts().map(e => e.resolveContext()),
            properties: this.properties.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Service {
    manifest: Definition;
    name: string;
    methods: ServiceMethod[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.methods = _.map(props.methods || [], props => new ServiceMethod(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            methods: this.methods.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}

class ContractProperty {
    contract: Contract;
    name: string;
    type: DataType;
    extensions: Object;

    source: Object;

    constructor(contract: Contract, props: Object) {
        this.contract = contract;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.contract.manifest);
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};

        this.source = props;
    }

    createModelProperty(model: Model): ModelProperty {
        return new ModelProperty(model, this.source);
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext(),

            extensions: _.assign({}, this.contract.manifest.extensions, this.contract.extensions, this.extensions)
        };
    }
}
class ModelProperty {
    model: Model;
    name: string;
    type: DataType;
    extensions: Object;

    constructor(model: Model, props: Object) {
        this.model = model;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.model.manifest);
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext(),

            extensions: _.assign({}, this.model.manifest.extensions, this.model.extensions, this.extensions)
        };
    }
}

class ServiceMethod {
    service: Service;
    name: string;
    returnType: DataType;
    params: MethodParam[];
    extensions: Object;

    constructor(service: Service, props: Object) {
        this.service = service;

        this.name = props.name;
        if (props.returnType) { this.returnType = DataType.parseDataType(props.returnType, this.service.manifest); }
        this.params = _.map(props.params || [], props => new MethodParam(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            returnType: this.returnType ? this.returnType.resolveContext() : undefined,
            params: this.params.map(e => e.resolveContext()),

            extensions: _.assign({}, this.service.manifest.extensions, this.service.extensions, this.extensions)
        };
    }
}
class MethodParam {
    serviceMethod: ServiceMethod;
    name: string;
    type: DataType;

    constructor(serviceMethod: ServiceMethod, props: Object) {
        this.serviceMethod = serviceMethod;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.serviceMethod.service.manifest);
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext()
        };
    }
}

class DataType {
    manifest: Definition;
    nullable: boolean;

    static parseDataType(dataType: string, manifest: Definition) {
        let normalizedDataType: string = _.trimEnd(dataType, '?');
        let nullable: boolean = _.endsWith(dataType, '?');

        switch (normalizedDataType) {
            case 'string':
                return new StringDataType(manifest, nullable);
            case 'bool':
            case 'boolean':
                return new BooleanDataType(manifest, nullable);
            case 'int':
            case 'integer':
                return new IntegerDataType(manifest, nullable);
            case 'float':
            case 'single':
                return new FloatDataType(manifest, nullable);
            case 'double':
                return new DoubleDataType(manifest, nullable);
            case 'byte':
                return new ByteDataType(manifest, nullable);
            case 'any':
                return new AnyDataType(manifest, nullable);
            default:
                if (_.some(manifest.enumNames, e => e === normalizedDataType)) {
                    return new EnumDataType(manifest, nullable, normalizedDataType);
                }
                else if (_.some(manifest.modelNames, e => e === normalizedDataType)) {
                    return new ModelDataType(manifest, nullable, normalizedDataType);
                }
                else if (_.startsWith(normalizedDataType, 'list:')) {
                    return new ListDataType(manifest, nullable, normalizedDataType.slice(5));
                }
                else {
                    throw new Error(`Type "${dataType}" not supported`);
                }
        }
    }

    constructor(manifest: Definition, nullable: boolean) {
        this.manifest = manifest;
        this.nullable = nullable;
    }

    resolveContext() {
        throw new Error('Not implemented');
    }
}
class StringDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'string'
        };
    }
}
class BooleanDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'boolean'
        };
    }
}
class IntegerDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'integer'
        };
    }
}
class FloatDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'float'
        };
    }
}
class DoubleDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'double'
        };
    }
}
class ByteDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'byte'
        };
    }
}
class EnumDataType extends DataType {
    enumName: string;

    constructor(manifest: Definition, nullable: boolean, enumName: string) {
        super(manifest, nullable);

        this.enumName = enumName;
    }

    getEnum(): Enum {
        let foundEnum = _.find(this.manifest.enums, e => e.name === this.enumName);
        if (!foundEnum) { throw new Error(`Enum "${this.enumName}" not defined`); }

        return foundEnum;
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'enum',
            enumName: this.getEnum().name
        };
    }
}
class ModelDataType extends DataType {
    modelName: string;

    constructor(manifest: Definition, nullable: boolean, modelName: string) {
        super(manifest, nullable);

        this.modelName = modelName;
    }

    getModel(): Model {
        let foundModel = _.find(this.manifest.models, e => e.name === this.modelName);
        if (!foundModel) { throw new Error(`Model "${this.modelName}" not defined`); }

        return foundModel;
    }

    resolveContext(): Object {
        let model = this.getModel();

        return {
            nullable: this.nullable,
            dataType: 'model',
            modelName: model.name,
            abstract: model.abstract
        };
    }
}
class ListDataType extends DataType {
    itemType: DataType;

    constructor(manifest: Definition, nullable: boolean, itemType: string) {
        super(manifest, nullable);

        this.itemType = DataType.parseDataType(itemType, manifest);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'list',
            itemType: this.itemType.resolveContext()
        };
    }
}
class AnyDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'any'
        };
    }
}<commit_msg>Added support for model methods<commit_after>// @flow

import _ from 'lodash';

// Declare the private dataset.
const privData = new WeakMap();
function priv(ctx) { return privData.get(ctx); }

export default class Definition {
    name: string;
    options: Object;
    enums: Enum[];
    contracts: Contract[];
    models: Model[];
    services: Service[];
    extensions: Object;

    enumNames: string[];
    modelNames: string[];

    constructor(name: string, props: Object, options: Object = {}) {
        privData.set(this, {
            name: name
        });

        this.enumNames = _.map(props.enums || [], e => e.name);
        this.modelNames = _.map(props.models || [], e => e.name);

        this.options = props.options ? _.cloneDeep(props.options) : {};
        this.enums = _.map(props.enums || [], props => new Enum(this, props));
        this.contracts = _.map(props.contracts || [], props => new Contract(this, props));
        this.models = _.map(props.models || [], props => new Model(this, props));
        this.services = _.map(props.services || [], props => new Service(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};

        _.assign(this.options, options);
    }

    get name(): string { return priv(this).name; }

    resolveContext(context: any): Object {
        return {
            name: this.name,
            options: this.options,
            enums: this.enums.map(e => e.resolveContext()),
            contracts: this.contracts.map(e => e.resolveContext()),
            models: this.models.map(e => e.resolveContext()),
            services: this.services.map(e => e.resolveContext()),

            extensions: _.assign({}, this.extensions),

            context: context
        };
    }
}

class Enum {
    manifest: Definition;
    name: string;
    values: string[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.values = props.values ? _.clone(props.values) : [];
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            values: _.clone(this.values),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Contract {
    manifest: Definition;
    name: string;
    properties: ContractProperty[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.properties = _.map(props.properties || [], props => new ContractProperty(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            properties: this.properties.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Model {
    manifest: Definition;
    name: string;
    abstract: boolean;
    baseModel: string;
    properties: ModelProperty[];
    methods: ModelMethod[];
    contracts: string[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.abstract = props.abstract;
        this.baseModel = props.baseModel;
        this.properties = _.map(props.properties || [], props => new ModelProperty(this, props));
        this.methods = _.map(props.methods || [], props => new ModelMethod(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
        this.contracts = props.contracts ? _.clone(props.contracts) : [];

        let manifestContracts = this.getContracts();
        for (let contract of manifestContracts) {
            for (let prop of contract.properties) {
                let existingProp = _.find(this.properties, existingProp => existingProp.name === prop.name);
                if (!existingProp) {
                    this.properties.push(prop.createModelProperty(this));
                }
                else {
                    if (existingProp.type !== prop.type) {
                        throw new Error(`Conflicting data types for contract property "${prop.name}"`);
                    }
                }
            }
        }
    }

    getContracts(): Contract[] {
        return _.map(this.contracts || [], (contractName) => {
            let contract = _.find(this.manifest.contracts, contract => contract.name === contractName);
            if (!contract) { throw new Error(`Contract "${contractName}" not defined`); }

            return contract;
        });
    }
    getBaseModel(): Model {
        let model = _.find(this.manifest.models, model => model.name === this.baseModel);
        if (!model) { throw new Error(`Base model "${this.baseModel}" not defined`); }

        return model;
    }

    resolveContext(): Object {
        return {
            name: this.name,
            abstract: this.abstract,
            baseModel: this.baseModel ? this.getBaseModel().resolveContext() : undefined,
            contracts: this.getContracts().map(e => e.resolveContext()),
            properties: this.properties.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}
class Service {
    manifest: Definition;
    name: string;
    methods: ServiceMethod[];
    extensions: Object;

    constructor(manifest: Definition, props: Object) {
        this.manifest = manifest;

        this.name = props.name;
        this.methods = _.map(props.methods || [], props => new ServiceMethod(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            methods: this.methods.map(e => e.resolveContext()),

            extensions: _.assign({}, this.manifest.extensions, this.extensions)
        };
    }
}

class ContractProperty {
    contract: Contract;
    name: string;
    type: DataType;
    extensions: Object;

    source: Object;

    constructor(contract: Contract, props: Object) {
        this.contract = contract;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.contract.manifest);
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};

        this.source = props;
    }

    createModelProperty(model: Model): ModelProperty {
        return new ModelProperty(model, this.source);
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext(),

            extensions: _.assign({}, this.contract.manifest.extensions, this.contract.extensions, this.extensions)
        };
    }
}
class ModelProperty {
    model: Model;
    name: string;
    type: DataType;
    extensions: Object;

    constructor(model: Model, props: Object) {
        this.model = model;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.model.manifest);
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext(),

            extensions: _.assign({}, this.model.manifest.extensions, this.model.extensions, this.extensions)
        };
    }
}

class ModelMethod {
    model: Model;
    name: string;
    returnType: DataType;
    params: ModelMethodParam[];
    extensions: Object;

    constructor(model: Model, props: Object) {
        this.model = model;

        this.name = props.name;
        if (props.returnType) { this.returnType = DataType.parseDataType(props.returnType, this.model.manifest); }
        this.params = _.map(props.params || [], props => new ModelMethodParam(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            returnType: this.returnType ? this.returnType.resolveContext() : undefined,
            params: this.params.map(e => e.resolveContext()),

            extensions: _.assign({}, this.model.manifest.extensions, this.model.extensions, this.extensions)
        };
    }
}
class ModelMethodParam {
    modelMethod: ModelMethod;
    name: string;
    type: DataType;

    constructor(modelMethod: ModelMethod, props: Object) {
        this.modelMethod = modelMethod;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.modelMethod.model.manifest);
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext()
        };
    }
}

class ServiceMethod {
    service: Service;
    name: string;
    returnType: DataType;
    params: ServiceMethodParam[];
    extensions: Object;

    constructor(service: Service, props: Object) {
        this.service = service;

        this.name = props.name;
        if (props.returnType) { this.returnType = DataType.parseDataType(props.returnType, this.service.manifest); }
        this.params = _.map(props.params || [], props => new ServiceMethodParam(this, props));
        this.extensions = props.extensions ? _.cloneDeep(props.extensions) : {};
    }

    resolveContext(): Object {
        return {
            name: this.name,
            returnType: this.returnType ? this.returnType.resolveContext() : undefined,
            params: this.params.map(e => e.resolveContext()),

            extensions: _.assign({}, this.service.manifest.extensions, this.service.extensions, this.extensions)
        };
    }
}
class ServiceMethodParam {
    serviceMethod: ServiceMethod;
    name: string;
    type: DataType;

    constructor(serviceMethod: ServiceMethod, props: Object) {
        this.serviceMethod = serviceMethod;

        this.name = props.name;
        this.type = DataType.parseDataType(props.type, this.serviceMethod.service.manifest);
    }

    resolveContext(): Object {
        return {
            name: this.name,
            type: this.type.resolveContext()
        };
    }
}

class DataType {
    manifest: Definition;
    nullable: boolean;

    static parseDataType(dataType: string, manifest: Definition) {
        let normalizedDataType: string = _.trimEnd(dataType, '?');
        let nullable: boolean = _.endsWith(dataType, '?');

        switch (normalizedDataType) {
            case 'string':
                return new StringDataType(manifest, nullable);
            case 'bool':
            case 'boolean':
                return new BooleanDataType(manifest, nullable);
            case 'int':
            case 'integer':
                return new IntegerDataType(manifest, nullable);
            case 'float':
            case 'single':
                return new FloatDataType(manifest, nullable);
            case 'double':
                return new DoubleDataType(manifest, nullable);
            case 'byte':
                return new ByteDataType(manifest, nullable);
            case 'any':
                return new AnyDataType(manifest, nullable);
            default:
                if (_.some(manifest.enumNames, e => e === normalizedDataType)) {
                    return new EnumDataType(manifest, nullable, normalizedDataType);
                }
                else if (_.some(manifest.modelNames, e => e === normalizedDataType)) {
                    return new ModelDataType(manifest, nullable, normalizedDataType);
                }
                else if (_.startsWith(normalizedDataType, 'list:')) {
                    return new ListDataType(manifest, nullable, normalizedDataType.slice(5));
                }
                else {
                    throw new Error(`Type "${dataType}" not supported`);
                }
        }
    }

    constructor(manifest: Definition, nullable: boolean) {
        this.manifest = manifest;
        this.nullable = nullable;
    }

    resolveContext() {
        throw new Error('Not implemented');
    }
}
class StringDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'string'
        };
    }
}
class BooleanDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'boolean'
        };
    }
}
class IntegerDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'integer'
        };
    }
}
class FloatDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'float'
        };
    }
}
class DoubleDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'double'
        };
    }
}
class ByteDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'byte'
        };
    }
}
class EnumDataType extends DataType {
    enumName: string;

    constructor(manifest: Definition, nullable: boolean, enumName: string) {
        super(manifest, nullable);

        this.enumName = enumName;
    }

    getEnum(): Enum {
        let foundEnum = _.find(this.manifest.enums, e => e.name === this.enumName);
        if (!foundEnum) { throw new Error(`Enum "${this.enumName}" not defined`); }

        return foundEnum;
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'enum',
            enumName: this.getEnum().name
        };
    }
}
class ModelDataType extends DataType {
    modelName: string;

    constructor(manifest: Definition, nullable: boolean, modelName: string) {
        super(manifest, nullable);

        this.modelName = modelName;
    }

    getModel(): Model {
        let foundModel = _.find(this.manifest.models, e => e.name === this.modelName);
        if (!foundModel) { throw new Error(`Model "${this.modelName}" not defined`); }

        return foundModel;
    }

    resolveContext(): Object {
        let model = this.getModel();

        return {
            nullable: this.nullable,
            dataType: 'model',
            modelName: model.name,
            abstract: model.abstract
        };
    }
}
class ListDataType extends DataType {
    itemType: DataType;

    constructor(manifest: Definition, nullable: boolean, itemType: string) {
        super(manifest, nullable);

        this.itemType = DataType.parseDataType(itemType, manifest);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'list',
            itemType: this.itemType.resolveContext()
        };
    }
}
class AnyDataType extends DataType {
    constructor(manifest: Definition, nullable: boolean) {
        super(manifest, nullable);
    }

    resolveContext(): Object {
        return {
            nullable: this.nullable,
            dataType: 'any'
        };
    }
}<|endoftext|>


<commit_before>/**
 * @fileoverview Helpers for measuring elements.
 */

goog.provide('treesaver.dimensions');

goog.require('treesaver.capabilities');
goog.require('treesaver.css');
goog.require('treesaver.debug');

goog.scope(function() {
  var dimensions = treesaver.dimensions,
      capabilities = treesaver.capabilities,
      css = treesaver.css,
      debug = treesaver.debug;

  /**
   * Alias for Size type
   *
   * @typedef {{ w: number, h: number }}
   */
  dimensions.Size;

  /**
   * Alias for SizeRange type
   *
   * @typedef {{ w: number, h: number, maxW: number, maxH: number }}
   */
  dimensions.SizeRange;

  /**
   * Regex to determine whether a value is a pixel value.
   * @private
   */
  dimensions.pixel = /^-?\d+(?:px)?$/i;

  /**
   * Regex to determine whether a value contains a number.
   * @private
   */
  dimensions.number = /^-?\d/;

  /**
   * Whether the given size fits within the bounds set by the range
   *
   * @param {treesaver.dimensions.SizeRange|treesaver.dimensions.Metrics} range
   * @param {treesaver.dimensions.Size} size
   * @return {boolean} True if both dimensions are within the min and max.
   */
  dimensions.inSizeRange = function(range, size) {
    if (!range) {
      return false;
    }

    // Use minW/minH for Metrics, w/h for a range
    // TODO: Make this consistent
    var w = (range.minW || range.minW === 0) ? range.minW : range.w,
        h = (range.minH || range.minH === 0) ? range.minH : range.h;

    return size.w >= w && size.h >= h &&
      size.w <= range.maxW && size.h <= range.maxH;
  };

  /**
   *
   * @param {treesaver.dimensions.SizeRange} range
   * @param {treesaver.dimensions.Metrics} metrics
   * @param {boolean} outer
   * @return {treesaver.dimensions.SizeRange}
   */
  dimensions.mergeSizeRange = function(range, metrics, outer) {
    var a = range || {},
        b = metrics || {};

    var bpHeight = outer ? b.bpHeight || (b.outerH ? b.outerH - b.h : 0) : 0,
        bpWidth = outer ? b.bpWidth || (b.outerW ? b.outerW - b.w : 0) : 0;

    return {
      w: Math.max(a.w || 0, (b.w + bpWidth) || 0),
      h: Math.max(a.h || 0, (b.h + bpHeight) || 0),
      maxW: Math.min(a.maxW || Infinity, b.maxW + bpWidth || Infinity),
      maxH: Math.min(a.maxH || Infinity, b.maxH + bpHeight || Infinity)
    };
  };

  /**
   * Convert a string value to pixels
   *
   * @param {!Element} el
   * @param {?string} val
   * @return {?number} Value in pixels.
   */
  dimensions.toPixels = function(el, val) {
    if (val && dimensions.pixel.test(val)) {
      return parseFloat(val) || 0;
    }
    return null;
  };

  /**
   * Return the width and height element in a simple object
   *
   * @param {Element} el
   * @return {!dimensions.Size}
   */
  dimensions.getSize = function(el) {
    return {
      w: dimensions.getOffsetWidth(el),
      h: dimensions.getOffsetHeight(el)
    };
  };

  /**
   * Return the offsetHeight of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetHeight = function(el) {
    return el && el.offsetHeight || 0;
  };

  /**
   * Return the offsetWidth of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetWidth = function(el) {
    return el && el.offsetWidth || 0;
  };

  /**
   * Return the offsetTop of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetTop = function(el) {
    return el && el.offsetTop || 0;
  }

  /**
   * Helper for setting a CSS value in pixels
   *
   * @param {!Element} el
   * @param {!string} propName
   * @param {!number} val
   * @return {!number} The value supplied.
   */
  dimensions.setCssPx = function(el, propName, val) {
    el.style[propName] = val + 'px';

    return val;
  };

  /**
    * Helper for setting the transform property on an element
    *
    * @param {!Element} el
    * @param {!string} val
    */
  dimensions.setTransformProperty_ = function(el, val) {
    // TODO: Detect once
    if ('transformProperty' in el.style) {
      el.style['transformProperty'] = val;
    }
    else {
      el.style[capabilities.domCSSPrefix + 'Transform'] = val;
    }
  };

  /**
   * Clear out any offset
   *
   * @param {!Element} el
   */
  dimensions.clearOffset = function(el) {
    dimensions.setTransformProperty_(el, 'none');
  };

  /**
   * Helper for setting the offset on an element, using CSS transforms if
   * supported, absolute positioning if not
   *
   * @param {!Element} el
   * @param {!number} x
   * @param {!number} y
   */
  dimensions.setOffset = function(el, x, y) {
    dimensions.setTransformProperty_(el,
      'translate(' + x + 'px,' + y + 'px)');
  };

  // Use hw-accelerated 3D transforms if present
  if (capabilities.SUPPORTS_CSSTRANSFORMS3D) {
    dimensions.setOffset = function(el, x, y) {
      dimensions.setTransformProperty_(el,
        'translate3d(' + x + 'px,' + y + 'px,0)');
    };
  }

  /**
   * Helper for setting the x-offset on an element
   *
   * @param {!Element} el
   * @param {!number} x
   */
  dimensions.setOffsetX = function(el, x) {
    dimensions.setOffset(el, x, 0);
  };

  /**
   * Round up to the nearest multiple of the base number
   *
   * @param {!number} number
   * @param {!number} base
   * @return {number} A multiple of the base number.
   */
  dimensions.roundUp = function(number, base) {
    return Math.ceil(number) + base - (number % base);
  };

  /**
   * The style dimensions of an element including margin, border, and
   * padding as well as line height
   *
   * @constructor
   * @param {!Element=} el
   */
  dimensions.Metrics = function(el) {
    if (!el) {
      return;
    }

    var style = css.getStyleObject(el),
        oldPosition = el.style.position,
        oldStyleAttribute = el.getAttribute('style'),
        tmp;

    this.display = style.display;
    this.position = style.position;

    // Webkit gives incorrect right margins for non-absolutely
    // positioned elements
    //if (this.position !== 'absolute') {
      //el.style.position = 'absolute';
    //}
    // Disable this for now, as it can give incorrect formatting
    // for elements in the flow
    // Also: Getting computed style is kinda silly if we change the
    // styling -- may affect the measurements anyway

    // Margin
    this.marginTop = dimensions.toPixels(el, style.marginTop) || 0;
    this.marginBottom = dimensions.toPixels(el, style.marginBottom) || 0;
    this.marginLeft = dimensions.toPixels(el, style.marginLeft) || 0;
    this.marginRight = dimensions.toPixels(el, style.marginRight) || 0;
    // Summed totals
    this.marginHeight = this.marginTop + this.marginBottom;
    this.marginWidth = this.marginLeft + this.marginRight;

    // Border
    this.borderTop = dimensions.toPixels(el, style.borderTopWidth);
    this.borderBottom = dimensions.toPixels(el, style.borderBottomWidth);
    this.borderLeft = dimensions.toPixels(el, style.borderLeftWidth);
    this.borderRight = dimensions.toPixels(el, style.borderRightWidth);

    // Padding
    this.paddingTop = dimensions.toPixels(el, style.paddingTop);
    this.paddingBottom = dimensions.toPixels(el, style.paddingBottom);
    this.paddingLeft = dimensions.toPixels(el, style.paddingLeft);
    this.paddingRight = dimensions.toPixels(el, style.paddingRight);

    // Summed totals for border & padding
    this.bpTop = this.borderTop + this.paddingTop;
    this.bpBottom = this.borderBottom + this.paddingBottom;
    this.bpHeight = this.bpTop + this.bpBottom;
    this.bpLeft = this.borderLeft + this.paddingLeft;
    this.bpRight = this.borderRight + this.paddingRight;
    this.bpWidth = this.bpLeft + this.bpRight;

    // Outer Width & Height
    this.outerW = dimensions.getOffsetWidth(el);
    this.outerH = dimensions.getOffsetHeight(el);

    // Inner Width & Height
    this.w = this.outerW - this.bpWidth;
    this.h = this.outerH - this.bpHeight;

    // Min & Max : Width & Height
    this.minW = dimensions.toPixels(el, style.minWidth) || 0;
    this.minH = dimensions.toPixels(el, style.minHeight) || 0;

    // Opera returns -1 for a max-width or max-height that is not set.
    tmp = dimensions.toPixels(el, style.maxWidth);
    this.maxW = (!tmp || tmp === -1) ? Infinity : tmp;

    tmp = dimensions.toPixels(el, style.maxHeight);
    this.maxH = (!tmp || tmp === -1) ? Infinity : tmp;

    // Line height
    this.lineHeight = dimensions.toPixels(el, style.lineHeight) || null;

    // Restore the original position property on style
    //if (this.position !== 'absolute') {
      //el.style.position = oldPosition;
      //if (!el.getAttribute('style')) {
        //el.removeAttribute('style');
      //}
    //}
  };

  /**
   * Make a copy of the object
   *
   * @return {!dimensions.Metrics}
   */
  dimensions.Metrics.prototype.clone = function() {
    var copy = new dimensions.Metrics(),
        key;

    for (key in this) {
      if (copy[key] !== this[key]) {
        copy[key] = this[key];
      }
    }

    return copy;
  };

  // TODO: MergeSizeRange

  if (goog.DEBUG) {
    dimensions.Metrics.prototype.toString = function() {
      return '[Metrics: ' + this.w + 'x' + this.h + ']';
    };
  }
});
<commit_msg>Firefox 9 started reporting fractional lineHeights, so we need to adjust our pixel and number regular expressions.<commit_after>/**
 * @fileoverview Helpers for measuring elements.
 */

goog.provide('treesaver.dimensions');

goog.require('treesaver.capabilities');
goog.require('treesaver.css');
goog.require('treesaver.debug');

goog.scope(function() {
  var dimensions = treesaver.dimensions,
      capabilities = treesaver.capabilities,
      css = treesaver.css,
      debug = treesaver.debug;

  /**
   * Alias for Size type
   *
   * @typedef {{ w: number, h: number }}
   */
  dimensions.Size;

  /**
   * Alias for SizeRange type
   *
   * @typedef {{ w: number, h: number, maxW: number, maxH: number }}
   */
  dimensions.SizeRange;

  /**
   * Regex to determine whether a value is a pixel value.
   * @private
   */
  dimensions.pixel = /^-?\d+(:?\.\d+)?(?:px)?$/i;

  /**
   * Regex to determine whether a value contains a number.
   * @private
   */
  dimensions.number = /^-?\d(:?\.\d+)?/;

  /**
   * Whether the given size fits within the bounds set by the range
   *
   * @param {treesaver.dimensions.SizeRange|treesaver.dimensions.Metrics} range
   * @param {treesaver.dimensions.Size} size
   * @return {boolean} True if both dimensions are within the min and max.
   */
  dimensions.inSizeRange = function(range, size) {
    if (!range) {
      return false;
    }

    // Use minW/minH for Metrics, w/h for a range
    // TODO: Make this consistent
    var w = (range.minW || range.minW === 0) ? range.minW : range.w,
        h = (range.minH || range.minH === 0) ? range.minH : range.h;

    return size.w >= w && size.h >= h &&
      size.w <= range.maxW && size.h <= range.maxH;
  };

  /**
   *
   * @param {treesaver.dimensions.SizeRange} range
   * @param {treesaver.dimensions.Metrics} metrics
   * @param {boolean} outer
   * @return {treesaver.dimensions.SizeRange}
   */
  dimensions.mergeSizeRange = function(range, metrics, outer) {
    var a = range || {},
        b = metrics || {};

    var bpHeight = outer ? b.bpHeight || (b.outerH ? b.outerH - b.h : 0) : 0,
        bpWidth = outer ? b.bpWidth || (b.outerW ? b.outerW - b.w : 0) : 0;

    return {
      w: Math.max(a.w || 0, (b.w + bpWidth) || 0),
      h: Math.max(a.h || 0, (b.h + bpHeight) || 0),
      maxW: Math.min(a.maxW || Infinity, b.maxW + bpWidth || Infinity),
      maxH: Math.min(a.maxH || Infinity, b.maxH + bpHeight || Infinity)
    };
  };

  /**
   * Convert a string value to pixels
   *
   * @param {!Element} el
   * @param {?string} val
   * @return {?number} Value in pixels.
   */
  dimensions.toPixels = function(el, val) {
    if (val && dimensions.pixel.test(val)) {
      return parseFloat(val) || 0;
    }
    return null;
  };

  /**
   * Return the width and height element in a simple object
   *
   * @param {Element} el
   * @return {!dimensions.Size}
   */
  dimensions.getSize = function(el) {
    return {
      w: dimensions.getOffsetWidth(el),
      h: dimensions.getOffsetHeight(el)
    };
  };

  /**
   * Return the offsetHeight of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetHeight = function(el) {
    return el && el.offsetHeight || 0;
  };

  /**
   * Return the offsetWidth of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetWidth = function(el) {
    return el && el.offsetWidth || 0;
  };

  /**
   * Return the offsetTop of the element.
   *
   * @param {?Element} el
   * @return {!number} Value in pixels.
   */
  dimensions.getOffsetTop = function(el) {
    return el && el.offsetTop || 0;
  }

  /**
   * Helper for setting a CSS value in pixels
   *
   * @param {!Element} el
   * @param {!string} propName
   * @param {!number} val
   * @return {!number} The value supplied.
   */
  dimensions.setCssPx = function(el, propName, val) {
    el.style[propName] = val + 'px';

    return val;
  };

  /**
    * Helper for setting the transform property on an element
    *
    * @param {!Element} el
    * @param {!string} val
    */
  dimensions.setTransformProperty_ = function(el, val) {
    // TODO: Detect once
    if ('transformProperty' in el.style) {
      el.style['transformProperty'] = val;
    }
    else {
      el.style[capabilities.domCSSPrefix + 'Transform'] = val;
    }
  };

  /**
   * Clear out any offset
   *
   * @param {!Element} el
   */
  dimensions.clearOffset = function(el) {
    dimensions.setTransformProperty_(el, 'none');
  };

  /**
   * Helper for setting the offset on an element, using CSS transforms if
   * supported, absolute positioning if not
   *
   * @param {!Element} el
   * @param {!number} x
   * @param {!number} y
   */
  dimensions.setOffset = function(el, x, y) {
    dimensions.setTransformProperty_(el,
      'translate(' + x + 'px,' + y + 'px)');
  };

  // Use hw-accelerated 3D transforms if present
  if (capabilities.SUPPORTS_CSSTRANSFORMS3D) {
    dimensions.setOffset = function(el, x, y) {
      dimensions.setTransformProperty_(el,
        'translate3d(' + x + 'px,' + y + 'px,0)');
    };
  }

  /**
   * Helper for setting the x-offset on an element
   *
   * @param {!Element} el
   * @param {!number} x
   */
  dimensions.setOffsetX = function(el, x) {
    dimensions.setOffset(el, x, 0);
  };

  /**
   * Round up to the nearest multiple of the base number
   *
   * @param {!number} number
   * @param {!number} base
   * @return {number} A multiple of the base number.
   */
  dimensions.roundUp = function(number, base) {
    return Math.ceil(number) + base - (number % base);
  };

  /**
   * The style dimensions of an element including margin, border, and
   * padding as well as line height
   *
   * @constructor
   * @param {!Element=} el
   */
  dimensions.Metrics = function(el) {
    if (!el) {
      return;
    }

    var style = css.getStyleObject(el),
        oldPosition = el.style.position,
        oldStyleAttribute = el.getAttribute('style'),
        tmp;

    this.display = style.display;
    this.position = style.position;

    // Webkit gives incorrect right margins for non-absolutely
    // positioned elements
    //if (this.position !== 'absolute') {
      //el.style.position = 'absolute';
    //}
    // Disable this for now, as it can give incorrect formatting
    // for elements in the flow
    // Also: Getting computed style is kinda silly if we change the
    // styling -- may affect the measurements anyway

    // Margin
    this.marginTop = dimensions.toPixels(el, style.marginTop) || 0;
    this.marginBottom = dimensions.toPixels(el, style.marginBottom) || 0;
    this.marginLeft = dimensions.toPixels(el, style.marginLeft) || 0;
    this.marginRight = dimensions.toPixels(el, style.marginRight) || 0;
    // Summed totals
    this.marginHeight = this.marginTop + this.marginBottom;
    this.marginWidth = this.marginLeft + this.marginRight;

    // Border
    this.borderTop = dimensions.toPixels(el, style.borderTopWidth);
    this.borderBottom = dimensions.toPixels(el, style.borderBottomWidth);
    this.borderLeft = dimensions.toPixels(el, style.borderLeftWidth);
    this.borderRight = dimensions.toPixels(el, style.borderRightWidth);

    // Padding
    this.paddingTop = dimensions.toPixels(el, style.paddingTop);
    this.paddingBottom = dimensions.toPixels(el, style.paddingBottom);
    this.paddingLeft = dimensions.toPixels(el, style.paddingLeft);
    this.paddingRight = dimensions.toPixels(el, style.paddingRight);

    // Summed totals for border & padding
    this.bpTop = this.borderTop + this.paddingTop;
    this.bpBottom = this.borderBottom + this.paddingBottom;
    this.bpHeight = this.bpTop + this.bpBottom;
    this.bpLeft = this.borderLeft + this.paddingLeft;
    this.bpRight = this.borderRight + this.paddingRight;
    this.bpWidth = this.bpLeft + this.bpRight;

    // Outer Width & Height
    this.outerW = dimensions.getOffsetWidth(el);
    this.outerH = dimensions.getOffsetHeight(el);

    // Inner Width & Height
    this.w = this.outerW - this.bpWidth;
    this.h = this.outerH - this.bpHeight;

    // Min & Max : Width & Height
    this.minW = dimensions.toPixels(el, style.minWidth) || 0;
    this.minH = dimensions.toPixels(el, style.minHeight) || 0;

    // Opera returns -1 for a max-width or max-height that is not set.
    tmp = dimensions.toPixels(el, style.maxWidth);
    this.maxW = (!tmp || tmp === -1) ? Infinity : tmp;

    tmp = dimensions.toPixels(el, style.maxHeight);
    this.maxH = (!tmp || tmp === -1) ? Infinity : tmp;

    // Line height
    this.lineHeight = dimensions.toPixels(el, style.lineHeight) || null;

    // Restore the original position property on style
    //if (this.position !== 'absolute') {
      //el.style.position = oldPosition;
      //if (!el.getAttribute('style')) {
        //el.removeAttribute('style');
      //}
    //}
  };

  /**
   * Make a copy of the object
   *
   * @return {!dimensions.Metrics}
   */
  dimensions.Metrics.prototype.clone = function() {
    var copy = new dimensions.Metrics(),
        key;

    for (key in this) {
      if (copy[key] !== this[key]) {
        copy[key] = this[key];
      }
    }

    return copy;
  };

  // TODO: MergeSizeRange

  if (goog.DEBUG) {
    dimensions.Metrics.prototype.toString = function() {
      return '[Metrics: ' + this.w + 'x' + this.h + ']';
    };
  }
});
<|endoftext|>


<commit_before>import React from 'react';
import {StyleSheet, View, ScrollView, Image, Text, TouchableOpacity, Animated, Dimensions, Platform} from 'react-native';
import {SharedElement} from 'navigation-react-native';
import ZoomShared from './ZoomShared';

export default class Detail extends React.Component {
  constructor(props, context) {
    super(props, context);
    const {url} = props.stateNavigator.stateContext;
    this.url = url;
    this.state = {
      contentAnimation: new Animated.Value(0),
      navbarAnimation: new Animated.Value(0),
    };
  }
  shouldComponentUpdate(props) {
    return this.url === props.stateNavigator.stateContext.url;
  }
  componentDidMount() {
    Animated.timing(this.state.contentAnimation, {
      toValue: 1,
      duration: 500,
      useNativeDriver: true,
    }).start();
  }
  _goBack = () => {
    const {stateNavigator} = this.props;
    if (this.url === stateNavigator.stateContext.url) {
      stateNavigator.navigateBack(1);
      Animated.timing(this.state.contentAnimation, {
        toValue: 0,
        duration: 500,
        useNativeDriver: true,
      }).start();
    }
  };
  render() {
    const {place, rowId, stateNavigator} = this.props;
    const contentTranslateY = this.state.contentAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: [200, 0],
    });
      return (
      <View style={{ flex: 1 }}>
        <ZoomShared stateNavigator={stateNavigator} />
        <ScrollView style={{ flex: 1 }}>
          <View style={styles.imageContainer}>
            <SharedElement
              name={`image${rowId}`}
              data={{image: place.image}}
              stateNavigator={stateNavigator}>
              <Image
                source={place.image}
                style={{ flex: 1 }}
              />
            </SharedElement>
            <SharedElement
              name={`label${rowId}`}
              data={{text: place.price}}
              stateNavigator={stateNavigator}>
              <View style={styles.priceLabel}>
                <Text style={styles.priceLabelText}>
                  ${place.price}
                </Text>
              </View>
            </SharedElement>
            <View
              style={styles.navbar}>
              <TouchableOpacity
                onPress={this._goBack}
                hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }}>
                <Image
                  style={styles.backButton}
                  source={{
                    uri: 'https://www.android.com/static/img/map/back-arrow.png',
                  }}
                />
              </TouchableOpacity>
              <Text style={styles.title} numberOfLines={1}>{place.title}</Text>
              <View style={styles.placeholder} />
            </View>
            <Animated.View
              style={{ transform: [{ translateY: contentTranslateY }] }}>
              <Text style={styles.descriptionText}>{place.description}</Text>
            </Animated.View>
          </View>
        </ScrollView>
      </View>
    );
  }
};

const styles = StyleSheet.create({
  imageContainer: {},
  image: {
    width: Dimensions.get('window').width,
    height: 220,
  },
  priceLabel: {
    alignSelf: 'flex-start',
    backgroundColor: 'rgba(0, 0, 0, .75)',
    marginVertical: 16,
    marginLeft: 10,
    paddingVertical: 7.5,
    paddingHorizontal: 10,
  },
  priceLabelText: {
    fontSize: 19,
    color: 'white',
  },
  navbar: {
    position: 'absolute',
    top: Platform.select({
      android: 0,
      ios: 20,
    }),
    left: 0,
    right: 0,
    height: 56,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'transparent',
  },
  backButton: {
    tintColor: 'white',
    width: 20,
    height: 20,
    marginLeft: 16,
  },
  title: {
    color: 'white',
    fontSize: 16,
    flex: 1,
    paddingHorizontal: 10,
    fontWeight: 'bold',
  },
  placeholder: {
    width: 20,
    height: 20,
    marginRight: 16,
  },
  descriptionText: {
    paddingHorizontal: 10,
    marginBottom: 200,
    fontWeight: 'bold',
  },
});
<commit_msg>Animated title in and out<commit_after>import React from 'react';
import {StyleSheet, View, ScrollView, Image, Text, TouchableOpacity, Animated, Dimensions, Platform} from 'react-native';
import {SharedElement} from 'navigation-react-native';
import ZoomShared from './ZoomShared';

export default class Detail extends React.Component {
  constructor(props, context) {
    super(props, context);
    const {url} = props.stateNavigator.stateContext;
    this.url = url;
    this.state = {
      contentAnimation: new Animated.Value(0),
      navbarAnimation: new Animated.Value(0),
    };
  }
  shouldComponentUpdate(props) {
    return this.url === props.stateNavigator.stateContext.url;
  }
  componentDidMount() {
    Animated.timing(this.state.contentAnimation, {
      toValue: 1,
      duration: 500,
      useNativeDriver: true,
    }).start();
    setTimeout(() => {
      Animated.timing(this.state.navbarAnimation, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }).start();
    }, 500);
  }
  _goBack = () => {
    const {stateNavigator} = this.props;
    if (this.url === stateNavigator.stateContext.url) {
      stateNavigator.navigateBack(1);
      Animated.timing(this.state.contentAnimation, {
        toValue: 0,
        duration: 500,
        useNativeDriver: true,
      }).start();
      Animated.timing(this.state.navbarAnimation, {
        toValue: 0,
        duration: 50,
        useNativeDriver: true,
      }).start();
    }
  };
  render() {
    const {place, rowId, stateNavigator} = this.props;
    const contentTranslateY = this.state.contentAnimation.interpolate({
      inputRange: [0, 1],
      outputRange: [200, 0],
    });
      return (
      <View style={{ flex: 1 }}>
        <ZoomShared stateNavigator={stateNavigator} />
        <ScrollView style={{ flex: 1 }}>
          <View style={styles.imageContainer}>
            <SharedElement
              name={`image${rowId}`}
              data={{image: place.image}}
              stateNavigator={stateNavigator}>
              <Image
                source={place.image}
                style={{ flex: 1 }}
              />
            </SharedElement>
            <SharedElement
              name={`label${rowId}`}
              data={{text: place.price}}
              stateNavigator={stateNavigator}>
              <View style={styles.priceLabel}>
                <Text style={styles.priceLabelText}>
                  ${place.price}
                </Text>
              </View>
            </SharedElement>
            <Animated.View
              style={[styles.navbar, { opacity: this.state.navbarAnimation }]}>
              <TouchableOpacity
                onPress={this._goBack}
                hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }}>
                <Image
                  style={styles.backButton}
                  source={{
                    uri: 'https://www.android.com/static/img/map/back-arrow.png',
                  }}
                />
              </TouchableOpacity>
              <Text style={styles.title} numberOfLines={1}>{place.title}</Text>
              <View style={styles.placeholder} />
            </Animated.View>
            <Animated.View
              style={{ transform: [{ translateY: contentTranslateY }] }}>
              <Text style={styles.descriptionText}>{place.description}</Text>
            </Animated.View>
          </View>
        </ScrollView>
      </View>
    );
  }
};

const styles = StyleSheet.create({
  imageContainer: {},
  image: {
    width: Dimensions.get('window').width,
    height: 220,
  },
  priceLabel: {
    alignSelf: 'flex-start',
    backgroundColor: 'rgba(0, 0, 0, .75)',
    marginVertical: 16,
    marginLeft: 10,
    paddingVertical: 7.5,
    paddingHorizontal: 10,
  },
  priceLabelText: {
    fontSize: 19,
    color: 'white',
  },
  navbar: {
    position: 'absolute',
    top: Platform.select({
      android: 0,
      ios: 20,
    }),
    left: 0,
    right: 0,
    height: 56,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: 'transparent',
  },
  backButton: {
    tintColor: 'white',
    width: 20,
    height: 20,
    marginLeft: 16,
  },
  title: {
    color: 'white',
    fontSize: 16,
    flex: 1,
    paddingHorizontal: 10,
    fontWeight: 'bold',
  },
  placeholder: {
    width: 20,
    height: 20,
    marginRight: 16,
  },
  descriptionText: {
    paddingHorizontal: 10,
    marginBottom: 200,
    fontWeight: 'bold',
  },
});
<|endoftext|>