<commit_before>var async = require('async'),
    util = require('util'),
    BitmeClient = require('bitme');

var logger = require('../logger.js'),
    order = require('../order.js'),
    transaction = require('../transaction.js'),
    BaseExchange = require('./base.js').BaseExchange;

/**
 * Liquid trading interface to Bitme.
 *
 * @param {BitmeClient} client
 * @param {number} delay Number of milliseconds to delay between ticks (default: 1000)
 * @param {boolean} pretend Don't execute any trades, just watch.
 */
var BitmeExchange = module.exports.BitmeExchange = function(client, delay, pretend) {
    BitmeExchange.super_.call(this, pretend);
    this.id = 'bitme';

    this.client = client;
    this.tickDelay = delay;
    this.tickLoop = null;
    this.tickCount = 0;
    this.tickCompleted = 0;
    this.tickSkipAlert = 60; // Log alert if we skip this many ticks in a row.

    // This can be switched to async.map if nonce doesn't need to be strictly-incremental.
    // Use async.mapSeries if nonce must be strictly-incrementing, async.map otherwise.
    this.requestMap = async.map;
};

util.inherits(BitmeExchange, BaseExchange);

BitmeExchange.configKeys = ['BITME_KEY', 'BITME_SECRET'];

/**
 * Instantiate necessary clients based on configuration and return a
 * {@code BitmeExchange} instance.
 *
 * @static
 * @param {{BITME_KEY: string, BITME_SECRET: string}}
 * @return {BitmeExchange}
 */
BitmeExchange.fromConfig = function(config) {
    var client = new BitmeClient(config.apiKeys.BITME_KEY, config.apiKeys.BITME_SECRET);

    var stagingServer = config.env.BITME_STAGING_SERVER;
    if (stagingServer) {
        logger.debug('[exchange:bitme] Overriding server to non-SSL staging:', stagingServer);
        client.strictSSL = false;
        client.baseUri = stagingServer;
    }

    return new BitmeExchange(client, config.tickDelay || 1000, config.pretend);
};

/**
 * Execute a unit of polling.
 */
BitmeExchange.prototype.tick = function() {
    var exchange = this;
    var tickCount = exchange.tickCount++;
    var tickSkipStreak = tickCount - exchange.tickCompleted;

    var hasOrders = exchange.getOrders().length > 0;
    if (!hasOrders && exchange.tickDelay && tickCount % 5 != 0) {
        // Poll 1/5 as often when there are no orders we're aware of.
        return;
    }

    if (!exchange.resources.acquire('requests', true /* exclusive */)) {
        // Discard tick while we're still processing changes.

        if (tickSkipStreak == exchange.tickSkipAlert) {
            // This should not happen.
            logger.alert("BitmeExchange stopped ticking", {
                tickCount: tickCount,
                tickCompleted: exchange.tickCompleted,
                pendingRequests: exchange.resources.using('requests'),
                placedOrders: exchange.getOrders().map(String)
            });
        }

        return;
    }

    exchange.client.ordersOpen(function(err, response) {
        exchange.resources.release('requests');

        // We only care about our orders.
        if (err) {
            logger.error('Failure during BitmeExchange polling:', err);
            return;
        }
        if (exchange.tickCount < tickCount) {
            // This shouldn't happen because we acquire the requests resource exclusively,
            // so this check should be safe to remove.
            logger.warn('Out-of-order tick (%d steps) in BitmeExchange polling, skipping.', exchange.tickCount-tickCount);
            return;
        }

        var responseOrders = response.orders.map(toOrder);
        if (exchange.pretend) {
            // Inject our pretend-saved orders.
            responseOrders = responseOrders.concat(exchange.getOrders());
        }

        var trades = order.diffOrders(exchange.getOrders(), responseOrders);
        if (!trades.length) {
            // No new trades.
            exchange.tickCompleted = tickCount;
            return;
        }

        var using = exchange.resources.using('requests');
        if (using) {
            // Discard tick mid-completion because there are changes in-progress.
            exchange.debug('Skipping tick update of %d trades due to %d pending requests. (%d ticks skipped in a row.)', trades.length, using, tickSkipStreak);
            return;
        }

        // Update any orders that changed
        responseOrders.forEach(function(order) {
            exchange.saveOrder(order, true /* isUpdate */);
        });

        trades.forEach(function(order) {
            if (order.id !== null) {
                exchange.deleteOrder(order);
            }
            exchange.emit('trade', order);
        });

        exchange.tickCompleted = tickCount;
    });
};

/**
 * Authenticate to the API and start polling loop.
 *
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.ready = function(callback) {
    this.debug('Preparing.');
    this.cleanup();

    var exchange = this;
    async.series([
        function authenticate(callback) {
            exchange.debug('Verifying credentials.');
            exchange.client.verifyCredentials(callback);
        },
        function loadOrders(callback) {
            exchange.client.ordersOpen(function(err, response) {
                if (err) {
                    logger.error('Failed to load placed orders:', err);
                    callback && callback.call(exchange, err);
                    return;
                }

                var placedOrders = response.orders.map(toOrder);
                placedOrders.map(exchange.saveOrder.bind(exchange));

                if (placedOrders.length) {
                    exchange.debug('Loaded placed orders:', placedOrders.length);
                }
                callback && callback.call(exchange, err);
            });
        },
        function checkBalance(callback) {
            // We don't really care what the minimums are at this point, we just
            // want to update the internal balance values.
            var minQuantity, minValue;
            exchange.checkBalance(minQuantity, minValue, callback);
        },
        function startPolling(callback) {
            if (!exchange.tickDelay) {
                exchange.debug('Skipping tick loop.');
                callback && callback.call(exchange);
                return;
            }

            exchange.debug('Starting tick loop.');
            exchange.tickLoop = setInterval(exchange.tick.bind(exchange), exchange.tickDelay);
            callback && callback.call(exchange);
        }
    ], callback);
};

/**
 * Clear polling loop.
 *
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.cleanup = function(callback) {
    if (this.tickLoop) { clearInterval(this.tickLoop); }

    BitmeExchange.super_.prototype.cleanup.call(this, callback);
};

/**
 * Check whether there is sufficient balance. Callback with err if not.
 *
 * @param {number=} minQuantity Minimum BTC to expect in balance.
 * @param {number=} minValue Minimum USD to expect in balance.
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.checkBalance = function(minQuantity, minValue, callback) {
    var exchange = this;
    exchange.client.accounts(function(err, response) {
        if (err) {
            logger.error('Failed to load balance for Bitme:', err);
            callback(err, response);
            return;
        }

        // Convert returned values to our balance representation params.
        var balance = toBalance(response.accounts);
        exchange.setBalance(balance.quantity, balance.value);

        if (minQuantity && exchange.balance.quantity.lt(minQuantity)) {
            err = new Error('Insufficient BTC balance on Bitme: ' + exchange.balance.quantity.toString());
        } else if (minValue && exchange.balance.value.lt(minValue)) {
            err = new Error('Insufficient USD balance on Bitme: ' + exchange.balance.quantity.toString());
        }

        callback && callback.call(exchange, err, balance);
    });
};

/**
 * Place an instruction of orders for this exchange.
 *
 * @param {Array.<Order>} orders List of orders to place concurrently.
 * @param {function} callback
 */
BitmeExchange.prototype.placeOrders = function(orders, callback) {
    var exchange = this;

    this.requestMap(orders, function(order, callback) {
        if (exchange.pretend) {
            logger.info('[exchange:bitme] Pretend placeOrder:', order.toString());
            exchange.saveOrder(order);
            callback();
            return;
        };

        exchange.resources.acquire('requests');
        exchange.client.orderCreate('BTCUSD', order.type, order.quantity.toFixed(8), order.rate.toFixed(3), function(err, result) {
            exchange.resources.release('requests');
            if (err) {
                callback(err, result);
                return;
            }
            var newOrder = toOrder(result.order, /* skipExecuted */ true);
            exchange.debug('Placed %s (from: %s)', newOrder.toString(), order.toString());

            // API truncates some fields, so we convert to reduced precision before comparing.
            if (newOrder.similarTo(order) !== 0) {
                logger.warn('Original Bitme order not equal to placed order: %s != %s', order.toString(), newOrder.toString());
            }

            exchange.saveOrder(newOrder);
            callback(err, newOrder);
        });

    }, callback);
};

/**
 * Cancel orders.
 *
 * @param {Array.<Order>} orders List of orders to cancel concurrently.
 * @param {function} callback
 */
BitmeExchange.prototype.cancelOrders = function(orders, callback) {
    var exchange = this;

    this.requestMap(orders, function(order, callback) {
        if (exchange.pretend) {
            logger.info('[exchange:bitme] Pretend cancelOrder:', order.toString());
            exchange.deleteOrder(order);
            callback();
            return;
        };

        exchange.resources.acquire('requests');
        exchange.client.orderCancel(order.id, function(err, result) {
            if (err) {
                var originalErr = err;

                // Confirm that order is closed.
                exchange.debug('Failed to cancel order, checking if it closed:', order.toString());
                exchange.client.orderGet(order.id, function(err, result) {
                    exchange.resources.release('requests');
                    if (err) {
                        logger.error('Failed to check failed BitmeExchange order cancel: ', err.message);
                        callback(err, result);
                        return;
                    }
                    if (!result.order.closed) {
                        // Tried to close the order and failed. Something is wrong. Raise the original error.
                        logger.error('Confirmed failure of BitmeExchange order cancel: ', originalErr.message);
                        callback(originalErr, result);
                        return;
                    }

                    // Order got filled before we tried to cancel. Don't delete it
                    // and let the next tick detect it as filled.
                    callback(err, result);
                });
                return;
            }

            // Confirm that returned result order is equivalent to input order
            var newOrder = toOrder(result.order);
            exchange.deleteOrder(newOrder);

            if (newOrder.quantity.toFixed(7) != order.quantity.toFixed(7)) {
                // Part of the order must have been filled before it was cancelled.
                var deltaOrder = newOrder.clone({
                    quantity: order.quantity.minus(newOrder.quantity)
                });
                exchange.debug('Order partially executed before cancel, emitting a partial order:', deltaOrder.toString());
                exchange.emit('trade', deltaOrder);
            } else if (newOrder.similarTo(order) !== 0) {
                logger.warn('Original Bitme order not equal to cancelled order: %s != %s', order.toString(), newOrder.toString());
            }

            exchange.debug('Cancelled %s (from: %s)', newOrder.toString(), order.toString());
            exchange.resources.release('requests');
            callback(err, newOrder);
        });

    }, callback);
};

/**
 * Given a Bitme order (as returned by the API), return a corresponding
 * {@code Order} object.
 *
 * @static
 * @param {object} d
 * @param {boolean=} skipExecuted Don't count executed amount.
 * @return {Order}
 */
var toOrder = BitmeExchange.toOrder = function(d, skipExecuted) {
    try{
        var o = new order.Order(d.uuid, d.order_type_cd, d.quantity, d.rate, null, 'bitme');

        if (!skipExecuted) {
            o.quantity = o.quantity.minus(d.executed);
        }
    } catch (e) {
        logger.warn('Failed to convert Bitme order:', d);
        throw e;
    }
    return o;
};

/**
 * Given a Bitme accounts list (as returned by the API), return normalized
 * parameters for {@code BaseExchange.prototype.setBalance}.
 *
 * @static
 * @param {object} accounts
 * @return {{value: string, quantity: string}}
 */
var toBalance = BitmeExchange.toBalance = function(accounts) {
    var args = {
        'value': '0.00000000000000000000',
        'quantity': '0.00000000000000000000'
    };
    accounts.forEach(function(account) {
        var currency = account['currency_cd'];
        var key = {'USD': 'value', 'BTC': 'quantity'}[currency];
        if (!key) return; // Skip unknown currencies.
        args[key] = account['available'];
    });
    return args;
};

// FIXME: This part is unused. We could cut it, or keep it for later.
/**
 * Given a Bitme transaction (as returned by the API), return a corresponding
 * {@code Transaction} object, or undefined if it's not relevant to us.
 *
 * @static
 * @param {object} d
 * @param {Array.<Order>=} placedOrders Orders to compare transactions against.
 * @return {Transaction}
 */
var toTransaction = BitmeExchange.toTransaction = function(t, placedOrders) {
    // FIXME: This part is tricky, will need extra review.

    // "If you have a PENDING DEBIT, you can deduce from that
    // fact that it represents the unexecuted quantity of an
    // open order. If you have a PENDING CREDIT, that means
    // that the execution already occurred and is just waiting
    // to be released by the escrow agent."

    // Discard transactions we don't care about.
    if (t['transaction_category_cd'] != 'ORDER_ESCROW') return;
    if (t['transaction_status_cd'] != 'CLEARED' && t['transaction_status_cd'] != 'PENDING') return;
    if (t['transaction_type_cd'] == 'CREDIT' && t['transaction_status_cd'] != 'PENDING') return;

    var type = {
        'DEBIT': 'ASK',
        'CREDIT': 'BID'
    }[t['transaction_type_cd']];

    var o = {
        'type': type,
        'quantity': t['amount'],
        'timestamp': t['cleared'] || t['created']
    };

    if (t['transaction_status_cd'] == 'PENDING' && placedOrders!==undefined) {
        // Is this transaction in the orderbook?
        for (var i in placedOrders) {
            var order = placedOrders[i];
            if (order.type == o.type && order.quantity.eq(o.quantity)) return;
        }
    }

    return new transaction.Transaction(o.type, o.quantity, o.timestamp);
};
<commit_msg>Add 'resumed ticking' message when updates get unstuck.<commit_after>var async = require('async'),
    util = require('util'),
    BitmeClient = require('bitme');

var logger = require('../logger.js'),
    order = require('../order.js'),
    transaction = require('../transaction.js'),
    BaseExchange = require('./base.js').BaseExchange;

/**
 * Liquid trading interface to Bitme.
 *
 * @param {BitmeClient} client
 * @param {number} delay Number of milliseconds to delay between ticks (default: 1000)
 * @param {boolean} pretend Don't execute any trades, just watch.
 */
var BitmeExchange = module.exports.BitmeExchange = function(client, delay, pretend) {
    BitmeExchange.super_.call(this, pretend);
    this.id = 'bitme';

    this.client = client;
    this.tickDelay = delay;
    this.tickLoop = null;
    this.tickCount = 0;
    this.tickCompleted = 0;
    this.tickSkipAlert = 60; // Log alert if we skip this many ticks in a row.

    // This can be switched to async.map if nonce doesn't need to be strictly-incremental.
    // Use async.mapSeries if nonce must be strictly-incrementing, async.map otherwise.
    this.requestMap = async.map;
};

util.inherits(BitmeExchange, BaseExchange);

BitmeExchange.configKeys = ['BITME_KEY', 'BITME_SECRET'];

/**
 * Instantiate necessary clients based on configuration and return a
 * {@code BitmeExchange} instance.
 *
 * @static
 * @param {{BITME_KEY: string, BITME_SECRET: string}}
 * @return {BitmeExchange}
 */
BitmeExchange.fromConfig = function(config) {
    var client = new BitmeClient(config.apiKeys.BITME_KEY, config.apiKeys.BITME_SECRET);

    var stagingServer = config.env.BITME_STAGING_SERVER;
    if (stagingServer) {
        logger.debug('[exchange:bitme] Overriding server to non-SSL staging:', stagingServer);
        client.strictSSL = false;
        client.baseUri = stagingServer;
    }

    return new BitmeExchange(client, config.tickDelay || 1000, config.pretend);
};

/**
 * Execute a unit of polling.
 */
BitmeExchange.prototype.tick = function() {
    var exchange = this;
    var tickCount = exchange.tickCount++;
    var tickSkipStreak = tickCount - exchange.tickCompleted;

    var hasOrders = exchange.getOrders().length > 0;
    if (!hasOrders && exchange.tickDelay && tickCount % 5 != 0) {
        // Poll 1/5 as often when there are no orders we're aware of.
        return;
    }

    if (!exchange.resources.acquire('requests', true /* exclusive */)) {
        // Discard tick while we're still processing changes.

        if (tickSkipStreak == exchange.tickSkipAlert) {
            // This should not happen.
            logger.alert("BitmeExchange stopped ticking", {
                tickCount: tickCount,
                tickCompleted: exchange.tickCompleted,
                pendingRequests: exchange.resources.using('requests'),
                placedOrders: exchange.getOrders().map(String)
            });
        }

        return;
    }

    exchange.client.ordersOpen(function(err, response) {
        exchange.resources.release('requests');

        // We only care about our orders.
        if (err) {
            logger.error('Failure during BitmeExchange polling:', err);
            return;
        }
        if (exchange.tickCount < tickCount) {
            // This shouldn't happen because we acquire the requests resource exclusively,
            // so this check should be safe to remove.
            logger.warn('Out-of-order tick (%d steps) in BitmeExchange polling, skipping.', exchange.tickCount-tickCount);
            return;
        }

        var responseOrders = response.orders.map(toOrder);
        if (exchange.pretend) {
            // Inject our pretend-saved orders.
            responseOrders = responseOrders.concat(exchange.getOrders());
        }

        var trades = order.diffOrders(exchange.getOrders(), responseOrders);
        if (!trades.length) {
            // No new trades.
            exchange.tickCompleted = tickCount;
            return;
        }

        var using = exchange.resources.using('requests');
        if (using) {
            // Discard tick mid-completion because there are changes in-progress.
            exchange.debug('Skipping tick update of %d trades due to %d pending requests. (%d ticks skipped in a row.)', trades.length, using, tickSkipStreak);
            return;
        }

        // Update any orders that changed
        responseOrders.forEach(function(order) {
            exchange.saveOrder(order, true /* isUpdate */);
        });

        trades.forEach(function(order) {
            if (order.id !== null) {
                exchange.deleteOrder(order);
            }
            exchange.emit('trade', order);
        });

        if (tickSkipStreak >= exchange.tickSkipAlert) {
            logger.info("BitmeExchange resumed ticking after %d skipped ticks.", tickSkipStreak);
        }

        exchange.tickCompleted = tickCount;
    });
};

/**
 * Authenticate to the API and start polling loop.
 *
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.ready = function(callback) {
    this.debug('Preparing.');
    this.cleanup();

    var exchange = this;
    async.series([
        function authenticate(callback) {
            exchange.debug('Verifying credentials.');
            exchange.client.verifyCredentials(callback);
        },
        function loadOrders(callback) {
            exchange.client.ordersOpen(function(err, response) {
                if (err) {
                    logger.error('Failed to load placed orders:', err);
                    callback && callback.call(exchange, err);
                    return;
                }

                var placedOrders = response.orders.map(toOrder);
                placedOrders.map(exchange.saveOrder.bind(exchange));

                if (placedOrders.length) {
                    exchange.debug('Loaded placed orders:', placedOrders.length);
                }
                callback && callback.call(exchange, err);
            });
        },
        function checkBalance(callback) {
            // We don't really care what the minimums are at this point, we just
            // want to update the internal balance values.
            var minQuantity, minValue;
            exchange.checkBalance(minQuantity, minValue, callback);
        },
        function startPolling(callback) {
            if (!exchange.tickDelay) {
                exchange.debug('Skipping tick loop.');
                callback && callback.call(exchange);
                return;
            }

            exchange.debug('Starting tick loop.');
            exchange.tickLoop = setInterval(exchange.tick.bind(exchange), exchange.tickDelay);
            callback && callback.call(exchange);
        }
    ], callback);
};

/**
 * Clear polling loop.
 *
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.cleanup = function(callback) {
    if (this.tickLoop) { clearInterval(this.tickLoop); }

    BitmeExchange.super_.prototype.cleanup.call(this, callback);
};

/**
 * Check whether there is sufficient balance. Callback with err if not.
 *
 * @param {number=} minQuantity Minimum BTC to expect in balance.
 * @param {number=} minValue Minimum USD to expect in balance.
 * @param {function=} callback Function called upon completion.
 */
BitmeExchange.prototype.checkBalance = function(minQuantity, minValue, callback) {
    var exchange = this;
    exchange.client.accounts(function(err, response) {
        if (err) {
            logger.error('Failed to load balance for Bitme:', err);
            callback(err, response);
            return;
        }

        // Convert returned values to our balance representation params.
        var balance = toBalance(response.accounts);
        exchange.setBalance(balance.quantity, balance.value);

        if (minQuantity && exchange.balance.quantity.lt(minQuantity)) {
            err = new Error('Insufficient BTC balance on Bitme: ' + exchange.balance.quantity.toString());
        } else if (minValue && exchange.balance.value.lt(minValue)) {
            err = new Error('Insufficient USD balance on Bitme: ' + exchange.balance.quantity.toString());
        }

        callback && callback.call(exchange, err, balance);
    });
};

/**
 * Place an instruction of orders for this exchange.
 *
 * @param {Array.<Order>} orders List of orders to place concurrently.
 * @param {function} callback
 */
BitmeExchange.prototype.placeOrders = function(orders, callback) {
    var exchange = this;

    this.requestMap(orders, function(order, callback) {
        if (exchange.pretend) {
            logger.info('[exchange:bitme] Pretend placeOrder:', order.toString());
            exchange.saveOrder(order);
            callback();
            return;
        };

        exchange.resources.acquire('requests');
        exchange.client.orderCreate('BTCUSD', order.type, order.quantity.toFixed(8), order.rate.toFixed(3), function(err, result) {
            exchange.resources.release('requests');
            if (err) {
                callback(err, result);
                return;
            }
            var newOrder = toOrder(result.order, /* skipExecuted */ true);
            exchange.debug('Placed %s (from: %s)', newOrder.toString(), order.toString());

            // API truncates some fields, so we convert to reduced precision before comparing.
            if (newOrder.similarTo(order) !== 0) {
                logger.warn('Original Bitme order not equal to placed order: %s != %s', order.toString(), newOrder.toString());
            }

            exchange.saveOrder(newOrder);
            callback(err, newOrder);
        });

    }, callback);
};

/**
 * Cancel orders.
 *
 * @param {Array.<Order>} orders List of orders to cancel concurrently.
 * @param {function} callback
 */
BitmeExchange.prototype.cancelOrders = function(orders, callback) {
    var exchange = this;

    this.requestMap(orders, function(order, callback) {
        if (exchange.pretend) {
            logger.info('[exchange:bitme] Pretend cancelOrder:', order.toString());
            exchange.deleteOrder(order);
            callback();
            return;
        };

        exchange.resources.acquire('requests');
        exchange.client.orderCancel(order.id, function(err, result) {
            if (err) {
                var originalErr = err;

                // Confirm that order is closed.
                exchange.debug('Failed to cancel order, checking if it closed:', order.toString());
                exchange.client.orderGet(order.id, function(err, result) {
                    exchange.resources.release('requests');
                    if (err) {
                        logger.error('Failed to check failed BitmeExchange order cancel: ', err.message);
                        callback(err, result);
                        return;
                    }
                    if (!result.order.closed) {
                        // Tried to close the order and failed. Something is wrong. Raise the original error.
                        logger.error('Confirmed failure of BitmeExchange order cancel: ', originalErr.message);
                        callback(originalErr, result);
                        return;
                    }

                    // Order got filled before we tried to cancel. Don't delete it
                    // and let the next tick detect it as filled.
                    callback(err, result);
                });
                return;
            }

            // Confirm that returned result order is equivalent to input order
            var newOrder = toOrder(result.order);
            exchange.deleteOrder(newOrder);

            if (newOrder.quantity.toFixed(7) != order.quantity.toFixed(7)) {
                // Part of the order must have been filled before it was cancelled.
                var deltaOrder = newOrder.clone({
                    quantity: order.quantity.minus(newOrder.quantity)
                });
                exchange.debug('Order partially executed before cancel, emitting a partial order:', deltaOrder.toString());
                exchange.emit('trade', deltaOrder);
            } else if (newOrder.similarTo(order) !== 0) {
                logger.warn('Original Bitme order not equal to cancelled order: %s != %s', order.toString(), newOrder.toString());
            }

            exchange.debug('Cancelled %s (from: %s)', newOrder.toString(), order.toString());
            exchange.resources.release('requests');
            callback(err, newOrder);
        });

    }, callback);
};

/**
 * Given a Bitme order (as returned by the API), return a corresponding
 * {@code Order} object.
 *
 * @static
 * @param {object} d
 * @param {boolean=} skipExecuted Don't count executed amount.
 * @return {Order}
 */
var toOrder = BitmeExchange.toOrder = function(d, skipExecuted) {
    try{
        var o = new order.Order(d.uuid, d.order_type_cd, d.quantity, d.rate, null, 'bitme');

        if (!skipExecuted) {
            o.quantity = o.quantity.minus(d.executed);
        }
    } catch (e) {
        logger.warn('Failed to convert Bitme order:', d);
        throw e;
    }
    return o;
};

/**
 * Given a Bitme accounts list (as returned by the API), return normalized
 * parameters for {@code BaseExchange.prototype.setBalance}.
 *
 * @static
 * @param {object} accounts
 * @return {{value: string, quantity: string}}
 */
var toBalance = BitmeExchange.toBalance = function(accounts) {
    var args = {
        'value': '0.00000000000000000000',
        'quantity': '0.00000000000000000000'
    };
    accounts.forEach(function(account) {
        var currency = account['currency_cd'];
        var key = {'USD': 'value', 'BTC': 'quantity'}[currency];
        if (!key) return; // Skip unknown currencies.
        args[key] = account['available'];
    });
    return args;
};

// FIXME: This part is unused. We could cut it, or keep it for later.
/**
 * Given a Bitme transaction (as returned by the API), return a corresponding
 * {@code Transaction} object, or undefined if it's not relevant to us.
 *
 * @static
 * @param {object} d
 * @param {Array.<Order>=} placedOrders Orders to compare transactions against.
 * @return {Transaction}
 */
var toTransaction = BitmeExchange.toTransaction = function(t, placedOrders) {
    // FIXME: This part is tricky, will need extra review.

    // "If you have a PENDING DEBIT, you can deduce from that
    // fact that it represents the unexecuted quantity of an
    // open order. If you have a PENDING CREDIT, that means
    // that the execution already occurred and is just waiting
    // to be released by the escrow agent."

    // Discard transactions we don't care about.
    if (t['transaction_category_cd'] != 'ORDER_ESCROW') return;
    if (t['transaction_status_cd'] != 'CLEARED' && t['transaction_status_cd'] != 'PENDING') return;
    if (t['transaction_type_cd'] == 'CREDIT' && t['transaction_status_cd'] != 'PENDING') return;

    var type = {
        'DEBIT': 'ASK',
        'CREDIT': 'BID'
    }[t['transaction_type_cd']];

    var o = {
        'type': type,
        'quantity': t['amount'],
        'timestamp': t['cleared'] || t['created']
    };

    if (t['transaction_status_cd'] == 'PENDING' && placedOrders!==undefined) {
        // Is this transaction in the orderbook?
        for (var i in placedOrders) {
            var order = placedOrders[i];
            if (order.type == o.type && order.quantity.eq(o.quantity)) return;
        }
    }

    return new transaction.Transaction(o.type, o.quantity, o.timestamp);
};
<|endoftext|>


<commit_before>(function(){
  'use strict';

  angular
    .module('topFive.search')
        .factory('searchFactory', searchFactory);

  searchFactory.$inject = ['$resource'];
  function searchFactory($resource){
    var searchResource = $resource('http://localhost:8080/search/');

    var search = function search(options){
      return searchResource.query(options).$promise;
    }

    return {
      search: search
    };
  };

})();
<commit_msg>edit searchFactory to set method type on  object<commit_after>(function(){
  'use strict';

  angular
    .module('topFive.search')
        .factory('searchFactory', searchFactory);

  searchFactory.$inject = ['$resource'];
  function searchFactory($resource){
    var searchResource = $resource('/search', {},{
          query: {method:'GET',isArray:true}
      });

    var search = function search(options){
      return searchResource.query(options).$promise;
    }

    return {
      search: search
    };
  };

})();
<|endoftext|>


<commit_before>/* eslint-disable camelcase*/
import pool from '../db-config';

const newGetAvgByProductOnTime = async (id, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 4;
      case 'halfyear': return 6;
      case 'year': return 12;
      default: return 99999999;
    }
  })(type);

  const farmIdFromProduct = await pool.query(`
    SELECT DISTINCT id, name
    FROM farm
    WHERE id IN(
        SELECT farm_id
        FROM farmproduct
        WHERE product_id = ${id}
      )
    ORDER BY id ASC
  `);
  const farmIdToName = farmIdFromProduct.rows.reduce((sum, val) => {
    sum[val.id] = val.name.replace(/\s+$/, '');
    return sum;
  }, {});

  const timeFromProduct = await pool.query(`
    SELECT DISTINCT date_part('year' ,date) AS year,
                    date_part('month', date) AS month
                    ${type === 'week' ? ",date_part('day', date) AS special" : ''}
                    ${type === 'month' ? ",date_part('day',date_trunc('week', date)) AS special" : ''}
    FROM pricestamp
    JOIN DATE
      ON pricestamp.date_id = date.id
    WHERE farmproductid IN (
      SELECT id
      FROM farmproduct
      WHERE product_id = ${id}
    )
    ORDER BY year DESC, month DESC ${(type === 'week' || type === 'month') ? ', special DESC' : ''}
    fetch first ${t} rows only
  `);

  const avgFromProduct = await pool.query(`
    SELECT farm_id, AVG(price),
            date_part('year' ,date) AS year,
            date_part('month', date) AS month
            ${type === 'week' ? ",date_part('day', date) AS special" : ''}
            ${type === 'month' ? ",date_part('day',date_trunc('week', date)) AS special" : ''}
    FROM price
    JOIN pricestamp
      ON price.price_id = pricestamp.id
    JOIN farmproduct
      ON farmproduct.id = farmproductid
    JOIN DATE
      ON pricestamp.date_id = date.id
    WHERE product_id = ${id}
    GROUP BY farm_id,product_id, year, month ${(type === 'week' || type === 'month') ? ', special' : ''}
    ORDER BY year DESC, month DESC ${(type === 'week' || type === 'month') ? ', special DESC' : ''}, farm_id ASC
    fetch first ${t * farmIdFromProduct.rows.length} rows only
  `);

  const formatName = (data) => {
    if (type === 'month') {
      return `${data.special}-${data.special + 7}/${data.month}/${data.year}`;
    }
    return `${data.special ? `${data.special}/` : ''}${data.month}/${data.year}`;
  };

  const formattedData = timeFromProduct.rows.reduce((sum, row) => {
    const data = {
      name: formatName(row),
      type
    };
    const price = avgFromProduct.rows.filter(val => (val.year === row.year && val.month === row.month && val.special === row.special));
    price.forEach((val) => {
      data[farmIdToName[val.farm_id]] = val.avg;
    });
    sum.push(data);
    return sum;
  }, []);

  return formattedData.reverse();
};

const getAvgOnFarmByProducOnTime = async (id, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  console.log(type);
  const res = await pool.query(`
SELECT farm.id AS farm_id,avg(price.price) AS farm_avg_${type}
    FROM pricestamp
    JOIN farmproduct
      ON farmproduct.id = pricestamp.farmproductid
    JOIN price
      ON pricestamp.id = price_id
    JOIN farm
      ON farm.id = farmproduct.farm_id
    JOIN DATE
      ON date.id = pricestamp.date_id
    WHERE farmproduct.product_id = ${id}
    AND (
        SELECT MAX(DATE)
        FROM pricestamp
        JOIN farmproduct
        ON farmproduct.id = pricestamp.farmproductid
        JOIN DATE
        ON date.id = pricestamp.date_id
        WHERE farmproduct.product_id = ${id}
        ) - date.date < ${t}
    GROUP BY farm.id
  `);
  return res.rows;
};

const getAvgOnFarmByProduct = async (id) => {
  const farmIdFromProduct = await pool.query(`
    SELECT DISTINCT farm_id, name
    FROM farmproduct
    JOIN farm
      ON farm_id = farm.id
    WHERE product_id = ${id}
    ORDER BY farm_id ASC
  `);
  const result = farmIdFromProduct.rows.map(item => (
    {
      farm_id: item.farm_id,
      farm_name: item.name.replace(/\s+$/, '')
    }
  ));
  const byWeek = await getAvgOnFarmByProducOnTime(id, 'week');
  const byMonth = await getAvgOnFarmByProducOnTime(id, 'month');
  const byHYear = await getAvgOnFarmByProducOnTime(id, 'halfyear');
  const byYear = await getAvgOnFarmByProducOnTime(id, 'year');

  const res = result.map(item => ({
    ...item,
    farm_avg_week: byWeek.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_week,
    farm_avg_month: byMonth.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_month,
    farm_avg_halfyear: byHYear.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_halfyear,
    farm_avg_year: byYear.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_year
  }));
  console.log(res);
  return res;
};

export const getAvgByProduct = async (id) => {
  const byWeek = await newGetAvgByProductOnTime(id, 'week');
  const byMonth = await newGetAvgByProductOnTime(id, 'month');
  const byHYear = await newGetAvgByProductOnTime(id, 'halfyear');
  const byYear = await newGetAvgByProductOnTime(id, 'year');
  const farm = await getAvgOnFarmByProduct(id);
  return { data: [...byWeek, ...byMonth, ...byHYear, ...byYear].map((item, id) => ({ ...item, id })), farm };
};

export const getCoordinateAllProduct = async (id1, id2, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  const res = await pool.query(`
    WITH temp AS (
      SELECT date_id, AVG(price), product_id
      FROM pricestamp
      JOIN price
        ON price.price_id = pricestamp.id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      WHERE date_id IN (
          SELECT DISTINCT T1.date_id
          FROM pricestamp AS T1
          JOIN pricestamp AS T2
            ON T1.date_id = T2.date_id
          JOIN farmproduct AS T3
            ON T1.farmproductid = T3.id
          JOIN farmproduct AS T4
            ON T2.farmproductid = T4.id
          WHERE T3.product_id = ${id1}
            AND T4.product_id = ${id2}
      )
      GROUP BY date_id,product_id
    )

    SELECT temp1.date_id AS id, temp1.avg AS x, temp2.avg AS y
    FROM temp AS temp1
    JOIN temp AS temp2
      ON temp1.date_id = temp2.date_id
    WHERE temp1.product_id = ${id1}
      AND temp2.product_id = ${id2}
    ORDER BY temp1.date_id DESC
    fetch first ${t} rows only
  `);
  return res.rows;
};

const getCorrAllProduct = async (id1, id2, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  const res = await pool.query(`
  SELECT corr(x,y) FROM(
    SELECT T1.avg AS x, T2.avg AS y
    FROM (
      SELECT date_id,farmproduct.product_id, avg(price) AS AVG
      FROM pricestamp
      JOIN price
        ON pricestamp.id = price_id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      GROUP BY date_id, farmproduct.product_id
      ) AS T1
    JOIN (
      SELECT date_id,farmproduct.product_id, avg(price) AS AVG
      FROM pricestamp
      JOIN price
        ON pricestamp.id = price_id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      GROUP BY date_id, farmproduct.product_id
      ) AS T2
    ON T2.date_id = T1.date_id
    WHERE T1.product_id = ${id1}
      AND T2.product_id = ${id2}
    ORDER BY T1.date_id DESC
    fetch first ${t} rows only
  ) AS T
`);
  return res.rows[0].corr || 0;
};

export const getCorrByProduct = async (id1, id2) => {
  const dataWeek = await getCoordinateAllProduct(id1, id2, 'week');
  const dataMonth = await getCoordinateAllProduct(id1, id2, 'month');
  const dataHYear = await getCoordinateAllProduct(id1, id2, 'halfyear');
  const dataYear = await getCoordinateAllProduct(id1, id2, 'year');

  const data = [...dataWeek.map(x => ({ ...x, type: 'week' })), ...dataMonth.map(x => ({ ...x, type: 'month' })), ...dataHYear.map(x => ({ ...x, type: 'halfyear' })), ...dataYear.map(x => ({ ...x, type: 'year' }))];
  const corr_week = await getCorrAllProduct(id1, id2, 'week');
  const corr_month = await getCorrAllProduct(id1, id2, 'month');
  const corr_halfyear = await getCorrAllProduct(id1, id2, 'halfyear');
  const corr_year = await getCorrAllProduct(id1, id2, 'year');

  const corr = {
    corr_week,
    corr_month,
    corr_halfyear,
    corr_year
  };

  return { data, corr };
};
<commit_msg>update price<commit_after>/* eslint-disable camelcase*/
import pool from '../db-config';

const newGetAvgByProductOnTime = async (id, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 4;
      case 'halfyear': return 6;
      case 'year': return 12;
      default: return 99999999;
    }
  })(type);

  const farmIdFromProduct = await pool.query(`
    SELECT DISTINCT id, name
    FROM farm
    WHERE EXISTS (
      SELECT *
      FROM farmproduct
      WHERE product_id = ${id}
        AND farm_id = farm.id
    )
    ORDER BY id ASC
  `);
  const farmIdToName = farmIdFromProduct.rows.reduce((sum, val) => {
    sum[val.id] = val.name.replace(/\s+$/, '');
    return sum;
  }, {});

  const timeFromProduct = await pool.query(`
    SELECT DISTINCT date_part('year' ,date) AS year,
                    date_part('month', date) AS month
                    ${type === 'week' ? ",date_part('day', date) AS special" : ''}
                    ${type === 'month' ? ",date_part('day',date_trunc('week', date)) AS special" : ''}
    FROM pricestamp
    JOIN DATE
      ON pricestamp.date_id = date.id
    WHERE farmproductid IN (
      SELECT id
      FROM farmproduct
      WHERE product_id = ${id}
    )
    ORDER BY year DESC, month DESC ${(type === 'week' || type === 'month') ? ', special DESC' : ''}
    fetch first ${t} rows only
  `);

  const avgFromProduct = await pool.query(`
    SELECT farm_id, AVG(price),
            date_part('year' ,date) AS year,
            date_part('month', date) AS month
            ${type === 'week' ? ",date_part('day', date) AS special" : ''}
            ${type === 'month' ? ",date_part('day',date_trunc('week', date)) AS special" : ''}
    FROM price
    JOIN pricestamp
      ON price.price_id = pricestamp.id
    JOIN farmproduct
      ON farmproduct.id = farmproductid
    JOIN DATE
      ON pricestamp.date_id = date.id
    WHERE product_id = ${id}
    GROUP BY farm_id,product_id, year, month ${(type === 'week' || type === 'month') ? ', special' : ''}
    ORDER BY year DESC, month DESC ${(type === 'week' || type === 'month') ? ', special DESC' : ''}, farm_id ASC
    fetch first ${t * farmIdFromProduct.rows.length} rows only
  `);

  const formatName = (data) => {
    if (type === 'month') {
      return `${data.special}-${data.special + 7}/${data.month}/${data.year}`;
    }
    return `${data.special ? `${data.special}/` : ''}${data.month}/${data.year}`;
  };

  const formattedData = timeFromProduct.rows.reduce((sum, row) => {
    const data = {
      name: formatName(row),
      type
    };
    const price = avgFromProduct.rows.filter(val => (val.year === row.year && val.month === row.month && val.special === row.special));
    price.forEach((val) => {
      data[farmIdToName[val.farm_id]] = val.avg;
    });
    sum.push(data);
    return sum;
  }, []);

  return formattedData.reverse();
};

const getAvgOnFarmByProducOnTime = async (id, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  console.log(type);
  const res = await pool.query(`
SELECT farm.id AS farm_id,avg(price.price) AS farm_avg_${type}
    FROM pricestamp
    JOIN farmproduct
      ON farmproduct.id = pricestamp.farmproductid
    JOIN price
      ON pricestamp.id = price_id
    JOIN farm
      ON farm.id = farmproduct.farm_id
    JOIN DATE
      ON date.id = pricestamp.date_id
    WHERE farmproduct.product_id = ${id}
    AND (
        SELECT MAX(DATE)
        FROM pricestamp
        JOIN farmproduct
        ON farmproduct.id = pricestamp.farmproductid
        JOIN DATE
        ON date.id = pricestamp.date_id
        WHERE farmproduct.product_id = ${id}
        ) - date.date < ${t}
    GROUP BY farm.id
  `);
  return res.rows;
};

const getAvgOnFarmByProduct = async (id) => {
  const farmIdFromProduct = await pool.query(`
    SELECT DISTINCT farm_id, name
    FROM farmproduct
    JOIN farm
      ON farm_id = farm.id
    WHERE product_id = ${id}
    ORDER BY farm_id ASC
  `);
  const result = farmIdFromProduct.rows.map(item => (
    {
      farm_id: item.farm_id,
      farm_name: item.name.replace(/\s+$/, '')
    }
  ));
  const byWeek = await getAvgOnFarmByProducOnTime(id, 'week');
  const byMonth = await getAvgOnFarmByProducOnTime(id, 'month');
  const byHYear = await getAvgOnFarmByProducOnTime(id, 'halfyear');
  const byYear = await getAvgOnFarmByProducOnTime(id, 'year');

  const res = result.map(item => ({
    ...item,
    farm_avg_week: byWeek.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_week,
    farm_avg_month: byMonth.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_month,
    farm_avg_halfyear: byHYear.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_halfyear,
    farm_avg_year: byYear.filter(x => (x.farm_id === item.farm_id))[0].farm_avg_year
  }));
  console.log(res);
  return res;
};

export const getAvgByProduct = async (id) => {
  const byWeek = await newGetAvgByProductOnTime(id, 'week');
  const byMonth = await newGetAvgByProductOnTime(id, 'month');
  const byHYear = await newGetAvgByProductOnTime(id, 'halfyear');
  const byYear = await newGetAvgByProductOnTime(id, 'year');
  const farm = await getAvgOnFarmByProduct(id);
  return { data: [...byWeek, ...byMonth, ...byHYear, ...byYear].map((item, id) => ({ ...item, id })), farm };
};

export const getCoordinateAllProduct = async (id1, id2, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  const res = await pool.query(`
    WITH temp AS (
      SELECT date_id, AVG(price), product_id
      FROM pricestamp
      JOIN price
        ON price.price_id = pricestamp.id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      WHERE date_id IN (
          SELECT DISTINCT T1.date_id
          FROM pricestamp AS T1
          JOIN pricestamp AS T2
            ON T1.date_id = T2.date_id
          JOIN farmproduct AS T3
            ON T1.farmproductid = T3.id
          JOIN farmproduct AS T4
            ON T2.farmproductid = T4.id
          WHERE T3.product_id = ${id1}
            AND T4.product_id = ${id2}
      )
      GROUP BY date_id,product_id
    )

    SELECT temp1.date_id AS id, temp1.avg AS x, temp2.avg AS y
    FROM temp AS temp1
    JOIN temp AS temp2
      ON temp1.date_id = temp2.date_id
    WHERE temp1.product_id = ${id1}
      AND temp2.product_id = ${id2}
    ORDER BY temp1.date_id DESC
    fetch first ${t} rows only
  `);
  return res.rows;
};

const getCorrAllProduct = async (id1, id2, type) => {
  const t = ((x) => {
    switch (x) {
      case 'week': return 7;
      case 'month': return 30;
      case 'halfyear': return 180;
      case 'year': return 360;
      default: return 99999999;
    }
  })(type);
  const res = await pool.query(`
  SELECT corr(x,y) FROM(
    SELECT T1.avg AS x, T2.avg AS y
    FROM (
      SELECT date_id,farmproduct.product_id, avg(price) AS AVG
      FROM pricestamp
      JOIN price
        ON pricestamp.id = price_id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      GROUP BY date_id, farmproduct.product_id
      ) AS T1
    JOIN (
      SELECT date_id,farmproduct.product_id, avg(price) AS AVG
      FROM pricestamp
      JOIN price
        ON pricestamp.id = price_id
      JOIN farmproduct
        ON pricestamp.farmproductid = farmproduct.id
      GROUP BY date_id, farmproduct.product_id
      ) AS T2
    ON T2.date_id = T1.date_id
    WHERE T1.product_id = ${id1}
      AND T2.product_id = ${id2}
    ORDER BY T1.date_id DESC
    fetch first ${t} rows only
  ) AS T
`);
  return res.rows[0].corr || 0;
};

export const getCorrByProduct = async (id1, id2) => {
  const dataWeek = await getCoordinateAllProduct(id1, id2, 'week');
  const dataMonth = await getCoordinateAllProduct(id1, id2, 'month');
  const dataHYear = await getCoordinateAllProduct(id1, id2, 'halfyear');
  const dataYear = await getCoordinateAllProduct(id1, id2, 'year');

  const data = [...dataWeek.map(x => ({ ...x, type: 'week' })), ...dataMonth.map(x => ({ ...x, type: 'month' })), ...dataHYear.map(x => ({ ...x, type: 'halfyear' })), ...dataYear.map(x => ({ ...x, type: 'year' }))];
  const corr_week = await getCorrAllProduct(id1, id2, 'week');
  const corr_month = await getCorrAllProduct(id1, id2, 'month');
  const corr_halfyear = await getCorrAllProduct(id1, id2, 'halfyear');
  const corr_year = await getCorrAllProduct(id1, id2, 'year');

  const corr = {
    corr_week,
    corr_month,
    corr_halfyear,
    corr_year
  };

  return { data, corr };
};
<|endoftext|>


<commit_before>const MetaTagsManager = {

  /**
   * Get CSRF Token from the DOM.
   *
   * @returns {String} - CSRF Token.
   */
  getCSRFToken() {
    const metas = document.getElementsByTagName('meta');
    for (let i = 0; i < metas.length; i++) {
      const meta = metas[i];
      if (meta.getAttribute('name') === 'csrf-token') {
        return meta.getAttribute('content');
      }
    }

    return null;
  },
};

export default MetaTagsManager;
<commit_msg>Refactoring MetaTagsManager<commit_after>const MetaTagsManager = {

  /**
   * Get CSRF Token from the DOM.
   *
   * @returns {String} - CSRF Token.
   */
  getCSRFToken() {
    const token = Array.from(document.getElementsByTagName('meta'))
      .find(tag => tag.name === 'csrf-token');

    return token ? token.content : null;
  },
};

export default MetaTagsManager;
<|endoftext|>


<commit_before>module.exports.Primal = Primal; // interface for creating magnet objects from javascript values

//module.exports.Library = Library;  interface for registering stdlib methods written in javascript

// utility
module.exports.repeatString = repeatString;

module.exports.interpret = function interpret(code, lib) {
  code += "\r\n";
  var b2mb = function(b) {
    return ((b / Math.pow(2, 10))/ Math.pow(2, 10)).toFixed(2) + ' MB';
  };
  var startmemory = process.memoryUsage().heapUsed;
  console.time('# Execution time');

  var globalScope = new Scope;
  globalScope.meta = {identifier: '<Global>'};
  // lib.attach(globalScope); --activate for stdlib support

  var opcode = [];
  var err_offsets = [];
  var err_lookaheads = [];
  var err_count = 0;
  var errors = [];

  if( ( err_count = __parse( code, err_offsets, err_lookaheads, opcode ) ) > 0 ) {
    for( var i = 0; i < err_count; i++ ) {
      var line = calcLineNo(code, err_offsets[i]);
      errors.push({
        line : line,
        col :  getLineCol(code, err_offsets[i]),
        msg : 'Parse Error: unexpected token '+JSON.stringify(code[err_offsets[i]])+' expecting ' + err_lookaheads[i].map(JSON.stringify).join(' or '),
        excerpt : getLineExcerpt(code, err_offsets[i])
      });
    }
    return {errors: errors};
  }

  try {
    var ret = globalScope.executeTokenList(opcode); // the returned value
  }catch(e){
    if(!e.scope) process.exit(console.log(e));
    var trace = e.scope.backtrace().map(function(call) {
      return {caller: call.caller, at: calcLineNo(code, call.at)};
    });
    return {errors: [{ msg: 'Runtime Error: '+e.message, line: calcLineNo(code, e.offset), col: getLineCol(code, e.offset), excerpt: getLineExcerpt(code, e.offset), backtrace: trace }]};
  };

  // post execution notes
  console.timeEnd('# Execution time');
  console.log('# Heap size: ', globalScope.env.heap.length);
  console.log('# Memory usage: ', b2mb(process.memoryUsage().heapUsed - startmemory));

  return {errors: errors};
};<commit_msg>Mention current scope in stack trace<commit_after>module.exports.Primal = Primal; // interface for creating magnet objects from javascript values

//module.exports.Library = Library;  interface for registering stdlib methods written in javascript

// utility
module.exports.repeatString = repeatString;

module.exports.interpret = function interpret(code, lib) {
  code += "\r\n";
  var b2mb = function(b) {
    return ((b / Math.pow(2, 10))/ Math.pow(2, 10)).toFixed(2) + ' MB';
  };
  var startmemory = process.memoryUsage().heapUsed;
  console.time('# Execution time');

  var globalScope = new Scope;
  globalScope.meta = {identifier: '<Global>'};
  // lib.attach(globalScope); --activate for stdlib support

  var opcode = [];
  var err_offsets = [];
  var err_lookaheads = [];
  var err_count = 0;
  var errors = [];

  if( ( err_count = __parse( code, err_offsets, err_lookaheads, opcode ) ) > 0 ) {
    for( var i = 0; i < err_count; i++ ) {
      var line = calcLineNo(code, err_offsets[i]);
      errors.push({
        line : line,
        col :  getLineCol(code, err_offsets[i]),
        msg : 'Parse Error: unexpected token '+JSON.stringify(code[err_offsets[i]])+' expecting ' + err_lookaheads[i].map(JSON.stringify).join(' or '),
        excerpt : getLineExcerpt(code, err_offsets[i])
      });
    }
    return {errors: errors};
  }

  try {
    var ret = globalScope.executeTokenList(opcode); // the returned value
  }catch(e){
    if(!e.scope) process.exit(console.log(e));
    var trace = e.scope.backtrace().map(function(call) {
      return {caller: call.caller, at: calcLineNo(code, call.at)};
    });
    trace.unshift({caller: e.scope.meta.identifier, at: calcLineNo(code, e.offset)});
    return {errors: [{ msg: 'Runtime Error: '+e.message, line: calcLineNo(code, e.offset), col: getLineCol(code, e.offset), excerpt: getLineExcerpt(code, e.offset), backtrace: trace }]};
  };

  // post execution notes
  console.timeEnd('# Execution time');
  console.log('# Heap size: ', globalScope.env.heap.length);
  console.log('# Memory usage: ', b2mb(process.memoryUsage().heapUsed - startmemory));

  return {errors: errors};
};<|endoftext|>


<commit_before>import React from 'react'
import { Link } from 'react-router'
import RestService from '../RestService'
import LanguageStats from './LanguageStats'
import RPCButton from '../RPCButton'
import SFConfigIndex from '../SFConfig/Index'
import _ from 'lodash'
import update from 'react-addons-update'
import Switch from '../Switch'
import SFReleaseFilter from './Filter'

export default class SFReleaseList extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      data: [],
      current: null,
      connectionError: false,
      loading: false,
      filter: {
        // empty: false
      }
    }
  }

  componentWillMount() {
    this.loadData()
  }

  async loadData() {
    try {
      this.setState({loading: true})

      let data = await RestService.load('release')
      // console.log(data)

      this.setState({data: data, connectionError: false, loading: false})
    } catch (promise) {
//      console.log('error', promise)
      this.setState({connectionError: true, loading: false})
    }
  }

  // toggleFilter() {
  //   this.setState(update(this.state, {filter: {$set: {empty: !this.state.filter.empty}}}))
  // }

  filter(item) {
    if (this.state.filter.empty) {
      return _.isEmpty(item.subtitles)
    }

    for (let lang of ["en", "vi"]) {
      let fieldName = `lang_${lang}`
      if (this.state.filter[fieldName]) {
        return !item.subtitles[lang] || item.subtitles[lang].length == 0
      }
    }

    return true
  }

  updateFilter(filter) {
    this.setState({filter: filter})
  }

  render() {

    return (

Movies

            <button type="button" className="btn btn-box-tool" data-widget="collapse">

            </button>

            <button type="button" className="btn btn-box-tool"
              onClick={this.loadData.bind(this)}>

            </button>

            <RPCButton query="release/scan-all" name="Scan All"
              onComplete={this.loadData.bind(this)}/>

          <SFReleaseFilter onChange={this.updateFilter.bind(this)}/>

          {this.state.data.filter(this.filter.bind(this)).map((item, k) => {
            let stateClass = ""
            if (_.isEmpty(item.subtitles)) {
              stateClass = " bg-warning"
            }
            return (

                    {item.name}

                  <LanguageStats data={item.subtitles} />

                  <RPCButton query="release/download" params={{src: item.src}}
                    onComplete={this.loadData.bind(this)} name="Download" />
                    <RPCButton query="release/remove-subtitle" params={{src: item.src, name: item.name}}
                      onComplete={this.loadData.bind(this)} name="Remove Subtitles" />
                  <a href={`https://subscene.com/subtitles/title?q=${item.title_query}&l=`}
                    target="subscence" className="btn btn-default">
                     Subscene

            )
          })}

    )
  }
}
<commit_msg>web - download button bug: only download related subtitle<commit_after>import React from 'react'
import { Link } from 'react-router'
import RestService from '../RestService'
import LanguageStats from './LanguageStats'
import RPCButton from '../RPCButton'
import SFConfigIndex from '../SFConfig/Index'
import _ from 'lodash'
import update from 'react-addons-update'
import Switch from '../Switch'
import SFReleaseFilter from './Filter'

export default class SFReleaseList extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      data: [],
      current: null,
      connectionError: false,
      loading: false,
      filter: {
        // empty: false
      }
    }
  }

  componentWillMount() {
    this.loadData()
  }

  async loadData() {
    try {
      this.setState({loading: true})

      let data = await RestService.load('release')
      // console.log(data)

      this.setState({data: data, connectionError: false, loading: false})
    } catch (promise) {
//      console.log('error', promise)
      this.setState({connectionError: true, loading: false})
    }
  }

  // toggleFilter() {
  //   this.setState(update(this.state, {filter: {$set: {empty: !this.state.filter.empty}}}))
  // }

  filter(item) {
    if (this.state.filter.empty) {
      return _.isEmpty(item.subtitles)
    }

    for (let lang of ["en", "vi"]) {
      let fieldName = `lang_${lang}`
      if (this.state.filter[fieldName]) {
        return !item.subtitles[lang] || item.subtitles[lang].length == 0
      }
    }

    return true
  }

  updateFilter(filter) {
    this.setState({filter: filter})
  }

  render() {

    return (

Movies

            <button type="button" className="btn btn-box-tool" data-widget="collapse">

            </button>

            <button type="button" className="btn btn-box-tool"
              onClick={this.loadData.bind(this)}>

            </button>

            <RPCButton query="release/scan-all" name="Scan All"
              onComplete={this.loadData.bind(this)}/>

          <SFReleaseFilter onChange={this.updateFilter.bind(this)}/>

          {this.state.data.filter(this.filter.bind(this)).map((item, k) => {
            let stateClass = ""
            if (_.isEmpty(item.subtitles)) {
              stateClass = " bg-warning"
            }
            return (

                    {item.name}

                  <LanguageStats data={item.subtitles} />

                  <RPCButton query="release/download" params={{src: item.src, name: item.name}}
                    onComplete={this.loadData.bind(this)} name="Download" />
                    <RPCButton query="release/remove-subtitle" params={{src: item.src, name: item.name}}
                      onComplete={this.loadData.bind(this)} name="Remove Subtitles" />
                  <a href={`https://subscene.com/subtitles/title?q=${item.title_query}&l=`}
                    target="subscence" className="btn btn-default">
                     Subscene

            )
          })}

    )
  }
}
<|endoftext|>


<commit_before>var Path = require('path'),
    fs = require('fs'),
    seq = require('seq'),
    passError = require('passerror'),
    importRegExp = /(@import(?:\s*'.*?'|\s*".*?"|\s+url\((?:[^'"]*?|'[^']*'|"[^"]*")\));)/,
    importRegExpWithCaptures = /@import(?:\s*(['"])(.*?)\1|\s+url\((['"]|)(.*?)\3\));/;

// Returns flattened less text, accumulates seen files in the isSeenByFileName object provided by the caller.
module.exports = function flattenLessText(lessText, baseDir, isSeenByFileName, cb) {
    seq(lessText.split(importRegExp))
        .parMap(function (chunk) {
            var cb = this,
                matchImport = chunk.match(importRegExpWithCaptures);
            if (matchImport) {
                var importedFileName = Path.resolve(baseDir.replace(/\/*$/, '/'), matchImport[2] || matchImport[4]);
                isSeenByFileName[importedFileName] = true;
                fs.readFile(importedFileName, 'utf-8', passError(cb, function (importedLessText) {
                    flattenLessText(importedLessText, Path.dirname(importedFileName), isSeenByFileName, passError(cb, function (lessText) {
                        cb(null, lessText);
                    }));
                }));
            } else {
                this(null, chunk);
            }
        })
        .seq(function () {
            cb(null, this.stack.join(''));
        });
}
<commit_msg>flattenLessText: Remove comments before looking for @imports.<commit_after>var Path = require('path'),
    fs = require('fs'),
    seq = require('seq'),
    passError = require('passerror'),
    importRegExp = /(@import(?:\s*'.*?'|\s*".*?"|\s+url\((?:[^'"]*?|'[^']*'|"[^"]*")\));)/,
    importRegExpWithCaptures = /@import(?:\s*(['"])(.*?)\1|\s+url\((['"]|)(.*?)\3\));/;

// Returns flattened less text, accumulates seen files in the isSeenByFileName object provided by the caller.
module.exports = function flattenLessText(lessText, baseDir, isSeenByFileName, cb) {
    lessText = lessText.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/[^\r\n]*/, ''); // Remove comments
    seq(lessText.split(importRegExp))
        .parMap(function (chunk) {
            var cb = this,
                matchImport = chunk.match(importRegExpWithCaptures);
            if (matchImport) {
                var importedFileName = Path.resolve(baseDir.replace(/\/*$/, '/'), matchImport[2] || matchImport[4]);
                isSeenByFileName[importedFileName] = true;
                fs.readFile(importedFileName, 'utf-8', passError(cb, function (importedLessText) {
                    flattenLessText(importedLessText, Path.dirname(importedFileName), isSeenByFileName, passError(cb, function (lessText) {
                        cb(null, lessText);
                    }));
                }));
            } else {
                this(null, chunk);
            }
        })
        .seq(function () {
            cb(null, this.stack.join(''));
        });
}
<|endoftext|>


<commit_before>/**
 * Created by anonymous on 01/12/15 23:20.
 */

(function() {
    'use strict';

    angular
        .module('app.core', [
            /* Angular modules */
            'ngMaterial',
            'ngMessages',

            /* Cross-app modules */
            'blocks.exception',
            'blocks.logger',
            'blocks.routes',
            /* 3rd-party modules */
            'ui.router',
            'satellizer',
            'restangular',
            'ngStorage',
            'angular-loading-bar',
            'ngMdIcons',
            'vAccordion'
        ]);

    angular.module('blocks.exception', []);
    angular.module('blocks.logger', []);
    angular.module('blocks.routes', []);

})();<commit_msg>Update app.core.module.js<commit_after>/**
 * Created by anonymous on 01/12/15 23:20.
 */

(function() {
    'use strict';

    angular
        .module('app.core', [
            /* Angular modules */
            'ngMaterial',
            'ngMessages',
            'ngResource',
            'ngMessages',

            /* Cross-app modules */
            'blocks.exception',
            'blocks.logger',
            'blocks.routes',
            /* 3rd-party modules */
            'ui.router',
            'satellizer',
            'restangular',
            'ngStorage',
            'angular-loading-bar',
            'ngMdIcons',
            'toastr',
            'vAccordion'
        ]);

    angular.module('blocks.exception', []);
    angular.module('blocks.logger', []);
    angular.module('blocks.routes', []);

})();<|endoftext|>


<commit_before>import Avatar from '../Avatar';
import Icon from '../Icon';
import React from 'react';
import Typography from '../Typography';
import classNames from 'classnames';
import styles from './styles.css';

function HeaderCompositUser(props) {
    return (

            <Avatar
                link={props.profileLink}
                size={"standard"}
                user={"all"}
                image={props.avatar}
            />

                <Typography
                    className={styles.title}
                    type="bodyTextTitle"
                    onClick={props.onProfileClick}
                >

                    {props.title}

                </Typography>

                    {props.children}

            <Icon
                icon={props.icon}
                onClick={props.onIconClick}
                size="large1"
            />

    );
}

HeaderCompositUser.propTypes = {
    profileLink: React.PropTypes.string,
    avatar: React.PropTypes.string,
    children: React.PropTypes.node,
    className: React.PropTypes.string,
    icon: React.PropTypes.string,
    onIconClick: React.PropTypes.func,
    title: React.PropTypes.string
};

export default HeaderCompositUser;
<commit_msg>Small fix<commit_after>import Avatar from '../Avatar';
import Icon from '../Icon';
import React from 'react';
import Typography from '../Typography';
import classNames from 'classnames';
import styles from './styles.css';

function HeaderCompositUser(props) {
    return (

            <Avatar
                link={props.profileLink}
                size={"standard"}
                image={props.avatar}
            />

                <Typography
                    className={styles.title}
                    type="bodyTextTitle"
                    onClick={props.onProfileClick}
                >

                    {props.title}

                </Typography>

                    {props.children}

            <Icon
                icon={props.icon}
                onClick={props.onIconClick}
                size="large1"
            />

    );
}

HeaderCompositUser.propTypes = {
    profileLink: React.PropTypes.string,
    avatar: React.PropTypes.string,
    children: React.PropTypes.node,
    className: React.PropTypes.string,
    icon: React.PropTypes.string,
    onIconClick: React.PropTypes.func,
    title: React.PropTypes.string
};

export default HeaderCompositUser;
<|endoftext|>


<commit_before>(function() {
	/**
	 * Main script for the game AD. Uses canvas to display the game board.
	 */

	// Creation of the 4 arrows to move the rows and columns.
	var d = document, createElement = 'createElement',
		arrow = d[createElement]('canvas'),
		controlSize = 100,
		controlThird = controlSize / 3,
		controlTwoThird = controlThird * 2,
		controlHalf = controlSize / 2,
		controls = [
			[
				d[createElement]('img'),
				[controlThird, controlThird],
				[controlTwoThird, controlThird],
				[controlHalf, controlTwoThird]
			],
			[
				d[createElement]('img'),
				[controlTwoThird, controlThird],
				[controlTwoThird, controlTwoThird],
				[controlThird, controlHalf]
			],
			[
				d[createElement]('img'),
				[controlThird, controlTwoThird],
				[controlTwoThird, controlTwoThird],
				[controlHalf, controlThird]
			],
			[
				d[createElement]('img'),
				[controlThird, controlThird],
				[controlThird, controlTwoThird],
				[controlTwoThird, controlHalf]
			]
		],
		ctx,
		c,
		und = undefined,
		// attributes strings
		cellSize = 'cellSize',
		gridWidth = 'gridWidth',
		grid = 'grid',

		// Methods
		ad,
		_init,
		_createInformationsTable,
		_getInformation,
		_updateInformation,
		_randomInt,
		_generateColors,
		_generateGrid,
		_displayGrid,
		_setEvents,
		_detectBlobs;

	if (!arrow.getContext) {
		throw 'This browser does not support the use of canvas';
	}

	arrow.width = arrow.height = controlSize;
	ctx = arrow.getContext('2d');

	ctx.fillStyle = '#888';
	ctx.strokeRect(0, 0, controlSize, controlSize);
	for (c = 0; c < 4; c++) {
		ctx.clearRect(1, 1, controlSize - 2, controlSize - 2);
		ctx.beginPath();
		ctx.moveTo(controls[c][1][0], controls[c][1][1]);
		ctx.lineTo(controls[c][2][0], controls[c][2][1]);
		ctx.lineTo(controls[c][3][0], controls[c][3][1]);
		ctx.fill();
		controls[c][0].src = arrow.toDataURL("image/png").replace("image/png", "image/octet-stream");
	}

	/**
	 * Game construct
	 */
	ad = function(parent, options) {
		var tmp, size, canvas;
		if (parent.tagName != 'DIV') {
			tmp = B.create('div');
			parent.parentNode.replaceChild(tmp, parent);
			parent = tmp;
		}

		this.parent = parent;
		options = options || {};
		size = options.size||300;
		canvas = B.create('canvas', {width: size, height: size}, this.parent);

		this.ctx = canvas.getContext('2d');
		this._controlButtons = [],
		_init.apply(this, [options.nbCellsSide||4, options.nbColors||4]);
	};

	_createInformationsTable = function() {
		this.infos = {blobs: ['Blobs', 0], moves: ['Moves', 0], colors: ['Colors', this.colors.length]};

		Object.keys(this.infos).forEach(function(key) {
			this.infos[key][1] = B.create('span', {text: this.infos[key][1]}, B.create('div', {text: this.infos[key][0] + ': '}, this.parent));
		}.bind(this));
	};

	_getInformation = function(info) {
		return this.infos[info] ? parseInt(this.infos[info][1].innerHTML) : false;
	};

	_updateInformation = function(info, value) {
		if (!this.infos[info]) return false;

		this.infos[info][1].innerHTML = value;
	};

	/**
	 * Method to init the game
	 * Private method
	 */
	_init = function(gridWidth, nbColors) {
		_generateColors.apply(this, [nbColors]);
		_generateGrid.apply(this, [gridWidth, nbColors]);
		_displayGrid.apply(this, [true]);
		_createInformationsTable.apply(this);
		_detectBlobs.apply(this);
		_setEvents.apply(this);
	};

	/**
	 * Method to generate a random integer
	 *
	 * Private method
	 */
	_randomInt = function(maxExcluded) {
		return 0 | Math.random() * maxExcluded;
	};

	/**
	 * Generate an array of colors. A color is an array of 3 integer(0, 255).
	 * The first color is randomly generated, the last one is the opposite of
	 * the first one. The others are calculated with a lerp computation.
	 */
	_generateColors = function(nb) {
		var colors = [],
			c,
			last = nb - 1,
			percentColor,
			_generateRandomColor,
			_lerp;

		_generateRandomColor = function() {
			return [
				_randomInt(256),
				_randomInt(256),
				_randomInt(256)
			]
		};

		_lerp = function(val1, val2, ratio) {
			return 0 | (Math.min(val1, val2) + Math.abs(val1 - val2) * ratio);
		};

		colors[0] = _generateRandomColor();
		colors[last] = [];

		for (c = 0; c < 3; c++) {
			colors[last].push((colors[0][c] + 128) % 256);
		}

		for (c = 1; c < last; c++) {
			percentColor = c / last;
			colors[c] = [
				_lerp(colors[0][0], colors[last][0], percentColor),
				_lerp(colors[0][2], colors[last][1], percentColor),
				_lerp(colors[0][1], colors[last][2], percentColor)
			];
		}

		this.colors = colors;
		this.nbColors = colors.length;
	};

	/**
	 * Generate the grid from a width (the grid is a square) and a number of
	 * colors.
	 * The returned grid is a 2 dimensions array containing, for each cell, an
	 * integer corresponding to the cell's color index (0, nbColors - 1)
	 */
	_generateGrid = function(width, nbColors) {
		var x, y;

		this[grid] = [];
		this[gridWidth] = width;

		for (x = 0; x < width; x++) {
			this[grid][x] = [];
			for (y = 0; y < width; y++) {
				this[grid][x][y] = _randomInt(nbColors);
			}
		}
	};

	/**
	 * Display the grid in the canvas
	 */
	_displayGrid = function(init) {
		var canvasWidth = this.ctx.canvas.clientWidth,
			x, y,
			_displayCell,
			_displayControl;

		this[cellSize] = canvasWidth / (this[gridWidth] + 2);

		_displayCell = function(x, y) {
			var color = this.colors[this[grid][x][y]];
			this.ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
			this.ctx.fillRect((x + 1) * this[cellSize], (y + 1) * this[cellSize], this[cellSize], this[cellSize]);
		};

		_displayControl = function(contX, contY, ctrls, c, tmp) {
			for (c = 0; c < ctrls.length; c++) {
				this._controlButtons.push([contX, contY]);
				this.ctx.drawImage(controls[ctrls[c]][0], contX, contY, this[cellSize], this[cellSize]);
				tmp = contX;
				contX = contY;
				contY = tmp;
			}
		};

		for (x = 0; x < this[gridWidth]; x++) {
			if (init) {
				// control buttons
				_displayControl.apply(this, [(x + 1) * this[cellSize], 0, [0, 3]]);
				_displayControl.apply(this, [canvasWidth - this[cellSize], (x + 1) * this[cellSize], [1, 2]]);
			}

			for (y = 0; y < this[gridWidth]; y++) {
				_displayCell.apply(this, [x, y]);
			}
		}
	};

	/**
	 * Method to set the click event on the game, to move the controls.
	 */
	_setEvents = function() {
		/**
		 * Method to check if the player clicked on a control.
		 */
		var _onControl = function(x, y) {
			var b, nbButtons = this._controlButtons.length;

			for (b = 0; b < nbButtons; b++) {
				if (
					this._controlButtons[b][0] <= x
					&& x <= this._controlButtons[b][0] + this[cellSize]
					&& this._controlButtons[b][1] <= y
					&& y <= this._controlButtons[b][1] + this[cellSize]
				) {
					break;
				}
			}

			return b == nbButtons ? null : b;
		};

		B.addEvent(this.parent, 'click', function(e){
			var button = _onControl.apply(this, [e.layerX, e.layerY]),
				_shiftDown, _shiftRight, _shiftLeft, _shiftUp,
				row, nbBlobs;
			if (button == null) return;

			/**
			 * Methods to move a row or column in the 4 directions
			 */
			_shiftDown = function(col) {
				var last = this[grid][col][this[grid][col].length - 1];
				this[grid][col].pop();
				this[grid][col].unshift(last);
			};
			_shiftRight = function(row) {
				var old1, old2 = -1, r, last = this[grid].length - 1;
				for (r in this[grid]) {
					old1 = this[grid][r][row];
					this[grid][r][row] = ~old2 ? old2 : this[grid][(r + last) % this[grid].length][row];
					old2 = old1;
				}
			};
			_shiftUp = function(col) {
				var first = this[grid][col][0];
				this[grid][col].shift();
				this[grid][col].push(first);
			};
			_shiftLeft = function(row) {
				var r, first = this[grid][0][row];
				for (r = 0; r < this[gridWidth]; r++) {
					this[grid][r][row] = this[grid][(parseInt(r) + 1) % this[grid].length][row];
				}
				this[grid][this[grid].length - 1][row] = first;
			};

			row = 0|button/4;
			switch (button % 4) {
				case 0:
					_shiftDown.apply(this, [row]);
					break;
				case 1:
					_shiftRight.apply(this, [row]);
					break;
				case 2:
					_shiftLeft.apply(this, [row]);
					break;
				case 3:
					_shiftUp.apply(this, [row]);
					break;
			};

			nbBlobs = _detectBlobs.apply(this);
			_displayGrid.apply(this, [false]);

			// Winning condition
			if (nbBlobs == this.nbColors) {
			}
		}.bind(this));
	};

	/**
	 * Method to detect the blobs (like in picture processing) in the board.
	 * Returns the number of blobs of the board.
	 */
	_detectBlobs = function() {
		var blobs, nbBlobs = 0,
			x, y,
			nbCells = this[gridWidth] * this[gridWidth],
			_setBlobsAndPropagate;

		blobs = new Array(nbCells);

		_setBlobsAndPropagate = function(x, y, id) {
			var current = this[grid][x][y],
				currentIndex = y * this[gridWidth] + x,
				north = currentIndex - this[gridWidth],
				south = currentIndex + this[gridWidth],
				east = currentIndex + 1,
				west = currentIndex - 1;
			blobs[currentIndex] = id;

			if (north > 0 && blobs[north] == und && this[grid][x][y-1] == current) {
				_setBlobsAndPropagate.apply(this, [x, y-1, id]);
			}
			if (east%this[gridWidth] > currentIndex%this[gridWidth] && blobs[east] == und && this[grid][x+1][y] == current) {
				_setBlobsAndPropagate.apply(this, [x+1, y, id]);
			}
			if (south < nbCells && blobs[south] == und && this[grid][x][y+1] == current) {
				_setBlobsAndPropagate.apply(this, [x, y+1, id]);
			}
			if (Math.abs(west%this[gridWidth]) < currentIndex%this[gridWidth] && blobs[west] == und && this[grid][x-1][y] == current) {
				_setBlobsAndPropagate.apply(this, [x-1, y, id]);
			}
		};

		for (x = 0; x < this[gridWidth]; x++) {
			for (y = 0; y < this[gridWidth]; y++) {
				if (blobs[y * this[gridWidth] + x] != und) {
					continue;
				}

				_setBlobsAndPropagate.apply(this, [x, y, nbBlobs]);
				nbBlobs++;
			}
		}

		return nbBlobs;
	};

	window.Ad = ad;
})();
<commit_msg>update the number of moves and blobs after each turn<commit_after>(function() {
	/**
	 * Main script for the game AD. Uses canvas to display the game board.
	 */

	// Creation of the 4 arrows to move the rows and columns.
	var d = document, createElement = 'createElement',
		arrow = d[createElement]('canvas'),
		controlSize = 100,
		controlThird = controlSize / 3,
		controlTwoThird = controlThird * 2,
		controlHalf = controlSize / 2,
		controls = [
			[
				d[createElement]('img'),
				[controlThird, controlThird],
				[controlTwoThird, controlThird],
				[controlHalf, controlTwoThird]
			],
			[
				d[createElement]('img'),
				[controlTwoThird, controlThird],
				[controlTwoThird, controlTwoThird],
				[controlThird, controlHalf]
			],
			[
				d[createElement]('img'),
				[controlThird, controlTwoThird],
				[controlTwoThird, controlTwoThird],
				[controlHalf, controlThird]
			],
			[
				d[createElement]('img'),
				[controlThird, controlThird],
				[controlThird, controlTwoThird],
				[controlTwoThird, controlHalf]
			]
		],
		ctx,
		c,
		und = undefined,
		// attributes strings
		cellSize = 'cellSize',
		gridWidth = 'gridWidth',
		grid = 'grid',

		// Methods
		ad,
		_init,
		_createInformationsTable,
		_getInformation,
		_updateInformation,
		_randomInt,
		_generateColors,
		_generateGrid,
		_displayGrid,
		_setEvents,
		_detectBlobs;

	if (!arrow.getContext) {
		throw 'This browser does not support the use of canvas';
	}

	arrow.width = arrow.height = controlSize;
	ctx = arrow.getContext('2d');

	ctx.fillStyle = '#888';
	ctx.strokeRect(0, 0, controlSize, controlSize);
	for (c = 0; c < 4; c++) {
		ctx.clearRect(1, 1, controlSize - 2, controlSize - 2);
		ctx.beginPath();
		ctx.moveTo(controls[c][1][0], controls[c][1][1]);
		ctx.lineTo(controls[c][2][0], controls[c][2][1]);
		ctx.lineTo(controls[c][3][0], controls[c][3][1]);
		ctx.fill();
		controls[c][0].src = arrow.toDataURL("image/png").replace("image/png", "image/octet-stream");
	}

	/**
	 * Game construct
	 */
	ad = function(parent, options) {
		var tmp, size, canvas;
		if (parent.tagName != 'DIV') {
			tmp = B.create('div');
			parent.parentNode.replaceChild(tmp, parent);
			parent = tmp;
		}

		this.parent = parent;
		options = options || {};
		size = options.size||300;
		canvas = B.create('canvas', {width: size, height: size}, this.parent);

		this.ctx = canvas.getContext('2d');
		this._controlButtons = [],
		_init.apply(this, [options.nbCellsSide||4, options.nbColors||4]);
	};

	_createInformationsTable = function() {
		this.infos = {blobs: ['Blobs', 0], moves: ['Moves', 0], colors: ['Colors', this.colors.length]};

		Object.keys(this.infos).forEach(function(key) {
			this.infos[key][1] = B.create('span', {text: this.infos[key][1]}, B.create('div', {text: this.infos[key][0] + ': '}, this.parent));
		}.bind(this));
	};

	_getInformation = function(info) {
		return this.infos[info] ? parseInt(this.infos[info][1].innerHTML) : false;
	};

	_updateInformation = function(info, value) {
		if (!this.infos[info]) return false;

		this.infos[info][1].innerHTML = value;
	};

	/**
	 * Method to init the game
	 * Private method
	 */
	_init = function(gridWidth, nbColors) {
		_generateColors.apply(this, [nbColors]);
		_generateGrid.apply(this, [gridWidth, nbColors]);
		_displayGrid.apply(this, [true]);
		_createInformationsTable.apply(this);
		_detectBlobs.apply(this);
		_setEvents.apply(this);
	};

	/**
	 * Method to generate a random integer
	 *
	 * Private method
	 */
	_randomInt = function(maxExcluded) {
		return 0 | Math.random() * maxExcluded;
	};

	/**
	 * Generate an array of colors. A color is an array of 3 integer(0, 255).
	 * The first color is randomly generated, the last one is the opposite of
	 * the first one. The others are calculated with a lerp computation.
	 */
	_generateColors = function(nb) {
		var colors = [],
			c,
			last = nb - 1,
			percentColor,
			_generateRandomColor,
			_lerp;

		_generateRandomColor = function() {
			return [
				_randomInt(256),
				_randomInt(256),
				_randomInt(256)
			]
		};

		_lerp = function(val1, val2, ratio) {
			return 0 | (Math.min(val1, val2) + Math.abs(val1 - val2) * ratio);
		};

		colors[0] = _generateRandomColor();
		colors[last] = [];

		for (c = 0; c < 3; c++) {
			colors[last].push((colors[0][c] + 128) % 256);
		}

		for (c = 1; c < last; c++) {
			percentColor = c / last;
			colors[c] = [
				_lerp(colors[0][0], colors[last][0], percentColor),
				_lerp(colors[0][2], colors[last][1], percentColor),
				_lerp(colors[0][1], colors[last][2], percentColor)
			];
		}

		this.colors = colors;
		this.nbColors = colors.length;
	};

	/**
	 * Generate the grid from a width (the grid is a square) and a number of
	 * colors.
	 * The returned grid is a 2 dimensions array containing, for each cell, an
	 * integer corresponding to the cell's color index (0, nbColors - 1)
	 */
	_generateGrid = function(width, nbColors) {
		var x, y;

		this[grid] = [];
		this[gridWidth] = width;

		for (x = 0; x < width; x++) {
			this[grid][x] = [];
			for (y = 0; y < width; y++) {
				this[grid][x][y] = _randomInt(nbColors);
			}
		}
	};

	/**
	 * Display the grid in the canvas
	 */
	_displayGrid = function(init) {
		var canvasWidth = this.ctx.canvas.clientWidth,
			x, y,
			_displayCell,
			_displayControl;

		this[cellSize] = canvasWidth / (this[gridWidth] + 2);

		_displayCell = function(x, y) {
			var color = this.colors[this[grid][x][y]];
			this.ctx.fillStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
			this.ctx.fillRect((x + 1) * this[cellSize], (y + 1) * this[cellSize], this[cellSize], this[cellSize]);
		};

		_displayControl = function(contX, contY, ctrls, c, tmp) {
			for (c = 0; c < ctrls.length; c++) {
				this._controlButtons.push([contX, contY]);
				this.ctx.drawImage(controls[ctrls[c]][0], contX, contY, this[cellSize], this[cellSize]);
				tmp = contX;
				contX = contY;
				contY = tmp;
			}
		};

		for (x = 0; x < this[gridWidth]; x++) {
			if (init) {
				// control buttons
				_displayControl.apply(this, [(x + 1) * this[cellSize], 0, [0, 3]]);
				_displayControl.apply(this, [canvasWidth - this[cellSize], (x + 1) * this[cellSize], [1, 2]]);
			}

			for (y = 0; y < this[gridWidth]; y++) {
				_displayCell.apply(this, [x, y]);
			}
		}
	};

	/**
	 * Method to set the click event on the game, to move the controls.
	 */
	_setEvents = function() {
		/**
		 * Method to check if the player clicked on a control.
		 */
		var _onControl = function(x, y) {
			var b, nbButtons = this._controlButtons.length;

			for (b = 0; b < nbButtons; b++) {
				if (
					this._controlButtons[b][0] <= x
					&& x <= this._controlButtons[b][0] + this[cellSize]
					&& this._controlButtons[b][1] <= y
					&& y <= this._controlButtons[b][1] + this[cellSize]
				) {
					break;
				}
			}

			return b == nbButtons ? null : b;
		};

		B.addEvent(this.parent, 'click', function(e){
			var button = _onControl.apply(this, [e.layerX, e.layerY]),
				_shiftDown, _shiftRight, _shiftLeft, _shiftUp,
				row, nbBlobs;
			if (button == null) return;

			/**
			 * Methods to move a row or column in the 4 directions
			 */
			_shiftDown = function(col) {
				var last = this[grid][col][this[grid][col].length - 1];
				this[grid][col].pop();
				this[grid][col].unshift(last);
			};
			_shiftRight = function(row) {
				var old1, old2 = -1, r, last = this[grid].length - 1;
				for (r in this[grid]) {
					old1 = this[grid][r][row];
					this[grid][r][row] = ~old2 ? old2 : this[grid][(r + last) % this[grid].length][row];
					old2 = old1;
				}
			};
			_shiftUp = function(col) {
				var first = this[grid][col][0];
				this[grid][col].shift();
				this[grid][col].push(first);
			};
			_shiftLeft = function(row) {
				var r, first = this[grid][0][row];
				for (r = 0; r < this[gridWidth]; r++) {
					this[grid][r][row] = this[grid][(parseInt(r) + 1) % this[grid].length][row];
				}
				this[grid][this[grid].length - 1][row] = first;
			};

			row = 0|button/4;
			switch (button % 4) {
				case 0:
					_shiftDown.apply(this, [row]);
					break;
				case 1:
					_shiftRight.apply(this, [row]);
					break;
				case 2:
					_shiftLeft.apply(this, [row]);
					break;
				case 3:
					_shiftUp.apply(this, [row]);
					break;
			};

			nbBlobs = _detectBlobs.apply(this);
			_updateInformation.apply(this, ['moves', parseInt(_getInformation.apply(this, ['moves'])) + 1]);
			_displayGrid.apply(this, [false]);

			// Winning condition
			if (nbBlobs == this.nbColors) {
			}
		}.bind(this));
	};

	/**
	 * Method to detect the blobs (like in picture processing) in the board.
	 * Returns the number of blobs of the board.
	 */
	_detectBlobs = function() {
		var blobs, nbBlobs = 0,
			x, y,
			nbCells = this[gridWidth] * this[gridWidth],
			_setBlobsAndPropagate;

		blobs = new Array(nbCells);

		_setBlobsAndPropagate = function(x, y, id) {
			var current = this[grid][x][y],
				currentIndex = y * this[gridWidth] + x,
				north = currentIndex - this[gridWidth],
				south = currentIndex + this[gridWidth],
				east = currentIndex + 1,
				west = currentIndex - 1;
			blobs[currentIndex] = id;

			if (north > 0 && blobs[north] == und && this[grid][x][y-1] == current) {
				_setBlobsAndPropagate.apply(this, [x, y-1, id]);
			}
			if (east%this[gridWidth] > currentIndex%this[gridWidth] && blobs[east] == und && this[grid][x+1][y] == current) {
				_setBlobsAndPropagate.apply(this, [x+1, y, id]);
			}
			if (south < nbCells && blobs[south] == und && this[grid][x][y+1] == current) {
				_setBlobsAndPropagate.apply(this, [x, y+1, id]);
			}
			if (Math.abs(west%this[gridWidth]) < currentIndex%this[gridWidth] && blobs[west] == und && this[grid][x-1][y] == current) {
				_setBlobsAndPropagate.apply(this, [x-1, y, id]);
			}
		};

		for (x = 0; x < this[gridWidth]; x++) {
			for (y = 0; y < this[gridWidth]; y++) {
				if (blobs[y * this[gridWidth] + x] != und) {
					continue;
				}

				_setBlobsAndPropagate.apply(this, [x, y, nbBlobs]);
				nbBlobs++;
			}
		}

		_updateInformation.apply(this, ['blobs', nbBlobs]);
		return nbBlobs;
	};

	window.Ad = ad;
})();
<|endoftext|>


<commit_before>const util = require('util');

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);

	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	for (var i in reasons) {
		if (!(reasons[i] instanceof CuvvaError))
			reasons[i] = CuvvaError.coerce(reasons[i]);
	}

	CuvvaError.super_(code);
	Error.captureStackTrace(this, this.constructor);

	const statusCode = CuvvaError.httpStatusMap[code] || 500;

	Object.defineProperty(this, 'name', { get: function () { return 'CuvvaError'; } });
	Object.defineProperty(this, 'message', { get: function () { return this.code; } });
	Object.defineProperty(this, 'httpStatus', { get: function () { return statusCode; } });

	this.code = code;
	this.meta = meta;
	this.reasons = reasons;
}

util.inherits(CuvvaError, Error);
module.exports = CuvvaError;

CuvvaError.httpStatusMap = {};

CuvvaError.coerce = function (error) {
	if (error instanceof CuvvaError)
		return error;

	var newError;

	if (error instanceof Error) {
		newError = new CuvvaError('unknown', { message: error.message });
		Object.defineProperty(newError, 'stack', { get: function () { return error.stack; } });
	} else {
		newError = new CuvvaError('unknown', { error: error });
	}

	if (error.statusCode)
		newError.httpStatus = error.statusCode;

	return newError;
};
<commit_msg>Better method of overriding status code<commit_after>const util = require('util');

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);

	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	for (var i in reasons) {
		if (!(reasons[i] instanceof CuvvaError))
			reasons[i] = CuvvaError.coerce(reasons[i]);
	}

	CuvvaError.super_(code);
	Error.captureStackTrace(this, this.constructor);

	const statusCode = CuvvaError.httpStatusMap[code] || 500;

	Object.defineProperty(this, 'name', { get: function () { return 'CuvvaError'; } });
	Object.defineProperty(this, 'message', { get: function () { return this.code; } });
	Object.defineProperty(this, 'httpStatus', { get: function () { return statusCode; } });

	this.code = code;
	this.meta = meta;
	this.reasons = reasons;
}

util.inherits(CuvvaError, Error);
module.exports = CuvvaError;

CuvvaError.httpStatusMap = {};

CuvvaError.coerce = function (error) {
	if (error instanceof CuvvaError)
		return error;

	var newError;

	if (error instanceof Error) {
		newError = new CuvvaError('unknown', { message: error.message });
		Object.defineProperty(newError, 'stack', { get: function () { return error.stack; } });
	} else {
		newError = new CuvvaError('unknown', { error: error });
	}

	if (error.statusCode)
		Object.defineProperty(newError, 'httpStatus', { get: function () { return error.statusCode; } });

	return newError;
};
<|endoftext|>


<commit_before>(function () {
  "use strict";

  angular
    .module('mnGroups')
    .controller('mnGroupsGroupDialogController', mnGroupsGroupDialogController);

  function mnGroupsGroupDialogController($scope, $uibModalInstance, mnGroupsService, mnPromiseHelper, group) {
    var vm = this;

    vm.isEditMode = !!group;
    vm.groupName = group ? group.name : "";
    vm.onSubmit = onSubmit;

    function onSubmit() {
      if (vm.viewLoading) {
        return;
      }

      var promise = vm.isEditMode ? mnGroupsService.updateGroup(vm.groupName, group.uri) :
                                    mnGroupsService.createGroup(vm.groupName);
      mnPromiseHelper(vm, promise, $uibModalInstance)
        .showErrorsSensitiveSpinner()
        .catchGlobalErrors()
        .closeOnSuccess()
        .reloadState();
    }
  }
})();
<commit_msg>spock-ui: MB-21064: use catchErrors instead of catchGlobalErrors<commit_after>(function () {
  "use strict";

  angular
    .module('mnGroups')
    .controller('mnGroupsGroupDialogController', mnGroupsGroupDialogController);

  function mnGroupsGroupDialogController($scope, $uibModalInstance, mnGroupsService, mnPromiseHelper, group) {
    var vm = this;

    vm.isEditMode = !!group;
    vm.groupName = group ? group.name : "";
    vm.onSubmit = onSubmit;

    function onSubmit() {
      if (vm.viewLoading) {
        return;
      }

      var promise = vm.isEditMode ? mnGroupsService.updateGroup(vm.groupName, group.uri) :
                                    mnGroupsService.createGroup(vm.groupName);
      mnPromiseHelper(vm, promise, $uibModalInstance)
        .showErrorsSensitiveSpinner()
        .catchErrors()
        .closeOnSuccess()
        .reloadState();
    }
  }
})();
<|endoftext|>


<commit_before>/*global module, process*/
const Buffer = require('buffer').Buffer;
const Stream = require('stream');
const util = require('util');

function DataStream(data) {
  this.buffer = Buffer(data||0);
  this.writable = true;
  this.readable = true;
  if (!data)
    return this;
  if (typeof data.pipe === 'function')
    data.pipe(this);
  else if (data.length) {
    this.writable = false;
    process.nextTick(function () {
      this.buffer = data;
      this.emit('end', data);
      this.readable = false;
      this.emit('close');
    }.bind(this));
  }
}
util.inherits(DataStream, Stream);

DataStream.prototype.write = function write(data) {
  this.buffer = Buffer.concat([this.buffer, Buffer(data)]);
  this.emit('data', data);
};

DataStream.prototype.end = function end(data) {
  if (data)
    this.write(data);
  this.emit('end', data);
  this.emit('close');
  this.writable = false;
  this.readable = false;
};

module.exports = DataStream;
<commit_msg>fix(DataStream) dont pass invalid inputs into Buffer<commit_after>/*global module, process*/
const Buffer = require('buffer').Buffer;
const Stream = require('stream');
const util = require('util');

function DataStream(data) {
  this.buffer = null;
  this.writable = true;
  this.readable = true;

  // No input
  if (!data) {
    this.buffer = new Buffer(0);
    return this;
  }

  // Stream
  if (typeof data.pipe === 'function') {
    this.buffer = new Buffer(0);
    data.pipe(this);
    return this;
  }

  // Buffer or String
  if (data.length) {
    this.writable = false;
    process.nextTick(function () {
      this.buffer = data;
      this.emit('end', data);
      this.readable = false;
      this.emit('close');
    }.bind(this));
  }
}
util.inherits(DataStream, Stream);

DataStream.prototype.write = function write(data) {
  this.buffer = Buffer.concat([this.buffer, Buffer(data)]);
  this.emit('data', data);
};

DataStream.prototype.end = function end(data) {
  if (data)
    this.write(data);
  this.emit('end', data);
  this.emit('close');
  this.writable = false;
  this.readable = false;
};

module.exports = DataStream;
<|endoftext|>


<commit_before>import React from 'react'
import MediaQuery from 'react-responsive'

const breakpoints = {
	desktop: '(min-width: 1025px)',
	tablet: '(min-width: 768px) and (max-width: 1024px)',
	phone: '(max-width: 767px)',
}

const Breakpoint = props => {
	return (

Device Test!

			<MediaQuery minDeviceWidth={1224}>

You are a desktop or laptop

			</MediaQuery>
			<MediaQuery maxWidth={1224}>

You are sized like a tablet or mobile phone though

			</MediaQuery>
			<MediaQuery minDeviceWidth={1824}>

You also have a huge screen

			</MediaQuery>
			<MediaQuery maxDeviceWidth={1224}>

You are a tablet or mobile phone

			</MediaQuery>
			<MediaQuery orientation="portrait">

You are portrait

			</MediaQuery>
			<MediaQuery orientation="landscape">

You are landscape

			</MediaQuery>
			<MediaQuery minResolution="2dppx">

You are retina

			</MediaQuery>

	)
}

export default Breakpoint

// export function DesktopBreakpoint(props) {
// 	console.log('DESKTOP BREAKPOINT')
// 	return <Breakpoint name="desktop">{props.children}</Breakpoint>
// }
<commit_msg>Get breakpoints to work<commit_after>import React from 'react'
import Responsive from 'react-responsive'

const DESKTOP_MIN = 992
const TABLET_MIN = 768
const TABLET_MAX = 991
const PHONE_MAX = 767

const Desktop = props => <Responsive {...props} minWidth={DESKTOP_MIN} />
const Tablet = props => (
	<Responsive {...props} minWidth={TABLET_MIN} maxWidth={TABLET_MAX} />
)
const Phone = props => <Responsive {...props} maxWidth={PHONE_MAX} />

export { Desktop, Tablet, Phone }
<|endoftext|>