<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, RequestTimeout, ArgumentsRequired } = require ('./base/errors');
const { ROUND, DECIMAL_PLACES, NO_PADDING } = require ('./base/functions/number');

//  ---------------------------------------------------------------------------

module.exports = class bw extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bw',
            'name': 'bw.com',
            'countries': [ 'CN' ],
            'rateLimit': 1500,
            'version': 'v1',
            'has': {
                'cancelAllOrders': false,
                'cancelOrder': true,
                'cancelOrders': false,
                'CORS': false,
                'createDepositAddress': false,
                'createLimitOrder': true,
                'createMarketOrder': false,
                'createOrder': true,
                'deposit': false,
                'editOrder': false,
                'fetchBalance': true,
                'fetchBidsAsks': false,
                'fetchClosedOrders': false,
                'fetchCurrencies': true,
                'fetchDepositAddress': false,
                'fetchDeposits': false,
                'fetchFundingFees': false,
                'fetchL2OrderBook': false,
                'fetchLedger': false,
                'fetchMarkets': true,
                'fetchMyTrades': false,
                'fetchOHLCV': false,
                'fetchOpenOrders': false,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrderBooks': false,
                'fetchOrders': false,
                'fetchTicker': false,
                'fetchTickers': false,
                'fetchTrades': false,
                'fetchTradingFee': false,
                'fetchTradingFees': false,
                'fetchTradingLimits': false,
                'fetchTransactions': false,
                'fetchWithdrawals': false,
                'privateAPI': false,
                'publicAPI': false,
                'withdraw': false,
            },
            'timeframes': {
                '1m': '1M',
                '5m': '5M',
                '15m': '15M',
                '30m': '30M',
                '1h': '1H',
                '1w': '1W',
            },
            'urls': {
                'api': 'https://www.bw.com/',
                'www': 'https://www.bw.com',
                'doc': 'https://www.bw.com/restApi',
                'fees': 'https://www.bw.com/feesRate',
                'referral': '',
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': 0.1 / 100,
                    'maker': 0.1 / 100,
                    'tiers': {
                        'taker': [
                            [0, 0.1 / 100],
                        ],
                        'maker': [
                            [0, 0.1 / 100],
                        ],
                    },
                },
                'funding': {
                },
            },
            'exceptions': {
                // TODO
                'exact': {
                    '999': AuthenticationError,
                },
            },
            'api': {
                'public': {
                    'get': [
                        'exchange/config/controller/website/marketcontroller/getByWebId',
                        'exchange/config/controller/website/currencycontroller/getCurrencyList',
                        'api/data/v1/entrusts',
                        'api/data/v1/klines',
                    ],
                },
                'private': {
                    'get': [
                        'exchange/entrust/controller/website/EntrustController/getEntrustById',
                    ],
                    'post': [
                        'exchange/fund/controller/website/fundcontroller/findbypage',
                        'exchange/entrust/controller/website/EntrustController/addEntrust',
                        'exchange/entrust/controller/website/EntrustController/cancelEntrust',
                    ],
                },
            },
            'commonCurrencies': {
            },
            'precisionMode': DECIMAL_PLACES,
            'options': {
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetExchangeConfigControllerWebsiteMarketcontrollerGetByWebId (params);
        const markets = this.safeValue (response, 'datas', []);
        const result = [];
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const id = this.safeString (market, 'marketId');
            const numericId = parseInt (id);
            const name = this.safeStringUpper (market, 'name');
            let [ quote, base ] = name.split ('_');
            base = this.safeCurrencyCode (base);
            quote = this.safeCurrencyCode (quote);
            const baseId = this.safeString (market, 'buyerCurrencyId');
            const quoteId = this.safeString (market, 'sellerCurrencyId');
            const baseNumericId = parseInt (baseId);
            const quoteNumericId = parseInt (quoteId);
            const symbol = quote + '/' + base;
            const state = this.safeInteger (market, 'state');
            const active = state === 1;
            result.push ({
                'id': id,
                'active': active,
                'numericId': numericId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'baseNumericId': baseNumericId,
                'quoteNumericId': quoteNumericId,
                'info': market,
                'precision': {
                    'amount': this.safeInteger (market, 'amountDecimal'),
                    'price': this.safeInteger (market, 'priceDecimal'),
                },
                'limits': {
                    'amount': {
                        'min': this.safeFloat (market, 'minAmount'),
                        'max': undefined,
                    },
                    'price': {
                        'min': 0,
                        'max': undefined,
                    },
                    'cost': {
                        'min': 0,
                        'max': undefined,
                    },
                },
            });
        }
        return result;
    }

    async fetchCurrencies (params = {}) {
        const response = await this.publicGetExchangeConfigControllerWebsiteCurrencycontrollerGetCurrencyList (params);
        const currencies = this.safeValue (response, 'datas', []);
        const result = {};
        for (let i = 0; i < currencies.length; i++) {
            const currency = currencies[i];
            const id = this.safeString (currency, 'currencyId');
            const code = this.safeCurrencyCode (this.safeStringUpper (currency, 'name'));
            const state = this.safeInteger (currency, 'state');
            const active = state === 1;
            result[code] = {
                'id': id,
                'code': code,
                'info': currency,
                'name': code,
                'active': active,
                'fee': undefined,
                'precision': undefined,
                'limits': {
                    'amount': {
                        'min': parseFloat (this.safeInteger(currency, 'limitAmount')),
                        'max': undefined,
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': parseFloat (this.safeInteger(currency, 'onceDrawLimit')),
                    },
                },
            };
        }
        return result;
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
        };
        if (limit !== undefined) {
            request['dataSize'] = limit;
        }
        const response = await this.publicGetApiDataV1Entrusts (this.extend (request, params));
        const orderbook = this.safeValue (response, 'datas', []);
        const ts = this.safeTimestamp (orderbook, 'timestamp');
        return this.parseOrderBook (orderbook, ts, 'bids', 'asks', 0, 1);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const response = await this.privatePostExchangeFundControllerWebsiteFundcontrollerFindbypage (params);
        const data = this.safeValue (response, 'datas', {});
        const balances = this.safeValue (data, 'list', []);
        const result = { 'info': response };
        for (let i = 0; i < balances.length; i++) {
            const balance = balances[i];
            let symbol = this.safeInteger (balance, 'currencyTypeId');
            if (symbol in this.currencies_by_id) {
                symbol = this.currencies_by_id[symbol]['code'];
            }
            const account = this.account ();
            const amount = this.safeFloat (balance, 'amount');
            account['free'] = amount;
            account['total'] = amount;
            account['used'] = 0;
            result[symbol] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        if (price === undefined) {
            throw new ExchangeError (this.id + ' allows limit orders only');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'amount': this.amountToPrecision (symbol, amount),
            'price': this.priceToPrecision (symbol, price),
            'type': 0, // sell
            'rangeType': 0, // limit order
            'marketId': market['id'],
        };
        if (type.toLowerCase () === 'buy') {
            request['type'] = 1; // buy
        }
        const response = await this.privatePostExchangeEntrustControllerWebsiteEntrustControllerAddEntrust (this.extend (request, params));
        const data = this.safeValue (response, 'datas');
        return {
            'id': this.safeString (data, 'entrustId'),
            'info': response,
        };
    }

    parseOrderStatus (status) {
        const statuses = {
            '-2': 'canceled',
            '-1': 'canceled',
            '0': 'open',
            '1': 'canceled',
            '2': 'closed',
            '3': 'open',
            '4': 'canceled',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        const marketId = this.safeString (order, 'marketId');
        if (marketId in this.markets_by_id) {
            market = this.markets_by_id[marketId];
        }
        const timestamp = this.safeInteger (order, 'createTime');
        let side = undefined;
        const orderSide = this.safeInteger (order, 'type');
        if (orderSide === 0) {
            side = 'sell';
        } else if (orderSide === 0) {
            side = 'buy';
        } else if (orderSide === -1) {
            cancled
        }
        const amount = this.safeFloat (order, 'amount');
        const price = this.safeFloat (order, 'price');
        const filled = this.safeFloat (order, 'completeAmount');
        const status = this.parseOrderStatus (this.safeInteger (order, 'status', '').toString ());
        return {
            'info': order,
            'id': this.safeString (order, 'entrustId'),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'symbol': this.safeString (market, 'symbol'),
            'type': 'limit',
            'side': side,
            'price': price,
            'amount': amount,
            'cost': undefined,
            'average': undefined,
            'filled': filled,
            'remaining': amount - filled,
            'status': status,
            'fee': undefined,
            'trades': undefined,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'entrustId': id,
        };
        const response = await this.privateGetExchangeEntrustControllerWebsiteEntrustControllerGetEntrustById (this.extend (request, params));
        const order = this.safeValue (response, 'datas', {})
        return this.parseOrder (order, market);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'entrustId': id,
        };
        const response = await this.privatePostExchangeEntrustControllerWebsiteEntrustControllerCancelEntrust (this.extend (request, params));
        return {
            'info': response,
            'id': id,
        };
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
        return [
            this.safeTimestamp (ohlcv, 3),
            this.safeFloat (ohlcv, 4),
            this.safeFloat (ohlcv, 5),
            this.safeFloat (ohlcv, 6),
            this.safeFloat (ohlcv, 7),
            this.safeFloat (ohlcv, 8),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'type': this.timeframes[timeframe],
            'dataSize': 500,
        };
        if (limit !== undefined) {
            request['dataSize'] = limit;
        }
        const response = await this.publicGetApiDataV1Klines (this.extend (request, params));
        const data = this.safeValue (response, 'datas', []);
        const ohlcvs = this.parseOHLCVs (data, market, timeframe, since, limit);
        return this.sortBy (ohlcvs, 0);
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'] + path;
        if (method === 'GET') {
            if (Object.keys (params).length) {
                url += '?' + this.urlencode (params);
            }
        } else {
            body = this.json (params);
        }
        if (api === 'private') {
            const ms = this.milliseconds ();
            let content = "";
            if (method === 'GET') {
                const sortedParams = this.keysort (params);
                for (let key in sortedParams) {
                    content += key + sortedParams[key];
                }
            } else {
                content = body;
            }
            let signing = this.apiKey + ms + content + this.secret;
            const hash = this.hash (signing, 'md5');
            if (!headers) {
                headers = {};
            }
            headers['Apiid'] = this.apiKey;
            headers['Timestamp'] = ms;
            headers['Sign'] = hash;
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        const resMsg = this.safeValue (response, 'resMsg');
        const errorCode = this.safeString (resMsg, 'code');
        if (errorCode !== '1') {
            const feedback = this.id + ' ' + this.json (response);
            const exact = this.exceptions['exact'];
            if (errorCode in exact) {
                throw new exact[errorCode] (feedback);
            }
            throw new ExchangeError (feedback); // unknown error
        }
    }
};
<commit_msg>bw.com: Fix build issues<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors');
const { DECIMAL_PLACES } = require ('./base/functions/number');

//  ---------------------------------------------------------------------------

module.exports = class bw extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bw',
            'name': 'bw.com',
            'countries': [ 'CN' ],
            'rateLimit': 1500,
            'version': 'v1',
            'has': {
                'cancelAllOrders': false,
                'cancelOrder': true,
                'cancelOrders': false,
                'CORS': false,
                'createDepositAddress': false,
                'createLimitOrder': true,
                'createMarketOrder': false,
                'createOrder': true,
                'deposit': false,
                'editOrder': false,
                'fetchBalance': true,
                'fetchBidsAsks': false,
                'fetchClosedOrders': false,
                'fetchCurrencies': true,
                'fetchDepositAddress': false,
                'fetchDeposits': false,
                'fetchFundingFees': false,
                'fetchL2OrderBook': false,
                'fetchLedger': false,
                'fetchMarkets': true,
                'fetchMyTrades': false,
                'fetchOHLCV': false,
                'fetchOpenOrders': false,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrderBooks': false,
                'fetchOrders': false,
                'fetchTicker': false,
                'fetchTickers': false,
                'fetchTrades': false,
                'fetchTradingFee': false,
                'fetchTradingFees': false,
                'fetchTradingLimits': false,
                'fetchTransactions': false,
                'fetchWithdrawals': false,
                'privateAPI': false,
                'publicAPI': false,
                'withdraw': false,
            },
            'timeframes': {
                '1m': '1M',
                '5m': '5M',
                '15m': '15M',
                '30m': '30M',
                '1h': '1H',
                '1w': '1W',
            },
            'urls': {
                'api': 'https://www.bw.com/',
                'www': 'https://www.bw.com',
                'doc': 'https://www.bw.com/restApi',
                'fees': 'https://www.bw.com/feesRate',
                'referral': '',
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'percentage': true,
                    'taker': 0.1 / 100,
                    'maker': 0.1 / 100,
                    'tiers': {
                        'taker': [
                            [0, 0.1 / 100],
                        ],
                        'maker': [
                            [0, 0.1 / 100],
                        ],
                    },
                },
                'funding': {
                },
            },
            'exceptions': {
                // TODO
                'exact': {
                    '999': AuthenticationError,
                },
            },
            'api': {
                'public': {
                    'get': [
                        'exchange/config/controller/website/marketcontroller/getByWebId',
                        'exchange/config/controller/website/currencycontroller/getCurrencyList',
                        'api/data/v1/entrusts',
                        'api/data/v1/klines',
                    ],
                },
                'private': {
                    'get': [
                        'exchange/entrust/controller/website/EntrustController/getEntrustById',
                    ],
                    'post': [
                        'exchange/fund/controller/website/fundcontroller/findbypage',
                        'exchange/entrust/controller/website/EntrustController/addEntrust',
                        'exchange/entrust/controller/website/EntrustController/cancelEntrust',
                    ],
                },
            },
            'commonCurrencies': {
            },
            'precisionMode': DECIMAL_PLACES,
            'options': {
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetExchangeConfigControllerWebsiteMarketcontrollerGetByWebId (params);
        const markets = this.safeValue (response, 'datas', []);
        const result = [];
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const id = this.safeString (market, 'marketId');
            const numericId = parseInt (id);
            const name = this.safeStringUpper (market, 'name');
            let [ quote, base ] = name.split ('_');
            base = this.safeCurrencyCode (base);
            quote = this.safeCurrencyCode (quote);
            const baseId = this.safeString (market, 'buyerCurrencyId');
            const quoteId = this.safeString (market, 'sellerCurrencyId');
            const baseNumericId = parseInt (baseId);
            const quoteNumericId = parseInt (quoteId);
            const symbol = quote + '/' + base;
            const state = this.safeInteger (market, 'state');
            const active = state === 1;
            result.push ({
                'id': id,
                'active': active,
                'numericId': numericId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'baseNumericId': baseNumericId,
                'quoteNumericId': quoteNumericId,
                'info': market,
                'precision': {
                    'amount': this.safeInteger (market, 'amountDecimal'),
                    'price': this.safeInteger (market, 'priceDecimal'),
                },
                'limits': {
                    'amount': {
                        'min': this.safeFloat (market, 'minAmount'),
                        'max': undefined,
                    },
                    'price': {
                        'min': 0,
                        'max': undefined,
                    },
                    'cost': {
                        'min': 0,
                        'max': undefined,
                    },
                },
            });
        }
        return result;
    }

    async fetchCurrencies (params = {}) {
        const response = await this.publicGetExchangeConfigControllerWebsiteCurrencycontrollerGetCurrencyList (params);
        const currencies = this.safeValue (response, 'datas', []);
        const result = {};
        for (let i = 0; i < currencies.length; i++) {
            const currency = currencies[i];
            const id = this.safeString (currency, 'currencyId');
            const code = this.safeCurrencyCode (this.safeStringUpper (currency, 'name'));
            const state = this.safeInteger (currency, 'state');
            const active = state === 1;
            result[code] = {
                'id': id,
                'code': code,
                'info': currency,
                'name': code,
                'active': active,
                'fee': undefined,
                'precision': undefined,
                'limits': {
                    'amount': {
                        'min': parseFloat (this.safeInteger (currency, 'limitAmount')),
                        'max': undefined,
                    },
                    'price': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': parseFloat (this.safeInteger (currency, 'onceDrawLimit')),
                    },
                },
            };
        }
        return result;
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
        };
        if (limit !== undefined) {
            request['dataSize'] = limit;
        }
        const response = await this.publicGetApiDataV1Entrusts (this.extend (request, params));
        const orderbook = this.safeValue (response, 'datas', []);
        const ts = this.safeTimestamp (orderbook, 'timestamp');
        return this.parseOrderBook (orderbook, ts, 'bids', 'asks', 0, 1);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const response = await this.privatePostExchangeFundControllerWebsiteFundcontrollerFindbypage (params);
        const data = this.safeValue (response, 'datas', {});
        const balances = this.safeValue (data, 'list', []);
        const result = { 'info': response };
        for (let i = 0; i < balances.length; i++) {
            const balance = balances[i];
            let symbol = this.safeInteger (balance, 'currencyTypeId');
            if (symbol in this.currencies_by_id) {
                symbol = this.currencies_by_id[symbol]['code'];
            }
            const account = this.account ();
            const amount = this.safeFloat (balance, 'amount');
            account['free'] = amount;
            account['total'] = amount;
            account['used'] = 0;
            result[symbol] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        if (price === undefined) {
            throw new ExchangeError (this.id + ' allows limit orders only');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'amount': this.amountToPrecision (symbol, amount),
            'price': this.priceToPrecision (symbol, price),
            'type': 0, // sell
            'rangeType': 0, // limit order
            'marketId': market['id'],
        };
        if (type.toLowerCase () === 'buy') {
            request['type'] = 1; // buy
        }
        const response = await this.privatePostExchangeEntrustControllerWebsiteEntrustControllerAddEntrust (this.extend (request, params));
        const data = this.safeValue (response, 'datas');
        return {
            'id': this.safeString (data, 'entrustId'),
            'info': response,
        };
    }

    parseOrderStatus (status) {
        const statuses = {
            '-2': 'canceled',
            '-1': 'canceled',
            '0': 'open',
            '1': 'canceled',
            '2': 'closed',
            '3': 'open',
            '4': 'canceled',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        const marketId = this.safeString (order, 'marketId');
        if (marketId in this.markets_by_id) {
            market = this.markets_by_id[marketId];
        }
        const timestamp = this.safeInteger (order, 'createTime');
        let side = undefined;
        const orderSide = this.safeInteger (order, 'type');
        if (orderSide === 0) {
            side = 'sell';
        } else if (orderSide === 1) {
            side = 'buy';
        }
        const amount = this.safeFloat (order, 'amount');
        const price = this.safeFloat (order, 'price');
        const filled = this.safeFloat (order, 'completeAmount');
        const status = this.parseOrderStatus (this.safeInteger (order, 'status', '').toString ());
        return {
            'info': order,
            'id': this.safeString (order, 'entrustId'),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'symbol': this.safeString (market, 'symbol'),
            'type': 'limit',
            'side': side,
            'price': price,
            'amount': amount,
            'cost': undefined,
            'average': undefined,
            'filled': filled,
            'remaining': amount - filled,
            'status': status,
            'fee': undefined,
            'trades': undefined,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'entrustId': id,
        };
        const response = await this.privateGetExchangeEntrustControllerWebsiteEntrustControllerGetEntrustById (this.extend (request, params));
        const order = this.safeValue (response, 'datas', {});
        return this.parseOrder (order, market);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'entrustId': id,
        };
        const response = await this.privatePostExchangeEntrustControllerWebsiteEntrustControllerCancelEntrust (this.extend (request, params));
        return {
            'info': response,
            'id': id,
        };
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
        return [
            this.safeTimestamp (ohlcv, 3),
            this.safeFloat (ohlcv, 4),
            this.safeFloat (ohlcv, 5),
            this.safeFloat (ohlcv, 6),
            this.safeFloat (ohlcv, 7),
            this.safeFloat (ohlcv, 8),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'marketId': market['id'],
            'type': this.timeframes[timeframe],
            'dataSize': 500,
        };
        if (limit !== undefined) {
            request['dataSize'] = limit;
        }
        const response = await this.publicGetApiDataV1Klines (this.extend (request, params));
        const data = this.safeValue (response, 'datas', []);
        const ohlcvs = this.parseOHLCVs (data, market, timeframe, since, limit);
        return this.sortBy (ohlcvs, 0);
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'] + path;
        if (method === 'GET') {
            if (Object.keys (params).length) {
                url += '?' + this.urlencode (params);
            }
        } else {
            body = this.json (params);
        }
        if (api === 'private') {
            const ms = this.milliseconds ();
            let content = '';
            if (method === 'GET') {
                const sortedParams = this.keysort (params);
                const keys = Object.keys (sortedParams);
                for (let i = 0; i < keys.length; i++) {
                    const key = keys[i];
                    content += key + sortedParams[key];
                }
            } else {
                content = body;
            }
            const signing = this.apiKey + ms + content + this.secret;
            const hash = this.hash (signing, 'md5');
            if (!headers) {
                headers = {};
            }
            headers['Apiid'] = this.apiKey;
            headers['Timestamp'] = ms;
            headers['Sign'] = hash;
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        const resMsg = this.safeValue (response, 'resMsg');
        const errorCode = this.safeString (resMsg, 'code');
        if (errorCode !== '1') {
            const feedback = this.id + ' ' + this.json (response);
            const exact = this.exceptions['exact'];
            if (errorCode in exact) {
                throw new exact[errorCode] (feedback);
            }
            throw new ExchangeError (feedback); // unknown error
        }
    }
};
<|endoftext|>


<commit_before>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');<commit_msg>Update ga.js<commit_after>$("meta[name='og:title']").attr('title', 'viewport');
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');
<|endoftext|>


<commit_before>var _gaq = _gaq || [];
  _gaq.push(['_setAccount', '{{site.google_analytics}}']);
  _gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();<commit_msg>rm ga.js<commit_after><|endoftext|>


<commit_before>$(window).on('load', function() {
    // Just replacing the value of the 'content' attribute will not work.
    $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0">');
	var x = document.getElementsByTagName("head");
	console.log(x.length);
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');
<commit_msg>Update ga.js<commit_after>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');
<|endoftext|>


<commit_before>if (typeof Mozilla === 'undefined') {
    var Mozilla = {};
}

if (typeof Mozilla.page === 'undefined') {
    Mozilla.page = {};
}

Mozilla.page.Home = {
    'closeText' : 'close',
    'shareText' : 'Share'
};

$(document).ready(function() {

    var hasMediaQueries = (typeof matchMedia !== 'undefined');
    var noVideo = (typeof HTMLMediaElement === 'undefined');

    var sizes = [
        {
            thumbWidth : 320,
            thumbHeight : 180,
            videoWidth : 320,
            videoHeight : 180,
            marginWidth : 0,
            marginHeight : 0
        },
        {
            thumbWidth : 440,
            thumbHeight : 248,
            videoWidth : 440,
            videoHeight : 248,
            marginWidth : 0,
            marginHeight : 0
        },
        {
            thumbWidth : 280,
            thumbHeight : 158,
            videoWidth : 720,
            videoHeight : 405,
            marginWidth : 20,
            marginHeight : 20
        },
        {
            thumbWidth : 380,
            thumbHeight : 214,
            videoWidth : 853,
            videoHeight : 480,
            marginWidth : 30,
            marginHeight : 25
        }
    ];

    function getSize() {
        if (hasMediaQueries && matchMedia('(max-width: 480px)').matches) {
            return sizes[0];
        }

        if (hasMediaQueries && matchMedia('(min-width: 480px) and (max-width: 760px)').matches) {
            return sizes[1];
        }

        if (hasMediaQueries && matchMedia('(min-width: 760px) and (max-width: 1000px)').matches) {
            return sizes[2];
        }

        return sizes[3];
    }

    function createVideo() {
        // IE9 didn't like a video element build using jQuery so we build it
        // using the DOM API.
        var video = document.createElement('video');
        video.id = 'video-player';
        video.className = 'video-js vjs-default-skin';
        video.controls = 'controls';
        video.preload = 'none';

        // create video sources
        var sources = [
            {
                src: 'http://videos.mozilla.org/uploads/brand/State%20of%20Mozilla%202011%20(fcp2)-RC%20-%20720p%20-%20MPEG-4.mp4',
                type: 'video/mp4'
            },
            {
                src: 'http://videos.mozilla.org/uploads/brand/State%20of%20Mozilla%202011%20(fcp2)-RC%20-%20720p%20-%20MPEG-4.webm',
                type: 'video/webm'
            }
        ];

        for (var i = 0; i < sources.length; i++) {
            var source = document.createElement('source');
            source.src = sources[i].src;
            source.type = sources[i].type;
            video.appendChild(source);
        }

        return $(video);
    }

    var currentSize = getSize();

    var $thumb = $('#promo-flicks-keyframe');
    var $link = $thumb.next();

    // create container that replaces the link when the video is open
    var $container = $('

');
    $container.css('display', 'none')
        .insertBefore($link);

    // create go link shown when video is open
    var $goLink = $('');
    $goLink.attr('href', $link.attr('href'))
        .text($link.find('.go').text())
        .appendTo($container);

    // get video-completed overlay and set up replay and continue button click
    // handlers
    var $overlay = $('#promo-flicks-overlay');
    $overlay.find('.video-replay').click(function(e) {
        e.preventDefault();
        hideOverlay();
        if (videoJS) {
            // let the loading and big play buttons show up again.
            $videoContainer.find('.video-js').removeClass('vjs-moz-ended');
            videoJS.currentTime(0);
            videoJS.play();
        }
    });
    $overlay.find('.video-continue').click(function(e) {
        e.preventDefault();
        hideOverlay();
        if (videoJS) {
            videoJS.play();
        }
    });

    var state = 'closed';

    // create close button for closing open video
    var $close = $(
        '×'
    );

    $close.attr('title', Mozilla.page.Home.closeText)
        .click(function(e) { close(); })
        .keypress(function(e) {
            if (e.keyCode == 13) {
                e.preventDefault(e);
                close();
            }
        });

    // shared animation settings
    var duration = 400;
    var easing = 'swing';

    // create container to hold the video player
    var $videoContainer = $('

');
    $videoContainer.css('display', 'none')
        .insertAfter($thumb);

    var $video = createVideo();
    $video.appendTo($videoContainer);

    // the video.js player when it exists
    var videoJS;

    // the share button, when it exists
    var $shareButton;

    function open() {
        if (state !== 'closed') {
            return;
        }

        state = 'opening';

        // if pager is auto-rotating, stop rotating when video opened
        Mozilla.Pager.pagers['home-promo'].stopAutoRotate();
        Mozilla.Pager.pagers['home-promo'].autoRotate = false;

        var thumbOffset = $thumb.offset();

        // show close link
        $close.insertBefore($container)
            .css('right', 'auto')
            .offset({
                'left' : thumbOffset.left + currentSize.thumbWidth,
                'top' : thumbOffset.top
            });

        if (currentSize.videoWidth >= 720) {

            var linkWidth = $link.width();

            hideLink();

            var goHeight = $goLink.height();

            $container.animate(
                {
                    'height' : currentSize.videoHeight + goHeight + 10 + currentSize.marginHeight * 2
                },
                duration,
                easing
            );

            $close.animate(
                {
                    'left' : Math.floor((linkWidth + currentSize.videoWidth) / 2),
                    'top'  : currentSize.marginHeight
                },
                duration
            );

            $thumb.css('right', 'auto')
                .offset({ 'left' : thumbOffset.left })
                .animate(
                    {
                        'height' : currentSize.videoHeight,
                        'width' : currentSize.videoWidth,
                        'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2),
                        'top' : currentSize.marginHeight
                    },
                    duration,
                    easing,
                    function() {
                        showVideo();
                        // only allow closing after opened
                        state = 'opened';
                    }
                );

            $('body').animate(
                {
                    scrollTop: $('#home-promo').position().top - 20
                },
                duration,
                easing
            );

        } else {
            // for small sizes, no animation required
            showVideo();
            state = 'opened';
        }
    }

    function hideLink() {
        var linkHeight = $link.height();
        var linkWidth = $link.width();

        // hide link and show container with same dimensions
        $link.css('display', 'none');
        $container.height(linkHeight)
            .css('display', 'block');

        $goLink.css(
            'left',
            Math.max(Math.floor((linkWidth - currentSize.videoWidth) / 2), 20)
        );
    }

    function showLink() {
        // hide container and show link at same dimensions
        $container.css('display', 'none');
        $link.css('display', 'block');
    }

    function showVideo() {
        var thumbPosition = $thumb.position();

        $video.attr('width', currentSize.videoWidth)
            .attr('height', currentSize.videoHeight);

        $thumb.css('display', 'none');

        $videoContainer.css({
            'top' : thumbPosition.top,
            'right' : 'auto',
            'left' : thumbPosition.left,
            'width' : currentSize.videoWidth,
            'height' : currentSize.videoHeight,
            'display' : 'block'
        });

        if (videoJS) {
            // let the loading and big play buttons show up again.
            $videoContainer.find('.video-js').removeClass('vjs-moz-ended');

            videoJS.size(currentSize.videoWidth, currentSize.videoHeight);
            videoJS.play();
        } else {
            _V_('video-player', {}, function() {
                videoJS = this;

                // add share button to controls on first play
                videoJS.addEvent('play', function() {
                    if (!$shareButton) {
                        $shareButton = $(
                            '<button class="vjs-sandstone-share">' +
                            Mozilla.page.Home.shareText +
                            '</button>'
                        );
                        $shareButton.click(function() {
                            videoJS.pause();
                            showOverlay(false);
                        });
                        var $controls = $(videoJS.controlBar.el);
                        $controls.append($shareButton);
                    }
                });

                // Flash player fails to initialize dynamically inserted source
                // elements. Set up the sources after the player exists. See
                // http://help.videojs.com/discussions/questions/350-flash-fallback-in-ie8
                if (noVideo) {
                    videoJS.src(sources);
                }
                videoJS.addEvent('ended', function() { showOverlay(true); });
                videoJS.play();
            });
        }
    }

    function showOverlay(ended) {
        var width = $videoContainer.width();
        var height = $videoContainer.height();
        var position = $videoContainer.position();

        if (ended) {
            $overlay.find('.video-replay').css('display', 'inline-block');
            $overlay.find('.video-continue').css('display', 'none');
        } else {
            $overlay.find('.video-replay').css('display', 'none');
            $overlay.find('.video-continue').css('display', 'inline-block');
        }

        $overlay.css({
            'top' : position.top,
            'left' : position.left,
            'width' : width,
            'height' : height,
            'display' : 'block'
        });

        if (ended) {
            // hide video-js big play button and loading spinner (Chrome
            // shows spinner for some videos after they are finished)
            $videoContainer.find('.video-js').addClass('vjs-moz-ended');
        }
    }

    function hideOverlay() {
        $overlay.css('display', 'none');
    }

    function hideVideo() {
        if (videoJS) {
            videoJS.pause();
        }

        var videoPosition = $videoContainer.position();

        $videoContainer.css('display', 'none');
        $overlay.css('display', 'none');

        $thumb.css({
            'top' : videoPosition.top,
            'right' : 'auto',
            'left' : videoPosition.left,
            'display' : 'block'
        });

        if (currentSize.videoWidth < 720) {
            $thumb.css({
                'width' : currentSize.thumbWidth,
                'height' : currentSize.thumbHeight
            });
        }

        $close.detach();
    }

    function close() {
        if (state !== 'opened') {
            return;
        }

        state = 'closing';

        hideVideo();

        var linkWidth = $container.width();
        var linkHeight = $container.height();

        if (currentSize.videoWidth >= 720) {

            showLink();
            $link.height(linkHeight)
                .animate(
                    {
                        'height' : currentSize.thumbHeight + 2 * currentSize.marginHeight
                    },
                    duration,
                    easing
                );

            $thumb.animate(
                {
                    'height' : currentSize.thumbHeight,
                    'width'  : currentSize.thumbWidth,
                    'left'   : linkWidth - currentSize.thumbWidth - currentSize.marginWidth
                },
                duration,
                easing,
                function() {
                    // only allow opening after closing finished
                    state = 'closed';
                }
            );
        } else {
            state = 'closed';
        }

    }

    $thumb.click(function(e) { open(); })
        .keypress(function(e) {
            if (e.keyCode == 13) {
                e.preventDefault(e);
                open();
            }
        });

    function handleResize() {
        var size = getSize();
        if (size.videoWidth !== currentSize.videoWidth) {
            currentSize = size;
            reposition();
        }
    }

    function reposition() {
        var linkWidth;

        if (state === 'opened' || state === 'opening') {

            // TODO: check for and stop animations

            if (videoJS) {
                videoJS.size(currentSize.videoWidth, currentSize.videoHeight);
            }

            $overlay.css({
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            var $offsetParent = $videoContainer.offsetParent();
            linkWidth = $offsetParent.width();

            $videoContainer.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2),
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            $overlay.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2)
            });

            $close.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth + currentSize.videoWidth) / 2)
            });

            $thumb.css({
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            if (currentSize.videoWidth >= 720) {
                $goLink.css({
                    'bottom' : 'auto',
                    'left' : Math.max(Math.floor((linkWidth - currentSize.videoWidth) / 2), 20),
                    'top' : currentSize.videoHeight + currentSize.marginHeight + 10
                });

                hideLink();

                var goHeight = $goLink.height();

                $container.css(
                    'height',
                    currentSize.marginHeight + currentSize.videoHeight + goHeight + 10 + 20
                );
            } else {
                showLink();
                $link.css('height', 'auto');
            }

        } else {

            // TODO: check for and stop animations

            linkWidth = $link.width();

            $thumb.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : linkWidth - currentSize.thumbWidth - currentSize.marginWidth,
                'width' : currentSize.thumbWidth,
                'height' : currentSize.thumbHeight
            });

            var height;
            if (currentSize.videoWidth >= 720) {
                height = currentSize.thumbHeight + currentSize.marginHeight * 2;
            } else {
                height = 'auto';
            }

            $link.css('height', height);
        }

    }

    if (hasMediaQueries) {
        $(window).resize(handleResize);
        handleResize();
    }

    // pause video if pager changes pages
    Mozilla.Pager.pagers['home-promo'].$container.bind('changePage', function() {
        if (videoJS) {
            videoJS.pause();
        }
    });

});
<commit_msg>Clean up and reorganize. Sort functions logically. Move jQuery element creation into individual functions. Move immediately executable code beneath all function definitions.<commit_after>if (typeof Mozilla === 'undefined') {
    var Mozilla = {};
}

if (typeof Mozilla.page === 'undefined') {
    Mozilla.page = {};
}

Mozilla.page.Home = {
    'closeText' : 'close',
    'shareText' : 'Share'
};

$(document).ready(function() {

    // {{{ showLink()

    function showLink() {
        // hide container and show link at same dimensions
        $container.css('display', 'none');
        $link.css('display', 'block');
    }

    // }}}
    // {{{ hideLink()

    function hideLink() {
        var linkHeight = $link.height();
        var linkWidth = $link.width();

        // hide link and show container with same dimensions
        $link.css('display', 'none');
        $container.height(linkHeight)
            .css('display', 'block');

        $goLink.css(
            'left',
            Math.max(Math.floor((linkWidth - currentSize.videoWidth) / 2), 20)
        );
    }

    // }}}
    // {{{ showVideo()

    function showVideo() {
        var thumbPosition = $thumb.position();

        $video.attr('width', currentSize.videoWidth)
            .attr('height', currentSize.videoHeight);

        $thumb.css('display', 'none');

        $videoContainer.css({
            'top' : thumbPosition.top,
            'right' : 'auto',
            'left' : thumbPosition.left,
            'width' : currentSize.videoWidth,
            'height' : currentSize.videoHeight,
            'display' : 'block'
        });

        if (videoJS) {
            // let the loading and big play buttons show up again.
            $videoContainer.find('.video-js').removeClass('vjs-moz-ended');

            videoJS.size(currentSize.videoWidth, currentSize.videoHeight);
            videoJS.play();
        } else {
            _V_('video-player', {}, function() {
                videoJS = this;

                // add share button to controls on first play
                videoJS.addEvent('play', function() {
                    if (!$shareButton) {
                        $shareButton = $(
                            '<button class="vjs-sandstone-share">' +
                            Mozilla.page.Home.shareText +
                            '</button>'
                        );
                        $shareButton.click(function() {
                            videoJS.pause();
                            showOverlay(false);
                        });
                        var $controls = $(videoJS.controlBar.el);
                        $controls.append($shareButton);
                    }
                });

                // Flash player fails to initialize dynamically inserted source
                // elements. Set up the sources after the player exists. See
                // http://help.videojs.com/discussions/questions/350-flash-fallback-in-ie8
                if (!hasVideo) {
                    videoJS.src(sources);
                }
                videoJS.addEvent('ended', function() { showOverlay(true); });
                videoJS.play();
            });
        }
    }

    // }}}
    // {{{ hideVideo()

    function hideVideo() {
        if (videoJS) {
            videoJS.pause();
        }

        var videoPosition = $videoContainer.position();

        $videoContainer.css('display', 'none');
        $overlay.css('display', 'none');

        $thumb.css({
            'top' : videoPosition.top,
            'right' : 'auto',
            'left' : videoPosition.left,
            'display' : 'block'
        });

        if (currentSize.videoWidth < 720) {
            $thumb.css({
                'width' : currentSize.thumbWidth,
                'height' : currentSize.thumbHeight
            });
        }

        $close.detach();
    }

    // }}}
    // {{{ showOverlay()

    function showOverlay(ended) {
        var width = $videoContainer.width();
        var height = $videoContainer.height();
        var position = $videoContainer.position();

        if (ended) {
            $overlay.find('.video-replay').css('display', 'inline-block');
            $overlay.find('.video-continue').css('display', 'none');
        } else {
            $overlay.find('.video-replay').css('display', 'none');
            $overlay.find('.video-continue').css('display', 'inline-block');
        }

        $overlay.css({
            'top' : position.top,
            'left' : position.left,
            'width' : width,
            'height' : height,
            'display' : 'block'
        });

        if (ended) {
            // hide video-js big play button and loading spinner (Chrome
            // shows spinner for some videos after they are finished)
            $videoContainer.find('.video-js').addClass('vjs-moz-ended');
        }
    }

    // }}}
    // {{{ hideOverlay()

    function hideOverlay() {
        $overlay.css('display', 'none');
    }

    // }}}
    // {{{ open()

    function open() {
        if (state !== 'closed') {
            return;
        }

        state = 'opening';

        // if pager is auto-rotating, stop rotating when video opened
        Mozilla.Pager.pagers['home-promo'].stopAutoRotate();
        Mozilla.Pager.pagers['home-promo'].autoRotate = false;

        var thumbOffset = $thumb.offset();

        // show close link
        $close.insertBefore($container)
            .css('right', 'auto')
            .offset({
                'left' : thumbOffset.left + currentSize.thumbWidth,
                'top' : thumbOffset.top
            });

        if (currentSize.videoWidth >= 720) {

            var linkWidth = $link.width();

            hideLink();

            var goHeight = $goLink.height();

            $container.animate(
                {
                    'height' : currentSize.videoHeight + goHeight + 10 + currentSize.marginHeight * 2
                },
                duration,
                easing
            );

            $close.animate(
                {
                    'left' : Math.floor((linkWidth + currentSize.videoWidth) / 2),
                    'top'  : currentSize.marginHeight
                },
                duration
            );

            $thumb.css('right', 'auto')
                .offset({ 'left' : thumbOffset.left })
                .animate(
                    {
                        'height' : currentSize.videoHeight,
                        'width' : currentSize.videoWidth,
                        'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2),
                        'top' : currentSize.marginHeight
                    },
                    duration,
                    easing,
                    function() {
                        showVideo();
                        // only allow closing after opened
                        state = 'opened';
                    }
                );

            $('body').animate(
                {
                    scrollTop: $('#home-promo').position().top - 20
                },
                duration,
                easing
            );

        } else {
            // for small sizes, no animation required
            showVideo();
            state = 'opened';
        }
    }

    // }}}
    // {{{ close()

    function close() {
        if (state !== 'opened') {
            return;
        }

        state = 'closing';

        hideVideo();

        var linkWidth = $container.width();
        var linkHeight = $container.height();

        if (currentSize.videoWidth >= 720) {

            showLink();
            $link.height(linkHeight)
                .animate(
                    {
                        'height' : currentSize.thumbHeight + 2 * currentSize.marginHeight
                    },
                    duration,
                    easing
                );

            $thumb.animate(
                {
                    'height' : currentSize.thumbHeight,
                    'width'  : currentSize.thumbWidth,
                    'left'   : linkWidth - currentSize.thumbWidth - currentSize.marginWidth
                },
                duration,
                easing,
                function() {
                    // only allow opening after closing finished
                    state = 'closed';
                }
            );
        } else {
            state = 'closed';
        }

    }

    // }}}
    // {{{ getSize()

    function getSize() {
        if (hasMediaQueries && matchMedia('(max-width: 480px)').matches) {
            return sizes[0];
        }

        if (hasMediaQueries && matchMedia('(min-width: 480px) and (max-width: 760px)').matches) {
            return sizes[1];
        }

        if (hasMediaQueries && matchMedia('(min-width: 760px) and (max-width: 1000px)').matches) {
            return sizes[2];
        }

        return sizes[3];
    }

    // }}}
    // {{{ handleResize()

    function handleResize() {
        var size = getSize();
        if (size.videoWidth !== currentSize.videoWidth) {
            currentSize = size;
            reposition();
        }
    }

    // }}}
    // {{{ resposition()

    function reposition() {
        var linkWidth;

        // TODO: check for and stop animations
        if (state === 'opened' || state === 'opening') {
            if (videoJS) {
                videoJS.size(currentSize.videoWidth, currentSize.videoHeight);
            }

            $overlay.css({
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            var $offsetParent = $videoContainer.offsetParent();
            linkWidth = $offsetParent.width();

            $videoContainer.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2),
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            $overlay.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth - currentSize.videoWidth) / 2)
            });

            $close.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : Math.floor((linkWidth + currentSize.videoWidth) / 2)
            });

            $thumb.css({
                'width' : currentSize.videoWidth,
                'height' : currentSize.videoHeight
            });

            if (currentSize.videoWidth >= 720) {
                $goLink.css({
                    'bottom' : 'auto',
                    'left' : Math.max(Math.floor((linkWidth - currentSize.videoWidth) / 2), 20),
                    'top' : currentSize.videoHeight + currentSize.marginHeight + 10
                });

                hideLink();

                var goHeight = $goLink.height();

                $container.css(
                    'height',
                    currentSize.marginHeight + currentSize.videoHeight + goHeight + 10 + 20
                );
            } else {
                showLink();
                $link.css('height', 'auto');
            }
        // TODO: check for and stop animations
        } else {
            linkWidth = $link.width();

            $thumb.css({
                'right' : 'auto',
                'top' : currentSize.marginHeight,
                'left' : linkWidth - currentSize.thumbWidth - currentSize.marginWidth,
                'width' : currentSize.thumbWidth,
                'height' : currentSize.thumbHeight
            });

            var height;
            if (currentSize.videoWidth >= 720) {
                height = currentSize.thumbHeight + currentSize.marginHeight * 2;
            } else {
                height = 'auto';
            }

            $link.css('height', height);
        }
    }

    // }}}
    // {{{ createVideo()

    function createVideo() {
        // IE9 didn't like a video element build using jQuery so we build it
        // using the DOM API.
        var video = document.createElement('video');
        video.id = 'video-player';
        video.className = 'video-js vjs-default-skin';
        video.controls = 'controls';
        video.preload = 'none';

        // create video sources
        var sources = [
            {
                src: 'http://videos.mozilla.org/uploads/brand/State%20of%20Mozilla%202011%20(fcp2)-RC%20-%20720p%20-%20MPEG-4.mp4',
                type: 'video/mp4'
            },
            {
                src: 'http://videos.mozilla.org/uploads/brand/State%20of%20Mozilla%202011%20(fcp2)-RC%20-%20720p%20-%20MPEG-4.webm',
                type: 'video/webm'
            }
        ];

        for (var i = 0; i < sources.length; i++) {
            var source = document.createElement('source');
            source.src = sources[i].src;
            source.type = sources[i].type;
            video.appendChild(source);
        }

        return $(video);
    }

    // }}}
    // {{{ createCloseButton()

    function createCloseButton() {
        var $close = $(
            '×'
        );

        $close.attr('title', Mozilla.page.Home.closeText)
            .click(function(e) { close(); })
            .keypress(function(e) {
                if (e.keyCode == 13) {
                    e.preventDefault(e);
                    close();
                }
            });

        return $close;
    }

    // }}}
    // {{{ createThumb()

    function createThumb() {
        var $thumb = $('#promo-flicks-keyframe');

        $thumb.click(function(e) { open(); })
            .keypress(function(e) {
                if (e.keyCode == 13) {
                    e.preventDefault(e);
                    open();
                }
            });

        return $thumb;
    }

    // }}}
    // {{{ createContainer()

    function createContainer() {
        var $container = $('

');
        $container.css('display', 'none')
        return $container;
    }

    // }}}
    // {{{ createGoLink()

    function createGoLink($link) {
        var $goLink = $('');
        $goLink.attr('href', $link.attr('href'))
            .text($link.find('.go').text());

        return $goLink;
    }

    // }}}
    // {{{ createVideoContainer()

    function createVideoContainer() {
        var $videoContainer = $('

');
        $videoContainer.css('display', 'none')
        return $videoContainer;
    }

    // }}}
    // {{{ createSocialOverlay()

    function createSocialOverlay() {
        var $overlay = $('#promo-flicks-overlay');
        $overlay.find('.video-replay').click(function(e) {
            e.preventDefault();
            hideOverlay();
            if (videoJS) {
                // let the loading and big play buttons show up again.
                $videoContainer.find('.video-js').removeClass('vjs-moz-ended');
                videoJS.currentTime(0);
                videoJS.play();
            }
        });
        $overlay.find('.video-continue').click(function(e) {
            e.preventDefault();
            hideOverlay();
            if (videoJS) {
                videoJS.play();
            }
        });
        return $overlay;
    }

    // }}}

    var hasMediaQueries = (typeof matchMedia !== 'undefined');
    var hasVideo = (typeof HTMLMediaElement !== 'undefined');

    var sizes = [
        {
            thumbWidth : 320,
            thumbHeight : 180,
            videoWidth : 320,
            videoHeight : 180,
            marginWidth : 0,
            marginHeight : 0
        },
        {
            thumbWidth : 440,
            thumbHeight : 248,
            videoWidth : 440,
            videoHeight : 248,
            marginWidth : 0,
            marginHeight : 0
        },
        {
            thumbWidth : 280,
            thumbHeight : 158,
            videoWidth : 720,
            videoHeight : 405,
            marginWidth : 20,
            marginHeight : 20
        },
        {
            thumbWidth : 380,
            thumbHeight : 214,
            videoWidth : 853,
            videoHeight : 480,
            marginWidth : 30,
            marginHeight : 25
        }
    ];

    var currentSize = getSize();
    var $thumb = createThumb();
    var $link = $thumb.next();
    var $container = createContainer();
    var $goLink = createGoLink($link);
    var $close = createCloseButton();
    var $videoContainer = createVideoContainer();
    var $video = createVideo();
    var $overlay = createSocialOverlay();
    var $shareButton;

    $container.insertBefore($link);
    $goLink.appendTo($container);
    $videoContainer.insertAfter($thumb);
    $video.appendTo($videoContainer);

    var state = 'closed';

    // shared animation settings
    var duration = 400;
    var easing = 'swing';

    // the video.js player when it exists
    var videoJS;

    if (hasMediaQueries) {
        $(window).resize(handleResize);
        handleResize();
    }

    // pause video if pager changes pages
    Mozilla.Pager.pagers['home-promo'].$container.bind('changePage', function() {
        if (videoJS) {
            videoJS.pause();
        }
    });

});
<|endoftext|>


<commit_before>/*
* @version $Id$
* @copyright Copyright (C) 2008 Abricos All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
*/

// Обработчик интерфейса размещенного на страницах сайта
var Component = new Brick.Component();
Component.requires = {
	yahoo: ['dom'],
	mod:[{name: 'sys', files: ['wait.js']}]
};
Component.entryPoint = function(){

	var Dom = YAHOO.util.Dom,
		E = YAHOO.util.Event,
		L = YAHOO.lang;

	var NS = this.namespace,
		API = NS.API,
		F = Brick.Component.API.fire,
		FF = Brick.Component.API.fireFunction,
		TMG = this.template;

	var LW = Brick.widget.LayWait;

	var gel = function(id){
		return L.isString(id) ? Dom.get(id) : id;
	};
	var gval = function(id){
		var el = gel(id);
		if (L.isNull(el)){ return ''; }
		return el.value;
	};
	var sval = function(id, val){
		var el = gel(id);
		if (L.isNull(el)){ return; }
		el.value = val;
	};
	var find = function(el, className, cnt){
		if (Dom.hasClass(el, className)){ return el; }
		cnt = (cnt || 0)+1;
		if (L.isNull(el) || el.parentNode == document.body || cnt > 30){
			return false;
		}
		return find(el.parentNode, className);
	};
	var parseid = function(el, pfx){
        var trim = YAHOO.lang.trim;
		pfx = trim(pfx.toUpperCase());
        var arr = Dom.getAttribute(el, "className").toUpperCase().split(' ');
        for (var i=0;i<arr.length;i++){
        	var arr1 = trim(arr[i]).split('-');
        	if (arr1.length == 2 && arr1[0] == pfx){
        		return arr1[1]*1;
        	}
        }
        return 0;
	};

	var getFElCl = function(className){
		var els = Dom.getElementsByClassName(className);
		return els.length > 0 ? els[0] : null;
	};

	var isInitButtons = false;

	/**
	 * Прикрутить событие на клик всех кнопок, чтобы отловить клики
	 * "Добавить в корзину", "Показать корзину" и т.п.
	 */
	API.buyButtonsInit = function(elId){
		if (isInitButtons){ return; }

		isInitButtons = true;
		var container = document.body;
		if (L.isNull(container)){ return; }

		var onClick = function(el){

			var fel;

			if (fel=find(el, 'btn-show-cart')){
				var lw = new LW(fel.parentNode, true);

				FF('eshop', 'cart', function(){
					lw.hide();
					API.cartPanelShow();
				});

			}else if (fel=find(el, 'btn-show-order')){

				var lw = new LW(fel.parentNode, true);

				FF('eshop', 'order', function(){
					lw.hide();
					API.showOrderPanel();
				});

			}else if (fel=find(el, 'btn-product-buy')){
				var productid = parseid(fel, 'product');

				var txtBuyCount = getFElCl('txt-product-bcount-'+productid);
				var count = L.isNull(txtBuyCount) ? 1 : gval(txtBuyCount)*1;
				if (count < 1){ return; }

				var lw = new LW(fel.parentNode, true);
				FF('eshop', 'cart', function(){
					API.productAddToCart(productid, count, function(cartinfo){
						lw.hide();

						// произошло чтото непоправимое
						if (L.isNull(cartinfo)){
							// TODO: необходимо доработать систему оповещения ошибок пользователю
							alert('Error in eshop/ui.js');
							return;
						}

						// забросить товар в корзину - почти баскетбольно-анимированный бросок фотки
						var img = getFElCl('img-product-'+productid);
						var to = Dom.get('basket');
						var cartPanel = NS.CartPanel.instance;
						if (!L.isNull(cartPanel)){
							to = cartPanel.body;
						}

						var pcma = new NS.ProductCartMoveAnim(img, to, function(){
							// После того, как товар улетел в корзину, необходимо обновить
							// информацию в ней (даже если их несколько на странице)
							var els = Dom.getElementsByClassName('eshop-cart-count');
							for (var n in els){
								els[n].innerHTML = cartinfo['qty'];
							}
							var els = Dom.getElementsByClassName('eshop-cart-summ');
							for (var n in els){
								els[n].innerHTML = API.formatPrice(cartinfo['sum']);
							}
							if (!L.isNull(cartPanel)){
								cartPanel.cartWidget.refresh();
							}
						});

					});
				});

			}else {
				return false;
			}
			return true;
		};

		E.on(container, 'click', function(e){
			var el = E.getTarget(e);
			if (onClick(el)){ E.preventDefault(e); }
		});
	};

	API.showBigPhoto = function(cfg) {
		var pid = cfg.fid, tmb = cfg.el;
	    var p = gel("bigPhoto");
	    gel("loading").style.display = "block";
	    p.className = "big loading_bg";
	    p.onload = function () {gel("loading").style.display = "none";p.className = "big";};
	    p.src=tmb.src.replace("w_40-h_40","w_200-h_200");
	    gel("tmb" + pidCurrent).className = "tmb";
	    tmb.className = "currentPhoto";
	    pidCurrent = pid;
	};

	var ViewImagePanel = null;

	var viewBigImage = function(fel, fid){
		if (L.isNull(ViewImagePanel)){
			var lw = new LW(fel.parentNode, true);

			Brick.Component.API.fireFunction('eshop', 'cart', function(){
				lw.hide();

				ViewImagePanel = function(fileId){
					this.fileId = fileId;
					ViewImagePanel.superclass.constructor.call(this, {
						fixedcenter: true, resize: true,
						width: '640px', height: '480px'
					});
				};
				YAHOO.extend(ViewImagePanel, Brick.widget.Panel, {
					initTemplate: function(){
						var TM = TMG.build('viewimagepanel'), T = TM.data, TId = TM.idManager;

						return TM.replace('viewimagepanel', {'fid': this.fileId});
					}
				});
				new ViewImagePanel(fid);
			});
		}else{
			new ViewImagePanel(fid);
		}
	};

	API.showMaxPhoto = function(tmb) {
		var a = tmb.src.split('/');
		for (var i=0;i<a.length;i++){
			if (a[i] == 'i' && i < a.length-1){
				viewBigImage(tmb, a[i+1]);
			}
		}
	};
};
<commit_msg>Интернет магазин: тонкая настройка размера фотографии на странице товара<commit_after>/*
* @version $Id$
* @copyright Copyright (C) 2008 Abricos All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
*/

// Обработчик интерфейса размещенного на страницах сайта
var Component = new Brick.Component();
Component.requires = {
	yahoo: ['dom'],
	mod:[{name: 'sys', files: ['wait.js']}]
};
Component.entryPoint = function(){

	var Dom = YAHOO.util.Dom,
		E = YAHOO.util.Event,
		L = YAHOO.lang;

	var NS = this.namespace,
		API = NS.API,
		F = Brick.Component.API.fire,
		FF = Brick.Component.API.fireFunction,
		TMG = this.template;

	var LW = Brick.widget.LayWait;

	var gel = function(id){
		return L.isString(id) ? Dom.get(id) : id;
	};
	var gval = function(id){
		var el = gel(id);
		if (L.isNull(el)){ return ''; }
		return el.value;
	};
	var sval = function(id, val){
		var el = gel(id);
		if (L.isNull(el)){ return; }
		el.value = val;
	};
	var find = function(el, className, cnt){
		if (Dom.hasClass(el, className)){ return el; }
		cnt = (cnt || 0)+1;
		if (L.isNull(el) || el.parentNode == document.body || cnt > 30){
			return false;
		}
		return find(el.parentNode, className);
	};
	var parseid = function(el, pfx){
        var trim = YAHOO.lang.trim;
		pfx = trim(pfx.toUpperCase());
        var arr = Dom.getAttribute(el, "className").toUpperCase().split(' ');
        for (var i=0;i<arr.length;i++){
        	var arr1 = trim(arr[i]).split('-');
        	if (arr1.length == 2 && arr1[0] == pfx){
        		return arr1[1]*1;
        	}
        }
        return 0;
	};

	var getFElCl = function(className){
		var els = Dom.getElementsByClassName(className);
		return els.length > 0 ? els[0] : null;
	};

	var isInitButtons = false;

	/**
	 * Прикрутить событие на клик всех кнопок, чтобы отловить клики
	 * "Добавить в корзину", "Показать корзину" и т.п.
	 */
	API.buyButtonsInit = function(elId){
		if (isInitButtons){ return; }

		isInitButtons = true;
		var container = document.body;
		if (L.isNull(container)){ return; }

		var onClick = function(el){

			var fel;

			if (fel=find(el, 'btn-show-cart')){
				var lw = new LW(fel.parentNode, true);

				FF('eshop', 'cart', function(){
					lw.hide();
					API.cartPanelShow();
				});

			}else if (fel=find(el, 'btn-show-order')){

				var lw = new LW(fel.parentNode, true);

				FF('eshop', 'order', function(){
					lw.hide();
					API.showOrderPanel();
				});

			}else if (fel=find(el, 'btn-product-buy')){
				var productid = parseid(fel, 'product');

				var txtBuyCount = getFElCl('txt-product-bcount-'+productid);
				var count = L.isNull(txtBuyCount) ? 1 : gval(txtBuyCount)*1;
				if (count < 1){ return; }

				var lw = new LW(fel.parentNode, true);
				FF('eshop', 'cart', function(){
					API.productAddToCart(productid, count, function(cartinfo){
						lw.hide();

						// произошло чтото непоправимое
						if (L.isNull(cartinfo)){
							// TODO: необходимо доработать систему оповещения ошибок пользователю
							alert('Error in eshop/ui.js');
							return;
						}

						// забросить товар в корзину - почти баскетбольно-анимированный бросок фотки
						var img = getFElCl('img-product-'+productid);
						var to = Dom.get('basket');
						var cartPanel = NS.CartPanel.instance;
						if (!L.isNull(cartPanel)){
							to = cartPanel.body;
						}

						var pcma = new NS.ProductCartMoveAnim(img, to, function(){
							// После того, как товар улетел в корзину, необходимо обновить
							// информацию в ней (даже если их несколько на странице)
							var els = Dom.getElementsByClassName('eshop-cart-count');
							for (var n in els){
								els[n].innerHTML = cartinfo['qty'];
							}
							var els = Dom.getElementsByClassName('eshop-cart-summ');
							for (var n in els){
								els[n].innerHTML = API.formatPrice(cartinfo['sum']);
							}
							if (!L.isNull(cartPanel)){
								cartPanel.cartWidget.refresh();
							}
						});

					});
				});

			}else {
				return false;
			}
			return true;
		};

		E.on(container, 'click', function(e){
			var el = E.getTarget(e);
			if (onClick(el)){ E.preventDefault(e); }
		});
	};

	API.showBigPhoto = function(cfg) {
		cfg = L.merge({
			'w': 200,
			'h': 200
		}, cfg || {});
		var pid = cfg.fid, tmb = cfg.el;
	    var p = gel("bigPhoto");
	    gel("loading").style.display = "block";
	    p.className = "big loading_bg";
	    p.onload = function () {gel("loading").style.display = "none";p.className = "big";};
	    p.src=tmb.src.replace("w_40-h_40","w_"+cfg['w']+"-h_"+cfg['h']+"");
	    gel("tmb" + pidCurrent).className = "tmb";
	    tmb.className = "currentPhoto";
	    pidCurrent = pid;
	};

	var ViewImagePanel = null;

	var viewBigImage = function(fel, fid){
		if (L.isNull(ViewImagePanel)){
			var lw = new LW(fel.parentNode, true);

			Brick.Component.API.fireFunction('eshop', 'cart', function(){
				lw.hide();

				ViewImagePanel = function(fileId){
					this.fileId = fileId;
					ViewImagePanel.superclass.constructor.call(this, {
						fixedcenter: true, resize: true,
						width: '640px', height: '480px'
					});
				};
				YAHOO.extend(ViewImagePanel, Brick.widget.Panel, {
					initTemplate: function(){
						var TM = TMG.build('viewimagepanel'), T = TM.data, TId = TM.idManager;

						return TM.replace('viewimagepanel', {'fid': this.fileId});
					}
				});
				new ViewImagePanel(fid);
			});
		}else{
			new ViewImagePanel(fid);
		}
	};

	API.showMaxPhoto = function(tmb) {
		var a = tmb.src.split('/');
		for (var i=0;i<a.length;i++){
			if (a[i] == 'i' && i < a.length-1){
				viewBigImage(tmb, a[i+1]);
			}
		}
	};
};
<|endoftext|>