<commit_before>'use strict';

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

const Exchange = require ('./base/Exchange');
const { BadSymbol, ExchangeError, NotSupported } = require ('./base/errors');
const Precise = require ('./base/Precise');

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

module.exports = class bitstamp1 extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitstamp1',
            'name': 'Bitstamp',
            'countries': [ 'GB' ],
            'rateLimit': 1000,
            'version': 'v1',
            'has': {
                'cancelOrder': true,
                'CORS': true,
                'createOrder': true,
                'fetchBalance': true,
                'fetchMyTrades': true,
                'fetchOrder': undefined,
                'fetchOrderBook': true,
                'fetchTicker': true,
                'fetchTrades': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
                'api': 'https://www.bitstamp.net/api',
                'www': 'https://www.bitstamp.net',
                'doc': 'https://www.bitstamp.net/api',
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
                'uid': true,
            },
            'api': {
                'public': {
                    'get': [
                        'ticker',
                        'ticker_hour',
                        'order_book',
                        'transactions',
                        'eur_usd',
                    ],
                },
                'private': {
                    'post': [
                        'balance',
                        'user_transactions',
                        'open_orders',
                        'order_status',
                        'cancel_order',
                        'cancel_all_orders',
                        'buy',
                        'sell',
                        'bitcoin_deposit_address',
                        'unconfirmed_btc',
                        'ripple_withdrawal',
                        'ripple_address',
                        'withdrawal_requests',
                        'bitcoin_withdrawal',
                    ],
                },
            },
            'markets': {
                'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
                'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
                'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
                'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
                'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
                'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
                'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
                'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
                'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
                'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
                'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
                'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
            },
        });
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' ' + this.version + " fetchOrderBook doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const orderbook = await this.publicGetOrderBook (params);
        const timestamp = this.safeTimestamp (orderbook, 'timestamp');
        return this.parseOrderBook (orderbook, symbol, timestamp);
    }

    async fetchTicker (symbol, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' ' + this.version + " fetchTicker doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const ticker = await this.publicGetTicker (params);
        const timestamp = this.safeTimestamp (ticker, 'timestamp');
        const vwap = this.safeNumber (ticker, 'vwap');
        const baseVolume = this.safeNumber (ticker, 'volume');
        let quoteVolume = undefined;
        if (baseVolume !== undefined && vwap !== undefined) {
            quoteVolume = baseVolume * vwap;
        }
        const last = this.safeNumber (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeNumber (ticker, 'high'),
            'low': this.safeNumber (ticker, 'low'),
            'bid': this.safeNumber (ticker, 'bid'),
            'bidVolume': undefined,
            'ask': this.safeNumber (ticker, 'ask'),
            'askVolume': undefined,
            'vwap': vwap,
            'open': this.safeNumber (ticker, 'open'),
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        };
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.safeTimestamp2 (trade, 'date', 'datetime');
        const side = (trade['type'] === 0) ? 'buy' : 'sell';
        const orderId = this.safeString (trade, 'order_id');
        if ('currency_pair' in trade) {
            if (trade['currency_pair'] in this.markets_by_id) {
                market = this.markets_by_id[trade['currency_pair']];
            }
        }
        const id = this.safeString (trade, 'tid');
        const priceString = this.safeString (trade, 'price');
        const amountString = this.safeString (trade, 'amount');
        const price = this.parseNumber (priceString);
        const amount = this.parseNumber (amountString);
        const cost = this.parseNumber (Precise.stringMul (priceString, amountString));
        let symbol = undefined;
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        return {
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new BadSymbol (this.id + ' ' + this.version + " fetchTrades doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'time': 'minute',
        };
        const response = await this.publicGetTransactions (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        const balance = await this.privatePostBalance (params);
        const result = { 'info': balance };
        const codes = Object.keys (this.currencies);
        for (let i = 0; i < codes.length; i++) {
            const code = codes[i];
            const currency = this.currency (code);
            const currencyId = currency['id'];
            const account = this.account ();
            account['free'] = this.safeString (balance, currencyId + '_available');
            account['used'] = this.safeString (balance, currencyId + '_reserved');
            account['total'] = this.safeString (balance, currencyId + '_balance');
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        if (type !== 'limit') {
            throw new ExchangeError (this.id + ' ' + this.version + ' accepts limit orders only');
        }
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' v1 supports BTC/USD orders only');
        }
        await this.loadMarkets ();
        const method = 'privatePost' + this.capitalize (side);
        const request = {
            'amount': amount,
            'price': price,
        };
        const response = await this[method] (this.extend (request, params));
        const id = this.safeString (response, 'id');
        return {
            'info': response,
            'id': id,
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        return await this.privatePostCancelOrder ({ 'id': id });
    }

    parseOrderStatus (status) {
        const statuses = {
            'In Queue': 'open',
            'Open': 'open',
            'Finished': 'closed',
            'Canceled': 'canceled',
        };
        return this.safeString (statuses, status, status);
    }

    async fetchOrderStatus (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privatePostOrderStatus (this.extend (request, params));
        return this.parseOrderStatus (response);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market (symbol);
        }
        const pair = market ? market['id'] : 'all';
        const request = {
            'id': pair,
        };
        const response = await this.privatePostOpenOrdersId (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' fetchOrder is not implemented yet');
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'] + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        } else {
            this.checkRequiredCredentials ();
            const nonce = this.nonce ().toString ();
            const auth = nonce + this.uid + this.apiKey;
            const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret)));
            query = this.extend ({
                'key': this.apiKey,
                'signature': signature.toUpperCase (),
                'nonce': nonce,
            }, query);
            body = this.urlencode (query);
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (response === undefined) {
            return;
        }
        const status = this.safeString (response, 'status');
        if (status === 'error') {
            throw new ExchangeError (this.id + ' ' + this.json (response));
        }
    }
};
<commit_msg>bitstamp1 market type<commit_after>'use strict';

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

const Exchange = require ('./base/Exchange');
const { BadSymbol, ExchangeError, NotSupported } = require ('./base/errors');
const Precise = require ('./base/Precise');

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

module.exports = class bitstamp1 extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitstamp1',
            'name': 'Bitstamp',
            'countries': [ 'GB' ],
            'rateLimit': 1000,
            'version': 'v1',
            'has': {
                'cancelOrder': true,
                'CORS': true,
                'createOrder': true,
                'fetchBalance': true,
                'fetchMyTrades': true,
                'fetchOrder': undefined,
                'fetchOrderBook': true,
                'fetchTicker': true,
                'fetchTrades': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
                'api': 'https://www.bitstamp.net/api',
                'www': 'https://www.bitstamp.net',
                'doc': 'https://www.bitstamp.net/api',
            },
            'requiredCredentials': {
                'apiKey': true,
                'secret': true,
                'uid': true,
            },
            'api': {
                'public': {
                    'get': [
                        'ticker',
                        'ticker_hour',
                        'order_book',
                        'transactions',
                        'eur_usd',
                    ],
                },
                'private': {
                    'post': [
                        'balance',
                        'user_transactions',
                        'open_orders',
                        'order_status',
                        'cancel_order',
                        'cancel_all_orders',
                        'buy',
                        'sell',
                        'bitcoin_deposit_address',
                        'unconfirmed_btc',
                        'ripple_withdrawal',
                        'ripple_address',
                        'withdrawal_requests',
                        'bitcoin_withdrawal',
                    ],
                },
            },
            'markets': {
                'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
                'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005, 'type': 'spot', 'spot': true },
            },
        });
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' ' + this.version + " fetchOrderBook doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const orderbook = await this.publicGetOrderBook (params);
        const timestamp = this.safeTimestamp (orderbook, 'timestamp');
        return this.parseOrderBook (orderbook, symbol, timestamp);
    }

    async fetchTicker (symbol, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' ' + this.version + " fetchTicker doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const ticker = await this.publicGetTicker (params);
        const timestamp = this.safeTimestamp (ticker, 'timestamp');
        const vwap = this.safeNumber (ticker, 'vwap');
        const baseVolume = this.safeNumber (ticker, 'volume');
        let quoteVolume = undefined;
        if (baseVolume !== undefined && vwap !== undefined) {
            quoteVolume = baseVolume * vwap;
        }
        const last = this.safeNumber (ticker, 'last');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeNumber (ticker, 'high'),
            'low': this.safeNumber (ticker, 'low'),
            'bid': this.safeNumber (ticker, 'bid'),
            'bidVolume': undefined,
            'ask': this.safeNumber (ticker, 'ask'),
            'askVolume': undefined,
            'vwap': vwap,
            'open': this.safeNumber (ticker, 'open'),
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        };
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.safeTimestamp2 (trade, 'date', 'datetime');
        const side = (trade['type'] === 0) ? 'buy' : 'sell';
        const orderId = this.safeString (trade, 'order_id');
        if ('currency_pair' in trade) {
            if (trade['currency_pair'] in this.markets_by_id) {
                market = this.markets_by_id[trade['currency_pair']];
            }
        }
        const id = this.safeString (trade, 'tid');
        const priceString = this.safeString (trade, 'price');
        const amountString = this.safeString (trade, 'amount');
        const price = this.parseNumber (priceString);
        const amount = this.parseNumber (amountString);
        const cost = this.parseNumber (Precise.stringMul (priceString, amountString));
        let symbol = undefined;
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        return {
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        if (symbol !== 'BTC/USD') {
            throw new BadSymbol (this.id + ' ' + this.version + " fetchTrades doesn't support " + symbol + ', use it for BTC/USD only');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'time': 'minute',
        };
        const response = await this.publicGetTransactions (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchBalance (params = {}) {
        const balance = await this.privatePostBalance (params);
        const result = { 'info': balance };
        const codes = Object.keys (this.currencies);
        for (let i = 0; i < codes.length; i++) {
            const code = codes[i];
            const currency = this.currency (code);
            const currencyId = currency['id'];
            const account = this.account ();
            account['free'] = this.safeString (balance, currencyId + '_available');
            account['used'] = this.safeString (balance, currencyId + '_reserved');
            account['total'] = this.safeString (balance, currencyId + '_balance');
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        if (type !== 'limit') {
            throw new ExchangeError (this.id + ' ' + this.version + ' accepts limit orders only');
        }
        if (symbol !== 'BTC/USD') {
            throw new ExchangeError (this.id + ' v1 supports BTC/USD orders only');
        }
        await this.loadMarkets ();
        const method = 'privatePost' + this.capitalize (side);
        const request = {
            'amount': amount,
            'price': price,
        };
        const response = await this[method] (this.extend (request, params));
        const id = this.safeString (response, 'id');
        return {
            'info': response,
            'id': id,
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        return await this.privatePostCancelOrder ({ 'id': id });
    }

    parseOrderStatus (status) {
        const statuses = {
            'In Queue': 'open',
            'Open': 'open',
            'Finished': 'closed',
            'Canceled': 'canceled',
        };
        return this.safeString (statuses, status, status);
    }

    async fetchOrderStatus (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privatePostOrderStatus (this.extend (request, params));
        return this.parseOrderStatus (response);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market (symbol);
        }
        const pair = market ? market['id'] : 'all';
        const request = {
            'id': pair,
        };
        const response = await this.privatePostOpenOrdersId (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' fetchOrder is not implemented yet');
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'] + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        } else {
            this.checkRequiredCredentials ();
            const nonce = this.nonce ().toString ();
            const auth = nonce + this.uid + this.apiKey;
            const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret)));
            query = this.extend ({
                'key': this.apiKey,
                'signature': signature.toUpperCase (),
                'nonce': nonce,
            }, query);
            body = this.urlencode (query);
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (response === undefined) {
            return;
        }
        const status = this.safeString (response, 'status');
        if (status === 'error') {
            throw new ExchangeError (this.id + ' ' + this.json (response));
        }
    }
};
<|endoftext|>


<commit_before>var boomerang = angular.module('gdgBoomerang', ['ngSanitize', 'ui.bootstrap'])
    .config([
    '$httpProvider',
    '$interpolateProvider',
    '$routeProvider',
    function($httpProvider, $interpolateProvider, $routeProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        $routeProvider.
          when("/about", {templateUrl: 'views/about.html', controller: "AboutControl"}).
          when("/news", {templateUrl: 'views/news.html', controller: "NewsControl"}).
          when("/events", {templateUrl: 'views/events.html', controller: "EventsControl"}).
          when("/photos", {templateUrl: 'views/photos.html', controller: "PhotosControl"}).
          otherwise({ redirectTo: '/about' });
    }]);

boomerang.controller('MainControl', function ($scope, Config) {
    $scope.chapter_name = Config.name;

    $scope.chapter_id = Config.id;
    $scope.site_link = 'http://' + angular.lowercase(Config.name.replace(new RegExp(' ', 'g'), '')) + '.appspot.com';
    $scope.google_plus_link = 'https://plus.google.com/' + Config.id;
    $scope.isNavCollapsed = true;
});

boomerang.controller('AboutControl', function ($scope, $http, $location, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "about";
    $scope.cover = Config.cover;
    $http.jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '?callback=JSON_CALLBACK&fields=aboutMe%2Ccover%2Cimage%2CplusOneCount&key=' + Config.google_api).
        success(function (data) {
            console.log(data);
            $scope.desc = data.aboutMe;
            if (data.cover && data.cover.coverPhoto.url) {
                $scope.cover.url = data.cover.coverPhoto.url;
            }
            $scope.loading = false;
        });
});

boomerang.controller("NewsControl", function ($scope, $http, $timeout, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "news";
    $http.
        jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '/activities/public?callback=JSON_CALLBACK&maxResults=10&key=' + Config.google_api).
        success(function (response) {
            var entries = [], i, j;
            for (i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var actor = item.actor || {};
                var object = item.object || {};
                // Normalize tweet to a FriendFeed-like entry.
                // var itemTitle = '' + item.title + '';
                var itemTitle = object.content;

                if(item.annotation)
                  itemTitle = item.annotation;

                var html = [itemTitle.replace(new RegExp('\n', 'g'), '
').replace('

', '
')];
                //html.push(' Read More »');

                var thumbnails = [];

                var attachments = object.attachments || [];
                for (j = 0; j < attachments.length; j++) {
                    var attachment = attachments[j];
                    switch (attachment.objectType) {
                        case 'album':
                            break;// TODO needs more work
                            var upper = attachment.thumbnails.length > 7 ? 7 : attachment.thumbnails.length;
                            html.push('
');
                            for (var k = 1; k < upper; k++) {
                                html.push('

');
                            }
                            html.push('
');
                            break;
                        case 'photo':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.fullImage.url
                            });
                            break;

                        case 'video':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.url
                            });
                            break;

                        case 'article': case 'event':
                            html.push('
' + attachment.displayName + '');
                            if (attachment.content) {
                                html.push('
' + attachment.content + '');
                            }
                            html.push('
');
                            break;
                        /* case 'event':
                            console.log(attachment);
                            html.push('
' + attachment.displayName + '');
                            html.push('
' + attachment.content.replace(new RegExp('\n', 'g'), '
') + '
');
                            break; */
                        default :
                            console.log(attachment.objectType);
                    }
                }

                html = html.join('');

                var actorImage = actor.image.url;
                actorImage = actorImage.substr(0, actorImage.length - 2) + '16';
                // The replace in the item URL is a dirty quick fix for issue #20 which seems to be a g+ api bug
                var entry = {
                    via: {
                        name: 'Google+',
                        url: item.url.replace('https://plus.google.com/https://plus.google.com', 'https://plus.google.com')
                    },
                    body: html,
                    date: item.updated,
                    reshares: (object.resharers || {}).totalItems,
                    plusones: (object.plusoners || {}).totalItems,
                    comments: (object.replies || {}).totalItems,
                    thumbnails: thumbnails,
                    icon: actorImage
                };

                entries.push(entry);
            }
            $scope.news = entries;
            $timeout(function () {
                gapi.plusone.go();
            });
            $scope.loading = false;
        });

});

boomerang.controller("EventsControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "events";

    $scope.events = {past: [], future: []};
    $http.get("http://gdgfresno.com/gdgfeed.php?id=" + Config.id).
        success(function (data) {
            var now = new Date();
            for (var i = data.length - 1; i >= 0; i--) {
                var start = new Date(data[i].start);

                data[i].start = start;
                data[i].end = new Date(data[i].end);

                if (start < now) {
                    $scope.events.past.push(data[i]);
                } else {
                    $scope.events.future.push(data[i]);
                }
            }
            $scope.loading = false;
        });

});

boomerang.controller("PhotosControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "photos";
    $scope.photos = [];

    var pwa = 'https://picasaweb.google.com/data/feed/api/user/' + Config.id + '/albumid/' + Config.pwa_id +
        '?access=public&alt=json-in-script&kind=photo&max-results=20&fields=entry(title,link/@href,summary,content/@src)&v=2.0&callback=JSON_CALLBACK';

    $http.jsonp(pwa).
        success(function (d) {
            var p = d.feed.entry;
            for (var x in p) {
                var photo = {
                    link: p[x].link[1].href,
                    src: p[x].content.src,
                    alt: p[x].title.$t,
                    title: p[x].summary.$t
                };
                $scope.photos.push(photo);
            }
            $scope.loading = false;
        });
});

// HTML-ified linky from http://plnkr.co/edit/IEpLfZ8gO2B9mJcTKuWY?p=preview
boomerang.filter('htmlLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var linkify = function linkify(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    linkify(currentNode);
                    break;
                case TEXT_NODE:
                    linkifiedDOM.innerHTML = linkyFilter(currentNode.textContent);
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length)
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);

                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return linkify(inputDOM).innerHTML;
    };
});

boomerang.filter('hashLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var hashLinky = function hashLinky(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    hashLinky(currentNode);
                    break;
                case TEXT_NODE:
                    var hashtagRegex = /#([A-Za-z0-9-_]+)/g;
                    currentNode.textContent =  currentNode.textContent.replace(hashtagRegex,
                        '#$1');

                    linkifiedDOM.innerHTML = currentNode.textContent;
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length) {
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);
                    }
                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return hashLinky(inputDOM).innerHTML;
    };
});
<commit_msg>clean up white spacing<commit_after>var boomerang = angular.module('gdgBoomerang', ['ngSanitize', 'ui.bootstrap'])
    .config([
    '$httpProvider',
    '$interpolateProvider',
    '$routeProvider',
    function($httpProvider, $interpolateProvider, $routeProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        $routeProvider.
          when("/about", {templateUrl: 'views/about.html', controller: "AboutControl"}).
          when("/news", {templateUrl: 'views/news.html', controller: "NewsControl"}).
          when("/events", {templateUrl: 'views/events.html', controller: "EventsControl"}).
          when("/photos", {templateUrl: 'views/photos.html', controller: "PhotosControl"}).
          otherwise({ redirectTo: '/about' });
    }]);

boomerang.controller('MainControl', function ($scope, Config) {
    $scope.chapter_name = Config.name;
    $scope.chapter_id = Config.id;
    $scope.site_link = 'http://' + angular.lowercase(Config.name.replace(new RegExp(' ', 'g'), '')) + '.appspot.com';
    $scope.google_plus_link = 'https://plus.google.com/' + Config.id;
    $scope.isNavCollapsed = true;
});

boomerang.controller('AboutControl', function ($scope, $http, $location, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "about";
    $scope.cover = Config.cover;
    $http.jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '?callback=JSON_CALLBACK&fields=aboutMe%2Ccover%2Cimage%2CplusOneCount&key=' + Config.google_api).
        success(function (data) {
            console.log(data);
            $scope.desc = data.aboutMe;
            if (data.cover && data.cover.coverPhoto.url) {
                $scope.cover.url = data.cover.coverPhoto.url;
            }
            $scope.loading = false;
        });
});

boomerang.controller("NewsControl", function ($scope, $http, $timeout, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "news";
    $http.
        jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '/activities/public?callback=JSON_CALLBACK&maxResults=10&key=' + Config.google_api).
        success(function (response) {
            var entries = [], i, j;
            for (i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var actor = item.actor || {};
                var object = item.object || {};
                // Normalize tweet to a FriendFeed-like entry.
                // var itemTitle = '' + item.title + '';
                var itemTitle = object.content;

                if(item.annotation)
                  itemTitle = item.annotation;

                var html = [itemTitle.replace(new RegExp('\n', 'g'), '
').replace('

', '
')];
                //html.push(' Read More »');

                var thumbnails = [];

                var attachments = object.attachments || [];
                for (j = 0; j < attachments.length; j++) {
                    var attachment = attachments[j];
                    switch (attachment.objectType) {
                        case 'album':
                            break;// TODO needs more work
                            var upper = attachment.thumbnails.length > 7 ? 7 : attachment.thumbnails.length;
                            html.push('
');
                            for (var k = 1; k < upper; k++) {
                                html.push('

');
                            }
                            html.push('
');
                            break;
                        case 'photo':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.fullImage.url
                            });
                            break;
                        case 'video':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.url
                            });
                            break;
                        case 'article': case 'event':
                            html.push('
' + attachment.displayName + '');
                            if (attachment.content) {
                                html.push('
' + attachment.content + '');
                            }
                            html.push('
');
                            break;
                        /* case 'event':
                            console.log(attachment);
                            html.push('
' + attachment.displayName + '');
                            html.push('
' + attachment.content.replace(new RegExp('\n', 'g'), '
') + '
');
                            break; */
                        default :
                            console.log(attachment.objectType);
                    }
                }

                html = html.join('');

                var actorImage = actor.image.url;
                actorImage = actorImage.substr(0, actorImage.length - 2) + '16';
                // The replace in the item URL is a dirty quick fix for issue #20 which seems to be a g+ api bug
                var entry = {
                    via: {
                        name: 'Google+',
                        url: item.url.replace('https://plus.google.com/https://plus.google.com', 'https://plus.google.com')
                    },
                    body: html,
                    date: item.updated,
                    reshares: (object.resharers || {}).totalItems,
                    plusones: (object.plusoners || {}).totalItems,
                    comments: (object.replies || {}).totalItems,
                    thumbnails: thumbnails,
                    icon: actorImage
                };

                entries.push(entry);
            }
            $scope.news = entries;
            $timeout(function () {
                gapi.plusone.go();
            });
            $scope.loading = false;
        });
});

boomerang.controller("EventsControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "events";
    $scope.events = {past: [], future: []};
    $http.get("http://gdgfresno.com/gdgfeed.php?id=" + Config.id).
        success(function (data) {
            var now = new Date();
            for (var i = data.length - 1; i >= 0; i--) {
                var start = new Date(data[i].start);

                data[i].start = start;
                data[i].end = new Date(data[i].end);

                if (start < now) {
                    $scope.events.past.push(data[i]);
                } else {
                    $scope.events.future.push(data[i]);
                }
            }
            $scope.loading = false;
        });
});

boomerang.controller("PhotosControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "photos";
    $scope.photos = [];

    var pwa = 'https://picasaweb.google.com/data/feed/api/user/' + Config.id + '/albumid/' + Config.pwa_id +
        '?access=public&alt=json-in-script&kind=photo&max-results=20&fields=entry(title,link/@href,summary,content/@src)&v=2.0&callback=JSON_CALLBACK';

    $http.jsonp(pwa).
        success(function (d) {
            var p = d.feed.entry;
            for (var x in p) {
                var photo = {
                    link: p[x].link[1].href,
                    src: p[x].content.src,
                    alt: p[x].title.$t,
                    title: p[x].summary.$t
                };
                $scope.photos.push(photo);
            }
            $scope.loading = false;
        });
});

// HTML-ified linky from http://plnkr.co/edit/IEpLfZ8gO2B9mJcTKuWY?p=preview
boomerang.filter('htmlLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var linkify = function linkify(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    linkify(currentNode);
                    break;
                case TEXT_NODE:
                    linkifiedDOM.innerHTML = linkyFilter(currentNode.textContent);
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length)
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);

                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return linkify(inputDOM).innerHTML;
    };
});

boomerang.filter('hashLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var hashLinky = function hashLinky(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    hashLinky(currentNode);
                    break;
                case TEXT_NODE:
                    var hashtagRegex = /#([A-Za-z0-9-_]+)/g;
                    currentNode.textContent =  currentNode.textContent.replace(hashtagRegex,
                        '#$1');

                    linkifiedDOM.innerHTML = currentNode.textContent;
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length) {
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);
                    }
                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return hashLinky(inputDOM).innerHTML;
    };
});
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var Select = require('rc-select');
var Option = Select.Option;
require('rc-select/assets/index.css');
var children = [];
for (var i = 10; i < 36; i++) {
  children.push(<Option value={i.toString(36) + i}>{i.toString(36) + i}</Option>);
}

function handleChange(value) {
  console.log('selected ' + value);
}

var style = '.rc-select-menu {max-height:200px;overflow:auto;}';

var c2 = (

multiple select（scroll the menu）

      <Select
        style={{width:500}}
        multiple
        value={['name2', 'name3']}
        onChange={handleChange}>
    {children}
      </Select>

);

React.render(c2, document.getElementById('__react-content'));
<commit_msg>update examples<commit_after>'use strict';

var React = require('react');
var Select = require('rc-select');
var Option = Select.Option;
require('rc-select/assets/index.css');
var children = [];
for (var i = 10; i < 36; i++) {
  children.push(<Option value={i.toString(36) + i} key={i.toString(36) + i}>{i.toString(36) + i}</Option>);
}

function handleChange(value) {
  console.log('selected ' + value);
}

var style = '.rc-select-menu {max-height:200px;overflow:auto;}';

var c2 = (

multiple select（scroll the menu）

      <Select
        style={{width:500}}
        multiple
        value={['name2', 'name3']}
        onChange={handleChange}>
    {children}
      </Select>

);

React.render(c2, document.getElementById('__react-content'));
<|endoftext|>


<commit_before>define(['App', 'views/view', 'text!templates/lead/form.html'], function(App, BaseView, tmpl) {

  var View = {
    tagName     : 'div',
    className   : 'four columns',
    id          : 'lead-form',

    tmpl        : tmpl,
    editMode    : false,

    events : {
      'click .submit': 'submitLead',
      'click .cancel': 'cancelEdit'
    },

    getFormData : function() {
      var formData = {};

      $.each($('#lead-add input[type=text]'), function(key, input){
        formData[$(input).attr('placeholder')] = $(input).val();
      });

      return formData;
    },

    submitLead : function(e) {
      var formData = this.getFormData();

      if(this.editMode) {
        var model = this.collection.get(this.getFormId());

        if(!_.isEmpty(model)) {
          model.save(formData, {
            success: _.bind(this.addSuccessCallback, this)
          });
        }
      }
      else {
        this.collection.create(
          formData,
          {
            silent: true,
            wait  : false,
            success : _.bind(this.addSuccessCallback, this),
            error   : _.bind(this.addErrorCallback, this)
          }
        );
      }

      return false;
    },

    addErrorCallback : function(collection, response) {
      var objResponse = JSON.parse(response.responseText);

      if(!_.isUndefined(objResponse.errors)) {
        this.cleanErrors();
        this.showErrors(objResponse.errors);
      }
    },

    showErrors : function(errors) {
      for(var i in errors) {
        var small = '' + errors[i] + '';
        $('input[name=' + i + ']').addClass('error').after(small);
        $('small.error').fadeIn('normal');
      }
    },

    cleanForm : function() {
      $('#lead-add input, #lead-add textarea').not('[type=submit]').val('');
    },

    addSuccessCallback : function(collection, response) {
      this.cleanErrors();
      this.cleanForm();

      App.vent.trigger('layout:message', { type: "success", message : 'Lead added!'});
      App.vent.trigger('lead:add');
    },

    cleanErrors : function() {
      $('small.error').remove();
      $('input.error').removeClass('error');
    },

    customRender: function() {
      $.get(this.options.url.api + 'get/form/lead/', _.bind(function(response) {
        response = JSON.parse(response).form;
        this.$el.append(this.getHtml(response));
      }, this));
    },

    getCsfrToken: function() {
      $.get(this.options.url.api + 'get/token/', function(response) {
        this.token = response.token;
      });
    },

    setInputData : function(model, key, input){
        var value = model.get($(input).attr('name'));
        $(input).val(this.formatInputValue(input, value));
    },

    setFormData : function(model) {
      $.each(
        $('#lead-add input, #lead-add textarea').not('[type=submit]'),
        _.bind(this.setInputData, this, model)
      );
    },

    formatInputValue : function(input, value) {
      if(!_.isEmpty($(input).attr('data-format'))) {
        value = moment(value).calendar();
      }

      return value;
    },

    editMode : function(model) {
      this.editMode = true;

      this.setEditId(model.get('id'));

      this.setFormData(model);
      this.setButtons();
    },

    getEditId : function() {
      return $('#lead-add').attr('data-lead-id');
    },

    setEditId : function(id) {
      $('#lead-add').attr('data-lead-id', (_.isUndefined(id) ? '' : id ));
    },

    setButtons : function() {
      $('#lead-add .button.cancel')[(this.editMode) ? 'show' : 'hide']();
      $('#lead-add .button.submit').val(((this.editMode) ? 'Edit' : 'Create new') + ' LEAD');
    },

    cancelEdit : function() {
      this.editMode = false;

      this.cleanForm();
      this.cleanErrors();

      this.setEditId();

      this.setButtons();

      return false;
    },

    initialize: function(options) {
      console.log('LeadFormView::initialize');

      App.vent.on('lead:edit', _.bind(this.editMode, this) );

      this.options = options;
      this.getCsfrToken();
    }
  };

  var LeadFormView = Backbone.View.extend(_.extend(View, new BaseView()));

  return LeadFormView;
});<commit_msg>small quick fixes after form.js refactoring<commit_after>define(['App', 'views/view', 'text!templates/lead/form.html'], function(App, BaseView, tmpl) {

  var View = {
    tagName     : 'div',
    className   : 'four columns',
    id          : 'lead-form',

    tmpl          : tmpl,
    isEditMode    : false,

    events : {
      'click input.submit' : 'submitLead',
      'click input.cancel'  : 'cancelEdit'
    },

    getFormData : function() {
      var formData = {};

      $.each($('#lead-add input[type=text]'), function(key, input){
        formData[$(input).attr('placeholder')] = $(input).val();
      });

      return formData;
    },

    submitLead : function(e) {
      e.preventDefault();

      var formData = this.getFormData();

      if(this.isEditMode) {
        var model = this.collection.get(this.getEditId());

        if(!_.isEmpty(model)) {
          model.save(formData, {
            success: _.bind(this.addSuccessCallback, this)
          });
        }
      }
      else {
        this.collection.create(
          formData,
          {
            silent: true,
            wait  : false,
            success : _.bind(this.addSuccessCallback, this),
            error   : _.bind(this.addErrorCallback, this)
          }
        );
      }

      return false;
    },

    addErrorCallback : function(collection, response) {
      var objResponse = JSON.parse(response.responseText);

      if(!_.isUndefined(objResponse.errors)) {
        this.cleanErrors();
        this.showErrors(objResponse.errors);
      }
    },

    showErrors : function(errors) {
      for(var i in errors) {
        var   attr  = '[name=' + i + ']'
            , small = '' + errors[i] + ''
            ;

        $('input, textarea').filter(attr).addClass('error').after(small);
        $('small.error').fadeIn('normal');
      }
    },

    cleanForm : function() {
      $('#lead-add input, #lead-add textarea').not('[type=submit]').val('');
    },

    addSuccessCallback : function(collection, response) {
      this.cleanErrors();
      this.cleanForm();

      App.vent.trigger('layout:message', { type: "success", message : 'Lead added!'});
      App.vent.trigger('lead:add');
    },

    cleanErrors : function() {
      $('small.error').remove();
      $('#lead-add input, #lead-add textarea').filter('.error').removeClass('error');
    },

    customRender: function() {
      $.get(this.options.url.api + 'get/form/lead/', _.bind(function(response) {
        response = JSON.parse(response).form;
        this.$el.append(this.getHtml(response));
      }, this));
    },

    getCsfrToken: function() {
      $.get(this.options.url.api + 'get/token/', function(response) {
        this.token = response.token;
      });
    },

    setInputData : function(model, key, input){
        var value = model.get($(input).attr('name'));
        $(input).val(this.formatInputValue(input, value));
    },

    setFormData : function(model) {
      $.each(
        $('#lead-add input, #lead-add textarea').not('[type=submit]'),
        _.bind(this.setInputData, this, model)
      );
    },

    formatInputValue : function(input, value) {
      if(!_.isEmpty($(input).attr('data-format'))) {
        value = moment(value).calendar();
      }

      return value;
    },

    setEditMode : function(model) {
      this.isEditMode = true;

      this.cleanErrors();
      this.setEditId(model.get('id'));

      this.setFormData(model);
      this.setButtons();
    },

    getEditId : function() {
      return $('#lead-add').attr('data-lead-id');
    },

    setEditId : function(id) {
      $('#lead-add').attr('data-lead-id', (_.isUndefined(id) ? '' : id ));
    },

    setButtons : function() {
      $('#lead-add .button.cancel')[(this.isEditMode) ? 'show' : 'hide']();
      $('#lead-add .button.submit').val(((this.isEditMode) ? 'Edit' : 'Create new') + ' LEAD');
    },

    cancelEdit : function() {
      this.isEditMode = false;

      this.cleanForm();
      this.cleanErrors();

      this.setEditId();

      this.setButtons();

      return false;
    },

    initialize: function(options) {
      console.log('LeadFormView::initialize');

      App.vent.on('lead:edit', _.bind(this.setEditMode, this) );

      this.options = options;
      this.getCsfrToken();
    }
  };

  var LeadFormView = Backbone.View.extend(_.extend(View, new BaseView()));

  return LeadFormView;
});<|endoftext|>


<commit_before>function cited(text) {
    return Citation.find(text, {
        context: {
            dc_code: {
                source: 'dc_code'
            }
        },
        excerpt: 15,
        types: ['dc_code', 'dc_register', 'dc_law', 'law', 'stat'],
        replace: {
            dc_code: codeCited,
            law: lawCited,
            dc_register: dcrCited,
            stat: statCited,
            dc_law: dcLawCited
        }
    }).text;

    function linked(url, text) {
        return "" + text + "";
    }

    function noted(note, text) {
        note = note.replace(/\"/g, """);
        return "" + text + "";
    }

    // The detected citation is a DC "Law" - a slip law number, assigned
    // to an act after it becomes law.
    //
    // However, DC's legislative portal, LIMS, does not know law numbers,
    // only act numbers. @vdavez and @adamturoff created a crosswalk between
    // the two.
    //
    // The crosswalk is a JSON object, loaded into the global namespace as "dc_laws".
    // At cite time, this function does a quick lookup in that crosswalk and links
    // the user to the act which became the cited law.
    function dcLawCited(cite) {
        var lawNumber = cite.dc_law.period + "-" + cite.dc_law.number;
        var prefixedLawNumber = cite.dc_law.period + "-" + zeroPrefix(cite.dc_law.number, 3);

        var billNumber = dc_laws[prefixedLawNumber];

        // we don't have bill numbers for periods < 15
        if (!billNumber)
            return noted("We can only link to DC laws from Council Period 15 onwards.", cite.match);

        var pieces = billNumber.split("-");
        billNumber = pieces[0] + "-" + zeroPrefix(pieces[1], 4);
        console.log(billNumber);

        var text = "D.C. Law " + lawNumber;
        var url = "http://dcclims1.dccouncil.us/lims/legislation.aspx?LegNo=B" + billNumber;
        return linked(url, text);
    }

    function statCited(cite) {
        if (parseInt(cite.stat.volume, 10) < 65)
            return noted("We can only link to US statutes from 1951 (Vol 65) onwards.", cite.match);

        return linked('http://api.fdsys.gov/link?collection=statute&volume=' + cite.stat.volume + '&page=' + cite.stat.page,
            cite.match);
    }

    // is this a current DC Code cite (something we should cross-link),
    // or is it to a prior version of the DC Code?
    function codeCited(cite) {
        var match = /(1981|1973)\s+Ed\.?\,?/i.exec(cite.excerpt);
        if (match && match.index > 0 && match.index < 15) // found, and to the left of the cite
            return noted("We can only link to current versions of the DC Code (not the " + match[1] + " Edition).", cite.match);

        return linked("#/" + cite.dc_code.title + "/" + cite.dc_code.title + "-" + cite.dc_code.section,
            cite.match);
    }

    function lawCited(cite) {
        var lawName = cite.law.type + " law " + cite.law.congress + "-" + cite.law.number;
        var url = 'http://www.govtrack.us/search?q=' + encodeURIComponent(lawName);
        return linked(url, cite.match);
    }

    // just link to that year's copy on the DC Register website
    function dcrCited(cite) {
        if (parseInt(cite.dc_register.volume, 10) < 57)
            return noted("We can only link to the DC Register from 2010 (Vol. 57) onwards.", cite.match);

        var year = parseInt(cite.dc_register.volume, 10) + 1953;
        return linked('http://www.dcregs.dc.gov/Gateway/IssueList.aspx?IssueYear=' + year,
            cite.match);
    }

    // utils

    // what in Ruby would be:
    // "0" * 5 => "00000"
    function repeated(num, string) {
        return new Array(num + 1).join(string);
    }

    // handles a max of 4
    function zeroPrefix(number, zeroes) {
        number = parseInt(number); // strip off any existing leading zeroes

        var toAdd;
        if (number < 10)
            toAdd = zeroes - 1;
        else if (number < 100)
            toAdd = zeroes - 2;
        else if (number < 1000)
            toAdd = zeroes - 3;
        else
            toAdd = zeroes - 4;

        if (toAdd < 0) toAdd = 0;

        return repeated(toAdd, "0") + number;
    }
}
<commit_msg>I am a terrible person<commit_after>function cited(text) {
    return Citation.find(text, {
        context: {
            dc_code: {
                source: 'dc_code'
            }
        },
        excerpt: 15,
        types: ['dc_code', 'dc_register', 'dc_law', 'law', 'stat'],
        replace: {
            dc_code: codeCited,
            law: lawCited,
            dc_register: dcrCited,
            stat: statCited,
            dc_law: dcLawCited
        }
    }).text;

    function linked(url, text) {
        return "" + text + "";
    }

    function noted(note, text) {
        note = note.replace(/\"/g, """);
        return "" + text + "";
    }

    // The detected citation is a DC "Law" - a slip law number, assigned
    // to an act after it becomes law.
    //
    // However, DC's legislative portal, LIMS, does not know law numbers,
    // only act numbers. @vdavez and @adamturoff created a crosswalk between
    // the two.
    //
    // The crosswalk is a JSON object, loaded into the global namespace as "dc_laws".
    // At cite time, this function does a quick lookup in that crosswalk and links
    // the user to the act which became the cited law.
    function dcLawCited(cite) {
        var lawNumber = cite.dc_law.period + "-" + cite.dc_law.number;
        var prefixedLawNumber = cite.dc_law.period + "-" + zeroPrefix(cite.dc_law.number, 3);

        var billNumber = dc_laws[prefixedLawNumber];

        // we don't have bill numbers for periods < 15
        if (!billNumber)
            return noted("We can only link to DC laws from Council Period 15 onwards.", cite.match);

        var pieces = billNumber.split("-");
        billNumber = pieces[0] + "-" + zeroPrefix(pieces[1], 4);

        var text = "D.C. Law " + lawNumber;
        var url = "http://dcclims1.dccouncil.us/lims/legislation.aspx?LegNo=B" + billNumber;
        return linked(url, text);
    }

    function statCited(cite) {
        if (parseInt(cite.stat.volume, 10) < 65)
            return noted("We can only link to US statutes from 1951 (Vol 65) onwards.", cite.match);

        return linked('http://api.fdsys.gov/link?collection=statute&volume=' + cite.stat.volume + '&page=' + cite.stat.page,
            cite.match);
    }

    // is this a current DC Code cite (something we should cross-link),
    // or is it to a prior version of the DC Code?
    function codeCited(cite) {
        var match = /(1981|1973)\s+Ed\.?\,?/i.exec(cite.excerpt);
        if (match && match.index > 0 && match.index < 15) // found, and to the left of the cite
            return noted("We can only link to current versions of the DC Code (not the " + match[1] + " Edition).", cite.match);

        return linked("#/" + cite.dc_code.title + "/" + cite.dc_code.title + "-" + cite.dc_code.section,
            cite.match);
    }

    function lawCited(cite) {
        var lawName = cite.law.type + " law " + cite.law.congress + "-" + cite.law.number;
        var url = 'http://www.govtrack.us/search?q=' + encodeURIComponent(lawName);
        return linked(url, cite.match);
    }

    // just link to that year's copy on the DC Register website
    function dcrCited(cite) {
        if (parseInt(cite.dc_register.volume, 10) < 57)
            return noted("We can only link to the DC Register from 2010 (Vol. 57) onwards.", cite.match);

        var year = parseInt(cite.dc_register.volume, 10) + 1953;
        return linked('http://www.dcregs.dc.gov/Gateway/IssueList.aspx?IssueYear=' + year,
            cite.match);
    }

    // utils

    // what in Ruby would be:
    // "0" * 5 => "00000"
    function repeated(num, string) {
        return new Array(num + 1).join(string);
    }

    // handles a max of 4
    function zeroPrefix(number, zeroes) {
        number = parseInt(number); // strip off any existing leading zeroes

        var toAdd;
        if (number < 10)
            toAdd = zeroes - 1;
        else if (number < 100)
            toAdd = zeroes - 2;
        else if (number < 1000)
            toAdd = zeroes - 3;
        else
            toAdd = zeroes - 4;

        if (toAdd < 0) toAdd = 0;

        return repeated(toAdd, "0") + number;
    }
}
<|endoftext|>


<commit_before>(function($, cb){
    var settings = {
        api_url: "https://api.cloudmine.me",
        app_id: null,
        api_key: null
    };

    var merge = function(to, from1, from2){
        var from_list = [from1 || {}, from2 || {}];
        for(var from in from_list){
            if(from_list.hasOwnProperty(from)){
                from = from_list[from];
                if(from){
                    for(var key in from){
                        if(from.hasOwnProperty(key)){
                            to[key] = from[key];
                        }
                    }
                }
            }
        }
        return to;
    };

    var forEach = function(fn){
        $.each(this, function(key, value){
            if( value !== forEach )
                fn(key, value);
        });
    };

    var build_url = function(opts, postfix){
        var user = opts.user ? "/user" : "";
        return opts.api_url + "/v1/app/" + opts.app_id + user + "/" + postfix;
    };

    var qs = {
        stringify: function(data){
            var ret = [];
            for (var d in data){
                if(data.hasOwnProperty(d)){
                    ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
                }
            }
            return ret.join("&");
        }
    };

    var append_to_url = function(url, params){
        if(!url) return url;

        var sep = (url.indexOf("?") > -1) ? "&" : "?";
        url += sep + qs.stringify(params);

        return url;
    };

    /**
     * Applies server-side code and paging params to the given URL
     */
    var apply_params = function(url, opts){
        var params = {};
        var valid_params = ["f", "count", "skip", "limit"];
        var param;
        for(var index in valid_params){
            if(valid_params.hasOwnProperty(index)){
                param = valid_params[index];
                if(opts[param] !== undefined){
                    params[param] = opts[param];
                }
            }
        }

        return append_to_url(url, params);
    };

    var get_auth = function(user){
        return user ?
            'Basic ' + cm.Base64.encode(user.username + ':' + user.password)
            : undefined;
    }

    var cm = {
        /**
         * Initialize the library with the APPID and API Key
         *
         * Parameter: opts
         *     An object with the following keys:
         *       app_id:  The app id
         *       api_key: The API key
         */
        init: function(opts){
            settings = merge({}, settings, opts);
        },

        /**
         * Set (overwrite) new values for provided keys.
         *
         * Parameter: values
         *     An object of key/value pairs.  The keys in this object are
         *     the top-level keys in the CloudMine API.
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, usero
         *     And to specify extension parameters: f, limit, count, etc.
         */
        setValues: function(values, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "text");

            url = apply_params(url, opts);

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                processData: false,
                type: opts.method || 'POST',
                contentType: 'application/json',
                data: JSON.stringify(values),
                success: callback
            });
        },

        /**
         * Update the value for a single key
         *
         * Parameter: key
         *     The key for the value to update
         *
         * Parameter: value
         *     The object with the updated data
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        updateValue: function(key, value, callback, opts){
            var data = {};
            data[key] = value;
            cm.setValues(data, callback, merge(opts || {}, {method: "POST"}));
        },

        /**
         * Sets the value for a single key
         *
         * Parameter: key
         *     The key for the value to update
         *
         * Parameter: value
         *     The object with the data to set
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        setValue: function(key, value, callback, opts){
            var data = {};
            data[key] = value;
            cm.setValues(data, callback, merge(opts || {}, {method: "PUT"}));
        },

        /**
         * Gets key/value pairs for the specified keys
         *
         * Parameter: keys
         *     An array of key names to get.  Can be set to null to get all data.
         *
         * Parameter: callbacks
         *     Either a function that will be called with an object of succesfully
         *     retreived key/value pairs that match the request or an object
         *     with 'success' and 'errors' callback functions.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        getValues: function(keys, callbacks, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "text");

            if(keys){
                url = append_to_url(url, {keys: keys.join(",")});
            }

            url = apply_params(url, opts);

            if( typeof(callbacks) == "function" ){
                callbacks = { success: callbacks };
            }

            var callback_wrapper = callbacks && function(data){
                // data has .success and .errors
                if(data.success){
                    if(!data.success.forEach){
                        merge(data.success, {forEach: forEach});
                    }

                    callbacks.success(data.success);
                };

                if(callbacks.error){
                    if(!data.errors.forEach){
                        merge(data.errors, {forEach: forEach});
                    }
                    callbacks.error(data.errors);
                };
            };

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                success: callback_wrapper
            });
        },

        /**
         * DEPRECATED!  Use deleteKeys instead!
         *
         * Deletes specified key/value pairs
         *
         * Parameter: callback
         *     Gets called when the request returns.
         *
         * Parameter: keys
         *     An array of key names to delete.  Can be set to null to delete all data.
         */
        deleteValues: function(callback, keys, opts){
            return cm.deleteKeys(keys, callback, opts);
        },

        /**
         * Deletes specified key/value pairs
         *
         * Parameter: callback
         *     Gets called when the request returns.
         *
         * Parameter: keys
         *     An array of key names to delete.  Can be set to null to delete all data.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        deleteKeys: function(keys, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "data");

            if(keys){
                url = append_to_url(url, {keys: keys.join(",")});
            } else {
                url = append_to_url(url, {all: true});
            }

            url = apply_params(url, opts);

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                type: 'DELETE',
                success: callback
            });
        },

        /**
         * Performs a search query
         *
         * Parameter: query
         *     A string query. See API documentation for details.
         *   Examples:
         *        [type="student"]
         *        a.b[x > 5, x < 10]
         *
         * Parameter: callback
         *     A function that will be called with an object of succesfully
         *     retreived key/value pairs that match the query
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        search: function(query, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "search");

            if(query){
                url = append_to_url(url, {q: query});
            }

            url = apply_params(url, opts);

            var callback_wrapper = callback && function(data){
                // data has .success and .errors
                if(data.success && !data.success.forEach){
                    merge(data.success, {forEach: forEach});
                };

                if(data.errors && !data.errors.forEach){
                    merge(data.errors, {forEach: forEach});
                };

                callback(data);
            };

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                success: callback_wrapper
            });
        },

        /**
         * Verifies supplied user credentials
         *
         * Parameter: user
         *     An object with username and password to verify
         *
         * Parameter: callbacks
         *     An object with callbacks for various response scenarios:
         *     {
         *        valid: function(){...},  // called when the user credentials are valid
         *        created: function(){...}, // called when the user did not exist and was created
         *        unauthorized: function(){...}, // called when the user exists and credentials are invalid
         *        error: function(){...} // called on other errors: 400 and 404
         *     }
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         *
         * Returns: the composed URL
         */
        verifyUserAccount: function(user, callbacks, opts){
            opts = merge({user: user}, settings, opts);

            var url = build_url(opts, "account");

            callbacks = callbacks || {};

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                type: opts.method || 'POST',
                statusCode: {
                    200: callbacks.valid,
                    201: callbacks.created,
                    401: callbacks.unauthorized,
                    404: callbacks.error,
                    400: callbacks.error
                }
            });
        },

        /**
         * Builds and returns a URL for a file resource given its key
         *
         * Parameter: key
         *     A string key for the file resource.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         *
         * Returns: the composed URL
         */
        getFileURL: function(key, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "binary");

            url += "/" + key;

            // inline API key to fetch binary data
            url = append_to_url(url, {apikey: opts.api_key});

            return url;
        },

        log: function(msg){
            window.console && console.log(msg);
        }
    };

    // Base64 Library from http://www.webtoolkit.info
    cm.Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(a){var b="";var c,d,e,f,g,h,i;var j=0;a=cm.Base64._utf8_encode(a);while(j<a.length){c=a.charCodeAt(j++);d=a.charCodeAt(j++);e=a.charCodeAt(j++);f=c>>2;g=(c&3)<<4|d>>4;h=(d&15)<<2|e>>6;i=e&63;if(isNaN(d)){h=i=64}else if(isNaN(e)){i=64}b=b+this._keyStr.charAt(f)+this._keyStr.charAt(g)+this._keyStr.charAt(h)+this._keyStr.charAt(i)}return b},decode:function(a){var b="";var c,d,e;var f,g,h,i;var j=0;a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(j<a.length){f=this._keyStr.indexOf(a.charAt(j++));g=this._keyStr.indexOf(a.charAt(j++));h=this._keyStr.indexOf(a.charAt(j++));i=this._keyStr.indexOf(a.charAt(j++));c=f<<2|g>>4;d=(g&15)<<4|h>>2;e=(h&3)<<6|i;b=b+String.fromCharCode(c);if(h!=64){b=b+String.fromCharCode(d)}if(i!=64){b=b+String.fromCharCode(e)}}b=cm.Base64._utf8_decode(b);return b},_utf8_encode:function(a){a=a.replace(/\r\n/g,"\n");var b="";for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d)}else if(d>127&&d<2048){b+=String.fromCharCode(d>>6|192);b+=String.fromCharCode(d&63|128)}else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128);b+=String.fromCharCode(d&63|128)}}return b},_utf8_decode:function(a){var b="";var c=0;var d=c1=c2=0;while(c<a.length){d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d);c++}else if(d>191&&d<224){c2=a.charCodeAt(c+1);b+=String.fromCharCode((d&31)<<6|c2&63);c+=2}else{c2=a.charCodeAt(c+1);c3=a.charCodeAt(c+2);b+=String.fromCharCode((d&15)<<12|(c2&63)<<6|c3&63);c+=3}}return b}};

    cb && cb(cm);
})(jQuery, function(cm){
    window.cloudmine = cm;
});

<commit_msg>added "params" to valid params list<commit_after>(function($, cb){
    var settings = {
        api_url: "https://api.cloudmine.me",
        app_id: null,
        api_key: null
    };

    var merge = function(to, from1, from2){
        var from_list = [from1 || {}, from2 || {}];
        for(var from in from_list){
            if(from_list.hasOwnProperty(from)){
                from = from_list[from];
                if(from){
                    for(var key in from){
                        if(from.hasOwnProperty(key)){
                            to[key] = from[key];
                        }
                    }
                }
            }
        }
        return to;
    };

    var forEach = function(fn){
        $.each(this, function(key, value){
            if( value !== forEach )
                fn(key, value);
        });
    };

    var build_url = function(opts, postfix){
        var user = opts.user ? "/user" : "";
        return opts.api_url + "/v1/app/" + opts.app_id + user + "/" + postfix;
    };

    var qs = {
        stringify: function(data){
            var ret = [];
            for (var d in data){
                if(data.hasOwnProperty(d)){
                    ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
                }
            }
            return ret.join("&");
        }
    };

    var append_to_url = function(url, params){
        if(!url) return url;

        var sep = (url.indexOf("?") > -1) ? "&" : "?";
        url += sep + qs.stringify(params);

        return url;
    };

    /**
     * Applies server-side code and paging params to the given URL
     */
    var apply_params = function(url, opts){
        var params = {};
        var valid_params = ["f", "count", "skip", "limit", "params"];
        var param;
        for(var index in valid_params){
            if(valid_params.hasOwnProperty(index)){
                param = valid_params[index];
                if(opts[param] !== undefined){
                    params[param] = opts[param];
                }
            }
        }

        return append_to_url(url, params);
    };

    var get_auth = function(user){
        return user ?
            'Basic ' + cm.Base64.encode(user.username + ':' + user.password)
            : undefined;
    }

    var cm = {
        /**
         * Initialize the library with the APPID and API Key
         *
         * Parameter: opts
         *     An object with the following keys:
         *       app_id:  The app id
         *       api_key: The API key
         */
        init: function(opts){
            settings = merge({}, settings, opts);
        },

        /**
         * Set (overwrite) new values for provided keys.
         *
         * Parameter: values
         *     An object of key/value pairs.  The keys in this object are
         *     the top-level keys in the CloudMine API.
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, usero
         *     And to specify extension parameters: f, limit, count, etc.
         */
        setValues: function(values, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "text");

            url = apply_params(url, opts);

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                processData: false,
                type: opts.method || 'POST',
                contentType: 'application/json',
                data: JSON.stringify(values),
                success: callback
            });
        },

        /**
         * Update the value for a single key
         *
         * Parameter: key
         *     The key for the value to update
         *
         * Parameter: value
         *     The object with the updated data
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        updateValue: function(key, value, callback, opts){
            var data = {};
            data[key] = value;
            cm.setValues(data, callback, merge(opts || {}, {method: "POST"}));
        },

        /**
         * Sets the value for a single key
         *
         * Parameter: key
         *     The key for the value to update
         *
         * Parameter: value
         *     The object with the data to set
         *
         * Parameter: callback
         *     Gets called with the JSON response when the request returns.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        setValue: function(key, value, callback, opts){
            var data = {};
            data[key] = value;
            cm.setValues(data, callback, merge(opts || {}, {method: "PUT"}));
        },

        /**
         * Gets key/value pairs for the specified keys
         *
         * Parameter: keys
         *     An array of key names to get.  Can be set to null to get all data.
         *
         * Parameter: callbacks
         *     Either a function that will be called with an object of succesfully
         *     retreived key/value pairs that match the request or an object
         *     with 'success' and 'errors' callback functions.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        getValues: function(keys, callbacks, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "text");

            if(keys){
                url = append_to_url(url, {keys: keys.join(",")});
            }

            url = apply_params(url, opts);

            if( typeof(callbacks) == "function" ){
                callbacks = { success: callbacks };
            }

            var callback_wrapper = callbacks && function(data){
                // data has .success and .errors
                if(data.success){
                    if(!data.success.forEach){
                        merge(data.success, {forEach: forEach});
                    }

                    callbacks.success(data.success);
                };

                if(callbacks.error){
                    if(!data.errors.forEach){
                        merge(data.errors, {forEach: forEach});
                    }
                    callbacks.error(data.errors);
                };
            };

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                success: callback_wrapper
            });
        },

        /**
         * DEPRECATED!  Use deleteKeys instead!
         *
         * Deletes specified key/value pairs
         *
         * Parameter: callback
         *     Gets called when the request returns.
         *
         * Parameter: keys
         *     An array of key names to delete.  Can be set to null to delete all data.
         */
        deleteValues: function(callback, keys, opts){
            return cm.deleteKeys(keys, callback, opts);
        },

        /**
         * Deletes specified key/value pairs
         *
         * Parameter: callback
         *     Gets called when the request returns.
         *
         * Parameter: keys
         *     An array of key names to delete.  Can be set to null to delete all data.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        deleteKeys: function(keys, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "data");

            if(keys){
                url = append_to_url(url, {keys: keys.join(",")});
            } else {
                url = append_to_url(url, {all: true});
            }

            url = apply_params(url, opts);

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                type: 'DELETE',
                success: callback
            });
        },

        /**
         * Performs a search query
         *
         * Parameter: query
         *     A string query. See API documentation for details.
         *   Examples:
         *        [type="student"]
         *        a.b[x > 5, x < 10]
         *
         * Parameter: callback
         *     A function that will be called with an object of succesfully
         *     retreived key/value pairs that match the query
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         */
        search: function(query, callback, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "search");

            if(query){
                url = append_to_url(url, {q: query});
            }

            url = apply_params(url, opts);

            var callback_wrapper = callback && function(data){
                // data has .success and .errors
                if(data.success && !data.success.forEach){
                    merge(data.success, {forEach: forEach});
                };

                if(data.errors && !data.errors.forEach){
                    merge(data.errors, {forEach: forEach});
                };

                callback(data);
            };

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                dataType: 'json',
                success: callback_wrapper
            });
        },

        /**
         * Verifies supplied user credentials
         *
         * Parameter: user
         *     An object with username and password to verify
         *
         * Parameter: callbacks
         *     An object with callbacks for various response scenarios:
         *     {
         *        valid: function(){...},  // called when the user credentials are valid
         *        created: function(){...}, // called when the user did not exist and was created
         *        unauthorized: function(){...}, // called when the user exists and credentials are invalid
         *        error: function(){...} // called on other errors: 400 and 404
         *     }
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         *
         * Returns: the composed URL
         */
        verifyUserAccount: function(user, callbacks, opts){
            opts = merge({user: user}, settings, opts);

            var url = build_url(opts, "account");

            callbacks = callbacks || {};

            $.ajax(url, {
                headers: { 'X-CloudMine-ApiKey': opts.api_key,
                           'Authorization': get_auth(opts.user) },
                type: opts.method || 'POST',
                statusCode: {
                    200: callbacks.valid,
                    201: callbacks.created,
                    401: callbacks.unauthorized,
                    404: callbacks.error,
                    400: callbacks.error
                }
            });
        },

        /**
         * Builds and returns a URL for a file resource given its key
         *
         * Parameter: key
         *     A string key for the file resource.
         *
         * Parameter: opts
         *     An object with additional configuration options.
         *     Can be used to override: api_url, app_id, api_key, method, user
         *     And to specify extension parameters: f, limit, count, etc.
         *
         * Returns: the composed URL
         */
        getFileURL: function(key, opts){
            opts = merge({}, settings, opts);
            var url = build_url(opts, "binary");

            url += "/" + key;

            // inline API key to fetch binary data
            url = append_to_url(url, {apikey: opts.api_key});

            return url;
        },

        log: function(msg){
            window.console && console.log(msg);
        }
    };

    // Base64 Library from http://www.webtoolkit.info
    cm.Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(a){var b="";var c,d,e,f,g,h,i;var j=0;a=cm.Base64._utf8_encode(a);while(j<a.length){c=a.charCodeAt(j++);d=a.charCodeAt(j++);e=a.charCodeAt(j++);f=c>>2;g=(c&3)<<4|d>>4;h=(d&15)<<2|e>>6;i=e&63;if(isNaN(d)){h=i=64}else if(isNaN(e)){i=64}b=b+this._keyStr.charAt(f)+this._keyStr.charAt(g)+this._keyStr.charAt(h)+this._keyStr.charAt(i)}return b},decode:function(a){var b="";var c,d,e;var f,g,h,i;var j=0;a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(j<a.length){f=this._keyStr.indexOf(a.charAt(j++));g=this._keyStr.indexOf(a.charAt(j++));h=this._keyStr.indexOf(a.charAt(j++));i=this._keyStr.indexOf(a.charAt(j++));c=f<<2|g>>4;d=(g&15)<<4|h>>2;e=(h&3)<<6|i;b=b+String.fromCharCode(c);if(h!=64){b=b+String.fromCharCode(d)}if(i!=64){b=b+String.fromCharCode(e)}}b=cm.Base64._utf8_decode(b);return b},_utf8_encode:function(a){a=a.replace(/\r\n/g,"\n");var b="";for(var c=0;c<a.length;c++){var d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d)}else if(d>127&&d<2048){b+=String.fromCharCode(d>>6|192);b+=String.fromCharCode(d&63|128)}else{b+=String.fromCharCode(d>>12|224);b+=String.fromCharCode(d>>6&63|128);b+=String.fromCharCode(d&63|128)}}return b},_utf8_decode:function(a){var b="";var c=0;var d=c1=c2=0;while(c<a.length){d=a.charCodeAt(c);if(d<128){b+=String.fromCharCode(d);c++}else if(d>191&&d<224){c2=a.charCodeAt(c+1);b+=String.fromCharCode((d&31)<<6|c2&63);c+=2}else{c2=a.charCodeAt(c+1);c3=a.charCodeAt(c+2);b+=String.fromCharCode((d&15)<<12|(c2&63)<<6|c3&63);c+=3}}return b}};

    cb && cb(cm);
})(jQuery, function(cm){
    window.cloudmine = cm;
});

<|endoftext|>


<commit_before>function onOpen(e) {
  DocumentApp.getUi()
    .createMenu('Form Management')
    .addItem('Update Values in Form', 'updateValuesInForm')
    .addToUi();
}

var doc  = DocumentApp.getActiveDocument();
var body = doc.getBody();

var instruction = [
  "Social and Emotional and Approaches to Learning", "Mathematics",

]

// gaskit

function checkValIn(arr, val) {
	return arr.indexOf(val) > -1;
}

// action

function updateValuesInForm() {
  var tables = body.getTables();
  Logger.log(tables.length);

  for (var i = 0; i < tables.length; i++) {
    var table = tables[i].asTable();
    Logger.log(i);
    var rows   = table.getNumRows();
    var header = table.getRow(0).getCell(0).getChild(0).asParagraph().getText();
    Logger.log(header);

    if (checkValIn(instruction, header) && (rows >= 2)){
        var _arr = [];
        for (var i = 2; i < rows; i++) {
          var cell    = table.getRow(i).getCell(0);
          var content = cell.getChild(0).asParagraph().getText().trim();
          cell.setText(content);
           _arr.push(content);
        }
      // set values in form
      // index over _arr and set values in the form
      // Logger.log(header);
      // Logger.log(_arr);
    }
  }
}

function loop() {
  var tables = body.getTables();
  Logger.log(tables.length);
  for (var i = 0; i < tables.length; i++) {
    var table  = tables[i].asTable();
    var header = table.getRow(0).getCell(0).getChild(0).asParagraph().getText();
    var rows   = table.getNumRows();
    // var header = tables[i].getRow(0).getCell(0).getChild(0).asParagraph().getText();
    // var rows   = tables[i].getNumRows();
    Logger.log(i);
    Logger.log(header);
    Logger.log(rows);
  }
}

function getParagraphs() {
  var paragraphs = body.getParagraphs();
  for (var i = 0; i < paragraphs.length; i++) {
    var p = paragraphs[i].asParagraph().getText();
    if (p.length !== 0) {
      Logger.log(p);
    }
  }
}

<commit_msg>01/20/2017 Friday<commit_after><|endoftext|>